1 /* memberof.c - back-reference for group membership */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2005-2007 Pierangelo Masarati <ando@sys-net.it>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
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>.
15 */
16 /* ACKNOWLEDGMENTS:
17 * This work was initially developed by Pierangelo Masarati for inclusion
18 * in OpenLDAP Software, sponsored by SysNet s.r.l.
19 */
20
21 #include "portable.h"
22
23 #ifdef SLAPD_OVER_MEMBEROF
24
25 #include <stdio.h>
26
27 #include "ac/string.h"
28 #include "ac/socket.h"
29
30 #include "slap.h"
31 #include "config.h"
32 #include "lutil.h"
33
34 /*
35 * Glossary:
36 *
37 * GROUP a group object (an entry with GROUP_OC
38 * objectClass)
39 * MEMBER a member object (an entry whose DN is
40 * listed as MEMBER_AT value of a GROUP)
41 * GROUP_OC the objectClass of the group object
42 * (default: groupOfNames)
43 * MEMBER_AT the membership attribute, DN-valued;
44 * note: nameAndOptionalUID is tolerated
45 * as soon as the optionalUID is absent
46 * (default: member)
47 * MEMBER_OF reverse membership attribute
48 * (default: memberOf)
49 *
50 * - add:
51 * - if the entry that is being added is a GROUP,
52 * the MEMBER_AT defined as values of the add operation
53 * get the MEMBER_OF value directly from the request.
54 *
55 * if configured to do so, the MEMBER objects do not exist,
56 * and no relax control is issued, either:
57 * - fail
58 * - drop non-existing members
59 * (by default: don't muck with values)
60 *
61 * - if (configured to do so,) the referenced GROUP exists,
62 * the relax control is set and the user has
63 * "manage" privileges, allow to add MEMBER_OF values to
64 * generic entries.
65 *
66 * - modify:
67 * - if the entry being modified is a GROUP_OC and the
68 * MEMBER_AT attribute is modified, the MEMBER_OF value
69 * of the (existing) MEMBER_AT entries that are affected
70 * is modified according to the request:
71 * - if a MEMBER is removed from the group,
72 * delete the corresponding MEMBER_OF
73 * - if a MEMBER is added to a group,
74 * add the corresponding MEMBER_OF
75 *
76 * We need to determine, from the database, if it is
77 * a GROUP_OC, and we need to check, from the
78 * modification list, if the MEMBER_AT attribute is being
79 * affected, and what MEMBER_AT values are affected.
80 *
81 * if configured to do so, the entries corresponding to
82 * the MEMBER_AT values do not exist, and no relax control
83 * is issued, either:
84 * - fail
85 * - drop non-existing members
86 * (by default: don't muck with values)
87 *
88 * - if configured to do so, the referenced GROUP exists,
89 * (the relax control is set) and the user has
90 * "manage" privileges, allow to add MEMBER_OF values to
91 * generic entries; the change is NOT automatically reflected
92 * in the MEMBER attribute of the GROUP referenced
93 * by the value of MEMBER_OF; a separate modification,
94 * with or without relax control, needs to be performed.
95 *
96 * - modrdn:
97 * - if the entry being renamed is a GROUP, the MEMBER_OF
98 * value of the (existing) MEMBER objects is modified
99 * accordingly based on the newDN of the GROUP.
100 *
101 * We need to determine, from the database, if it is
102 * a GROUP; the list of MEMBER objects is obtained from
103 * the database.
104 *
105 * Non-existing MEMBER objects are ignored, since the
106 * MEMBER_AT is not being addressed by the operation.
107 *
108 * - if the entry being renamed has the MEMBER_OF attribute,
109 * the corresponding MEMBER value must be modified in the
110 * respective group entries.
111 *
112 *
113 * - delete:
114 * - if the entry being deleted is a GROUP, the (existing)
115 * MEMBER objects are modified accordingly; a copy of the
116 * values of the MEMBER_AT is saved and, if the delete
117 * succeeds, the MEMBER_OF value of the (existing) MEMBER
118 * objects is deleted.
119 *
120 * We need to determine, from the database, if it is
121 * a GROUP.
122 *
123 * Non-existing MEMBER objects are ignored, since the entry
124 * is being deleted.
125 *
126 * - if the entry being deleted has the MEMBER_OF attribute,
127 * the corresponding value of the MEMBER_AT must be deleted
128 * from the respective GROUP entries.
129 */
130
131 #define SLAPD_MEMBEROF_ATTR "memberOf"
132
133 static AttributeDescription *ad_member;
134 static AttributeDescription *ad_memberOf;
135
136 static ObjectClass *oc_group;
137
138 static slap_overinst memberof;
139
140 typedef struct memberof_t {
141 struct berval mo_dn;
142 struct berval mo_ndn;
143
144 ObjectClass *mo_oc_group;
145 AttributeDescription *mo_ad_member;
146 AttributeDescription *mo_ad_memberof;
147
148 struct berval mo_groupFilterstr;
149 AttributeAssertion mo_groupAVA;
150 Filter mo_groupFilter;
151
152 struct berval mo_memberFilterstr;
153 Filter mo_memberFilter;
154
155 unsigned mo_flags;
156 #define MEMBEROF_NONE 0x00U
157 #define MEMBEROF_FDANGLING_DROP 0x01U
158 #define MEMBEROF_FDANGLING_ERROR 0x02U
159 #define MEMBEROF_FDANGLING_MASK (MEMBEROF_FDANGLING_DROP|MEMBEROF_FDANGLING_ERROR)
160 #define MEMBEROF_FREFINT 0x04U
161 #define MEMBEROF_FREVERSE 0x08U
162
163 ber_int_t mo_dangling_err;
164
165 #define MEMBEROF_CHK(mo,f) \
166 (((mo)->mo_flags & (f)) == (f))
167 #define MEMBEROF_DANGLING_CHECK(mo) \
168 ((mo)->mo_flags & MEMBEROF_FDANGLING_MASK)
169 #define MEMBEROF_DANGLING_DROP(mo) \
170 MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_DROP)
171 #define MEMBEROF_DANGLING_ERROR(mo) \
172 MEMBEROF_CHK((mo),MEMBEROF_FDANGLING_ERROR)
173 #define MEMBEROF_REFINT(mo) \
174 MEMBEROF_CHK((mo),MEMBEROF_FREFINT)
175 #define MEMBEROF_REVERSE(mo) \
176 MEMBEROF_CHK((mo),MEMBEROF_FREVERSE)
177 } memberof_t;
178
179 typedef enum memberof_is_t {
180 MEMBEROF_IS_NONE = 0x00,
181 MEMBEROF_IS_GROUP = 0x01,
182 MEMBEROF_IS_MEMBER = 0x02,
183 MEMBEROF_IS_BOTH = (MEMBEROF_IS_GROUP|MEMBEROF_IS_MEMBER)
184 } memberof_is_t;
185
186 typedef struct memberof_cookie_t {
187 AttributeDescription *ad;
188 BerVarray vals;
189 int foundit;
190 } memberof_cookie_t;
191
192 typedef struct memberof_cbinfo_t {
193 slap_overinst *on;
194 BerVarray member;
195 BerVarray memberof;
196 memberof_is_t what;
197 } memberof_cbinfo_t;
198
199 static void
memberof_set_backend(Operation * op_target,Operation * op,slap_overinst * on)200 memberof_set_backend( Operation *op_target, Operation *op, slap_overinst *on )
201 {
202 BackendInfo *bi = op->o_bd->bd_info;
203
204 if ( bi->bi_type == memberof.on_bi.bi_type )
205 op_target->o_bd->bd_info = (BackendInfo *)on->on_info;
206 }
207
208 static int
memberof_isGroupOrMember_cb(Operation * op,SlapReply * rs)209 memberof_isGroupOrMember_cb( Operation *op, SlapReply *rs )
210 {
211 if ( rs->sr_type == REP_SEARCH ) {
212 memberof_cookie_t *mc;
213
214 mc = (memberof_cookie_t *)op->o_callback->sc_private;
215 mc->foundit = 1;
216 }
217
218 return 0;
219 }
220
221 /*
222 * callback for internal search that saves the member attribute values
223 * of groups being deleted.
224 */
225 static int
memberof_saveMember_cb(Operation * op,SlapReply * rs)226 memberof_saveMember_cb( Operation *op, SlapReply *rs )
227 {
228 if ( rs->sr_type == REP_SEARCH ) {
229 memberof_cookie_t *mc;
230 Attribute *a;
231
232 mc = (memberof_cookie_t *)op->o_callback->sc_private;
233 mc->foundit = 1;
234
235 assert( rs->sr_entry != NULL );
236 assert( rs->sr_entry->e_attrs != NULL );
237
238 a = attr_find( rs->sr_entry->e_attrs, mc->ad );
239 if ( a != NULL ) {
240 ber_bvarray_dup_x( &mc->vals, a->a_nvals, op->o_tmpmemctx );
241
242 assert( attr_find( a->a_next, mc->ad ) == NULL );
243 }
244 }
245
246 return 0;
247 }
248
249 /*
250 * the delete hook performs an internal search that saves the member
251 * attribute values of groups being deleted.
252 */
253 static int
memberof_isGroupOrMember(Operation * op,memberof_cbinfo_t * mci)254 memberof_isGroupOrMember( Operation *op, memberof_cbinfo_t *mci )
255 {
256 slap_overinst *on = mci->on;
257 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
258
259 Operation op2 = *op;
260 slap_callback cb = { 0 };
261 BackendInfo *bi = op->o_bd->bd_info;
262 AttributeName an[ 2 ];
263
264 memberof_is_t iswhat = MEMBEROF_IS_NONE;
265 memberof_cookie_t mc;
266
267 assert( mci->what != MEMBEROF_IS_NONE );
268
269 cb.sc_private = &mc;
270 if ( op->o_tag == LDAP_REQ_DELETE ) {
271 cb.sc_response = memberof_saveMember_cb;
272
273 } else {
274 cb.sc_response = memberof_isGroupOrMember_cb;
275 }
276
277 op2.o_tag = LDAP_REQ_SEARCH;
278 op2.o_callback = &cb;
279 op2.o_dn = op->o_bd->be_rootdn;
280 op2.o_ndn = op->o_bd->be_rootndn;
281
282 op2.ors_scope = LDAP_SCOPE_BASE;
283 op2.ors_deref = LDAP_DEREF_NEVER;
284 BER_BVZERO( &an[ 1 ].an_name );
285 op2.ors_attrs = an;
286 op2.ors_attrsonly = 0;
287 op2.ors_limit = NULL;
288 op2.ors_slimit = 1;
289 op2.ors_tlimit = SLAP_NO_LIMIT;
290
291 if ( mci->what & MEMBEROF_IS_GROUP ) {
292 SlapReply rs2 = { REP_RESULT };
293
294 mc.ad = mo->mo_ad_member;
295 mc.foundit = 0;
296 mc.vals = NULL;
297 an[ 0 ].an_desc = mo->mo_ad_member;
298 an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
299 op2.ors_filterstr = mo->mo_groupFilterstr;
300 op2.ors_filter = &mo->mo_groupFilter;
301 op2.o_do_not_cache = 1; /* internal search, don't log */
302
303 memberof_set_backend( &op2, op, on );
304 (void)op->o_bd->be_search( &op2, &rs2 );
305 op2.o_bd->bd_info = bi;
306
307 if ( mc.foundit ) {
308 iswhat |= MEMBEROF_IS_GROUP;
309 if ( mc.vals ) mci->member = mc.vals;
310
311 }
312 }
313
314 if ( mci->what & MEMBEROF_IS_MEMBER ) {
315 SlapReply rs2 = { REP_RESULT };
316
317 mc.ad = mo->mo_ad_memberof;
318 mc.foundit = 0;
319 mc.vals = NULL;
320 an[ 0 ].an_desc = mo->mo_ad_memberof;
321 an[ 0 ].an_name = an[ 0 ].an_desc->ad_cname;
322 op2.ors_filterstr = mo->mo_memberFilterstr;
323 op2.ors_filter = &mo->mo_memberFilter;
324 op2.o_do_not_cache = 1; /* internal search, don't log */
325
326 memberof_set_backend( &op2, op, on );
327 (void)op->o_bd->be_search( &op2, &rs2 );
328 op2.o_bd->bd_info = bi;
329
330 if ( mc.foundit ) {
331 iswhat |= MEMBEROF_IS_MEMBER;
332 if ( mc.vals ) mci->memberof = mc.vals;
333
334 }
335 }
336
337 mci->what = iswhat;
338
339 return LDAP_SUCCESS;
340 }
341
342 /*
343 * response callback that adds memberof values when a group is modified.
344 */
345 static void
memberof_value_modify(Operation * op,struct berval * ndn,AttributeDescription * ad,struct berval * old_dn,struct berval * old_ndn,struct berval * new_dn,struct berval * new_ndn)346 memberof_value_modify(
347 Operation *op,
348 struct berval *ndn,
349 AttributeDescription *ad,
350 struct berval *old_dn,
351 struct berval *old_ndn,
352 struct berval *new_dn,
353 struct berval *new_ndn )
354 {
355 memberof_cbinfo_t *mci = op->o_callback->sc_private;
356 slap_overinst *on = mci->on;
357 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
358
359 Operation op2 = *op;
360 unsigned long opid = op->o_opid;
361 SlapReply rs2 = { REP_RESULT };
362 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
363 Modifications mod[ 2 ] = { { { 0 } } }, *ml;
364 struct berval values[ 4 ], nvalues[ 4 ];
365 int mcnt = 0;
366
367 if ( old_ndn != NULL && new_ndn != NULL &&
368 ber_bvcmp( old_ndn, new_ndn ) == 0 ) {
369 /* DNs compare equal, it's a noop */
370 return;
371 }
372
373 op2.o_tag = LDAP_REQ_MODIFY;
374
375 op2.o_req_dn = *ndn;
376 op2.o_req_ndn = *ndn;
377
378 op2.o_callback = &cb;
379 op2.o_dn = op->o_bd->be_rootdn;
380 op2.o_ndn = op->o_bd->be_rootndn;
381 op2.orm_modlist = NULL;
382
383 /* Internal ops, never replicate these */
384 op2.o_opid = 0; /* shared with op, saved above */
385 op2.orm_no_opattrs = 1;
386 op2.o_dont_replicate = 1;
387
388 if ( !BER_BVISNULL( &mo->mo_ndn ) ) {
389 ml = &mod[ mcnt ];
390 ml->sml_numvals = 1;
391 ml->sml_values = &values[ 0 ];
392 ml->sml_values[ 0 ] = mo->mo_dn;
393 BER_BVZERO( &ml->sml_values[ 1 ] );
394 ml->sml_nvalues = &nvalues[ 0 ];
395 ml->sml_nvalues[ 0 ] = mo->mo_ndn;
396 BER_BVZERO( &ml->sml_nvalues[ 1 ] );
397 ml->sml_desc = slap_schema.si_ad_modifiersName;
398 ml->sml_type = ml->sml_desc->ad_cname;
399 ml->sml_op = LDAP_MOD_REPLACE;
400 ml->sml_flags = SLAP_MOD_INTERNAL;
401 ml->sml_next = op2.orm_modlist;
402 op2.orm_modlist = ml;
403
404 mcnt++;
405 }
406
407 ml = &mod[ mcnt ];
408 ml->sml_numvals = 1;
409 ml->sml_values = &values[ 2 ];
410 BER_BVZERO( &ml->sml_values[ 1 ] );
411 ml->sml_nvalues = &nvalues[ 2 ];
412 BER_BVZERO( &ml->sml_nvalues[ 1 ] );
413 ml->sml_desc = ad;
414 ml->sml_type = ml->sml_desc->ad_cname;
415 ml->sml_flags = SLAP_MOD_INTERNAL;
416 ml->sml_next = op2.orm_modlist;
417 op2.orm_modlist = ml;
418
419 if ( new_ndn != NULL ) {
420 BackendInfo *bi = op2.o_bd->bd_info;
421 OpExtra oex;
422
423 assert( !BER_BVISNULL( new_dn ) );
424 assert( !BER_BVISNULL( new_ndn ) );
425
426 ml = &mod[ mcnt ];
427 ml->sml_op = LDAP_MOD_ADD;
428
429 ml->sml_values[ 0 ] = *new_dn;
430 ml->sml_nvalues[ 0 ] = *new_ndn;
431
432 oex.oe_key = (void *)&memberof;
433 LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
434 memberof_set_backend( &op2, op, on );
435 (void)op->o_bd->be_modify( &op2, &rs2 );
436 op2.o_bd->bd_info = bi;
437 LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
438 if ( rs2.sr_err != LDAP_SUCCESS ) {
439 char buf[ SLAP_TEXT_BUFLEN ];
440 snprintf( buf, sizeof( buf ),
441 "memberof_value_modify DN=\"%s\" add %s=\"%s\" failed err=%d",
442 op2.o_req_dn.bv_val, ad->ad_cname.bv_val, new_dn->bv_val, rs2.sr_err );
443 Debug( LDAP_DEBUG_ANY, "%s: %s\n",
444 op->o_log_prefix, buf, 0 );
445 }
446
447 assert( op2.orm_modlist == &mod[ mcnt ] );
448 assert( mcnt == 0 || op2.orm_modlist->sml_next == &mod[ 0 ] );
449 ml = op2.orm_modlist->sml_next;
450 if ( mcnt == 1 ) {
451 assert( ml == &mod[ 0 ] );
452 ml = ml->sml_next;
453 }
454 if ( ml != NULL ) {
455 slap_mods_free( ml, 1 );
456 }
457
458 mod[ 0 ].sml_next = NULL;
459 }
460
461 if ( old_ndn != NULL ) {
462 BackendInfo *bi = op2.o_bd->bd_info;
463 OpExtra oex;
464
465 assert( !BER_BVISNULL( old_dn ) );
466 assert( !BER_BVISNULL( old_ndn ) );
467
468 ml = &mod[ mcnt ];
469 ml->sml_op = LDAP_MOD_DELETE;
470
471 ml->sml_values[ 0 ] = *old_dn;
472 ml->sml_nvalues[ 0 ] = *old_ndn;
473
474 oex.oe_key = (void *)&memberof;
475 LDAP_SLIST_INSERT_HEAD(&op2.o_extra, &oex, oe_next);
476 memberof_set_backend( &op2, op, on );
477 (void)op->o_bd->be_modify( &op2, &rs2 );
478 op2.o_bd->bd_info = bi;
479 LDAP_SLIST_REMOVE(&op2.o_extra, &oex, OpExtra, oe_next);
480 if ( rs2.sr_err != LDAP_SUCCESS ) {
481 char buf[ SLAP_TEXT_BUFLEN ];
482 snprintf( buf, sizeof( buf ),
483 "memberof_value_modify DN=\"%s\" delete %s=\"%s\" failed err=%d",
484 op2.o_req_dn.bv_val, ad->ad_cname.bv_val, old_dn->bv_val, rs2.sr_err );
485 Debug( LDAP_DEBUG_ANY, "%s: %s\n",
486 op->o_log_prefix, buf, 0 );
487 }
488
489 assert( op2.orm_modlist == &mod[ mcnt ] );
490 ml = op2.orm_modlist->sml_next;
491 if ( mcnt == 1 ) {
492 assert( ml == &mod[ 0 ] );
493 ml = ml->sml_next;
494 }
495 if ( ml != NULL ) {
496 slap_mods_free( ml, 1 );
497 }
498 }
499 /* restore original opid */
500 op->o_opid = opid;
501
502 /* FIXME: if old_group_ndn doesn't exist, both delete __and__
503 * add will fail; better split in two operations, although
504 * not optimal in terms of performance. At least it would
505 * move towards self-repairing capabilities. */
506 }
507
508 static int
memberof_cleanup(Operation * op,SlapReply * rs)509 memberof_cleanup( Operation *op, SlapReply *rs )
510 {
511 slap_callback *sc = op->o_callback;
512 memberof_cbinfo_t *mci = sc->sc_private;
513
514 op->o_callback = sc->sc_next;
515 if ( mci->memberof )
516 ber_bvarray_free_x( mci->memberof, op->o_tmpmemctx );
517 if ( mci->member )
518 ber_bvarray_free_x( mci->member, op->o_tmpmemctx );
519 op->o_tmpfree( sc, op->o_tmpmemctx );
520 return 0;
521 }
522
523 static int memberof_res_add( Operation *op, SlapReply *rs );
524 static int memberof_res_delete( Operation *op, SlapReply *rs );
525 static int memberof_res_modify( Operation *op, SlapReply *rs );
526 static int memberof_res_modrdn( Operation *op, SlapReply *rs );
527
528 static int
memberof_op_add(Operation * op,SlapReply * rs)529 memberof_op_add( Operation *op, SlapReply *rs )
530 {
531 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
532 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
533
534 Attribute **ap, **map = NULL;
535 int rc = SLAP_CB_CONTINUE;
536 int i;
537 struct berval save_dn, save_ndn;
538 slap_callback *sc;
539 memberof_cbinfo_t *mci;
540 OpExtra *oex;
541
542 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
543 if ( oex->oe_key == (void *)&memberof )
544 return SLAP_CB_CONTINUE;
545 }
546
547 if ( op->ora_e->e_attrs == NULL ) {
548 /* FIXME: global overlay; need to deal with */
549 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
550 "consistency checks not implemented when overlay "
551 "is instantiated as global.\n",
552 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
553 return SLAP_CB_CONTINUE;
554 }
555
556 if ( MEMBEROF_REVERSE( mo ) ) {
557 for ( ap = &op->ora_e->e_attrs; *ap; ap = &(*ap)->a_next ) {
558 Attribute *a = *ap;
559
560 if ( a->a_desc == mo->mo_ad_memberof ) {
561 map = ap;
562 break;
563 }
564 }
565 }
566
567 save_dn = op->o_dn;
568 save_ndn = op->o_ndn;
569
570 if ( MEMBEROF_DANGLING_CHECK( mo )
571 && !get_relax( op )
572 && is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) )
573 {
574 op->o_dn = op->o_bd->be_rootdn;
575 op->o_ndn = op->o_bd->be_rootndn;
576 op->o_bd->bd_info = (BackendInfo *)on->on_info;
577
578 for ( ap = &op->ora_e->e_attrs; *ap; ) {
579 Attribute *a = *ap;
580
581 if ( !is_ad_subtype( a->a_desc, mo->mo_ad_member ) ) {
582 ap = &a->a_next;
583 continue;
584 }
585
586 assert( a->a_nvals != NULL );
587
588 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
589 Entry *e = NULL;
590
591 /* ITS#6670 Ignore member pointing to this entry */
592 if ( dn_match( &a->a_nvals[i], &save_ndn ))
593 continue;
594
595 rc = be_entry_get_rw( op, &a->a_nvals[ i ],
596 NULL, NULL, 0, &e );
597 if ( rc == LDAP_SUCCESS ) {
598 be_entry_release_r( op, e );
599 continue;
600 }
601
602 if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
603 rc = rs->sr_err = mo->mo_dangling_err;
604 rs->sr_text = "adding non-existing object "
605 "as group member";
606 send_ldap_result( op, rs );
607 goto done;
608 }
609
610 if ( MEMBEROF_DANGLING_DROP( mo ) ) {
611 int j;
612
613 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
614 "member=\"%s\" does not exist (stripping...)\n",
615 op->o_log_prefix, op->ora_e->e_name.bv_val,
616 a->a_vals[ i ].bv_val );
617
618 for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ );
619 ber_memfree( a->a_vals[ i ].bv_val );
620 BER_BVZERO( &a->a_vals[ i ] );
621 if ( a->a_nvals != a->a_vals ) {
622 ber_memfree( a->a_nvals[ i ].bv_val );
623 BER_BVZERO( &a->a_nvals[ i ] );
624 }
625 a->a_numvals--;
626 if ( j - i == 1 ) {
627 break;
628 }
629
630 AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ],
631 sizeof( struct berval ) * ( j - i ) );
632 if ( a->a_nvals != a->a_vals ) {
633 AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ],
634 sizeof( struct berval ) * ( j - i ) );
635 }
636 i--;
637 }
638 }
639
640 /* If all values have been removed,
641 * remove the attribute itself. */
642 if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) {
643 *ap = a->a_next;
644 attr_free( a );
645
646 } else {
647 ap = &a->a_next;
648 }
649 }
650 op->o_dn = save_dn;
651 op->o_ndn = save_ndn;
652 op->o_bd->bd_info = (BackendInfo *)on;
653 }
654
655 if ( map != NULL ) {
656 Attribute *a = *map;
657 AccessControlState acl_state = ACL_STATE_INIT;
658
659 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
660 Entry *e;
661
662 op->o_bd->bd_info = (BackendInfo *)on->on_info;
663 /* access is checked with the original identity */
664 rc = access_allowed( op, op->ora_e, mo->mo_ad_memberof,
665 &a->a_nvals[ i ], ACL_WADD,
666 &acl_state );
667 if ( rc == 0 ) {
668 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
669 rs->sr_text = NULL;
670 send_ldap_result( op, rs );
671 goto done;
672 }
673 /* ITS#6670 Ignore member pointing to this entry */
674 if ( dn_match( &a->a_nvals[i], &save_ndn ))
675 continue;
676
677 rc = be_entry_get_rw( op, &a->a_nvals[ i ],
678 NULL, NULL, 0, &e );
679 op->o_bd->bd_info = (BackendInfo *)on;
680 if ( rc != LDAP_SUCCESS ) {
681 if ( get_relax( op ) ) {
682 continue;
683 }
684
685 if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
686 rc = rs->sr_err = mo->mo_dangling_err;
687 rs->sr_text = "adding non-existing object "
688 "as memberof";
689 send_ldap_result( op, rs );
690 goto done;
691 }
692
693 if ( MEMBEROF_DANGLING_DROP( mo ) ) {
694 int j;
695
696 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_add(\"%s\"): "
697 "memberof=\"%s\" does not exist (stripping...)\n",
698 op->o_log_prefix, op->ora_e->e_name.bv_val,
699 a->a_nvals[ i ].bv_val );
700
701 for ( j = i + 1; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ );
702 ber_memfree( a->a_vals[ i ].bv_val );
703 BER_BVZERO( &a->a_vals[ i ] );
704 if ( a->a_nvals != a->a_vals ) {
705 ber_memfree( a->a_nvals[ i ].bv_val );
706 BER_BVZERO( &a->a_nvals[ i ] );
707 }
708 if ( j - i == 1 ) {
709 break;
710 }
711
712 AC_MEMCPY( &a->a_vals[ i ], &a->a_vals[ i + 1 ],
713 sizeof( struct berval ) * ( j - i ) );
714 if ( a->a_nvals != a->a_vals ) {
715 AC_MEMCPY( &a->a_nvals[ i ], &a->a_nvals[ i + 1 ],
716 sizeof( struct berval ) * ( j - i ) );
717 }
718 i--;
719 }
720
721 continue;
722 }
723
724 /* access is checked with the original identity */
725 op->o_bd->bd_info = (BackendInfo *)on->on_info;
726 rc = access_allowed( op, e, mo->mo_ad_member,
727 &op->o_req_ndn, ACL_WADD, NULL );
728 be_entry_release_r( op, e );
729 op->o_bd->bd_info = (BackendInfo *)on;
730
731 if ( !rc ) {
732 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
733 rs->sr_text = "insufficient access to object referenced by memberof";
734 send_ldap_result( op, rs );
735 goto done;
736 }
737 }
738
739 if ( BER_BVISNULL( &a->a_nvals[ 0 ] ) ) {
740 *map = a->a_next;
741 attr_free( a );
742 }
743 }
744
745 rc = SLAP_CB_CONTINUE;
746
747 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
748 sc->sc_private = sc+1;
749 sc->sc_response = memberof_res_add;
750 sc->sc_cleanup = memberof_cleanup;
751 sc->sc_writewait = 0;
752 mci = sc->sc_private;
753 mci->on = on;
754 mci->member = NULL;
755 mci->memberof = NULL;
756 sc->sc_next = op->o_callback;
757 op->o_callback = sc;
758
759 done:;
760 op->o_dn = save_dn;
761 op->o_ndn = save_ndn;
762 op->o_bd->bd_info = (BackendInfo *)on;
763
764 return rc;
765 }
766
767 static int
memberof_op_delete(Operation * op,SlapReply * rs)768 memberof_op_delete( Operation *op, SlapReply *rs )
769 {
770 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
771 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
772
773 slap_callback *sc;
774 memberof_cbinfo_t *mci;
775 OpExtra *oex;
776
777 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
778 if ( oex->oe_key == (void *)&memberof )
779 return SLAP_CB_CONTINUE;
780 }
781
782 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
783 sc->sc_private = sc+1;
784 sc->sc_response = memberof_res_delete;
785 sc->sc_cleanup = memberof_cleanup;
786 sc->sc_writewait = 0;
787 mci = sc->sc_private;
788 mci->on = on;
789 mci->member = NULL;
790 mci->memberof = NULL;
791 mci->what = MEMBEROF_IS_GROUP;
792 if ( MEMBEROF_REFINT( mo ) ) {
793 mci->what = MEMBEROF_IS_BOTH;
794 }
795
796 memberof_isGroupOrMember( op, mci );
797
798 sc->sc_next = op->o_callback;
799 op->o_callback = sc;
800
801 return SLAP_CB_CONTINUE;
802 }
803
804 static int
memberof_op_modify(Operation * op,SlapReply * rs)805 memberof_op_modify( Operation *op, SlapReply *rs )
806 {
807 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
808 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
809
810 Modifications **mlp, **mmlp = NULL;
811 int rc = SLAP_CB_CONTINUE, save_member = 0;
812 struct berval save_dn, save_ndn;
813 slap_callback *sc;
814 memberof_cbinfo_t *mci, mcis;
815 OpExtra *oex;
816
817 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
818 if ( oex->oe_key == (void *)&memberof )
819 return SLAP_CB_CONTINUE;
820 }
821
822 if ( MEMBEROF_REVERSE( mo ) ) {
823 for ( mlp = &op->orm_modlist; *mlp; mlp = &(*mlp)->sml_next ) {
824 Modifications *ml = *mlp;
825
826 if ( ml->sml_desc == mo->mo_ad_memberof ) {
827 mmlp = mlp;
828 break;
829 }
830 }
831 }
832
833 save_dn = op->o_dn;
834 save_ndn = op->o_ndn;
835 mcis.on = on;
836 mcis.what = MEMBEROF_IS_GROUP;
837
838 if ( memberof_isGroupOrMember( op, &mcis ) == LDAP_SUCCESS
839 && ( mcis.what & MEMBEROF_IS_GROUP ) )
840 {
841 Modifications *ml;
842
843 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
844 if ( ml->sml_desc == mo->mo_ad_member ) {
845 switch ( ml->sml_op ) {
846 case LDAP_MOD_DELETE:
847 case LDAP_MOD_REPLACE:
848 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */
849 save_member = 1;
850 break;
851 }
852 }
853 }
854
855
856 if ( MEMBEROF_DANGLING_CHECK( mo )
857 && !get_relax( op ) )
858 {
859 op->o_dn = op->o_bd->be_rootdn;
860 op->o_ndn = op->o_bd->be_rootndn;
861 op->o_bd->bd_info = (BackendInfo *)on->on_info;
862
863 assert( op->orm_modlist != NULL );
864
865 for ( mlp = &op->orm_modlist; *mlp; ) {
866 Modifications *ml = *mlp;
867 int i;
868
869 if ( !is_ad_subtype( ml->sml_desc, mo->mo_ad_member ) ) {
870 mlp = &ml->sml_next;
871 continue;
872 }
873
874 switch ( ml->sml_op ) {
875 case LDAP_MOD_DELETE:
876 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */
877 /* we don't care about cancellations: if the value
878 * exists, fine; if it doesn't, we let the underlying
879 * database fail as appropriate; */
880 mlp = &ml->sml_next;
881 break;
882
883 case LDAP_MOD_REPLACE:
884 /* Handle this just like a delete (see above) */
885 if ( !ml->sml_values ) {
886 mlp = &ml->sml_next;
887 break;
888 }
889
890 case LDAP_MOD_ADD:
891 case SLAP_MOD_SOFTADD: /* ITS#7487 */
892 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */
893 /* NOTE: right now, the attributeType we use
894 * for member must have a normalized value */
895 assert( ml->sml_nvalues != NULL );
896
897 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
898 Entry *e;
899
900 /* ITS#6670 Ignore member pointing to this entry */
901 if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
902 continue;
903
904 if ( be_entry_get_rw( op, &ml->sml_nvalues[ i ],
905 NULL, NULL, 0, &e ) == LDAP_SUCCESS )
906 {
907 be_entry_release_r( op, e );
908 continue;
909 }
910
911 if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
912 rc = rs->sr_err = mo->mo_dangling_err;
913 rs->sr_text = "adding non-existing object "
914 "as group member";
915 send_ldap_result( op, rs );
916 goto done;
917 }
918
919 if ( MEMBEROF_DANGLING_DROP( mo ) ) {
920 int j;
921
922 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
923 "member=\"%s\" does not exist (stripping...)\n",
924 op->o_log_prefix, op->o_req_dn.bv_val,
925 ml->sml_nvalues[ i ].bv_val );
926
927 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
928 ber_memfree( ml->sml_values[ i ].bv_val );
929 BER_BVZERO( &ml->sml_values[ i ] );
930 ber_memfree( ml->sml_nvalues[ i ].bv_val );
931 BER_BVZERO( &ml->sml_nvalues[ i ] );
932 ml->sml_numvals--;
933 if ( j - i == 1 ) {
934 break;
935 }
936
937 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
938 sizeof( struct berval ) * ( j - i ) );
939 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
940 sizeof( struct berval ) * ( j - i ) );
941 i--;
942 }
943 }
944
945 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
946 *mlp = ml->sml_next;
947 slap_mod_free( &ml->sml_mod, 0 );
948 free( ml );
949
950 } else {
951 mlp = &ml->sml_next;
952 }
953
954 break;
955
956 default:
957 assert( 0 );
958 }
959 }
960 }
961 }
962
963 if ( mmlp != NULL ) {
964 Modifications *ml = *mmlp;
965 int i;
966 Entry *target;
967
968 op->o_bd->bd_info = (BackendInfo *)on->on_info;
969 rc = be_entry_get_rw( op, &op->o_req_ndn,
970 NULL, NULL, 0, &target );
971 op->o_bd->bd_info = (BackendInfo *)on;
972 if ( rc != LDAP_SUCCESS ) {
973 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
974 send_ldap_result( op, rs );
975 goto done;
976 }
977
978 switch ( ml->sml_op ) {
979 case LDAP_MOD_DELETE:
980 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */
981 if ( ml->sml_nvalues != NULL ) {
982 AccessControlState acl_state = ACL_STATE_INIT;
983
984 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
985 Entry *e;
986
987 op->o_bd->bd_info = (BackendInfo *)on->on_info;
988 /* access is checked with the original identity */
989 rc = access_allowed( op, target,
990 mo->mo_ad_memberof,
991 &ml->sml_nvalues[ i ],
992 ACL_WDEL,
993 &acl_state );
994 if ( rc == 0 ) {
995 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
996 rs->sr_text = NULL;
997 send_ldap_result( op, rs );
998 goto done2;
999 }
1000
1001 rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ],
1002 NULL, NULL, 0, &e );
1003 op->o_bd->bd_info = (BackendInfo *)on;
1004 if ( rc != LDAP_SUCCESS ) {
1005 if ( get_relax( op ) ) {
1006 continue;
1007 }
1008
1009 if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
1010 rc = rs->sr_err = mo->mo_dangling_err;
1011 rs->sr_text = "deleting non-existing object "
1012 "as memberof";
1013 send_ldap_result( op, rs );
1014 goto done2;
1015 }
1016
1017 if ( MEMBEROF_DANGLING_DROP( mo ) ) {
1018 int j;
1019
1020 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
1021 "memberof=\"%s\" does not exist (stripping...)\n",
1022 op->o_log_prefix, op->o_req_ndn.bv_val,
1023 ml->sml_nvalues[ i ].bv_val );
1024
1025 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
1026 ber_memfree( ml->sml_values[ i ].bv_val );
1027 BER_BVZERO( &ml->sml_values[ i ] );
1028 if ( ml->sml_nvalues != ml->sml_values ) {
1029 ber_memfree( ml->sml_nvalues[ i ].bv_val );
1030 BER_BVZERO( &ml->sml_nvalues[ i ] );
1031 }
1032 ml->sml_numvals--;
1033 if ( j - i == 1 ) {
1034 break;
1035 }
1036
1037 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
1038 sizeof( struct berval ) * ( j - i ) );
1039 if ( ml->sml_nvalues != ml->sml_values ) {
1040 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
1041 sizeof( struct berval ) * ( j - i ) );
1042 }
1043 i--;
1044 }
1045
1046 continue;
1047 }
1048
1049 /* access is checked with the original identity */
1050 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1051 rc = access_allowed( op, e, mo->mo_ad_member,
1052 &op->o_req_ndn,
1053 ACL_WDEL, NULL );
1054 be_entry_release_r( op, e );
1055 op->o_bd->bd_info = (BackendInfo *)on;
1056
1057 if ( !rc ) {
1058 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1059 rs->sr_text = "insufficient access to object referenced by memberof";
1060 send_ldap_result( op, rs );
1061 goto done;
1062 }
1063 }
1064
1065 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
1066 *mmlp = ml->sml_next;
1067 slap_mod_free( &ml->sml_mod, 0 );
1068 free( ml );
1069 }
1070
1071 break;
1072 }
1073 /* fall thru */
1074
1075 case LDAP_MOD_REPLACE:
1076
1077 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1078 /* access is checked with the original identity */
1079 rc = access_allowed( op, target,
1080 mo->mo_ad_memberof,
1081 NULL,
1082 ACL_WDEL, NULL );
1083 op->o_bd->bd_info = (BackendInfo *)on;
1084 if ( rc == 0 ) {
1085 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1086 rs->sr_text = NULL;
1087 send_ldap_result( op, rs );
1088 goto done2;
1089 }
1090
1091 if ( ml->sml_op == LDAP_MOD_DELETE || ml->sml_op == SLAP_MOD_SOFTDEL || !ml->sml_values ) {
1092 break;
1093 }
1094 /* fall thru */
1095
1096 case LDAP_MOD_ADD:
1097 case SLAP_MOD_SOFTADD: /* ITS#7487 */
1098 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */
1099 {
1100 AccessControlState acl_state = ACL_STATE_INIT;
1101
1102 for ( i = 0; !BER_BVISNULL( &ml->sml_nvalues[ i ] ); i++ ) {
1103 Entry *e;
1104
1105 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1106 /* access is checked with the original identity */
1107 rc = access_allowed( op, target,
1108 mo->mo_ad_memberof,
1109 &ml->sml_nvalues[ i ],
1110 ACL_WADD,
1111 &acl_state );
1112 if ( rc == 0 ) {
1113 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1114 rs->sr_text = NULL;
1115 send_ldap_result( op, rs );
1116 goto done2;
1117 }
1118
1119 /* ITS#6670 Ignore member pointing to this entry */
1120 if ( dn_match( &ml->sml_nvalues[i], &save_ndn ))
1121 continue;
1122
1123 rc = be_entry_get_rw( op, &ml->sml_nvalues[ i ],
1124 NULL, NULL, 0, &e );
1125 op->o_bd->bd_info = (BackendInfo *)on;
1126 if ( rc != LDAP_SUCCESS ) {
1127 if ( MEMBEROF_DANGLING_ERROR( mo ) ) {
1128 rc = rs->sr_err = mo->mo_dangling_err;
1129 rs->sr_text = "adding non-existing object "
1130 "as memberof";
1131 send_ldap_result( op, rs );
1132 goto done2;
1133 }
1134
1135 if ( MEMBEROF_DANGLING_DROP( mo ) ) {
1136 int j;
1137
1138 Debug( LDAP_DEBUG_ANY, "%s: memberof_op_modify(\"%s\"): "
1139 "memberof=\"%s\" does not exist (stripping...)\n",
1140 op->o_log_prefix, op->o_req_ndn.bv_val,
1141 ml->sml_nvalues[ i ].bv_val );
1142
1143 for ( j = i + 1; !BER_BVISNULL( &ml->sml_nvalues[ j ] ); j++ );
1144 ber_memfree( ml->sml_values[ i ].bv_val );
1145 BER_BVZERO( &ml->sml_values[ i ] );
1146 if ( ml->sml_nvalues != ml->sml_values ) {
1147 ber_memfree( ml->sml_nvalues[ i ].bv_val );
1148 BER_BVZERO( &ml->sml_nvalues[ i ] );
1149 }
1150 ml->sml_numvals--;
1151 if ( j - i == 1 ) {
1152 break;
1153 }
1154
1155 AC_MEMCPY( &ml->sml_values[ i ], &ml->sml_values[ i + 1 ],
1156 sizeof( struct berval ) * ( j - i ) );
1157 if ( ml->sml_nvalues != ml->sml_values ) {
1158 AC_MEMCPY( &ml->sml_nvalues[ i ], &ml->sml_nvalues[ i + 1 ],
1159 sizeof( struct berval ) * ( j - i ) );
1160 }
1161 i--;
1162 }
1163
1164 continue;
1165 }
1166
1167 /* access is checked with the original identity */
1168 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1169 rc = access_allowed( op, e, mo->mo_ad_member,
1170 &op->o_req_ndn,
1171 ACL_WDEL, NULL );
1172 be_entry_release_r( op, e );
1173 op->o_bd->bd_info = (BackendInfo *)on;
1174
1175 if ( !rc ) {
1176 rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1177 rs->sr_text = "insufficient access to object referenced by memberof";
1178 send_ldap_result( op, rs );
1179 goto done;
1180 }
1181 }
1182
1183 if ( BER_BVISNULL( &ml->sml_nvalues[ 0 ] ) ) {
1184 *mmlp = ml->sml_next;
1185 slap_mod_free( &ml->sml_mod, 0 );
1186 free( ml );
1187 }
1188
1189 } break;
1190
1191 default:
1192 assert( 0 );
1193 }
1194
1195 done2:;
1196 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1197 be_entry_release_r( op, target );
1198 op->o_bd->bd_info = (BackendInfo *)on;
1199 }
1200
1201 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
1202 sc->sc_private = sc+1;
1203 sc->sc_response = memberof_res_modify;
1204 sc->sc_cleanup = memberof_cleanup;
1205 sc->sc_writewait = 0;
1206 mci = sc->sc_private;
1207 mci->on = on;
1208 mci->member = NULL;
1209 mci->memberof = NULL;
1210 mci->what = mcis.what;
1211
1212 if ( save_member ) {
1213 op->o_dn = op->o_bd->be_rootdn;
1214 op->o_ndn = op->o_bd->be_rootndn;
1215 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1216 rc = backend_attribute( op, NULL, &op->o_req_ndn,
1217 mo->mo_ad_member, &mci->member, ACL_READ );
1218 op->o_bd->bd_info = (BackendInfo *)on;
1219 }
1220
1221 sc->sc_next = op->o_callback;
1222 op->o_callback = sc;
1223
1224 rc = SLAP_CB_CONTINUE;
1225
1226 done:;
1227 op->o_dn = save_dn;
1228 op->o_ndn = save_ndn;
1229 op->o_bd->bd_info = (BackendInfo *)on;
1230
1231 return rc;
1232 }
1233
1234 static int
memberof_op_modrdn(Operation * op,SlapReply * rs)1235 memberof_op_modrdn( Operation *op, SlapReply *rs )
1236 {
1237 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1238 slap_callback *sc;
1239 memberof_cbinfo_t *mci;
1240 OpExtra *oex;
1241
1242 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1243 if ( oex->oe_key == (void *)&memberof )
1244 return SLAP_CB_CONTINUE;
1245 }
1246
1247 sc = op->o_tmpalloc( sizeof(slap_callback)+sizeof(*mci), op->o_tmpmemctx );
1248 sc->sc_private = sc+1;
1249 sc->sc_response = memberof_res_modrdn;
1250 sc->sc_cleanup = memberof_cleanup;
1251 sc->sc_writewait = 0;
1252 mci = sc->sc_private;
1253 mci->on = on;
1254 mci->member = NULL;
1255 mci->memberof = NULL;
1256
1257 sc->sc_next = op->o_callback;
1258 op->o_callback = sc;
1259
1260 return SLAP_CB_CONTINUE;
1261 }
1262
1263 /*
1264 * response callback that adds memberof values when a group is added.
1265 */
1266 static int
memberof_res_add(Operation * op,SlapReply * rs)1267 memberof_res_add( Operation *op, SlapReply *rs )
1268 {
1269 memberof_cbinfo_t *mci = op->o_callback->sc_private;
1270 slap_overinst *on = mci->on;
1271 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
1272
1273 int i;
1274
1275 if ( rs->sr_err != LDAP_SUCCESS ) {
1276 return SLAP_CB_CONTINUE;
1277 }
1278
1279 if ( MEMBEROF_REVERSE( mo ) ) {
1280 Attribute *ma;
1281
1282 ma = attr_find( op->ora_e->e_attrs, mo->mo_ad_memberof );
1283 if ( ma != NULL ) {
1284 /* relax is required to allow to add
1285 * a non-existing member */
1286 op->o_relax = SLAP_CONTROL_CRITICAL;
1287
1288 for ( i = 0; !BER_BVISNULL( &ma->a_nvals[ i ] ); i++ ) {
1289
1290 /* ITS#6670 Ignore member pointing to this entry */
1291 if ( dn_match( &ma->a_nvals[i], &op->o_req_ndn ))
1292 continue;
1293
1294 /* the modification is attempted
1295 * with the original identity */
1296 memberof_value_modify( op,
1297 &ma->a_nvals[ i ], mo->mo_ad_member,
1298 NULL, NULL, &op->o_req_dn, &op->o_req_ndn );
1299 }
1300 }
1301 }
1302
1303 if ( is_entry_objectclass_or_sub( op->ora_e, mo->mo_oc_group ) ) {
1304 Attribute *a;
1305
1306 for ( a = attrs_find( op->ora_e->e_attrs, mo->mo_ad_member );
1307 a != NULL;
1308 a = attrs_find( a->a_next, mo->mo_ad_member ) )
1309 {
1310 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
1311 /* ITS#6670 Ignore member pointing to this entry */
1312 if ( dn_match( &a->a_nvals[i], &op->o_req_ndn ))
1313 continue;
1314
1315 memberof_value_modify( op,
1316 &a->a_nvals[ i ],
1317 mo->mo_ad_memberof,
1318 NULL, NULL,
1319 &op->o_req_dn,
1320 &op->o_req_ndn );
1321 }
1322 }
1323 }
1324
1325 return SLAP_CB_CONTINUE;
1326 }
1327
1328 /*
1329 * response callback that deletes memberof values when a group is deleted.
1330 */
1331 static int
memberof_res_delete(Operation * op,SlapReply * rs)1332 memberof_res_delete( Operation *op, SlapReply *rs )
1333 {
1334 memberof_cbinfo_t *mci = op->o_callback->sc_private;
1335 slap_overinst *on = mci->on;
1336 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
1337
1338 BerVarray vals;
1339 int i;
1340
1341 if ( rs->sr_err != LDAP_SUCCESS ) {
1342 return SLAP_CB_CONTINUE;
1343 }
1344
1345 vals = mci->member;
1346 if ( vals != NULL ) {
1347 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1348 memberof_value_modify( op,
1349 &vals[ i ], mo->mo_ad_memberof,
1350 &op->o_req_dn, &op->o_req_ndn,
1351 NULL, NULL );
1352 }
1353 }
1354
1355 if ( MEMBEROF_REFINT( mo ) ) {
1356 vals = mci->memberof;
1357 if ( vals != NULL ) {
1358 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1359 memberof_value_modify( op,
1360 &vals[ i ], mo->mo_ad_member,
1361 &op->o_req_dn, &op->o_req_ndn,
1362 NULL, NULL );
1363 }
1364 }
1365 }
1366
1367 return SLAP_CB_CONTINUE;
1368 }
1369
1370 /*
1371 * response callback that adds/deletes memberof values when a group
1372 * is modified.
1373 */
1374 static int
memberof_res_modify(Operation * op,SlapReply * rs)1375 memberof_res_modify( Operation *op, SlapReply *rs )
1376 {
1377 memberof_cbinfo_t *mci = op->o_callback->sc_private;
1378 slap_overinst *on = mci->on;
1379 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
1380
1381 int i, rc;
1382 Modifications *ml, *mml = NULL;
1383 BerVarray vals;
1384
1385 if ( rs->sr_err != LDAP_SUCCESS ) {
1386 return SLAP_CB_CONTINUE;
1387 }
1388
1389 if ( MEMBEROF_REVERSE( mo ) ) {
1390 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
1391 if ( ml->sml_desc == mo->mo_ad_memberof ) {
1392 mml = ml;
1393 break;
1394 }
1395 }
1396 }
1397
1398 if ( mml != NULL ) {
1399 BerVarray vals = mml->sml_nvalues;
1400
1401 switch ( mml->sml_op ) {
1402 case LDAP_MOD_DELETE:
1403 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */
1404 if ( vals != NULL ) {
1405 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1406 memberof_value_modify( op,
1407 &vals[ i ], mo->mo_ad_member,
1408 &op->o_req_dn, &op->o_req_ndn,
1409 NULL, NULL );
1410 }
1411 break;
1412 }
1413 /* fall thru */
1414
1415 case LDAP_MOD_REPLACE:
1416 /* delete all ... */
1417 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1418 rc = backend_attribute( op, NULL, &op->o_req_ndn,
1419 mo->mo_ad_memberof, &vals, ACL_READ );
1420 op->o_bd->bd_info = (BackendInfo *)on;
1421 if ( rc == LDAP_SUCCESS ) {
1422 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1423 memberof_value_modify( op,
1424 &vals[ i ], mo->mo_ad_member,
1425 &op->o_req_dn, &op->o_req_ndn,
1426 NULL, NULL );
1427 }
1428 ber_bvarray_free_x( vals, op->o_tmpmemctx );
1429 }
1430
1431 if ( ml->sml_op == LDAP_MOD_DELETE || !mml->sml_values ) {
1432 break;
1433 }
1434 /* fall thru */
1435
1436 case LDAP_MOD_ADD:
1437 case SLAP_MOD_SOFTADD: /* ITS#7487 */
1438 case SLAP_MOD_ADD_IF_NOT_PRESENT: /* ITS#7487 */
1439 assert( vals != NULL );
1440
1441 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1442 memberof_value_modify( op,
1443 &vals[ i ], mo->mo_ad_member,
1444 NULL, NULL,
1445 &op->o_req_dn, &op->o_req_ndn );
1446 }
1447 break;
1448
1449 default:
1450 assert( 0 );
1451 }
1452 }
1453
1454 if ( mci->what & MEMBEROF_IS_GROUP )
1455 {
1456 for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
1457 if ( ml->sml_desc != mo->mo_ad_member ) {
1458 continue;
1459 }
1460
1461 switch ( ml->sml_op ) {
1462 case LDAP_MOD_DELETE:
1463 case SLAP_MOD_SOFTDEL: /* ITS#7487: can be used by syncrepl (in mirror mode?) */
1464 vals = ml->sml_nvalues;
1465 if ( vals != NULL ) {
1466 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1467 memberof_value_modify( op,
1468 &vals[ i ], mo->mo_ad_memberof,
1469 &op->o_req_dn, &op->o_req_ndn,
1470 NULL, NULL );
1471 }
1472 break;
1473 }
1474 /* fall thru */
1475
1476 case LDAP_MOD_REPLACE:
1477 vals = mci->member;
1478
1479 /* delete all ... */
1480 if ( vals != NULL ) {
1481 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1482 memberof_value_modify( op,
1483 &vals[ i ], mo->mo_ad_memberof,
1484 &op->o_req_dn, &op->o_req_ndn,
1485 NULL, NULL );
1486 }
1487 }
1488
1489 if ( ml->sml_op == LDAP_MOD_DELETE || ml->sml_op == SLAP_MOD_SOFTDEL || !ml->sml_values ) {
1490 break;
1491 }
1492 /* fall thru */
1493
1494 case LDAP_MOD_ADD:
1495 case SLAP_MOD_SOFTADD: /* ITS#7487 */
1496 case SLAP_MOD_ADD_IF_NOT_PRESENT : /* ITS#7487 */
1497 assert( ml->sml_nvalues != NULL );
1498 vals = ml->sml_nvalues;
1499 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1500 memberof_value_modify( op,
1501 &vals[ i ], mo->mo_ad_memberof,
1502 NULL, NULL,
1503 &op->o_req_dn, &op->o_req_ndn );
1504 }
1505 break;
1506
1507 default:
1508 assert( 0 );
1509 }
1510 }
1511 }
1512
1513 return SLAP_CB_CONTINUE;
1514 }
1515
1516 /*
1517 * response callback that adds/deletes member values when a group member
1518 * is renamed.
1519 */
1520 static int
memberof_res_modrdn(Operation * op,SlapReply * rs)1521 memberof_res_modrdn( Operation *op, SlapReply *rs )
1522 {
1523 memberof_cbinfo_t *mci = op->o_callback->sc_private;
1524 slap_overinst *on = mci->on;
1525 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
1526
1527 struct berval newPDN, newDN = BER_BVNULL, newPNDN, newNDN;
1528 int i, rc;
1529 BerVarray vals;
1530
1531 struct berval save_dn, save_ndn;
1532
1533 if ( rs->sr_err != LDAP_SUCCESS ) {
1534 return SLAP_CB_CONTINUE;
1535 }
1536
1537 mci->what = MEMBEROF_IS_GROUP;
1538 if ( MEMBEROF_REFINT( mo ) ) {
1539 mci->what |= MEMBEROF_IS_MEMBER;
1540 }
1541
1542 if ( op->orr_nnewSup ) {
1543 newPNDN = *op->orr_nnewSup;
1544
1545 } else {
1546 dnParent( &op->o_req_ndn, &newPNDN );
1547 }
1548
1549 build_new_dn( &newNDN, &newPNDN, &op->orr_nnewrdn, op->o_tmpmemctx );
1550
1551 save_dn = op->o_req_dn;
1552 save_ndn = op->o_req_ndn;
1553
1554 op->o_req_dn = newNDN;
1555 op->o_req_ndn = newNDN;
1556 rc = memberof_isGroupOrMember( op, mci );
1557 op->o_req_dn = save_dn;
1558 op->o_req_ndn = save_ndn;
1559
1560 if ( rc != LDAP_SUCCESS || mci->what == MEMBEROF_IS_NONE ) {
1561 goto done;
1562 }
1563
1564 if ( op->orr_newSup ) {
1565 newPDN = *op->orr_newSup;
1566
1567 } else {
1568 dnParent( &op->o_req_dn, &newPDN );
1569 }
1570
1571 build_new_dn( &newDN, &newPDN, &op->orr_newrdn, op->o_tmpmemctx );
1572
1573 if ( mci->what & MEMBEROF_IS_GROUP ) {
1574 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1575 rc = backend_attribute( op, NULL, &newNDN,
1576 mo->mo_ad_member, &vals, ACL_READ );
1577 op->o_bd->bd_info = (BackendInfo *)on;
1578
1579 if ( rc == LDAP_SUCCESS ) {
1580 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1581 memberof_value_modify( op,
1582 &vals[ i ], mo->mo_ad_memberof,
1583 &op->o_req_dn, &op->o_req_ndn,
1584 &newDN, &newNDN );
1585 }
1586 ber_bvarray_free_x( vals, op->o_tmpmemctx );
1587 }
1588 }
1589
1590 if ( MEMBEROF_REFINT( mo ) && ( mci->what & MEMBEROF_IS_MEMBER ) ) {
1591 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1592 rc = backend_attribute( op, NULL, &newNDN,
1593 mo->mo_ad_memberof, &vals, ACL_READ );
1594 op->o_bd->bd_info = (BackendInfo *)on;
1595
1596 if ( rc == LDAP_SUCCESS ) {
1597 for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
1598 memberof_value_modify( op,
1599 &vals[ i ], mo->mo_ad_member,
1600 &op->o_req_dn, &op->o_req_ndn,
1601 &newDN, &newNDN );
1602 }
1603 ber_bvarray_free_x( vals, op->o_tmpmemctx );
1604 }
1605 }
1606
1607 done:;
1608 if ( !BER_BVISNULL( &newDN ) ) {
1609 op->o_tmpfree( newDN.bv_val, op->o_tmpmemctx );
1610 }
1611 op->o_tmpfree( newNDN.bv_val, op->o_tmpmemctx );
1612
1613 return SLAP_CB_CONTINUE;
1614 }
1615
1616
1617 static int
memberof_db_init(BackendDB * be,ConfigReply * cr)1618 memberof_db_init(
1619 BackendDB *be,
1620 ConfigReply *cr )
1621 {
1622 slap_overinst *on = (slap_overinst *)be->bd_info;
1623 memberof_t *mo;
1624 const char *text = NULL;
1625 int rc;
1626
1627 mo = (memberof_t *)ch_calloc( 1, sizeof( memberof_t ) );
1628
1629 /* safe default */
1630 mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
1631
1632 if ( !ad_memberOf ) {
1633 rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &ad_memberOf, &text );
1634 if ( rc != LDAP_SUCCESS ) {
1635 Debug( LDAP_DEBUG_ANY, "memberof_db_init: "
1636 "unable to find attribute=\"%s\": %s (%d)\n",
1637 SLAPD_MEMBEROF_ATTR, text, rc );
1638 return rc;
1639 }
1640 }
1641
1642 if ( !ad_member ) {
1643 rc = slap_str2ad( SLAPD_GROUP_ATTR, &ad_member, &text );
1644 if ( rc != LDAP_SUCCESS ) {
1645 Debug( LDAP_DEBUG_ANY, "memberof_db_init: "
1646 "unable to find attribute=\"%s\": %s (%d)\n",
1647 SLAPD_GROUP_ATTR, text, rc );
1648 return rc;
1649 }
1650 }
1651
1652 if ( !oc_group ) {
1653 oc_group = oc_find( SLAPD_GROUP_CLASS );
1654 if ( oc_group == NULL ) {
1655 Debug( LDAP_DEBUG_ANY,
1656 "memberof_db_init: "
1657 "unable to find objectClass=\"%s\"\n",
1658 SLAPD_GROUP_CLASS, 0, 0 );
1659 return 1;
1660 }
1661 }
1662
1663 on->on_bi.bi_private = (void *)mo;
1664
1665 return 0;
1666 }
1667
1668 enum {
1669 MO_DN = 1,
1670 MO_DANGLING,
1671 MO_REFINT,
1672 MO_GROUP_OC,
1673 MO_MEMBER_AD,
1674 MO_MEMBER_OF_AD,
1675 #if 0
1676 MO_REVERSE,
1677 #endif
1678
1679 MO_DANGLING_ERROR,
1680
1681 MO_LAST
1682 };
1683
1684 static ConfigDriver mo_cf_gen;
1685
1686 #define OID "1.3.6.1.4.1.7136.2.666.4"
1687 #define OIDAT OID ".1.1"
1688 #define OIDCFGAT OID ".1.2"
1689 #define OIDOC OID ".2.1"
1690 #define OIDCFGOC OID ".2.2"
1691
1692
1693 static ConfigTable mo_cfg[] = {
1694 { "memberof-dn", "modifiersName",
1695 2, 2, 0, ARG_MAGIC|ARG_DN|MO_DN, mo_cf_gen,
1696 "( OLcfgOvAt:18.0 NAME 'olcMemberOfDN' "
1697 "DESC 'DN to be used as modifiersName' "
1698 "SYNTAX OMsDN SINGLE-VALUE )",
1699 NULL, NULL },
1700
1701 { "memberof-dangling", "ignore|drop|error",
1702 2, 2, 0, ARG_MAGIC|MO_DANGLING, mo_cf_gen,
1703 "( OLcfgOvAt:18.1 NAME 'olcMemberOfDangling' "
1704 "DESC 'Behavior with respect to dangling members, "
1705 "constrained to ignore, drop, error' "
1706 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1707 NULL, NULL },
1708
1709 { "memberof-refint", "true|FALSE",
1710 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REFINT, mo_cf_gen,
1711 "( OLcfgOvAt:18.2 NAME 'olcMemberOfRefInt' "
1712 "DESC 'Take care of referential integrity' "
1713 "SYNTAX OMsBoolean SINGLE-VALUE )",
1714 NULL, NULL },
1715
1716 { "memberof-group-oc", "objectClass",
1717 2, 2, 0, ARG_MAGIC|MO_GROUP_OC, mo_cf_gen,
1718 "( OLcfgOvAt:18.3 NAME 'olcMemberOfGroupOC' "
1719 "DESC 'Group objectClass' "
1720 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1721 NULL, NULL },
1722
1723 { "memberof-member-ad", "member attribute",
1724 2, 2, 0, ARG_MAGIC|ARG_ATDESC|MO_MEMBER_AD, mo_cf_gen,
1725 "( OLcfgOvAt:18.4 NAME 'olcMemberOfMemberAD' "
1726 "DESC 'member attribute' "
1727 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1728 NULL, NULL },
1729
1730 { "memberof-memberof-ad", "memberOf attribute",
1731 2, 2, 0, ARG_MAGIC|ARG_ATDESC|MO_MEMBER_OF_AD, mo_cf_gen,
1732 "( OLcfgOvAt:18.5 NAME 'olcMemberOfMemberOfAD' "
1733 "DESC 'memberOf attribute' "
1734 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1735 NULL, NULL },
1736
1737 #if 0
1738 { "memberof-reverse", "true|FALSE",
1739 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|MO_REVERSE, mo_cf_gen,
1740 "( OLcfgOvAt:18.6 NAME 'olcMemberOfReverse' "
1741 "DESC 'Take care of referential integrity "
1742 "also when directly modifying memberOf' "
1743 "SYNTAX OMsBoolean SINGLE-VALUE )",
1744 NULL, NULL },
1745 #endif
1746
1747 { "memberof-dangling-error", "error code",
1748 2, 2, 0, ARG_MAGIC|MO_DANGLING_ERROR, mo_cf_gen,
1749 "( OLcfgOvAt:18.7 NAME 'olcMemberOfDanglingError' "
1750 "DESC 'Error code returned in case of dangling back reference' "
1751 "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1752 NULL, NULL },
1753
1754 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1755 };
1756
1757 static ConfigOCs mo_ocs[] = {
1758 { "( OLcfgOvOc:18.1 "
1759 "NAME 'olcMemberOf' "
1760 "DESC 'Member-of configuration' "
1761 "SUP olcOverlayConfig "
1762 "MAY ( "
1763 "olcMemberOfDN "
1764 "$ olcMemberOfDangling "
1765 "$ olcMemberOfDanglingError"
1766 "$ olcMemberOfRefInt "
1767 "$ olcMemberOfGroupOC "
1768 "$ olcMemberOfMemberAD "
1769 "$ olcMemberOfMemberOfAD "
1770 #if 0
1771 "$ olcMemberOfReverse "
1772 #endif
1773 ") "
1774 ")",
1775 Cft_Overlay, mo_cfg, NULL, NULL },
1776 { NULL, 0, NULL }
1777 };
1778
1779 static slap_verbmasks dangling_mode[] = {
1780 { BER_BVC( "ignore" ), MEMBEROF_NONE },
1781 { BER_BVC( "drop" ), MEMBEROF_FDANGLING_DROP },
1782 { BER_BVC( "error" ), MEMBEROF_FDANGLING_ERROR },
1783 { BER_BVNULL, 0 }
1784 };
1785
1786 static int
memberof_make_group_filter(memberof_t * mo)1787 memberof_make_group_filter( memberof_t *mo )
1788 {
1789 char *ptr;
1790
1791 if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
1792 ch_free( mo->mo_groupFilterstr.bv_val );
1793 }
1794
1795 mo->mo_groupFilter.f_choice = LDAP_FILTER_EQUALITY;
1796 mo->mo_groupFilter.f_ava = &mo->mo_groupAVA;
1797
1798 mo->mo_groupFilter.f_av_desc = slap_schema.si_ad_objectClass;
1799 mo->mo_groupFilter.f_av_value = mo->mo_oc_group->soc_cname;
1800
1801 mo->mo_groupFilterstr.bv_len = STRLENOF( "(=)" )
1802 + slap_schema.si_ad_objectClass->ad_cname.bv_len
1803 + mo->mo_oc_group->soc_cname.bv_len;
1804 ptr = mo->mo_groupFilterstr.bv_val = ch_malloc( mo->mo_groupFilterstr.bv_len + 1 );
1805 *ptr++ = '(';
1806 ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1807 *ptr++ = '=';
1808 ptr = lutil_strcopy( ptr, mo->mo_oc_group->soc_cname.bv_val );
1809 *ptr++ = ')';
1810 *ptr = '\0';
1811
1812 return 0;
1813 }
1814
1815 static int
memberof_make_member_filter(memberof_t * mo)1816 memberof_make_member_filter( memberof_t *mo )
1817 {
1818 char *ptr;
1819
1820 if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
1821 ch_free( mo->mo_memberFilterstr.bv_val );
1822 }
1823
1824 mo->mo_memberFilter.f_choice = LDAP_FILTER_PRESENT;
1825 mo->mo_memberFilter.f_desc = mo->mo_ad_memberof;
1826
1827 mo->mo_memberFilterstr.bv_len = STRLENOF( "(=*)" )
1828 + mo->mo_ad_memberof->ad_cname.bv_len;
1829 ptr = mo->mo_memberFilterstr.bv_val = ch_malloc( mo->mo_memberFilterstr.bv_len + 1 );
1830 *ptr++ = '(';
1831 ptr = lutil_strcopy( ptr, mo->mo_ad_memberof->ad_cname.bv_val );
1832 ptr = lutil_strcopy( ptr, "=*)" );
1833
1834 return 0;
1835 }
1836
1837 static int
mo_cf_gen(ConfigArgs * c)1838 mo_cf_gen( ConfigArgs *c )
1839 {
1840 slap_overinst *on = (slap_overinst *)c->bi;
1841 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
1842
1843 int i, rc = 0;
1844
1845 if ( c->op == SLAP_CONFIG_EMIT ) {
1846 struct berval bv = BER_BVNULL;
1847
1848 switch( c->type ) {
1849 case MO_DN:
1850 if ( mo->mo_dn.bv_val != NULL) {
1851 value_add_one( &c->rvalue_vals, &mo->mo_dn );
1852 value_add_one( &c->rvalue_nvals, &mo->mo_ndn );
1853 }
1854 break;
1855
1856 case MO_DANGLING:
1857 enum_to_verb( dangling_mode, (mo->mo_flags & MEMBEROF_FDANGLING_MASK), &bv );
1858 if ( BER_BVISNULL( &bv ) ) {
1859 /* there's something wrong... */
1860 assert( 0 );
1861 rc = 1;
1862
1863 } else {
1864 value_add_one( &c->rvalue_vals, &bv );
1865 }
1866 break;
1867
1868 case MO_DANGLING_ERROR:
1869 if ( mo->mo_flags & MEMBEROF_FDANGLING_ERROR ) {
1870 char buf[ SLAP_TEXT_BUFLEN ];
1871 enum_to_verb( slap_ldap_response_code, mo->mo_dangling_err, &bv );
1872 if ( BER_BVISNULL( &bv ) ) {
1873 bv.bv_len = snprintf( buf, sizeof( buf ), "0x%x", mo->mo_dangling_err );
1874 if ( bv.bv_len < sizeof( buf ) ) {
1875 bv.bv_val = buf;
1876 } else {
1877 rc = 1;
1878 break;
1879 }
1880 }
1881 value_add_one( &c->rvalue_vals, &bv );
1882 } else {
1883 rc = 1;
1884 }
1885 break;
1886
1887 case MO_REFINT:
1888 c->value_int = MEMBEROF_REFINT( mo );
1889 break;
1890
1891 #if 0
1892 case MO_REVERSE:
1893 c->value_int = MEMBEROF_REVERSE( mo );
1894 break;
1895 #endif
1896
1897 case MO_GROUP_OC:
1898 if ( mo->mo_oc_group != NULL ){
1899 value_add_one( &c->rvalue_vals, &mo->mo_oc_group->soc_cname );
1900 }
1901 break;
1902
1903 case MO_MEMBER_AD:
1904 c->value_ad = mo->mo_ad_member;
1905 break;
1906
1907 case MO_MEMBER_OF_AD:
1908 c->value_ad = mo->mo_ad_memberof;
1909 break;
1910
1911 default:
1912 assert( 0 );
1913 return 1;
1914 }
1915
1916 return rc;
1917
1918 } else if ( c->op == LDAP_MOD_DELETE ) {
1919 switch( c->type ) {
1920 case MO_DN:
1921 if ( !BER_BVISNULL( &mo->mo_dn ) ) {
1922 ber_memfree( mo->mo_dn.bv_val );
1923 ber_memfree( mo->mo_ndn.bv_val );
1924 BER_BVZERO( &mo->mo_dn );
1925 BER_BVZERO( &mo->mo_ndn );
1926 }
1927 break;
1928
1929 case MO_DANGLING:
1930 mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK;
1931 break;
1932
1933 case MO_DANGLING_ERROR:
1934 mo->mo_dangling_err = LDAP_CONSTRAINT_VIOLATION;
1935 break;
1936
1937 case MO_REFINT:
1938 mo->mo_flags &= ~MEMBEROF_FREFINT;
1939 break;
1940
1941 #if 0
1942 case MO_REVERSE:
1943 mo->mo_flags &= ~MEMBEROF_FREVERSE;
1944 break;
1945 #endif
1946
1947 case MO_GROUP_OC:
1948 mo->mo_oc_group = oc_group;
1949 memberof_make_group_filter( mo );
1950 break;
1951
1952 case MO_MEMBER_AD:
1953 mo->mo_ad_member = ad_member;
1954 break;
1955
1956 case MO_MEMBER_OF_AD:
1957 mo->mo_ad_memberof = ad_memberOf;
1958 memberof_make_member_filter( mo );
1959 break;
1960
1961 default:
1962 assert( 0 );
1963 return 1;
1964 }
1965
1966 } else {
1967 switch( c->type ) {
1968 case MO_DN:
1969 if ( !BER_BVISNULL( &mo->mo_dn ) ) {
1970 ber_memfree( mo->mo_dn.bv_val );
1971 ber_memfree( mo->mo_ndn.bv_val );
1972 }
1973 mo->mo_dn = c->value_dn;
1974 mo->mo_ndn = c->value_ndn;
1975 break;
1976
1977 case MO_DANGLING:
1978 i = verb_to_mask( c->argv[ 1 ], dangling_mode );
1979 if ( BER_BVISNULL( &dangling_mode[ i ].word ) ) {
1980 return 1;
1981 }
1982
1983 mo->mo_flags &= ~MEMBEROF_FDANGLING_MASK;
1984 mo->mo_flags |= dangling_mode[ i ].mask;
1985 break;
1986
1987 case MO_DANGLING_ERROR:
1988 i = verb_to_mask( c->argv[ 1 ], slap_ldap_response_code );
1989 if ( !BER_BVISNULL( &slap_ldap_response_code[ i ].word ) ) {
1990 mo->mo_dangling_err = slap_ldap_response_code[ i ].mask;
1991 } else if ( lutil_atoix( &mo->mo_dangling_err, c->argv[ 1 ], 0 ) ) {
1992 return 1;
1993 }
1994 break;
1995
1996 case MO_REFINT:
1997 if ( c->value_int ) {
1998 mo->mo_flags |= MEMBEROF_FREFINT;
1999
2000 } else {
2001 mo->mo_flags &= ~MEMBEROF_FREFINT;
2002 }
2003 break;
2004
2005 #if 0
2006 case MO_REVERSE:
2007 if ( c->value_int ) {
2008 mo->mo_flags |= MEMBEROF_FREVERSE;
2009
2010 } else {
2011 mo->mo_flags &= ~MEMBEROF_FREVERSE;
2012 }
2013 break;
2014 #endif
2015
2016 case MO_GROUP_OC: {
2017 ObjectClass *oc = NULL;
2018
2019 oc = oc_find( c->argv[ 1 ] );
2020 if ( oc == NULL ) {
2021 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2022 "unable to find group objectClass=\"%s\"",
2023 c->argv[ 1 ] );
2024 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
2025 c->log, c->cr_msg, 0 );
2026 return 1;
2027 }
2028
2029 mo->mo_oc_group = oc;
2030 memberof_make_group_filter( mo );
2031 } break;
2032
2033 case MO_MEMBER_AD: {
2034 AttributeDescription *ad = c->value_ad;
2035
2036 if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */
2037 && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
2038 {
2039 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2040 "member attribute=\"%s\" must either "
2041 "have DN (%s) or nameUID (%s) syntax",
2042 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
2043 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
2044 c->log, c->cr_msg, 0 );
2045 return 1;
2046 }
2047
2048 mo->mo_ad_member = ad;
2049 } break;
2050
2051 case MO_MEMBER_OF_AD: {
2052 AttributeDescription *ad = c->value_ad;
2053
2054 if ( !is_at_syntax( ad->ad_type, SLAPD_DN_SYNTAX ) /* e.g. "member" */
2055 && !is_at_syntax( ad->ad_type, SLAPD_NAMEUID_SYNTAX ) ) /* e.g. "uniqueMember" */
2056 {
2057 snprintf( c->cr_msg, sizeof( c->cr_msg ),
2058 "memberof attribute=\"%s\" must either "
2059 "have DN (%s) or nameUID (%s) syntax",
2060 c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
2061 Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n",
2062 c->log, c->cr_msg, 0 );
2063 return 1;
2064 }
2065
2066 mo->mo_ad_memberof = ad;
2067 memberof_make_member_filter( mo );
2068 } break;
2069
2070 default:
2071 assert( 0 );
2072 return 1;
2073 }
2074 }
2075
2076 return 0;
2077 }
2078
2079 static int
memberof_db_open(BackendDB * be,ConfigReply * cr)2080 memberof_db_open(
2081 BackendDB *be,
2082 ConfigReply *cr )
2083 {
2084 slap_overinst *on = (slap_overinst *)be->bd_info;
2085 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
2086
2087 int rc;
2088
2089 if ( !mo->mo_ad_memberof ) {
2090 mo->mo_ad_memberof = ad_memberOf;
2091 }
2092
2093 if ( ! mo->mo_ad_member ) {
2094 mo->mo_ad_member = ad_member;
2095 }
2096
2097 if ( ! mo->mo_oc_group ) {
2098 mo->mo_oc_group = oc_group;
2099 }
2100
2101 if ( BER_BVISNULL( &mo->mo_dn ) && !BER_BVISNULL( &be->be_rootdn ) ) {
2102 ber_dupbv( &mo->mo_dn, &be->be_rootdn );
2103 ber_dupbv( &mo->mo_ndn, &be->be_rootndn );
2104 }
2105
2106 if ( BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
2107 memberof_make_group_filter( mo );
2108 }
2109
2110 if ( BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
2111 memberof_make_member_filter( mo );
2112 }
2113
2114 return 0;
2115 }
2116
2117 static int
memberof_db_destroy(BackendDB * be,ConfigReply * cr)2118 memberof_db_destroy(
2119 BackendDB *be,
2120 ConfigReply *cr )
2121 {
2122 slap_overinst *on = (slap_overinst *)be->bd_info;
2123 memberof_t *mo = (memberof_t *)on->on_bi.bi_private;
2124
2125 if ( mo ) {
2126 if ( !BER_BVISNULL( &mo->mo_dn ) ) {
2127 ber_memfree( mo->mo_dn.bv_val );
2128 ber_memfree( mo->mo_ndn.bv_val );
2129 }
2130
2131 if ( !BER_BVISNULL( &mo->mo_groupFilterstr ) ) {
2132 ber_memfree( mo->mo_groupFilterstr.bv_val );
2133 }
2134
2135 if ( !BER_BVISNULL( &mo->mo_memberFilterstr ) ) {
2136 ber_memfree( mo->mo_memberFilterstr.bv_val );
2137 }
2138
2139 ber_memfree( mo );
2140 }
2141
2142 return 0;
2143 }
2144
2145 static struct {
2146 char *desc;
2147 AttributeDescription **adp;
2148 } as[] = {
2149 { "( 1.2.840.113556.1.2.102 "
2150 "NAME 'memberOf' "
2151 "DESC 'Group that the entry belongs to' "
2152 "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' "
2153 "EQUALITY distinguishedNameMatch " /* added */
2154 "USAGE dSAOperation " /* added; questioned */
2155 /* "NO-USER-MODIFICATION " */ /* add? */
2156 "X-ORIGIN 'iPlanet Delegated Administrator' )",
2157 &ad_memberOf },
2158 { NULL }
2159 };
2160
2161 #if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC
2162 static
2163 #endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */
2164 int
memberof_initialize(void)2165 memberof_initialize( void )
2166 {
2167 int code, i;
2168
2169 for ( i = 0; as[ i ].desc != NULL; i++ ) {
2170 code = register_at( as[ i ].desc, as[ i ].adp, 0 );
2171 if ( code ) {
2172 Debug( LDAP_DEBUG_ANY,
2173 "memberof_initialize: register_at #%d failed\n",
2174 i, 0, 0 );
2175 return code;
2176 }
2177 }
2178
2179 memberof.on_bi.bi_type = "memberof";
2180
2181 memberof.on_bi.bi_db_init = memberof_db_init;
2182 memberof.on_bi.bi_db_open = memberof_db_open;
2183 memberof.on_bi.bi_db_destroy = memberof_db_destroy;
2184
2185 memberof.on_bi.bi_op_add = memberof_op_add;
2186 memberof.on_bi.bi_op_delete = memberof_op_delete;
2187 memberof.on_bi.bi_op_modify = memberof_op_modify;
2188 memberof.on_bi.bi_op_modrdn = memberof_op_modrdn;
2189
2190 memberof.on_bi.bi_cf_ocs = mo_ocs;
2191
2192 code = config_register_schema( mo_cfg, mo_ocs );
2193 if ( code ) return code;
2194
2195 return overlay_register( &memberof );
2196 }
2197
2198 #if SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC
2199 int
init_module(int argc,char * argv[])2200 init_module( int argc, char *argv[] )
2201 {
2202 return memberof_initialize();
2203 }
2204 #endif /* SLAPD_OVER_MEMBEROF == SLAPD_MOD_DYNAMIC */
2205
2206 #endif /* SLAPD_OVER_MEMBEROF */
2207