1 /* $NetBSD: dds.c,v 1.3 2021/08/14 16:15:02 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2005-2021 The OpenLDAP Foundation.
7 * Portions Copyright 2005-2006 SysNet s.n.c.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18 /* ACKNOWLEDGEMENTS:
19 * This work was initially developed by Pierangelo Masarati for inclusion
20 * in OpenLDAP Software, sponsored by SysNet s.n.c.
21 */
22
23 #include <sys/cdefs.h>
24 __RCSID("$NetBSD: dds.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
25
26 #include "portable.h"
27
28 #ifdef SLAPD_OVER_DDS
29
30 #include <stdio.h>
31
32 #include <ac/string.h>
33 #include <ac/time.h>
34
35 #include "slap.h"
36 #include "lutil.h"
37 #include "ldap_rq.h"
38
39 #include "slap-config.h"
40
41 #define DDS_RF2589_MAX_TTL (31557600) /* 1 year + 6 hours */
42 #define DDS_RF2589_DEFAULT_TTL (86400) /* 1 day */
43 #define DDS_DEFAULT_INTERVAL (3600) /* 1 hour */
44
45 typedef struct dds_info_t {
46 unsigned di_flags;
47 #define DDS_FOFF (0x1U) /* is this really needed? */
48 #define DDS_SET(di, f) ( (di)->di_flags & (f) )
49
50 #define DDS_OFF(di) DDS_SET( (di), DDS_FOFF )
51
52 time_t di_max_ttl;
53 time_t di_min_ttl;
54 time_t di_default_ttl;
55 #define DDS_DEFAULT_TTL(di) \
56 ( (di)->di_default_ttl ? (di)->di_default_ttl : (di)->di_max_ttl )
57
58 time_t di_tolerance;
59
60 /* expire check interval and task */
61 time_t di_interval;
62 #define DDS_INTERVAL(di) \
63 ( (di)->di_interval ? (di)->di_interval : DDS_DEFAULT_INTERVAL )
64 struct re_s *di_expire_task;
65
66 /* allows to limit the maximum number of dynamic objects */
67 ldap_pvt_thread_mutex_t di_mutex;
68 int di_num_dynamicObjects;
69 int di_max_dynamicObjects;
70
71 /* used to advertise the dynamicSubtrees in the root DSE,
72 * and to select the database in the expiration task */
73 BerVarray di_suffix;
74 BerVarray di_nsuffix;
75 } dds_info_t;
76
77 static struct berval slap_EXOP_REFRESH = BER_BVC( LDAP_EXOP_REFRESH );
78 static AttributeDescription *ad_entryExpireTimestamp;
79
80 /* list of expired DNs */
81 typedef struct dds_expire_t {
82 struct berval de_ndn;
83 struct dds_expire_t *de_next;
84 } dds_expire_t;
85
86 typedef struct dds_cb_t {
87 dds_expire_t *dc_ndnlist;
88 } dds_cb_t;
89
90 static int
dds_expire_cb(Operation * op,SlapReply * rs)91 dds_expire_cb( Operation *op, SlapReply *rs )
92 {
93 dds_cb_t *dc = (dds_cb_t *)op->o_callback->sc_private;
94 dds_expire_t *de;
95 int rc;
96
97 switch ( rs->sr_type ) {
98 case REP_SEARCH:
99 /* alloc list and buffer for berval all in one */
100 de = op->o_tmpalloc( sizeof( dds_expire_t ) + rs->sr_entry->e_nname.bv_len + 1,
101 op->o_tmpmemctx );
102
103 de->de_next = dc->dc_ndnlist;
104 dc->dc_ndnlist = de;
105
106 de->de_ndn.bv_len = rs->sr_entry->e_nname.bv_len;
107 de->de_ndn.bv_val = (char *)&de[ 1 ];
108 AC_MEMCPY( de->de_ndn.bv_val, rs->sr_entry->e_nname.bv_val,
109 rs->sr_entry->e_nname.bv_len + 1 );
110 rc = 0;
111 break;
112
113 case REP_SEARCHREF:
114 case REP_RESULT:
115 rc = rs->sr_err;
116 break;
117
118 default:
119 assert( 0 );
120 }
121
122 return rc;
123 }
124
125 static int
dds_expire(void * ctx,dds_info_t * di)126 dds_expire( void *ctx, dds_info_t *di )
127 {
128 Connection conn = { 0 };
129 OperationBuffer opbuf;
130 Operation *op;
131 slap_callback sc = { 0 };
132 dds_cb_t dc = { 0 };
133 dds_expire_t *de = NULL, **dep;
134 SlapReply rs = { REP_RESULT };
135
136 time_t expire;
137 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
138 struct berval ts;
139
140 int ndeletes, ntotdeletes;
141
142 int rc;
143 char *extra = "";
144
145 connection_fake_init2( &conn, &opbuf, ctx, 0 );
146 op = &opbuf.ob_op;
147
148 op->o_tag = LDAP_REQ_SEARCH;
149 memset( &op->oq_search, 0, sizeof( op->oq_search ) );
150
151 op->o_bd = select_backend( &di->di_nsuffix[ 0 ], 0 );
152
153 op->o_req_dn = op->o_bd->be_suffix[ 0 ];
154 op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ];
155
156 op->o_dn = op->o_bd->be_rootdn;
157 op->o_ndn = op->o_bd->be_rootndn;
158
159 op->ors_scope = LDAP_SCOPE_SUBTREE;
160 op->ors_tlimit = DDS_INTERVAL( di )/2 + 1;
161 op->ors_slimit = SLAP_NO_LIMIT;
162 op->ors_attrs = slap_anlist_no_attrs;
163 op->o_do_not_cache = 1;
164
165 expire = slap_get_time() - di->di_tolerance;
166 ts.bv_val = tsbuf;
167 ts.bv_len = sizeof( tsbuf );
168 slap_timestamp( &expire, &ts );
169
170 op->ors_filterstr.bv_len = STRLENOF( "(&(objectClass=" ")(" "<=" "))" )
171 + slap_schema.si_oc_dynamicObject->soc_cname.bv_len
172 + ad_entryExpireTimestamp->ad_cname.bv_len
173 + ts.bv_len;
174 op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
175 snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1,
176 "(&(objectClass=%s)(%s<=%s))",
177 slap_schema.si_oc_dynamicObject->soc_cname.bv_val,
178 ad_entryExpireTimestamp->ad_cname.bv_val, ts.bv_val );
179
180 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
181 if ( op->ors_filter == NULL ) {
182 rs.sr_err = LDAP_OTHER;
183 goto done_search;
184 }
185
186 op->o_callback = ≻
187 sc.sc_response = dds_expire_cb;
188 sc.sc_private = &dc;
189
190 (void)op->o_bd->bd_info->bi_op_search( op, &rs );
191
192 done_search:;
193 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
194 filter_free_x( op, op->ors_filter, 1 );
195
196 rc = rs.sr_err;
197 switch ( rs.sr_err ) {
198 case LDAP_SUCCESS:
199 break;
200
201 case LDAP_NO_SUCH_OBJECT:
202 /* (ITS#5267) database not created yet? */
203 rs.sr_err = LDAP_SUCCESS;
204 extra = " (ignored)";
205 /* fallthru */
206
207 default:
208 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
209 "DDS expired objects lookup failed err=%d%s\n",
210 rc, extra );
211 goto done;
212 }
213
214 op->o_tag = LDAP_REQ_DELETE;
215 op->o_callback = ≻
216 sc.sc_response = slap_null_cb;
217 sc.sc_private = NULL;
218
219 for ( ntotdeletes = 0, ndeletes = 1; dc.dc_ndnlist != NULL && ndeletes > 0; ) {
220 ndeletes = 0;
221
222 for ( dep = &dc.dc_ndnlist; *dep != NULL; ) {
223 de = *dep;
224
225 op->o_req_dn = de->de_ndn;
226 op->o_req_ndn = de->de_ndn;
227 (void)op->o_bd->bd_info->bi_op_delete( op, &rs );
228 switch ( rs.sr_err ) {
229 case LDAP_SUCCESS:
230 Log( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
231 "DDS dn=\"%s\" expired.\n",
232 de->de_ndn.bv_val );
233 ndeletes++;
234 break;
235
236 case LDAP_NOT_ALLOWED_ON_NONLEAF:
237 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
238 "DDS dn=\"%s\" is non-leaf; "
239 "deferring.\n",
240 de->de_ndn.bv_val );
241 dep = &de->de_next;
242 de = NULL;
243 break;
244
245 default:
246 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
247 "DDS dn=\"%s\" err=%d; "
248 "deferring.\n",
249 de->de_ndn.bv_val, rs.sr_err );
250 break;
251 }
252
253 if ( de != NULL ) {
254 *dep = de->de_next;
255 op->o_tmpfree( de, op->o_tmpmemctx );
256 }
257 }
258
259 ntotdeletes += ndeletes;
260 }
261
262 rs.sr_err = LDAP_SUCCESS;
263
264 Log( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
265 "DDS expired=%d\n", ntotdeletes );
266
267 done:;
268 return rs.sr_err;
269 }
270
271 static void *
dds_expire_fn(void * ctx,void * arg)272 dds_expire_fn( void *ctx, void *arg )
273 {
274 struct re_s *rtask = arg;
275 dds_info_t *di = rtask->arg;
276
277 assert( di->di_expire_task == rtask );
278
279 (void)dds_expire( ctx, di );
280
281 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
282 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
283 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
284 }
285 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
286 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
287
288 return NULL;
289 }
290
291 /* frees the callback */
292 static int
dds_freeit_cb(Operation * op,SlapReply * rs)293 dds_freeit_cb( Operation *op, SlapReply *rs )
294 {
295 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
296 op->o_callback = NULL;
297
298 return SLAP_CB_CONTINUE;
299 }
300
301 /* updates counter - installed on add/delete only if required */
302 static int
dds_counter_cb(Operation * op,SlapReply * rs)303 dds_counter_cb( Operation *op, SlapReply *rs )
304 {
305 assert( rs->sr_type == REP_RESULT );
306
307 if ( rs->sr_err == LDAP_SUCCESS ) {
308 dds_info_t *di = op->o_callback->sc_private;
309
310 ldap_pvt_thread_mutex_lock( &di->di_mutex );
311 switch ( op->o_tag ) {
312 case LDAP_REQ_DELETE:
313 assert( di->di_num_dynamicObjects > 0 );
314 di->di_num_dynamicObjects--;
315 break;
316
317 case LDAP_REQ_ADD:
318 assert( di->di_num_dynamicObjects < di->di_max_dynamicObjects );
319 di->di_num_dynamicObjects++;
320 break;
321
322 default:
323 assert( 0 );
324 }
325 ldap_pvt_thread_mutex_unlock( &di->di_mutex );
326 }
327
328 return dds_freeit_cb( op, rs );
329 }
330
331 static int
dds_op_add(Operation * op,SlapReply * rs)332 dds_op_add( Operation *op, SlapReply *rs )
333 {
334 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
335 dds_info_t *di = on->on_bi.bi_private;
336 int is_dynamicObject;
337
338 if ( DDS_OFF( di ) ) {
339 return SLAP_CB_CONTINUE;
340 }
341
342 is_dynamicObject = is_entry_dynamicObject( op->ora_e );
343
344 /* FIXME: do not allow this right now, pending clarification */
345 if ( is_dynamicObject ) {
346 rs->sr_err = LDAP_SUCCESS;
347
348 if ( is_entry_referral( op->ora_e ) ) {
349 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
350 rs->sr_text = "a referral cannot be a dynamicObject";
351
352 } else if ( is_entry_alias( op->ora_e ) ) {
353 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
354 rs->sr_text = "an alias cannot be a dynamicObject";
355 }
356
357 if ( rs->sr_err != LDAP_SUCCESS ) {
358 op->o_bd->bd_info = (BackendInfo *)on->on_info;
359 send_ldap_result( op, rs );
360 return rs->sr_err;
361 }
362 }
363
364 /* we don't allow dynamicObjects to have static subordinates */
365 if ( !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[ 0 ] ) ) {
366 struct berval p_ndn;
367 Entry *e = NULL;
368 int rc;
369 BackendInfo *bi = op->o_bd->bd_info;
370
371 dnParent( &op->o_req_ndn, &p_ndn );
372 op->o_bd->bd_info = (BackendInfo *)on->on_info;
373 rc = be_entry_get_rw( op, &p_ndn,
374 slap_schema.si_oc_dynamicObject, NULL, 0, &e );
375 if ( rc == LDAP_SUCCESS && e != NULL ) {
376 if ( !is_dynamicObject ) {
377 /* return referral only if "disclose"
378 * is granted on the object */
379 if ( ! access_allowed( op, e,
380 slap_schema.si_ad_entry,
381 NULL, ACL_DISCLOSE, NULL ) )
382 {
383 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
384 send_ldap_result( op, rs );
385
386 } else {
387 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
388 send_ldap_error( op, rs, rc, "no static subordinate entries allowed for dynamicObject" );
389 }
390 }
391
392 be_entry_release_r( op, e );
393 if ( rc != LDAP_SUCCESS ) {
394 return rc;
395 }
396 }
397 op->o_bd->bd_info = bi;
398 }
399
400 /* handle dynamic object operational attr(s) */
401 if ( is_dynamicObject ) {
402 time_t ttl, expire;
403 char ttlbuf[STRLENOF("31557600") + 1];
404 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
405 struct berval bv;
406
407 if ( !be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
408 ldap_pvt_thread_mutex_lock( &di->di_mutex );
409 rs->sr_err = ( di->di_max_dynamicObjects &&
410 di->di_num_dynamicObjects >= di->di_max_dynamicObjects );
411 ldap_pvt_thread_mutex_unlock( &di->di_mutex );
412 if ( rs->sr_err ) {
413 op->o_bd->bd_info = (BackendInfo *)on->on_info;
414 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
415 "too many dynamicObjects in context" );
416 return rs->sr_err;
417 }
418 }
419
420 ttl = DDS_DEFAULT_TTL( di );
421
422 /* assert because should be checked at configure */
423 assert( ttl <= DDS_RF2589_MAX_TTL );
424
425 bv.bv_val = ttlbuf;
426 bv.bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
427 assert( bv.bv_len < sizeof( ttlbuf ) );
428
429 /* FIXME: apparently, values in op->ora_e are malloc'ed
430 * on the thread's slab; works fine by chance,
431 * only because the attribute doesn't exist yet. */
432 assert( attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryTtl ) == NULL );
433 attr_merge_one( op->ora_e, slap_schema.si_ad_entryTtl, &bv, &bv );
434
435 expire = slap_get_time() + ttl;
436 bv.bv_val = tsbuf;
437 bv.bv_len = sizeof( tsbuf );
438 slap_timestamp( &expire, &bv );
439 assert( attr_find( op->ora_e->e_attrs, ad_entryExpireTimestamp ) == NULL );
440 attr_merge_one( op->ora_e, ad_entryExpireTimestamp, &bv, &bv );
441
442 /* if required, install counter callback */
443 if ( di->di_max_dynamicObjects > 0) {
444 slap_callback *sc;
445
446 sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
447 sc->sc_cleanup = dds_freeit_cb;
448 sc->sc_response = dds_counter_cb;
449 sc->sc_private = di;
450 sc->sc_next = op->o_callback;
451 sc->sc_writewait = 0;
452
453 op->o_callback = sc;
454 }
455 }
456
457 return SLAP_CB_CONTINUE;
458 }
459
460 static int
dds_op_delete(Operation * op,SlapReply * rs)461 dds_op_delete( Operation *op, SlapReply *rs )
462 {
463 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
464 dds_info_t *di = on->on_bi.bi_private;
465
466 /* if required, install counter callback */
467 if ( !DDS_OFF( di ) && di->di_max_dynamicObjects > 0 ) {
468 Entry *e = NULL;
469 BackendInfo *bi = op->o_bd->bd_info;
470
471 op->o_bd->bd_info = (BackendInfo *)on->on_info;
472 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
473 slap_schema.si_oc_dynamicObject, NULL, 0, &e );
474
475 /* FIXME: couldn't the entry be added before deletion? */
476 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
477 slap_callback *sc;
478
479 be_entry_release_r( op, e );
480 e = NULL;
481
482 sc = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
483 sc->sc_cleanup = dds_freeit_cb;
484 sc->sc_response = dds_counter_cb;
485 sc->sc_private = di;
486 sc->sc_writewait = 0;
487 sc->sc_next = op->o_callback;
488
489 op->o_callback = sc;
490 }
491 op->o_bd->bd_info = bi;
492 }
493
494 return SLAP_CB_CONTINUE;
495 }
496
497 static int
dds_op_modify(Operation * op,SlapReply * rs)498 dds_op_modify( Operation *op, SlapReply *rs )
499 {
500 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
501 dds_info_t *di = (dds_info_t *)on->on_bi.bi_private;
502 Modifications *mod;
503 Entry *e = NULL;
504 BackendInfo *bi = op->o_bd->bd_info;
505 int was_dynamicObject = 0,
506 is_dynamicObject = 0;
507 struct berval bv_entryTtl = BER_BVNULL;
508 time_t entryTtl = 0;
509 char textbuf[ SLAP_TEXT_BUFLEN ];
510
511 if ( DDS_OFF( di ) ) {
512 return SLAP_CB_CONTINUE;
513 }
514
515 /* bv_entryTtl stores the string representation of the entryTtl
516 * across modifies for consistency checks of the final value;
517 * the bv_val points to a static buffer; the bv_len is zero when
518 * the attribute is deleted.
519 * entryTtl stores the integer representation of the entryTtl;
520 * its value is -1 when the attribute is deleted; it is 0 only
521 * if no modifications of the entryTtl occurred, as an entryTtl
522 * of 0 is invalid. */
523 bv_entryTtl.bv_val = textbuf;
524
525 op->o_bd->bd_info = (BackendInfo *)on->on_info;
526 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
527 slap_schema.si_oc_dynamicObject, slap_schema.si_ad_entryTtl, 0, &e );
528 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
529 Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryTtl );
530
531 /* the value of the entryTtl is saved for later checks */
532 if ( a != NULL ) {
533 unsigned long ttl;
534 int rc;
535
536 bv_entryTtl.bv_len = a->a_nvals[ 0 ].bv_len;
537 AC_MEMCPY( bv_entryTtl.bv_val, a->a_nvals[ 0 ].bv_val, bv_entryTtl.bv_len );
538 bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
539 rc = lutil_atoul( &ttl, bv_entryTtl.bv_val );
540 assert( rc == 0 );
541 entryTtl = (time_t)ttl;
542 }
543
544 be_entry_release_r( op, e );
545 e = NULL;
546 was_dynamicObject = is_dynamicObject = 1;
547 }
548 op->o_bd->bd_info = bi;
549
550 rs->sr_err = LDAP_SUCCESS;
551 for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) {
552 if ( mod->sml_desc == slap_schema.si_ad_objectClass ) {
553 int i;
554 ObjectClass *oc;
555
556 switch ( mod->sml_op ) {
557 case LDAP_MOD_DELETE:
558 if ( mod->sml_values == NULL ) {
559 is_dynamicObject = 0;
560 break;
561 }
562
563 for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
564 oc = oc_bvfind( &mod->sml_values[ i ] );
565 if ( oc == slap_schema.si_oc_dynamicObject ) {
566 is_dynamicObject = 0;
567 break;
568 }
569 }
570
571 break;
572
573 case LDAP_MOD_REPLACE:
574 if ( mod->sml_values == NULL ) {
575 is_dynamicObject = 0;
576 break;
577 }
578 /* fallthru */
579
580 case LDAP_MOD_ADD:
581 for ( i = 0; !BER_BVISNULL( &mod->sml_values[ i ] ); i++ ) {
582 oc = oc_bvfind( &mod->sml_values[ i ] );
583 if ( oc == slap_schema.si_oc_dynamicObject ) {
584 is_dynamicObject = 1;
585 break;
586 }
587 }
588 break;
589 }
590
591 } else if ( mod->sml_desc == slap_schema.si_ad_entryTtl ) {
592 unsigned long uttl;
593 time_t ttl;
594 int rc;
595
596 switch ( mod->sml_op ) {
597 case LDAP_MOD_DELETE:
598 case SLAP_MOD_SOFTDEL: /* FIXME? */
599 if ( mod->sml_values != NULL ) {
600 if ( BER_BVISEMPTY( &bv_entryTtl )
601 || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) )
602 {
603 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
604 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
605 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
606 rs->sr_err = LDAP_NO_SUCH_OBJECT;
607
608 } else {
609 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
610 }
611 goto done;
612 }
613 }
614 bv_entryTtl.bv_len = 0;
615 entryTtl = -1;
616 break;
617
618 case LDAP_MOD_REPLACE:
619 bv_entryTtl.bv_len = 0;
620 entryTtl = -1;
621 /* fallthru */
622
623 case LDAP_MOD_ADD:
624 case SLAP_MOD_SOFTADD: /* FIXME? */
625 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */
626 assert( mod->sml_values != NULL );
627 assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) );
628
629 if ( !BER_BVISEMPTY( &bv_entryTtl ) ) {
630 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
631 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
632 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
633 rs->sr_err = LDAP_NO_SUCH_OBJECT;
634
635 } else {
636 rs->sr_text = "attribute 'entryTtl' cannot have multiple values";
637 rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
638 }
639 goto done;
640 }
641
642 rc = lutil_atoul( &uttl, mod->sml_values[ 0 ].bv_val );
643 ttl = (time_t)uttl;
644 assert( rc == 0 );
645 if ( ttl > DDS_RF2589_MAX_TTL ) {
646 rs->sr_err = LDAP_PROTOCOL_ERROR;
647 rs->sr_text = "invalid time-to-live for dynamicObject";
648 goto done;
649 }
650
651 if ( ttl <= 0 || ttl > di->di_max_ttl ) {
652 /* FIXME: I don't understand if this has to be an error,
653 * or an indication that the requested Ttl has been
654 * shortened to di->di_max_ttl >= 1 day */
655 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
656 rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
657 goto done;
658 }
659
660 entryTtl = ttl;
661 bv_entryTtl.bv_len = mod->sml_values[ 0 ].bv_len;
662 AC_MEMCPY( bv_entryTtl.bv_val, mod->sml_values[ 0 ].bv_val, bv_entryTtl.bv_len );
663 bv_entryTtl.bv_val[ bv_entryTtl.bv_len ] = '\0';
664 break;
665
666 case LDAP_MOD_INCREMENT:
667 if ( BER_BVISEMPTY( &bv_entryTtl ) ) {
668 rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
669 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
670 if ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) {
671 rs->sr_err = LDAP_NO_SUCH_OBJECT;
672
673 } else {
674 rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
675 rs->sr_text = "modify/increment: entryTtl: no such attribute";
676 }
677 goto done;
678 }
679
680 entryTtl++;
681 if ( entryTtl > DDS_RF2589_MAX_TTL ) {
682 rs->sr_err = LDAP_PROTOCOL_ERROR;
683 rs->sr_text = "invalid time-to-live for dynamicObject";
684
685 } else if ( entryTtl <= 0 || entryTtl > di->di_max_ttl ) {
686 /* FIXME: I don't understand if this has to be an error,
687 * or an indication that the requested Ttl has been
688 * shortened to di->di_max_ttl >= 1 day */
689 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
690 rs->sr_text = "time-to-live for dynamicObject exceeds administrative limit";
691 }
692
693 if ( rs->sr_err != LDAP_SUCCESS ) {
694 rc = backend_attribute( op, NULL, &op->o_req_ndn,
695 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
696 if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
697 rs->sr_text = NULL;
698 rs->sr_err = LDAP_NO_SUCH_OBJECT;
699
700 }
701 goto done;
702 }
703
704 bv_entryTtl.bv_len = snprintf( textbuf, sizeof( textbuf ), "%ld", entryTtl );
705 break;
706
707 default:
708 assert( 0 );
709 break;
710 }
711
712 } else if ( mod->sml_desc == ad_entryExpireTimestamp ) {
713 /* should have been trapped earlier */
714 assert( mod->sml_flags & SLAP_MOD_INTERNAL );
715 }
716 }
717
718 done:;
719 if ( rs->sr_err == LDAP_SUCCESS ) {
720 int rc;
721
722 /* FIXME: this could be allowed when the Relax control is used...
723 * in that case:
724 *
725 * TODO
726 *
727 * static => dynamic:
728 * entryTtl must be provided; add
729 * entryExpireTimestamp accordingly
730 *
731 * dynamic => static:
732 * entryTtl must be removed; remove
733 * entryTimestamp accordingly
734 *
735 * ... but we need to make sure that there are no subordinate
736 * issues...
737 */
738 rc = is_dynamicObject - was_dynamicObject;
739 if ( rc ) {
740 #if 0 /* fix subordinate issues first */
741 if ( get_relax( op ) ) {
742 switch ( rc ) {
743 case -1:
744 /* need to delete entryTtl to have a consistent entry */
745 if ( entryTtl != -1 ) {
746 rs->sr_text = "objectClass modification from dynamicObject to static entry requires entryTtl deletion";
747 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
748 }
749 break;
750
751 case 1:
752 /* need to add entryTtl to have a consistent entry */
753 if ( entryTtl <= 0 ) {
754 rs->sr_text = "objectClass modification from static entry to dynamicObject requires entryTtl addition";
755 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
756 }
757 break;
758 }
759
760 } else
761 #endif
762 {
763 switch ( rc ) {
764 case -1:
765 rs->sr_text = "objectClass modification cannot turn dynamicObject into static entry";
766 break;
767
768 case 1:
769 rs->sr_text = "objectClass modification cannot turn static entry into dynamicObject";
770 break;
771 }
772 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
773 }
774
775 if ( rc != LDAP_SUCCESS ) {
776 rc = backend_attribute( op, NULL, &op->o_req_ndn,
777 slap_schema.si_ad_entry, NULL, ACL_DISCLOSE );
778 if ( rc == LDAP_INSUFFICIENT_ACCESS ) {
779 rs->sr_text = NULL;
780 rs->sr_err = LDAP_NO_SUCH_OBJECT;
781 }
782 }
783 }
784 }
785
786 if ( rs->sr_err == LDAP_SUCCESS && entryTtl != 0 ) {
787 Modifications *tmpmod = NULL, **modp;
788
789 for ( modp = &op->orm_modlist; *modp; modp = &(*modp)->sml_next )
790 ;
791
792 tmpmod = ch_calloc( 1, sizeof( Modifications ) );
793 tmpmod->sml_flags = SLAP_MOD_INTERNAL;
794 tmpmod->sml_type = ad_entryExpireTimestamp->ad_cname;
795 tmpmod->sml_desc = ad_entryExpireTimestamp;
796
797 *modp = tmpmod;
798
799 if ( entryTtl == -1 ) {
800 /* delete entryExpireTimestamp */
801 tmpmod->sml_op = LDAP_MOD_DELETE;
802
803 } else {
804 time_t expire;
805 char tsbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
806 struct berval bv;
807
808 /* keep entryExpireTimestamp consistent
809 * with entryTtl */
810 expire = slap_get_time() + entryTtl;
811 bv.bv_val = tsbuf;
812 bv.bv_len = sizeof( tsbuf );
813 slap_timestamp( &expire, &bv );
814
815 tmpmod->sml_op = LDAP_MOD_REPLACE;
816 value_add_one( &tmpmod->sml_values, &bv );
817 value_add_one( &tmpmod->sml_nvalues, &bv );
818 tmpmod->sml_numvals = 1;
819 }
820 }
821
822 if ( rs->sr_err ) {
823 op->o_bd->bd_info = (BackendInfo *)on->on_info;
824 send_ldap_result( op, rs );
825 return rs->sr_err;
826 }
827
828 return SLAP_CB_CONTINUE;
829 }
830
831 static int
dds_op_rename(Operation * op,SlapReply * rs)832 dds_op_rename( Operation *op, SlapReply *rs )
833 {
834 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
835 dds_info_t *di = on->on_bi.bi_private;
836
837 if ( DDS_OFF( di ) ) {
838 return SLAP_CB_CONTINUE;
839 }
840
841 /* we don't allow dynamicObjects to have static subordinates */
842 if ( op->orr_nnewSup != NULL ) {
843 Entry *e = NULL;
844 BackendInfo *bi = op->o_bd->bd_info;
845 int is_dynamicObject = 0,
846 rc;
847
848 rs->sr_err = LDAP_SUCCESS;
849
850 op->o_bd->bd_info = (BackendInfo *)on->on_info;
851 rc = be_entry_get_rw( op, &op->o_req_ndn,
852 slap_schema.si_oc_dynamicObject, NULL, 0, &e );
853 if ( rc == LDAP_SUCCESS && e != NULL ) {
854 be_entry_release_r( op, e );
855 e = NULL;
856 is_dynamicObject = 1;
857 }
858
859 rc = be_entry_get_rw( op, op->orr_nnewSup,
860 slap_schema.si_oc_dynamicObject, NULL, 0, &e );
861 if ( rc == LDAP_SUCCESS && e != NULL ) {
862 if ( !is_dynamicObject ) {
863 /* return referral only if "disclose"
864 * is granted on the object */
865 if ( ! access_allowed( op, e,
866 slap_schema.si_ad_entry,
867 NULL, ACL_DISCLOSE, NULL ) )
868 {
869 rs->sr_err = LDAP_NO_SUCH_OBJECT;
870 send_ldap_result( op, rs );
871
872 } else {
873 send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION,
874 "static entry cannot have dynamicObject as newSuperior" );
875 }
876 }
877 be_entry_release_r( op, e );
878 }
879 op->o_bd->bd_info = bi;
880 if ( rs->sr_err != LDAP_SUCCESS ) {
881 return rs->sr_err;
882 }
883 }
884
885 return SLAP_CB_CONTINUE;
886 }
887
888 /* entryTtl update for client */
889 static int
dds_response(Operation * op,SlapReply * rs)890 dds_response( Operation *op, SlapReply *rs )
891 {
892 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
893 dds_info_t *di = on->on_bi.bi_private;
894 int rc;
895
896 if ( !DDS_OFF( di )
897 && rs->sr_type == REP_SEARCH
898 && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryTtl ) )
899 {
900 BerVarray vals = NULL;
901 struct lutil_tm tm;
902 struct lutil_timet tt;
903 char ttlbuf[STRLENOF("31557600") + 1];
904 struct berval ttlvalue;
905 time_t ttl;
906 int len;
907
908 /* User already has access to entryTtl, skip ACL checks on
909 * entryExpireTimestamp */
910 rc = backend_attribute( op, NULL, &rs->sr_entry->e_nname,
911 ad_entryExpireTimestamp, &vals, ACL_NONE );
912 if ( rc != LDAP_SUCCESS ) {
913 return rc;
914 }
915
916 assert( vals[0].bv_val[vals[0].bv_len] == '\0' );
917 if ( lutil_parsetime( vals[0].bv_val, &tm ) ) {
918 goto done;
919 }
920
921 lutil_tm2time( &tm, &tt );
922 ttl = tt.tt_sec - op->o_time;
923 ttl = (ttl < 0) ? 0 : ttl;
924 assert( ttl <= DDS_RF2589_MAX_TTL );
925
926 len = snprintf( ttlbuf, sizeof(ttlbuf), "%ld", ttl );
927 if ( len < 0 )
928 {
929 goto done;
930 }
931 ttlvalue.bv_val = ttlbuf;
932 ttlvalue.bv_len = len;
933
934 rs_entry2modifiable( op, rs, on );
935
936 if ( attr_delete( &rs->sr_entry->e_attrs,
937 slap_schema.si_ad_entryTtl ) )
938 {
939 goto done;
940 }
941 if ( attr_merge_normalize_one( rs->sr_entry,
942 slap_schema.si_ad_entryTtl,
943 &ttlvalue, op->o_tmpmemctx ) )
944 {
945 goto done;
946 }
947
948 done:;
949 ber_bvarray_free_x( vals, op->o_tmpmemctx );
950 }
951 return SLAP_CB_CONTINUE;
952 }
953
954 static int
slap_parse_refresh(struct berval * in,struct berval * ndn,time_t * ttl,const char ** text,void * ctx)955 slap_parse_refresh(
956 struct berval *in,
957 struct berval *ndn,
958 time_t *ttl,
959 const char **text,
960 void *ctx )
961 {
962 int rc = LDAP_SUCCESS;
963 ber_tag_t tag;
964 ber_len_t len = -1;
965 BerElementBuffer berbuf;
966 BerElement *ber = (BerElement *)&berbuf;
967 struct berval reqdata = BER_BVNULL;
968 int tmp;
969
970 *text = NULL;
971
972 if ( ndn ) {
973 BER_BVZERO( ndn );
974 }
975
976 if ( in == NULL || in->bv_len == 0 ) {
977 *text = "empty request data field in refresh exop";
978 return LDAP_PROTOCOL_ERROR;
979 }
980
981 ber_dupbv_x( &reqdata, in, ctx );
982
983 /* ber_init2 uses reqdata directly, doesn't allocate new buffers */
984 ber_init2( ber, &reqdata, 0 );
985
986 tag = ber_scanf( ber, "{" /*}*/ );
987
988 if ( tag == LBER_ERROR ) {
989 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
990 "slap_parse_refresh: decoding error.\n" );
991 goto decoding_error;
992 }
993
994 tag = ber_peek_tag( ber, &len );
995 if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_DN ) {
996 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
997 "slap_parse_refresh: decoding error.\n" );
998 goto decoding_error;
999 }
1000
1001 if ( ndn ) {
1002 struct berval dn;
1003
1004 tag = ber_scanf( ber, "m", &dn );
1005 if ( tag == LBER_ERROR ) {
1006 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
1007 "slap_parse_refresh: DN parse failed.\n" );
1008 goto decoding_error;
1009 }
1010
1011 rc = dnNormalize( 0, NULL, NULL, &dn, ndn, ctx );
1012 if ( rc != LDAP_SUCCESS ) {
1013 *text = "invalid DN in refresh exop request data";
1014 goto done;
1015 }
1016
1017 } else {
1018 tag = ber_scanf( ber, "x" /* "m" */ );
1019 if ( tag == LBER_DEFAULT ) {
1020 goto decoding_error;
1021 }
1022 }
1023
1024 tag = ber_peek_tag( ber, &len );
1025
1026 if ( tag != LDAP_TAG_EXOP_REFRESH_REQ_TTL ) {
1027 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
1028 "slap_parse_refresh: decoding error.\n" );
1029 goto decoding_error;
1030 }
1031
1032 tag = ber_scanf( ber, "i", &tmp );
1033 if ( tag == LBER_ERROR ) {
1034 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
1035 "slap_parse_refresh: TTL parse failed.\n" );
1036 goto decoding_error;
1037 }
1038
1039 if ( ttl ) {
1040 *ttl = tmp;
1041 }
1042
1043 tag = ber_peek_tag( ber, &len );
1044
1045 if ( tag != LBER_DEFAULT || len != 0 ) {
1046 decoding_error:;
1047 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_ERR,
1048 "slap_parse_refresh: decoding error, len=%ld\n",
1049 (long)len );
1050 rc = LDAP_PROTOCOL_ERROR;
1051 *text = "data decoding error";
1052
1053 done:;
1054 if ( ndn && !BER_BVISNULL( ndn ) ) {
1055 slap_sl_free( ndn->bv_val, ctx );
1056 BER_BVZERO( ndn );
1057 }
1058 }
1059
1060 if ( !BER_BVISNULL( &reqdata ) ) {
1061 ber_memfree_x( reqdata.bv_val, ctx );
1062 }
1063
1064 return rc;
1065 }
1066
1067 static int
dds_op_extended(Operation * op,SlapReply * rs)1068 dds_op_extended( Operation *op, SlapReply *rs )
1069 {
1070 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1071 dds_info_t *di = on->on_bi.bi_private;
1072
1073 if ( DDS_OFF( di ) ) {
1074 return SLAP_CB_CONTINUE;
1075 }
1076
1077 if ( bvmatch( &op->ore_reqoid, &slap_EXOP_REFRESH ) ) {
1078 Entry *e = NULL;
1079 time_t ttl;
1080 BackendDB db = *op->o_bd;
1081 SlapReply rs2 = { REP_RESULT };
1082 Operation op2 = *op;
1083 slap_callback sc = { 0 };
1084 Modifications ttlmod = { { 0 } };
1085 struct berval ttlvalues[ 2 ];
1086 char ttlbuf[STRLENOF("31557600") + 1];
1087
1088 rs->sr_err = slap_parse_refresh( op->ore_reqdata, NULL, &ttl,
1089 &rs->sr_text, NULL );
1090 assert( rs->sr_err == LDAP_SUCCESS );
1091
1092 if ( ttl <= 0 || ttl > DDS_RF2589_MAX_TTL ) {
1093 rs->sr_err = LDAP_PROTOCOL_ERROR;
1094 rs->sr_text = "invalid time-to-live for dynamicObject";
1095 return rs->sr_err;
1096 }
1097
1098 if ( ttl > di->di_max_ttl ) {
1099 /* FIXME: I don't understand if this has to be an error,
1100 * or an indication that the requested Ttl has been
1101 * shortened to di->di_max_ttl >= 1 day */
1102 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
1103 rs->sr_text = "time-to-live for dynamicObject exceeds limit";
1104 return rs->sr_err;
1105 }
1106
1107 if ( di->di_min_ttl && ttl < di->di_min_ttl ) {
1108 ttl = di->di_min_ttl;
1109 }
1110
1111 /* This does not apply to multi-provider case */
1112 if ( !( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ) ) ) {
1113 /* we SHOULD return a referral in this case */
1114 BerVarray defref = op->o_bd->be_update_refs
1115 ? op->o_bd->be_update_refs : default_referral;
1116
1117 if ( defref != NULL ) {
1118 rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs,
1119 NULL, NULL, LDAP_SCOPE_DEFAULT );
1120 if ( rs->sr_ref ) {
1121 rs->sr_flags |= REP_REF_MUSTBEFREED;
1122 } else {
1123 rs->sr_ref = defref;
1124 }
1125 rs->sr_err = LDAP_REFERRAL;
1126
1127 } else {
1128 rs->sr_text = "shadow context; no update referral";
1129 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1130 }
1131
1132 return rs->sr_err;
1133 }
1134
1135 assert( !BER_BVISNULL( &op->o_req_ndn ) );
1136
1137
1138
1139 /* check if exists but not dynamicObject */
1140 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1141 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
1142 slap_schema.si_oc_dynamicObject, NULL, 0, &e );
1143 if ( rs->sr_err != LDAP_SUCCESS ) {
1144 rs->sr_err = be_entry_get_rw( op, &op->o_req_ndn,
1145 NULL, NULL, 0, &e );
1146 if ( rs->sr_err == LDAP_SUCCESS && e != NULL ) {
1147 /* return referral only if "disclose"
1148 * is granted on the object */
1149 if ( ! access_allowed( op, e,
1150 slap_schema.si_ad_entry,
1151 NULL, ACL_DISCLOSE, NULL ) )
1152 {
1153 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1154
1155 } else {
1156 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
1157 rs->sr_text = "refresh operation only applies to dynamic objects";
1158 }
1159 be_entry_release_r( op, e );
1160
1161 } else {
1162 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1163 }
1164 return rs->sr_err;
1165
1166 } else if ( e != NULL ) {
1167 be_entry_release_r( op, e );
1168 }
1169
1170 /* we require manage privileges on the entryTtl,
1171 * and fake a Relax control */
1172 op2.o_tag = LDAP_REQ_MODIFY;
1173 op2.o_bd = &db;
1174 db.bd_info = (BackendInfo *)on->on_info;
1175 op2.o_callback = ≻
1176 sc.sc_response = slap_null_cb;
1177 op2.o_relax = SLAP_CONTROL_CRITICAL;
1178 op2.orm_modlist = &ttlmod;
1179
1180 ttlmod.sml_op = LDAP_MOD_REPLACE;
1181 ttlmod.sml_flags = SLAP_MOD_MANAGING;
1182 ttlmod.sml_desc = slap_schema.si_ad_entryTtl;
1183 ttlmod.sml_values = ttlvalues;
1184 ttlmod.sml_numvals = 1;
1185 ttlvalues[ 0 ].bv_val = ttlbuf;
1186 ttlvalues[ 0 ].bv_len = snprintf( ttlbuf, sizeof( ttlbuf ), "%ld", ttl );
1187 BER_BVZERO( &ttlvalues[ 1 ] );
1188
1189 /* the entryExpireTimestamp is added by modify */
1190 rs->sr_err = op2.o_bd->be_modify( &op2, &rs2 );
1191
1192 if ( ttlmod.sml_next != NULL ) {
1193 slap_mods_free( ttlmod.sml_next, 1 );
1194 }
1195
1196 if ( rs->sr_err == LDAP_SUCCESS ) {
1197 int rc;
1198 BerElementBuffer berbuf;
1199 BerElement *ber = (BerElement *)&berbuf;
1200
1201 ber_init_w_nullc( ber, LBER_USE_DER );
1202
1203 rc = ber_printf( ber, "{tiN}", LDAP_TAG_EXOP_REFRESH_RES_TTL, (int)ttl );
1204
1205 if ( rc < 0 ) {
1206 rs->sr_err = LDAP_OTHER;
1207 rs->sr_text = "internal error";
1208
1209 } else {
1210 (void)ber_flatten( ber, &rs->sr_rspdata );
1211 rs->sr_rspoid = ch_strdup( slap_EXOP_REFRESH.bv_val );
1212
1213 Log( LDAP_DEBUG_TRACE, LDAP_LEVEL_INFO,
1214 "%s REFRESH dn=\"%s\" TTL=%ld\n",
1215 op->o_log_prefix, op->o_req_ndn.bv_val, ttl );
1216 }
1217
1218 ber_free_buf( ber );
1219 }
1220
1221 return rs->sr_err;
1222 }
1223
1224 return SLAP_CB_CONTINUE;
1225 }
1226
1227 enum {
1228 DDS_STATE = 1,
1229 DDS_MAXTTL,
1230 DDS_MINTTL,
1231 DDS_DEFAULTTTL,
1232 DDS_INTERVAL,
1233 DDS_TOLERANCE,
1234 DDS_MAXDYNAMICOBJS,
1235
1236 DDS_LAST
1237 };
1238
1239 static ConfigDriver dds_cfgen;
1240 #if 0
1241 static ConfigLDAPadd dds_ldadd;
1242 static ConfigCfAdd dds_cfadd;
1243 #endif
1244
1245 static ConfigTable dds_cfg[] = {
1246 { "dds-state", "on|off",
1247 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|DDS_STATE, dds_cfgen,
1248 "( OLcfgOvAt:9.1 NAME 'olcDDSstate' "
1249 "DESC 'RFC2589 Dynamic directory services state' "
1250 "EQUALITY booleanMatch "
1251 "SYNTAX OMsBoolean "
1252 "SINGLE-VALUE )", NULL, NULL },
1253 { "dds-max-ttl", "ttl",
1254 2, 2, 0, ARG_MAGIC|DDS_MAXTTL, dds_cfgen,
1255 "( OLcfgOvAt:9.2 NAME 'olcDDSmaxTtl' "
1256 "DESC 'RFC2589 Dynamic directory services max TTL' "
1257 "EQUALITY caseIgnoreMatch "
1258 "SYNTAX OMsDirectoryString "
1259 "SINGLE-VALUE )", NULL, NULL },
1260 { "dds-min-ttl", "ttl",
1261 2, 2, 0, ARG_MAGIC|DDS_MINTTL, dds_cfgen,
1262 "( OLcfgOvAt:9.3 NAME 'olcDDSminTtl' "
1263 "DESC 'RFC2589 Dynamic directory services min TTL' "
1264 "EQUALITY caseIgnoreMatch "
1265 "SYNTAX OMsDirectoryString "
1266 "SINGLE-VALUE )", NULL, NULL },
1267 { "dds-default-ttl", "ttl",
1268 2, 2, 0, ARG_MAGIC|DDS_DEFAULTTTL, dds_cfgen,
1269 "( OLcfgOvAt:9.4 NAME 'olcDDSdefaultTtl' "
1270 "DESC 'RFC2589 Dynamic directory services default TTL' "
1271 "EQUALITY caseIgnoreMatch "
1272 "SYNTAX OMsDirectoryString "
1273 "SINGLE-VALUE )", NULL, NULL },
1274 { "dds-interval", "interval",
1275 2, 2, 0, ARG_MAGIC|DDS_INTERVAL, dds_cfgen,
1276 "( OLcfgOvAt:9.5 NAME 'olcDDSinterval' "
1277 "DESC 'RFC2589 Dynamic directory services expiration "
1278 "task run interval' "
1279 "EQUALITY caseIgnoreMatch "
1280 "SYNTAX OMsDirectoryString "
1281 "SINGLE-VALUE )", NULL, NULL },
1282 { "dds-tolerance", "ttl",
1283 2, 2, 0, ARG_MAGIC|DDS_TOLERANCE, dds_cfgen,
1284 "( OLcfgOvAt:9.6 NAME 'olcDDStolerance' "
1285 "DESC 'RFC2589 Dynamic directory services additional "
1286 "TTL in expiration scheduling' "
1287 "EQUALITY caseIgnoreMatch "
1288 "SYNTAX OMsDirectoryString "
1289 "SINGLE-VALUE )", NULL, NULL },
1290 { "dds-max-dynamicObjects", "num",
1291 2, 2, 0, ARG_MAGIC|ARG_INT|DDS_MAXDYNAMICOBJS, dds_cfgen,
1292 "( OLcfgOvAt:9.7 NAME 'olcDDSmaxDynamicObjects' "
1293 "DESC 'RFC2589 Dynamic directory services max number of dynamic objects' "
1294 "EQUALITY integerMatch "
1295 "SYNTAX OMsInteger "
1296 "SINGLE-VALUE )", NULL, NULL },
1297 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1298 };
1299
1300 static ConfigOCs dds_ocs[] = {
1301 { "( OLcfgOvOc:9.1 "
1302 "NAME 'olcDDSConfig' "
1303 "DESC 'RFC2589 Dynamic directory services configuration' "
1304 "SUP olcOverlayConfig "
1305 "MAY ( "
1306 "olcDDSstate "
1307 "$ olcDDSmaxTtl "
1308 "$ olcDDSminTtl "
1309 "$ olcDDSdefaultTtl "
1310 "$ olcDDSinterval "
1311 "$ olcDDStolerance "
1312 "$ olcDDSmaxDynamicObjects "
1313 " ) "
1314 ")", Cft_Overlay, dds_cfg, NULL, NULL /* dds_cfadd */ },
1315 { NULL, 0, NULL }
1316 };
1317
1318 #if 0
1319 static int
1320 dds_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1321 {
1322 return LDAP_SUCCESS;
1323 }
1324
1325 static int
1326 dds_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1327 {
1328 return 0;
1329 }
1330 #endif
1331
1332 static int
dds_cfgen(ConfigArgs * c)1333 dds_cfgen( ConfigArgs *c )
1334 {
1335 slap_overinst *on = (slap_overinst *)c->bi;
1336 dds_info_t *di = on->on_bi.bi_private;
1337 int rc = 0;
1338 unsigned long t;
1339
1340
1341 if ( c->op == SLAP_CONFIG_EMIT ) {
1342 char buf[ SLAP_TEXT_BUFLEN ];
1343 struct berval bv;
1344
1345 switch( c->type ) {
1346 case DDS_STATE:
1347 c->value_int = !DDS_OFF( di );
1348 break;
1349
1350 case DDS_MAXTTL:
1351 lutil_unparse_time( buf, sizeof( buf ), di->di_max_ttl );
1352 ber_str2bv( buf, 0, 0, &bv );
1353 value_add_one( &c->rvalue_vals, &bv );
1354 break;
1355
1356 case DDS_MINTTL:
1357 if ( di->di_min_ttl ) {
1358 lutil_unparse_time( buf, sizeof( buf ), di->di_min_ttl );
1359 ber_str2bv( buf, 0, 0, &bv );
1360 value_add_one( &c->rvalue_vals, &bv );
1361
1362 } else {
1363 rc = 1;
1364 }
1365 break;
1366
1367 case DDS_DEFAULTTTL:
1368 if ( di->di_default_ttl ) {
1369 lutil_unparse_time( buf, sizeof( buf ), di->di_default_ttl );
1370 ber_str2bv( buf, 0, 0, &bv );
1371 value_add_one( &c->rvalue_vals, &bv );
1372
1373 } else {
1374 rc = 1;
1375 }
1376 break;
1377
1378 case DDS_INTERVAL:
1379 if ( di->di_interval ) {
1380 lutil_unparse_time( buf, sizeof( buf ), di->di_interval );
1381 ber_str2bv( buf, 0, 0, &bv );
1382 value_add_one( &c->rvalue_vals, &bv );
1383
1384 } else {
1385 rc = 1;
1386 }
1387 break;
1388
1389 case DDS_TOLERANCE:
1390 if ( di->di_tolerance ) {
1391 lutil_unparse_time( buf, sizeof( buf ), di->di_tolerance );
1392 ber_str2bv( buf, 0, 0, &bv );
1393 value_add_one( &c->rvalue_vals, &bv );
1394
1395 } else {
1396 rc = 1;
1397 }
1398 break;
1399
1400 case DDS_MAXDYNAMICOBJS:
1401 if ( di->di_max_dynamicObjects > 0 ) {
1402 c->value_int = di->di_max_dynamicObjects;
1403
1404 } else {
1405 rc = 1;
1406 }
1407 break;
1408
1409 default:
1410 rc = 1;
1411 break;
1412 }
1413
1414 return rc;
1415
1416 } else if ( c->op == LDAP_MOD_DELETE ) {
1417 switch( c->type ) {
1418 case DDS_STATE:
1419 di->di_flags &= ~DDS_FOFF;
1420 break;
1421
1422 case DDS_MAXTTL:
1423 di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;
1424 break;
1425
1426 case DDS_MINTTL:
1427 di->di_min_ttl = 0;
1428 break;
1429
1430 case DDS_DEFAULTTTL:
1431 di->di_default_ttl = 0;
1432 break;
1433
1434 case DDS_INTERVAL:
1435 di->di_interval = 0;
1436 break;
1437
1438 case DDS_TOLERANCE:
1439 di->di_tolerance = 0;
1440 break;
1441
1442 case DDS_MAXDYNAMICOBJS:
1443 di->di_max_dynamicObjects = 0;
1444 break;
1445
1446 default:
1447 rc = 1;
1448 break;
1449 }
1450
1451 return rc;
1452 }
1453
1454 switch ( c->type ) {
1455 case DDS_STATE:
1456 if ( c->value_int ) {
1457 di->di_flags &= ~DDS_FOFF;
1458
1459 } else {
1460 di->di_flags |= DDS_FOFF;
1461 }
1462 break;
1463
1464 case DDS_MAXTTL:
1465 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1466 snprintf( c->cr_msg, sizeof( c->cr_msg),
1467 "DDS unable to parse dds-max-ttl \"%s\"",
1468 c->argv[ 1 ] );
1469 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1470 "%s: %s.\n", c->log, c->cr_msg );
1471 return 1;
1472 }
1473
1474 if ( t < DDS_RF2589_DEFAULT_TTL || t > DDS_RF2589_MAX_TTL ) {
1475 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1476 "DDS invalid dds-max-ttl=%lu; must be between %d and %d",
1477 t, DDS_RF2589_DEFAULT_TTL, DDS_RF2589_MAX_TTL );
1478 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1479 "%s: %s.\n", c->log, c->cr_msg );
1480 return 1;
1481 }
1482
1483 di->di_max_ttl = (time_t)t;
1484 break;
1485
1486 case DDS_MINTTL:
1487 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1488 snprintf( c->cr_msg, sizeof( c->cr_msg),
1489 "DDS unable to parse dds-min-ttl \"%s\"",
1490 c->argv[ 1 ] );
1491 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1492 "%s: %s.\n", c->log, c->cr_msg );
1493 return 1;
1494 }
1495
1496 if ( t > DDS_RF2589_MAX_TTL ) {
1497 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1498 "DDS invalid dds-min-ttl=%lu",
1499 t );
1500 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1501 "%s: %s.\n", c->log, c->cr_msg );
1502 return 1;
1503 }
1504
1505 if ( t == 0 ) {
1506 di->di_min_ttl = DDS_RF2589_DEFAULT_TTL;
1507
1508 } else {
1509 di->di_min_ttl = (time_t)t;
1510 }
1511 break;
1512
1513 case DDS_DEFAULTTTL:
1514 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1515 snprintf( c->cr_msg, sizeof( c->cr_msg),
1516 "DDS unable to parse dds-default-ttl \"%s\"",
1517 c->argv[ 1 ] );
1518 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1519 "%s: %s.\n", c->log, c->cr_msg );
1520 return 1;
1521 }
1522
1523 if ( t > DDS_RF2589_MAX_TTL ) {
1524 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1525 "DDS invalid dds-default-ttl=%lu",
1526 t );
1527 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1528 "%s: %s.\n", c->log, c->cr_msg );
1529 return 1;
1530 }
1531
1532 if ( t == 0 ) {
1533 di->di_default_ttl = DDS_RF2589_DEFAULT_TTL;
1534
1535 } else {
1536 di->di_default_ttl = (time_t)t;
1537 }
1538 break;
1539
1540 case DDS_INTERVAL:
1541 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1542 snprintf( c->cr_msg, sizeof( c->cr_msg),
1543 "DDS unable to parse dds-interval \"%s\"",
1544 c->argv[ 1 ] );
1545 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1546 "%s: %s.\n", c->log, c->cr_msg );
1547 return 1;
1548 }
1549
1550 if ( t <= 0 ) {
1551 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1552 "DDS invalid dds-interval=%lu",
1553 t );
1554 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1555 "%s: %s.\n", c->log, c->cr_msg );
1556 return 1;
1557 }
1558
1559 if ( t < 60 ) {
1560 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_NOTICE,
1561 "%s: dds-interval=%lu may be too small.\n",
1562 c->log, t );
1563 }
1564
1565 di->di_interval = (time_t)t;
1566 if ( di->di_expire_task ) {
1567 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1568 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) {
1569 ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task );
1570 }
1571 di->di_expire_task->interval.tv_sec = DDS_INTERVAL( di );
1572 ldap_pvt_runqueue_resched( &slapd_rq, di->di_expire_task, 0 );
1573 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1574 }
1575 break;
1576
1577 case DDS_TOLERANCE:
1578 if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
1579 snprintf( c->cr_msg, sizeof( c->cr_msg),
1580 "DDS unable to parse dds-tolerance \"%s\"",
1581 c->argv[ 1 ] );
1582 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1583 "%s: %s.\n", c->log, c->cr_msg );
1584 return 1;
1585 }
1586
1587 if ( t > DDS_RF2589_MAX_TTL ) {
1588 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1589 "DDS invalid dds-tolerance=%lu",
1590 t );
1591 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1592 "%s: %s.\n", c->log, c->cr_msg );
1593 return 1;
1594 }
1595
1596 di->di_tolerance = (time_t)t;
1597 break;
1598
1599 case DDS_MAXDYNAMICOBJS:
1600 if ( c->value_int < 0 ) {
1601 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1602 "DDS invalid dds-max-dynamicObjects=%d", c->value_int );
1603 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1604 "%s: %s.\n", c->log, c->cr_msg );
1605 return 1;
1606 }
1607 di->di_max_dynamicObjects = c->value_int;
1608 break;
1609
1610 default:
1611 rc = 1;
1612 break;
1613 }
1614
1615 return rc;
1616 }
1617
1618 static int
dds_db_init(BackendDB * be,ConfigReply * cr)1619 dds_db_init(
1620 BackendDB *be,
1621 ConfigReply *cr)
1622 {
1623 slap_overinst *on = (slap_overinst *)be->bd_info;
1624 dds_info_t *di;
1625 BackendInfo *bi = on->on_info->oi_orig;
1626
1627 if ( SLAP_ISGLOBALOVERLAY( be ) ) {
1628 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1629 "DDS cannot be used as global overlay.\n" );
1630 return 1;
1631 }
1632
1633 /* check support for required functions */
1634 /* FIXME: some could be provided by other overlays in between */
1635 if ( bi->bi_op_add == NULL /* object creation */
1636 || bi->bi_op_delete == NULL /* object deletion */
1637 || bi->bi_op_modify == NULL /* object refresh */
1638 || bi->bi_op_search == NULL /* object expiration */
1639 || bi->bi_entry_get_rw == NULL ) /* object type/existence checking */
1640 {
1641 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1642 "DDS backend \"%s\" does not provide "
1643 "required functionality.\n",
1644 bi->bi_type );
1645 return 1;
1646 }
1647
1648 di = (dds_info_t *)ch_calloc( 1, sizeof( dds_info_t ) );
1649 on->on_bi.bi_private = di;
1650
1651 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
1652 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
1653
1654 ldap_pvt_thread_mutex_init( &di->di_mutex );
1655
1656 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_DYNAMIC;
1657
1658 return 0;
1659 }
1660
1661 /* adds dynamicSubtrees to root DSE */
1662 static int
dds_entry_info(void * arg,Entry * e)1663 dds_entry_info( void *arg, Entry *e )
1664 {
1665 dds_info_t *di = (dds_info_t *)arg;
1666
1667 attr_merge( e, slap_schema.si_ad_dynamicSubtrees,
1668 di->di_suffix, di->di_nsuffix );
1669
1670 return 0;
1671 }
1672
1673 /* callback that counts the returned entries, since the search
1674 * does not get to the point in slap_send_search_entries where
1675 * the actual count occurs */
1676 static int
dds_count_cb(Operation * op,SlapReply * rs)1677 dds_count_cb( Operation *op, SlapReply *rs )
1678 {
1679 int *nump = (int *)op->o_callback->sc_private;
1680
1681 switch ( rs->sr_type ) {
1682 case REP_SEARCH:
1683 (*nump)++;
1684 break;
1685
1686 case REP_SEARCHREF:
1687 case REP_RESULT:
1688 break;
1689
1690 default:
1691 assert( 0 );
1692 }
1693
1694 return 0;
1695 }
1696
1697 /* count dynamic objects existing in the database at startup */
1698 static int
dds_count(void * ctx,BackendDB * be)1699 dds_count( void *ctx, BackendDB *be )
1700 {
1701 slap_overinst *on = (slap_overinst *)be->bd_info;
1702 dds_info_t *di = (dds_info_t *)on->on_bi.bi_private;
1703
1704 Connection conn = { 0 };
1705 OperationBuffer opbuf;
1706 Operation *op;
1707 slap_callback sc = { 0 };
1708 SlapReply rs = { REP_RESULT };
1709
1710 int rc;
1711 char *extra = "";
1712
1713 connection_fake_init2( &conn, &opbuf, ctx, 0 );
1714 op = &opbuf.ob_op;
1715
1716 op->o_tag = LDAP_REQ_SEARCH;
1717 memset( &op->oq_search, 0, sizeof( op->oq_search ) );
1718
1719 op->o_bd = be;
1720
1721 op->o_req_dn = op->o_bd->be_suffix[ 0 ];
1722 op->o_req_ndn = op->o_bd->be_nsuffix[ 0 ];
1723
1724 op->o_dn = op->o_bd->be_rootdn;
1725 op->o_ndn = op->o_bd->be_rootndn;
1726
1727 op->ors_scope = LDAP_SCOPE_SUBTREE;
1728 op->ors_tlimit = SLAP_NO_LIMIT;
1729 op->ors_slimit = SLAP_NO_LIMIT;
1730 op->ors_attrs = slap_anlist_no_attrs;
1731 op->o_do_not_cache = 1;
1732
1733 op->ors_filterstr.bv_len = STRLENOF( "(objectClass=" ")" )
1734 + slap_schema.si_oc_dynamicObject->soc_cname.bv_len;
1735 op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1736 snprintf( op->ors_filterstr.bv_val, op->ors_filterstr.bv_len + 1,
1737 "(objectClass=%s)",
1738 slap_schema.si_oc_dynamicObject->soc_cname.bv_val );
1739
1740 op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1741 if ( op->ors_filter == NULL ) {
1742 rs.sr_err = LDAP_OTHER;
1743 goto done_search;
1744 }
1745
1746 op->o_callback = ≻
1747 sc.sc_response = dds_count_cb;
1748 sc.sc_private = &di->di_num_dynamicObjects;
1749 di->di_num_dynamicObjects = 0;
1750
1751 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1752 (void)op->o_bd->bd_info->bi_op_search( op, &rs );
1753 op->o_bd->bd_info = (BackendInfo *)on;
1754
1755 done_search:;
1756 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
1757 filter_free_x( op, op->ors_filter, 1 );
1758
1759 rc = rs.sr_err;
1760 switch ( rs.sr_err ) {
1761 case LDAP_SUCCESS:
1762 Log( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
1763 "DDS non-expired=%d\n",
1764 di->di_num_dynamicObjects );
1765 break;
1766
1767 case LDAP_NO_SUCH_OBJECT:
1768 /* (ITS#5267) database not created yet? */
1769 rs.sr_err = LDAP_SUCCESS;
1770 extra = " (ignored)";
1771 /* fallthru */
1772
1773 default:
1774 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1775 "DDS non-expired objects lookup failed err=%d%s\n",
1776 rc, extra );
1777 break;
1778 }
1779
1780 return rs.sr_err;
1781 }
1782
1783 static int
dds_db_open(BackendDB * be,ConfigReply * cr)1784 dds_db_open(
1785 BackendDB *be,
1786 ConfigReply *cr )
1787 {
1788 slap_overinst *on = (slap_overinst *)be->bd_info;
1789 dds_info_t *di = on->on_bi.bi_private;
1790 int rc = 0;
1791 void *thrctx = ldap_pvt_thread_pool_context();
1792
1793 if ( slapMode & SLAP_TOOL_MODE )
1794 return 0;
1795
1796 if ( DDS_OFF( di ) ) {
1797 goto done;
1798 }
1799
1800 if ( SLAP_SINGLE_SHADOW( be ) ) {
1801 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1802 "DDS incompatible with shadow database \"%s\".\n",
1803 be->be_suffix[ 0 ].bv_val );
1804 return 1;
1805 }
1806
1807 if ( di->di_max_ttl == 0 ) {
1808 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
1809 }
1810
1811 if ( di->di_min_ttl == 0 ) {
1812 di->di_max_ttl = DDS_RF2589_DEFAULT_TTL;
1813 }
1814
1815 di->di_suffix = be->be_suffix;
1816 di->di_nsuffix = be->be_nsuffix;
1817
1818 /* count the dynamic objects first */
1819 rc = dds_count( thrctx, be );
1820 if ( rc != LDAP_SUCCESS ) {
1821 rc = 1;
1822 goto done;
1823 }
1824
1825 /* start expire task */
1826 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1827 di->di_expire_task = ldap_pvt_runqueue_insert( &slapd_rq,
1828 DDS_INTERVAL( di ),
1829 dds_expire_fn, di, "dds_expire_fn",
1830 be->be_suffix[ 0 ].bv_val );
1831 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1832
1833 /* register dinamicSubtrees root DSE info support */
1834 rc = entry_info_register( dds_entry_info, (void *)di );
1835
1836 done:;
1837
1838 return rc;
1839 }
1840
1841 static int
dds_db_close(BackendDB * be,ConfigReply * cr)1842 dds_db_close(
1843 BackendDB *be,
1844 ConfigReply *cr )
1845 {
1846 slap_overinst *on = (slap_overinst *)be->bd_info;
1847 dds_info_t *di = on->on_bi.bi_private;
1848
1849 /* stop expire task */
1850 if ( di && di->di_expire_task ) {
1851 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1852 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, di->di_expire_task ) ) {
1853 ldap_pvt_runqueue_stoptask( &slapd_rq, di->di_expire_task );
1854 }
1855 ldap_pvt_runqueue_remove( &slapd_rq, di->di_expire_task );
1856 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1857 di->di_expire_task = NULL;
1858 }
1859
1860 (void)entry_info_unregister( dds_entry_info, (void *)di );
1861
1862 return 0;
1863 }
1864
1865 static int
dds_db_destroy(BackendDB * be,ConfigReply * cr)1866 dds_db_destroy(
1867 BackendDB *be,
1868 ConfigReply *cr )
1869 {
1870 slap_overinst *on = (slap_overinst *)be->bd_info;
1871 dds_info_t *di = on->on_bi.bi_private;
1872
1873 if ( di != NULL ) {
1874 ldap_pvt_thread_mutex_destroy( &di->di_mutex );
1875
1876 free( di );
1877 }
1878
1879 return 0;
1880 }
1881
1882 static int
slap_exop_refresh(Operation * op,SlapReply * rs)1883 slap_exop_refresh(
1884 Operation *op,
1885 SlapReply *rs )
1886 {
1887 BackendDB *bd = op->o_bd;
1888
1889 rs->sr_err = slap_parse_refresh( op->ore_reqdata, &op->o_req_ndn, NULL,
1890 &rs->sr_text, op->o_tmpmemctx );
1891 if ( rs->sr_err != LDAP_SUCCESS ) {
1892 return rs->sr_err;
1893 }
1894
1895 Log( LDAP_DEBUG_STATS, LDAP_LEVEL_INFO,
1896 "%s REFRESH dn=\"%s\"\n",
1897 op->o_log_prefix, op->o_req_ndn.bv_val );
1898 op->o_req_dn = op->o_req_ndn;
1899
1900 op->o_bd = select_backend( &op->o_req_ndn, 0 );
1901 if ( op->o_bd == NULL ) {
1902 send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT,
1903 "no global superior knowledge" );
1904 goto done;
1905 }
1906
1907 if ( !SLAP_DYNAMIC( op->o_bd ) ) {
1908 send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
1909 "backend does not support dynamic directory services" );
1910 goto done;
1911 }
1912
1913 rs->sr_err = backend_check_restrictions( op, rs,
1914 (struct berval *)&slap_EXOP_REFRESH );
1915 if ( rs->sr_err != LDAP_SUCCESS ) {
1916 goto done;
1917 }
1918
1919 if ( op->o_bd->be_extended == NULL ) {
1920 send_ldap_error( op, rs, LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
1921 "backend does not support extended operations" );
1922 goto done;
1923 }
1924
1925 op->o_bd->be_extended( op, rs );
1926
1927 done:;
1928 if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
1929 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
1930 BER_BVZERO( &op->o_req_ndn );
1931 BER_BVZERO( &op->o_req_dn );
1932 }
1933 op->o_bd = bd;
1934
1935 return rs->sr_err;
1936 }
1937
1938 static slap_overinst dds;
1939
1940 static int do_not_load_exop;
1941 static int do_not_replace_exop;
1942 static int do_not_load_schema;
1943
1944 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC
1945 static
1946 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */
1947 int
dds_initialize()1948 dds_initialize()
1949 {
1950 int rc = 0;
1951 int i, code;
1952
1953 /* Make sure we don't exceed the bits reserved for userland */
1954 config_check_userland( DDS_LAST );
1955
1956 if ( !do_not_load_schema ) {
1957 static struct {
1958 char *desc;
1959 slap_mask_t flags;
1960 AttributeDescription **ad;
1961 } s_at[] = {
1962 { "( 1.3.6.1.4.1.4203.666.1.57 "
1963 "NAME ( 'entryExpireTimestamp' ) "
1964 "DESC 'RFC2589 OpenLDAP extension: expire time of a dynamic object, "
1965 "computed as now + entryTtl' "
1966 "EQUALITY generalizedTimeMatch "
1967 "ORDERING generalizedTimeOrderingMatch "
1968 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
1969 "SINGLE-VALUE "
1970 "NO-USER-MODIFICATION "
1971 "USAGE dSAOperation )",
1972 SLAP_AT_HIDE,
1973 &ad_entryExpireTimestamp },
1974 { NULL }
1975 };
1976
1977 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
1978 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 0 );
1979 if ( code ) {
1980 Debug( LDAP_DEBUG_ANY,
1981 "dds_initialize: register_at failed\n" );
1982 return code;
1983 }
1984 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
1985 }
1986 }
1987
1988 if ( !do_not_load_exop ) {
1989 rc = load_extop2( (struct berval *)&slap_EXOP_REFRESH,
1990 SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, slap_exop_refresh,
1991 !do_not_replace_exop );
1992 if ( rc != LDAP_SUCCESS ) {
1993 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
1994 "DDS unable to register refresh exop: %d.\n",
1995 rc );
1996 return rc;
1997 }
1998 }
1999
2000 dds.on_bi.bi_type = "dds";
2001
2002 dds.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
2003 dds.on_bi.bi_db_init = dds_db_init;
2004 dds.on_bi.bi_db_open = dds_db_open;
2005 dds.on_bi.bi_db_close = dds_db_close;
2006 dds.on_bi.bi_db_destroy = dds_db_destroy;
2007
2008 dds.on_bi.bi_op_add = dds_op_add;
2009 dds.on_bi.bi_op_delete = dds_op_delete;
2010 dds.on_bi.bi_op_modify = dds_op_modify;
2011 dds.on_bi.bi_op_modrdn = dds_op_rename;
2012 dds.on_bi.bi_extended = dds_op_extended;
2013 dds.on_response = dds_response;
2014
2015 dds.on_bi.bi_cf_ocs = dds_ocs;
2016
2017 rc = config_register_schema( dds_cfg, dds_ocs );
2018 if ( rc ) {
2019 return rc;
2020 }
2021
2022 return overlay_register( &dds );
2023 }
2024
2025 #if SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC
2026 int
init_module(int argc,char * argv[])2027 init_module( int argc, char *argv[] )
2028 {
2029 int i;
2030
2031 for ( i = 0; i < argc; i++ ) {
2032 char *arg = argv[ i ];
2033 int no = 0;
2034
2035 if ( strncasecmp( arg, "no-", STRLENOF( "no-" ) ) == 0 ) {
2036 arg += STRLENOF( "no-" );
2037 no = 1;
2038 }
2039
2040 if ( strcasecmp( arg, "exop" ) == 0 ) {
2041 do_not_load_exop = no;
2042
2043 } else if ( strcasecmp( arg, "replace" ) == 0 ) {
2044 do_not_replace_exop = no;
2045
2046 } else if ( strcasecmp( arg, "schema" ) == 0 ) {
2047 do_not_load_schema = no;
2048
2049 } else {
2050 Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
2051 "DDS unknown module arg[#%d]=\"%s\".\n",
2052 i, argv[ i ] );
2053 return 1;
2054 }
2055 }
2056
2057 return dds_initialize();
2058 }
2059 #endif /* SLAPD_OVER_DDS == SLAPD_MOD_DYNAMIC */
2060
2061 #endif /* defined(SLAPD_OVER_DDS) */
2062