1 /* usn.c - Maintain Microsoft-style Update Sequence Numbers */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2007-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by Howard Chu for inclusion in
27 #include <ac/string.h>
28 #include <ac/socket.h>
33 /* This overlay intercepts write operations and adds a Microsoft-style
34 * USN to the target entry.
37 typedef struct usn_info {
39 ldap_pvt_thread_mutex_t ui_mutex;
42 static AttributeDescription *ad_usnCreated, *ad_usnChanged;
46 AttributeDescription **adp;
48 { "( 1.2.840.113556.1.2.19 "
50 "SYNTAX '1.2.840.113556.1.4.906' "
52 "NO-USER-MODIFICATION )",
54 { "( 1.2.840.113556.1.2.120 "
56 "SYNTAX '1.2.840.113556.1.4.906' "
58 "NO-USER-MODIFICATION )",
64 usn_func( Operation *op, SlapReply *rs )
66 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
67 usn_info_t *ui = on->on_bi.bi_private;
72 ldap_pvt_thread_mutex_lock( &ui->ui_mutex );
74 my_usn = ui->ui_current;
75 ldap_pvt_thread_mutex_unlock( &ui->ui_mutex );
78 bv[0].bv_val = intbuf;
79 bv[0].bv_len = snprintf( intbuf, sizeof(intbuf), "%d", my_usn );
82 attr_merge( op->ora_e, ad_usnCreated, bv, NULL );
83 attr_merge( op->ora_e, ad_usnChanged, bv, NULL );
86 /* Probably need to update root usnLastObjRem */
90 Modifications *ml, *mod = ch_calloc( sizeof( Modifications ), 1 );
91 for ( ml = op->orm_modlist; ml && ml->sml_next; ml = ml->sml_next );
93 mod->sml_desc = ad_usnChanged;
95 value_add_one( &mod->sml_values, &bv[0] );
96 mod->sml_nvalues = NULL;
97 mod->sml_op = LDAP_MOD_REPLACE;
103 return SLAP_CB_CONTINUE;
111 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
112 usn_info_t *ui = (usn_info_t *)on->on_bi.bi_private;
115 dn_match( &rs->sr_entry->e_nname, op->o_bd->be_nsuffix )) {
117 if ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
118 ad_inlist( ad_usnChanged, rs->sr_attrs )) {
119 Attribute *a, **ap = NULL;
124 for ( a=rs->sr_entry->e_attrs; a; a=a->a_next ) {
125 if ( a->a_desc == ad_usnChanged )
130 for ( ap = &rs->sr_operational_attrs; *ap;
133 a = attr_alloc( ad_usnChanged );
138 if ( !rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
139 rs->sr_entry = entry_dup( rs->sr_entry );
141 REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
142 a = attr_find( rs->sr_entry->e_attrs,
145 ber_bvarray_free( a->a_vals );
149 ldap_pvt_thread_mutex_lock( &ui->ui_mutex );
150 my_usn = ui->ui_current;
151 ldap_pvt_thread_mutex_unlock( &ui->ui_mutex );
152 bv.bv_len = snprintf( intbuf, sizeof(intbuf), "%d", my_usn );
154 attr_valadd( a, &bv, NULL, 1 );
157 return SLAP_CB_CONTINUE;
160 /* Read the old USN from the underlying DB. This code is
161 * stolen from the syncprov overlay.
168 slap_overinst *on = (slap_overinst *) be->bd_info;
169 usn_info_t *ui = (usn_info_t *)on->on_bi.bi_private;
171 Connection conn = { 0 };
172 OperationBuffer opbuf;
179 thrctx = ldap_pvt_thread_pool_context();
180 connection_fake_init( &conn, &opbuf, thrctx );
183 op->o_dn = be->be_rootdn;
184 op->o_ndn = be->be_rootndn;
186 rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
187 slap_schema.si_ad_contextCSN, 0, &e, on );
190 a = attr_find( e->e_attrs, ad_usnChanged );
192 ui->ui_current = atoi( a->a_vals[0].bv_val );
194 overlay_entry_release_ov( op, e, 0, on );
205 slap_overinst *on = (slap_overinst *)be->bd_info;
208 if ( SLAP_ISGLOBALOVERLAY( be ) ) {
209 Debug( LDAP_DEBUG_ANY,
210 "usn must be instantiated within a database.\n",
215 ui = ch_calloc(1, sizeof(usn_info_t));
216 ldap_pvt_thread_mutex_init( &ui->ui_mutex );
217 on->on_bi.bi_private = ui;
227 slap_overinst *on = (slap_overinst *)be->bd_info;
228 usn_info_t *ui = on->on_bi.bi_private;
229 Connection conn = {0};
230 OperationBuffer opbuf;
232 SlapReply rs = {REP_RESULT};
236 SlapReply rsm = { 0 };
237 slap_callback cb = {0};
241 thrctx = ldap_pvt_thread_pool_context();
242 connection_fake_init( &conn, &opbuf, thrctx );
245 BER_BVZERO( &bv[1] );
246 bv[0].bv_len = snprintf( intbuf, sizeof(intbuf), "%d", ui->ui_current );
247 bv[0].bv_val = intbuf;
250 mod.sml_nvalues = NULL;
251 mod.sml_desc = ad_usnChanged;
252 mod.sml_op = LDAP_MOD_REPLACE;
256 cb.sc_response = slap_null_cb;
257 op->o_tag = LDAP_REQ_MODIFY;
258 op->o_callback = &cb;
259 op->orm_modlist = &mod;
260 op->orm_no_opattrs = 1;
261 op->o_dn = be->be_rootdn;
262 op->o_ndn = be->be_rootndn;
263 op->o_req_dn = op->o_bd->be_suffix[0];
264 op->o_req_ndn = op->o_bd->be_nsuffix[0];
265 op->o_bd->bd_info = on->on_info->oi_orig;
266 op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
267 op->o_no_schema_check = 1;
268 op->o_bd->be_modify( op, &rs );
269 if ( mod.sml_next != NULL ) {
270 slap_mods_free( mod.sml_next, 1 );
281 slap_overinst *on = (slap_overinst *)be->bd_info;
282 usn_info_t *ui = on->on_bi.bi_private;
284 ldap_pvt_thread_mutex_destroy( &ui->ui_mutex );
286 on->on_bi.bi_private = NULL;
290 /* This overlay is set up for dynamic loading via moduleload. For static
291 * configuration, you'll need to arrange for the slap_overinst to be
292 * initialized and registered by some other function inside slapd.
295 static slap_overinst usn;
302 memset( &usn, 0, sizeof( slap_overinst ) );
303 usn.on_bi.bi_type = "usn";
304 usn.on_bi.bi_db_init = usn_db_init;
305 usn.on_bi.bi_db_destroy = usn_db_destroy;
306 usn.on_bi.bi_db_open = usn_db_open;
307 usn.on_bi.bi_db_close = usn_db_close;
309 usn.on_bi.bi_op_modify = usn_func;
310 usn.on_bi.bi_op_modrdn = usn_func;
311 usn.on_bi.bi_op_add = usn_func;
312 usn.on_bi.bi_op_delete = usn_func;
313 usn.on_bi.bi_operational = usn_operational;
315 for ( i = 0; as[i].desc; i++ ) {
316 code = register_at( as[i].desc, as[i].adp, 0 );
318 Debug( LDAP_DEBUG_ANY,
319 "usn_init: register_at #%d failed\n", i, 0, 0 );
323 return overlay_register( &usn );
326 #if SLAPD_OVER_USN == SLAPD_MOD_DYNAMIC
328 init_module( int argc, char *argv[] )
332 #endif /* SLAPD_OVER_USN == SLAPD_MOD_DYNAMIC */
334 #endif /* defined(SLAPD_OVER_USN) */