1 /*        $NetBSD: autogroup.c,v 1.3 2021/08/14 16:14:51 christos Exp $         */
2 
3 /* autogroup.c - automatic group overlay */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2007-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2007 Michał Szulczyński.
9  * Portions Copyright 2009 Howard Chu.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by Michał Szulczyński for inclusion in
22  * OpenLDAP Software.  Additional significant contributors include:
23  *   Howard Chu
24  *   Raphael Ouazana
25  *   Norbert Pueschel
26  *   Christian Manal
27  */
28 
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: autogroup.c,v 1.3 2021/08/14 16:14:51 christos Exp $");
31 
32 #include "portable.h"
33 
34 #include <stdio.h>
35 
36 #include <ac/string.h>
37 
38 #include "slap.h"
39 #include "slap-config.h"
40 #include "lutil.h"
41 
42 #ifndef SLAPD_MEMBEROF_ATTR
43 #define   SLAPD_MEMBEROF_ATTR "memberOf"
44 #endif
45 
46 static slap_overinst          autogroup;
47 
48 /* Filter represents the memberURL of a group. */
49 typedef struct autogroup_filter_t {
50           struct berval                           agf_dn;   /* The base DN in memberURL */
51           struct berval                           agf_ndn;
52           struct berval                           agf_filterstr;
53           Filter                                  *agf_filter;
54           int                                     agf_scope;
55           AttributeName                           *agf_anlist;
56           struct autogroup_filter_t     *agf_next;
57 } autogroup_filter_t;
58 
59 /* Description of group attributes. */
60 typedef struct autogroup_def_t {
61           ObjectClass                   *agd_oc;
62           AttributeDescription          *agd_member_url_ad;
63           AttributeDescription          *agd_member_ad;
64           struct autogroup_def_t        *agd_next;
65 } autogroup_def_t;
66 
67 /* Represents the group entry. */
68 typedef struct autogroup_entry_t {
69           BerValue            age_dn;
70           BerValue            age_ndn;
71           autogroup_filter_t  *age_filter; /* List of filters made from memberURLs */
72           autogroup_def_t               *age_def; /* Attribute definition */
73           ldap_pvt_thread_mutex_t age_mutex;
74           int                           age_mustrefresh; /* Defined in request to refresh in response */
75           int                           age_modrdn_olddnmodified; /* Defined in request to refresh in response */
76           struct autogroup_entry_t      *age_next;
77 } autogroup_entry_t;
78 
79 /* Holds pointers to attribute definitions and groups. */
80 typedef struct autogroup_info_t {
81           autogroup_def_t               *agi_def; /* Group attributes definitions. */
82           autogroup_entry_t   *agi_entry;         /* Group entries.  */
83           AttributeDescription          *agi_memberof_ad;   /* memberOf attribute description  */
84           ldap_pvt_thread_mutex_t agi_mutex;
85 } autogroup_info_t;
86 
87 /* Search callback for adding groups initially. */
88 typedef struct autogroup_sc_t {
89           autogroup_info_t              *ags_info;          /* Group definitions and entries.  */
90           autogroup_def_t               *ags_def; /* Attributes definition of the group being added. */
91 } autogroup_sc_t;
92 
93 /* Used for adding members, found when searching, to a group. */
94 typedef struct autogroup_ga_t {
95           autogroup_entry_t   *agg_group;         /* The group to which the members will be added. */
96           autogroup_filter_t  *agg_filter;        /* Current filter */
97           Entry                         *agg_entry;         /* Used in autogroup_member_search_cb to modify
98                                                             this entry with the search results. */
99 
100           Modifications                 *agg_mod; /* Used in autogroup_member_search_modify_cb to hold the
101                                                             search results which will be added to the group. */
102 
103           Modifications                 *agg_mod_last; /* Used in autogroup_member_search_modify_cb so we don't
104                                                             have to search for the last mod added. */
105 } autogroup_ga_t;
106 
107 
108 /*
109 **        dn, ndn   - the DN of the member to add
110 **        age       - the group to which the member DN will be added
111 */
112 static int
autogroup_add_member_to_group(Operation * op,BerValue * dn,BerValue * ndn,autogroup_entry_t * age)113 autogroup_add_member_to_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
114 {
115           slap_overinst       *on = (slap_overinst *)op->o_bd->bd_info;
116           Modifications       *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
117           SlapReply sreply = {REP_RESULT};
118           BerValue  *vals, *nvals;
119           slap_callback       cb = { NULL, slap_null_cb, NULL, NULL };
120           Operation o = *op;
121           unsigned long opid = op->o_opid;
122           OpExtra oex;
123 
124           assert( dn != NULL );
125           assert( ndn != NULL );
126           Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_to_group adding <%s> to <%s>\n",
127                     dn->bv_val, age->age_dn.bv_val );
128 
129           vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
130           nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
131           ber_dupbv( vals, dn );
132           BER_BVZERO( &vals[ 1 ] );
133           ber_dupbv( nvals, ndn );
134           BER_BVZERO( &nvals[ 1 ] );
135 
136           modlist->sml_op = LDAP_MOD_ADD;
137           modlist->sml_desc = age->age_def->agd_member_ad;
138           modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
139           modlist->sml_values = vals;
140           modlist->sml_nvalues = nvals;
141           modlist->sml_numvals = 1;
142           modlist->sml_flags = SLAP_MOD_INTERNAL;
143           modlist->sml_next = NULL;
144 
145           o.o_opid = 0;       /* shared with op, saved above */
146           o.o_tag = LDAP_REQ_MODIFY;
147           o.o_callback = &cb;
148           o.orm_modlist = modlist;
149           o.o_dn = op->o_bd->be_rootdn;
150           o.o_ndn = op->o_bd->be_rootndn;
151           o.o_req_dn = age->age_dn;
152           o.o_req_ndn = age->age_ndn;
153           o.o_permissive_modify = 1;
154           o.o_dont_replicate = 1;
155           o.orm_no_opattrs = 1;
156           o.o_managedsait = SLAP_CONTROL_CRITICAL;
157           o.o_relax = SLAP_CONTROL_CRITICAL;
158 
159           oex.oe_key = (void *)&autogroup;
160           LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
161 
162           o.o_bd->bd_info = (BackendInfo *)on->on_info;
163           (void)op->o_bd->be_modify( &o, &sreply );
164           o.o_bd->bd_info = (BackendInfo *)on;
165 
166           LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
167 
168           slap_mods_free( modlist, 1 );
169           op->o_opid = opid;
170 
171           return sreply.sr_err;
172 }
173 
174 /*
175 **        e         - the entry where to get the attribute values
176 **        age       - the group to which the values will be added
177 */
178 static int
autogroup_add_member_values_to_group(Operation * op,struct berval * dn,autogroup_entry_t * age,Attribute * attr)179 autogroup_add_member_values_to_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
180 {
181           slap_overinst       *on = (slap_overinst *)op->o_bd->bd_info;
182           Modifications       modlist;
183           SlapReply sreply = {REP_RESULT};
184           slap_callback       cb = { NULL, slap_null_cb, NULL, NULL };
185           Operation o = *op;
186           unsigned long opid = op->o_opid;
187           OpExtra oex;
188 
189           Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_member_values_to_group adding <%s> to <%s>\n",
190                     dn->bv_val, age->age_dn.bv_val );
191 
192           modlist.sml_op = LDAP_MOD_ADD;
193           modlist.sml_desc = age->age_def->agd_member_ad;
194           modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
195           modlist.sml_values = attr->a_vals;
196           modlist.sml_nvalues = attr->a_nvals;
197           modlist.sml_numvals = attr->a_numvals;
198           modlist.sml_flags = SLAP_MOD_INTERNAL;
199           modlist.sml_next = NULL;
200 
201           o.o_opid = 0;
202           o.o_tag = LDAP_REQ_MODIFY;
203           o.o_callback = &cb;
204           o.orm_modlist = &modlist;
205           o.o_dn = op->o_bd->be_rootdn;
206           o.o_ndn = op->o_bd->be_rootndn;
207           o.o_req_dn = age->age_dn;
208           o.o_req_ndn = age->age_ndn;
209           o.o_permissive_modify = 1;
210           o.o_dont_replicate = 1;
211           o.orm_no_opattrs = 1;
212           o.o_managedsait = SLAP_CONTROL_CRITICAL;
213           o.o_relax = SLAP_CONTROL_CRITICAL;
214 
215           oex.oe_key = (void *)&autogroup;
216           LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
217 
218           o.o_bd->bd_info = (BackendInfo *)on->on_info;
219           (void)op->o_bd->be_modify( &o, &sreply );
220           o.o_bd->bd_info = (BackendInfo *)on;
221           op->o_opid = opid;
222           LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
223 
224           return sreply.sr_err;
225 }
226 
227 /*
228 ** dn,ndn - the DN to be deleted
229 ** age              - the group from which the DN will be deleted
230 ** If we pass a NULL dn and ndn, all members are deleted from the group.
231 */
232 static int
autogroup_delete_member_from_group(Operation * op,BerValue * dn,BerValue * ndn,autogroup_entry_t * age)233 autogroup_delete_member_from_group( Operation *op, BerValue *dn, BerValue *ndn, autogroup_entry_t *age )
234 {
235           slap_overinst       *on = (slap_overinst *)op->o_bd->bd_info;
236           Modifications       *modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
237           SlapReply sreply = {REP_RESULT};
238           BerValue  *vals, *nvals;
239           slap_callback       cb = { NULL, slap_null_cb, NULL, NULL };
240           Operation o = *op;
241           unsigned long opid = op->o_opid;
242           OpExtra oex;
243 
244           if ( dn == NULL || ndn == NULL ) {
245                     Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing all members from <%s>\n",
246                               age->age_dn.bv_val );
247 
248                     modlist->sml_values = NULL;
249                     modlist->sml_nvalues = NULL;
250                     modlist->sml_numvals = 0;
251           } else {
252                     Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_from_group removing <%s> from <%s>\n",
253                               dn->bv_val, age->age_dn.bv_val );
254 
255                     vals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
256                     nvals = (BerValue *)ch_calloc( 2, sizeof( BerValue ) );
257                     ber_dupbv( vals, dn );
258                     BER_BVZERO( &vals[ 1 ] );
259                     ber_dupbv( nvals, ndn );
260                     BER_BVZERO( &nvals[ 1 ] );
261 
262                     modlist->sml_values = vals;
263                     modlist->sml_nvalues = nvals;
264                     modlist->sml_numvals = 1;
265           }
266 
267 
268           modlist->sml_op = LDAP_MOD_DELETE;
269           modlist->sml_desc = age->age_def->agd_member_ad;
270           modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
271           modlist->sml_flags = SLAP_MOD_INTERNAL;
272           modlist->sml_next = NULL;
273 
274           o.o_opid = 0;
275           o.o_callback = &cb;
276           o.o_tag = LDAP_REQ_MODIFY;
277           o.orm_modlist = modlist;
278           o.o_dn = op->o_bd->be_rootdn;
279           o.o_ndn = op->o_bd->be_rootndn;
280           o.o_req_dn = age->age_dn;
281           o.o_req_ndn = age->age_ndn;
282           o.o_relax = SLAP_CONTROL_CRITICAL;
283           o.o_managedsait = SLAP_CONTROL_CRITICAL;
284           o.o_permissive_modify = 1;
285           o.o_dont_replicate = 1;
286           o.orm_no_opattrs = 1;
287 
288           oex.oe_key = (void *)&autogroup;
289           LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
290 
291           o.o_bd->bd_info = (BackendInfo *)on->on_info;
292           (void)op->o_bd->be_modify( &o, &sreply );
293           o.o_bd->bd_info = (BackendInfo *)on;
294 
295           LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
296 
297           slap_mods_free( modlist, 1 );
298 
299           op->o_opid = opid;
300           return sreply.sr_err;
301 }
302 
303 /*
304 **      e       - the entry where to get the attribute values
305 **      age     - the group from which the values will be deleted
306 */
307 static int
autogroup_delete_member_values_from_group(Operation * op,struct berval * dn,autogroup_entry_t * age,Attribute * attr)308 autogroup_delete_member_values_from_group( Operation *op, struct berval *dn, autogroup_entry_t *age, Attribute *attr )
309 {
310         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
311         Modifications   modlist;
312         SlapReply       sreply = {REP_RESULT};
313         slap_callback   cb = { NULL, slap_null_cb, NULL, NULL };
314         Operation       o = *op;
315           unsigned long opid = op->o_opid;
316           OpExtra oex;
317 
318         Debug(LDAP_DEBUG_TRACE, "==> autogroup_delete_member_values_from_group removing <%s> from <%s>\n",
319                               dn->bv_val, age->age_dn.bv_val );
320 
321         modlist.sml_op = LDAP_MOD_DELETE;
322         modlist.sml_desc = age->age_def->agd_member_ad;
323         modlist.sml_type = age->age_def->agd_member_ad->ad_cname;
324         modlist.sml_values = attr->a_vals;
325         modlist.sml_nvalues = attr->a_nvals;
326         modlist.sml_numvals = attr->a_numvals;
327         modlist.sml_flags = SLAP_MOD_INTERNAL;
328         modlist.sml_next = NULL;
329 
330           o.o_opid = 0;
331         o.o_tag = LDAP_REQ_MODIFY;
332         o.o_callback = &cb;
333         o.orm_modlist = &modlist;
334                     o.o_dn = op->o_bd->be_rootdn;
335                     o.o_ndn = op->o_bd->be_rootndn;
336         o.o_req_dn = age->age_dn;
337         o.o_req_ndn = age->age_ndn;
338         o.o_permissive_modify = 1;
339           o.o_dont_replicate = 1;
340           o.orm_no_opattrs = 1;
341         o.o_managedsait = SLAP_CONTROL_CRITICAL;
342         o.o_relax = SLAP_CONTROL_CRITICAL;
343 
344           oex.oe_key = (void *)&autogroup;
345           LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
346 
347         o.o_bd->bd_info = (BackendInfo *)on->on_info;
348         (void)op->o_bd->be_modify( &o, &sreply );
349         o.o_bd->bd_info = (BackendInfo *)on;
350           op->o_opid = opid;
351 
352           LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
353 
354         return sreply.sr_err;
355 }
356 
357 /*
358 ** Callback used to add entries to a group,
359 ** which are going to be written in the database
360 ** (used in bi_op_add)
361 ** The group is passed in autogroup_ga_t->agg_group
362 */
363 static int
autogroup_member_search_cb(Operation * op,SlapReply * rs)364 autogroup_member_search_cb( Operation *op, SlapReply *rs )
365 {
366           assert( op->o_tag == LDAP_REQ_SEARCH );
367 
368           if ( rs->sr_type == REP_SEARCH ) {
369                     autogroup_ga_t                *agg = (autogroup_ga_t *)op->o_callback->sc_private;
370                     autogroup_entry_t   *age = agg->agg_group;
371                     autogroup_filter_t  *agf = agg->agg_filter;
372                     Modification                  mod;
373                     const char                    *text = NULL;
374                     char                          textbuf[1024];
375                     struct berval                 *vals, *nvals;
376                     struct berval                 lvals[ 2 ], lnvals[ 2 ];
377                     int                           numvals;
378 
379                     Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_cb <%s>\n",
380                               rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN" );
381 
382                     if ( agf->agf_anlist ) {
383                               Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
384                               if (attr) {
385                                         vals = attr->a_vals;
386                                         nvals = attr->a_nvals;
387                                         numvals = attr->a_numvals;
388                               } else {
389                                         // Nothing to add
390                                         return 0;
391                               }
392                     } else {
393                               lvals[ 0 ] = rs->sr_entry->e_name;
394                               BER_BVZERO( &lvals[ 1 ] );
395                               lnvals[ 0 ] = rs->sr_entry->e_nname;
396                               BER_BVZERO( &lnvals[ 1 ] );
397                               vals = lvals;
398                               nvals = lnvals;
399                               numvals = 1;
400                     }
401 
402                     mod.sm_op = LDAP_MOD_ADD;
403                     mod.sm_desc = age->age_def->agd_member_ad;
404                     mod.sm_type = age->age_def->agd_member_ad->ad_cname;
405                     mod.sm_values = vals;
406                     mod.sm_nvalues = nvals;
407                     mod.sm_numvals = numvals;
408 
409                     modify_add_values( agg->agg_entry, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
410           }
411 
412           return 0;
413 }
414 
415 /*
416 ** Callback used to add entries to a group, which is already in the database.
417 ** (used in on_response)
418 ** The group is passed in autogroup_ga_t->agg_group
419 ** NOTE: Very slow.
420 */
421 static int
autogroup_member_search_modify_cb(Operation * op,SlapReply * rs)422 autogroup_member_search_modify_cb( Operation *op, SlapReply *rs )
423 {
424           assert( op->o_tag == LDAP_REQ_SEARCH );
425 
426           if ( rs->sr_type == REP_SEARCH ) {
427                     autogroup_ga_t                *agg = (autogroup_ga_t *)op->o_callback->sc_private;
428                     autogroup_entry_t   *age = agg->agg_group;
429                     autogroup_filter_t  *agf = agg->agg_filter;
430                     Modifications                 *modlist;
431                     struct berval                 *vals, *nvals;
432                     struct berval                 lvals[ 2 ], lnvals[ 2 ];
433                     int                           numvals;
434 
435                     Debug(LDAP_DEBUG_TRACE, "==> autogroup_member_search_modify_cb <%s>\n",
436                               rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN" );
437 
438                     if ( agf->agf_anlist ) {
439                               Attribute *attr = attrs_find( rs->sr_entry->e_attrs, agf->agf_anlist[0].an_desc );
440                               if (attr) {
441                                         vals = attr->a_vals;
442                                         nvals = attr->a_nvals;
443                                         numvals = attr->a_numvals;
444                               } else {
445                                         // Nothing to add
446                                         return 0;
447                               }
448                     } else {
449                               lvals[ 0 ] = rs->sr_entry->e_name;
450                               BER_BVZERO( &lvals[ 1 ] );
451                               lnvals[ 0 ] = rs->sr_entry->e_nname;
452                               BER_BVZERO( &lnvals[ 1 ] );
453                               vals = lvals;
454                               nvals = lnvals;
455                               numvals = 1;
456                     }
457 
458                     if ( numvals ) {
459                               modlist = (Modifications *)ch_calloc( 1, sizeof( Modifications ) );
460 
461                               modlist->sml_op = LDAP_MOD_ADD;
462                               modlist->sml_desc = age->age_def->agd_member_ad;
463                               modlist->sml_type = age->age_def->agd_member_ad->ad_cname;
464 
465                               ber_bvarray_dup_x( &modlist->sml_values, vals, NULL );
466                               ber_bvarray_dup_x( &modlist->sml_nvalues, nvals, NULL );
467                               modlist->sml_numvals = numvals;
468 
469                               modlist->sml_flags = SLAP_MOD_INTERNAL;
470                               modlist->sml_next = NULL;
471 
472                               if ( agg->agg_mod == NULL ) {
473                                         agg->agg_mod = modlist;
474                                         agg->agg_mod_last = modlist;
475                               } else {
476                                         agg->agg_mod_last->sml_next = modlist;
477                                         agg->agg_mod_last = modlist;
478                               }
479                     }
480 
481           }
482 
483           return 0;
484 }
485 
486 
487 /*
488 ** Adds all entries matching the passed filter to the specified group.
489 ** If modify == 1, then we modify the group's entry in the database using be_modify.
490 ** If modify == 0, then, we must supply a rw entry for the group,
491 **        because we only modify the entry, without calling be_modify.
492 ** e      - the group entry, to which the members will be added
493 ** age    - the group
494 ** agf    - the filter
495 */
496 static int
autogroup_add_members_from_filter(Operation * op,Entry * e,autogroup_entry_t * age,autogroup_filter_t * agf,int modify)497 autogroup_add_members_from_filter( Operation *op, Entry *e, autogroup_entry_t *age, autogroup_filter_t *agf, int modify)
498 {
499           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
500           Operation           o = *op;
501           SlapReply           rs = { REP_SEARCH };
502           slap_callback                 cb = { 0 };
503           slap_callback                 null_cb = { NULL, slap_null_cb, NULL, NULL };
504           autogroup_ga_t                agg;
505           OpExtra oex;
506 
507           Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_members_from_filter <%s>\n",
508                     age->age_dn.bv_val );
509 
510           o.ors_attrsonly = 0;
511           o.o_tag = LDAP_REQ_SEARCH;
512 
513           o.o_dn = op->o_bd->be_rootdn;
514           o.o_ndn = op->o_bd->be_rootndn;
515           o.o_req_dn = agf->agf_dn;
516           o.o_req_ndn = agf->agf_ndn;
517 
518           o.ors_filterstr = agf->agf_filterstr;
519           o.ors_filter = agf->agf_filter;
520 
521           o.ors_scope = agf->agf_scope;
522           o.ors_deref = LDAP_DEREF_NEVER;
523           o.ors_limit = NULL;
524           o.ors_tlimit = SLAP_NO_LIMIT;
525           o.ors_slimit = SLAP_NO_LIMIT;
526           o.ors_attrs =  agf->agf_anlist ? agf->agf_anlist : slap_anlist_no_attrs;
527           o.o_do_not_cache = 1;
528 
529           agg.agg_group = age;
530           agg.agg_filter = agf;
531           agg.agg_mod = NULL;
532           agg.agg_mod_last = NULL;
533           agg.agg_entry = e;
534           cb.sc_private = &agg;
535 
536           if ( modify == 1 ) {
537                     cb.sc_response = autogroup_member_search_modify_cb;
538           } else {
539                     cb.sc_response = autogroup_member_search_cb;
540           }
541 
542           cb.sc_cleanup = NULL;
543           cb.sc_next = NULL;
544 
545           o.o_callback = &cb;
546 
547           o.o_bd->bd_info = (BackendInfo *)on->on_info;
548           op->o_bd->be_search( &o, &rs );
549           o.o_bd->bd_info = (BackendInfo *)on;
550 
551           if ( modify == 1 && agg.agg_mod ) {
552                     unsigned long opid = op->o_opid;
553 
554                     rs_reinit( &rs, REP_RESULT );
555 
556                     o = *op;
557                     o.o_opid = 0;
558                     o.o_callback = &null_cb;
559                     o.o_tag = LDAP_REQ_MODIFY;
560                     o.orm_modlist = agg.agg_mod;
561                     o.o_dn = op->o_bd->be_rootdn;
562                     o.o_ndn = op->o_bd->be_rootndn;
563                     o.o_req_dn = age->age_dn;
564                     o.o_req_ndn = age->age_ndn;
565                     o.o_relax = SLAP_CONTROL_CRITICAL;
566                     o.o_managedsait = SLAP_CONTROL_NONCRITICAL;
567                     o.o_permissive_modify = 1;
568                     o.o_dont_replicate = 1;
569                     o.orm_no_opattrs = 1;
570 
571           oex.oe_key = (void *)&autogroup;
572           LDAP_SLIST_INSERT_HEAD( &o.o_extra, &oex, oe_next );
573 
574                     o.o_bd->bd_info = (BackendInfo *)on->on_info;
575                     (void)op->o_bd->be_modify( &o, &rs );
576                     o.o_bd->bd_info = (BackendInfo *)on;
577 
578           LDAP_SLIST_REMOVE( &o.o_extra, &oex, OpExtra, oe_next );
579 
580                     slap_mods_free(agg.agg_mod, 1);
581                     op->o_opid = opid;
582           }
583 
584           return 0;
585 }
586 
587 /*
588 ** Adds a group to the internal list from the passed entry.
589 ** scan specifies whether to add all matching members to the group.
590 ** modify specifies whether to modify the given group entry (when modify == 0),
591 **        or to modify the group entry in the database (when modify == 1 and e = NULL and ndn != NULL).
592 ** agi    - pointer to the groups and the attribute definitions
593 ** agd - the attribute definition of the added group
594 ** e      - the entry representing the group, can be NULL if the ndn is specified, and modify == 1
595 ** ndn    - the DN of the group, can be NULL if we give a non-NULL e
596 */
597 static int
autogroup_add_group(Operation * op,autogroup_info_t * agi,autogroup_def_t * agd,Entry * e,BerValue * ndn,int scan,int modify)598 autogroup_add_group( Operation *op, autogroup_info_t *agi, autogroup_def_t *agd, Entry *e, BerValue *ndn, int scan, int modify)
599 {
600           autogroup_entry_t   **agep = &agi->agi_entry;
601           autogroup_filter_t  *agf, *agf_prev = NULL;
602           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
603           LDAPURLDesc                   *lud = NULL;
604           Attribute           *a;
605           BerValue            *bv, dn;
606           int                           rc = 0, match = 1, null_entry = 0;
607 
608           if ( e == NULL ) {
609                     if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) !=
610                               LDAP_SUCCESS || e == NULL ) {
611                               Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot get entry for <%s>\n", ndn->bv_val );
612                               return 1;
613                     }
614 
615                     null_entry = 1;
616           }
617 
618           Debug(LDAP_DEBUG_TRACE, "==> autogroup_add_group <%s>\n",
619                     e->e_name.bv_val );
620 
621           if ( agi->agi_entry != NULL ) {
622                     for ( ; *agep ; agep = &(*agep)->age_next ) {
623                               dnMatch( &match, 0, NULL, NULL, &e->e_nname, &(*agep)->age_ndn );
624                               if ( match == 0 ) {
625                                         Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group already exists: <%s>\n", e->e_name.bv_val );
626                                         return 1;
627                               }
628                               /* goto last */;
629                     }
630           }
631 
632 
633           *agep = (autogroup_entry_t *)ch_calloc( 1, sizeof( autogroup_entry_t ) );
634           ldap_pvt_thread_mutex_init( &(*agep)->age_mutex );
635           (*agep)->age_def = agd;
636           (*agep)->age_filter = NULL;
637           (*agep)->age_mustrefresh = 0;
638           (*agep)->age_modrdn_olddnmodified = 0;
639 
640           ber_dupbv( &(*agep)->age_dn, &e->e_name );
641           ber_dupbv( &(*agep)->age_ndn, &e->e_nname );
642 
643           a = attrs_find( e->e_attrs, agd->agd_member_url_ad );
644 
645           if ( null_entry == 1 ) {
646                     a = attrs_dup( a );
647                     overlay_entry_release_ov( op, e, 0, on );
648           }
649 
650           if( a == NULL ) {
651                     Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: group has no memberURL\n" );
652           } else {
653                     for ( bv = a->a_nvals; !BER_BVISNULL( bv ); bv++ ) {
654 
655                               agf = (autogroup_filter_t*)ch_calloc( 1, sizeof( autogroup_filter_t ) );
656 
657                               if ( ldap_url_parse( bv->bv_val, &lud ) != LDAP_URL_SUCCESS ) {
658                                         Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot parse url <%s>\n", bv->bv_val );
659                                         /* FIXME: error? */
660                                         ch_free( agf );
661                                         continue;
662                               }
663 
664                               agf->agf_scope = lud->lud_scope;
665 
666                               if ( lud->lud_dn == NULL ) {
667                                         BER_BVSTR( &dn, "" );
668                               } else {
669                                         ber_str2bv( lud->lud_dn, 0, 0, &dn );
670                               }
671 
672                               rc = dnPrettyNormal( NULL, &dn, &agf->agf_dn, &agf->agf_ndn, NULL );
673                               if ( rc != LDAP_SUCCESS ) {
674                                         Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: cannot normalize DN <%s>\n", dn.bv_val );
675                                         /* FIXME: error? */
676                                         goto cleanup;
677                               }
678 
679                               if ( lud->lud_filter != NULL ) {
680                                         ber_str2bv( lud->lud_filter, 0, 1, &agf->agf_filterstr);
681                                         agf->agf_filter = str2filter( lud->lud_filter );
682                               } else {
683                                         Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: URL filter is missing <%s>\n", bv->bv_val );
684                                         /* FIXME: error? */
685                                         goto cleanup;
686                               }
687 
688                               if ( lud->lud_attrs != NULL ) {
689                                         int i;
690 
691                                         for ( i=0 ; lud->lud_attrs[i]!=NULL ; i++) {
692                                                   /* Just counting */;
693                                         }
694 
695                                         if ( i > 1 ) {
696                                                   Debug( LDAP_DEBUG_ANY, "autogroup_add_group: too many attributes specified in url <%s>\n",
697                                                             bv->bv_val );
698                                                   /* FIXME: error? */
699                                                   filter_free( agf->agf_filter );
700                                                   ch_free( agf->agf_filterstr.bv_val );
701                                                   ch_free( agf->agf_dn.bv_val );
702                                                   ch_free( agf->agf_ndn.bv_val );
703                                                   ldap_free_urldesc( lud );
704                                                   ch_free( agf );
705                                                   continue;
706                                         }
707 
708                                         agf->agf_anlist = str2anlist( NULL, lud->lud_attrs[0], "," );
709 
710                                         if ( agf->agf_anlist == NULL ) {
711                                                   Debug( LDAP_DEBUG_ANY, "autogroup_add_group: unable to find AttributeDescription \"%s\".\n",
712                                                             lud->lud_attrs[0] );
713                                                   /* FIXME: error? */
714                                                   filter_free( agf->agf_filter );
715                                                   ch_free( agf->agf_filterstr.bv_val );
716                                                   ch_free( agf->agf_dn.bv_val );
717                                                   ch_free( agf->agf_ndn.bv_val );
718                                                   ldap_free_urldesc( lud );
719                                                   ch_free( agf );
720                                                   continue;
721                                         }
722                               }
723 
724                               agf->agf_next = NULL;
725 
726                               if( (*agep)->age_filter == NULL ) {
727                                         (*agep)->age_filter = agf;
728                               }
729 
730                               if( agf_prev != NULL ) {
731                                         agf_prev->agf_next = agf;
732                               }
733 
734                               agf_prev = agf;
735 
736                               if ( scan == 1 ){
737                                         autogroup_add_members_from_filter( op, e, (*agep), agf, modify );
738                               }
739 
740                               Debug( LDAP_DEBUG_TRACE, "autogroup_add_group: added memberURL DN <%s> with filter <%s>\n",
741                                         agf->agf_ndn.bv_val, agf->agf_filterstr.bv_val );
742 
743                               ldap_free_urldesc( lud );
744 
745                               continue;
746 
747 
748 cleanup:;
749 
750                               ch_free( agf->agf_ndn.bv_val );
751                               ch_free( agf->agf_dn.bv_val );
752                               ldap_free_urldesc( lud );
753                               ch_free( agf );
754                     }
755           }
756 
757           if ( null_entry == 1 ) {
758                     attrs_free( a );
759           }
760           return rc;
761 }
762 
763 /*
764 ** Used when opening the database to add all existing
765 ** groups from the database to our internal list.
766 */
767 static int
autogroup_group_add_cb(Operation * op,SlapReply * rs)768 autogroup_group_add_cb( Operation *op, SlapReply *rs )
769 {
770           assert( op->o_tag == LDAP_REQ_SEARCH );
771 
772           if ( rs->sr_type == REP_SEARCH ) {
773                     autogroup_sc_t                *ags = (autogroup_sc_t *)op->o_callback->sc_private;
774 
775                     Debug(LDAP_DEBUG_TRACE, "==> autogroup_group_add_cb <%s>\n",
776                               rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN" );
777 
778                     autogroup_add_group( op, ags->ags_info, ags->ags_def, rs->sr_entry, NULL, 0, 0);
779           }
780 
781           return 0;
782 }
783 
784 typedef struct ag_addinfo {
785           slap_overinst *on;
786           Entry *e;
787           autogroup_def_t               *agd;
788 } ag_addinfo;
789 
790 static int
autogroup_add_entry_cb(Operation * op,SlapReply * rs)791 autogroup_add_entry_cb( Operation *op, SlapReply *rs )
792 {
793           slap_callback *sc = op->o_callback;
794           ag_addinfo *aa = sc->sc_private;
795           slap_overinst *on = aa->on;
796           autogroup_info_t    *agi = (autogroup_info_t *)on->on_bi.bi_private;
797           BackendInfo *bi = op->o_bd->bd_info;
798 
799           if ( rs->sr_err != LDAP_SUCCESS )
800                     goto done;
801 
802           op->o_bd->bd_info = (BackendInfo *)on;
803           ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
804           if ( aa->agd ) {
805                     autogroup_add_group( op, agi, aa->agd, aa->e, NULL, 1 , 0);
806           } else {
807                     autogroup_entry_t   *age;
808                     autogroup_filter_t  *agf;
809                     struct berval odn, ondn;
810                     int rc;
811 
812                     /* must use rootdn when calling test_filter */
813                     odn = op->o_dn;
814                     ondn = op->o_ndn;
815                     op->o_dn = op->o_bd->be_rootdn;
816                     op->o_ndn = op->o_bd->be_rootndn;
817 
818                     for ( age = agi->agi_entry; age ; age = age->age_next ) {
819                               ldap_pvt_thread_mutex_lock( &age->age_mutex );
820 
821                               /* Check if any of the filters are the suffix to the entry DN.
822                                  If yes, we can test that filter against the entry. */
823 
824                               for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
825                                         if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
826                                                   rc = test_filter( op, aa->e, agf->agf_filter );
827                                                   if ( rc == LDAP_COMPARE_TRUE ) {
828                                                             if ( agf->agf_anlist ) {
829                                                                       Attribute *a = attr_find( aa->e->e_attrs, agf->agf_anlist[0].an_desc );
830                                                                       if ( a )
831                                                                                 autogroup_add_member_values_to_group( op, &op->o_req_dn, age, a );
832                                                             } else {
833                                                                       autogroup_add_member_to_group( op, &aa->e->e_name, &aa->e->e_nname, age );
834                                                             }
835                                                             break;
836                                                   }
837                                         }
838                               }
839                               ldap_pvt_thread_mutex_unlock( &age->age_mutex );
840                     }
841                     op->o_dn = odn;
842                     op->o_ndn = ondn;
843           }
844           ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
845 
846           op->o_bd->bd_info = bi;
847 
848 done:
849           op->o_callback = sc->sc_next;
850           op->o_tmpfree( sc, op->o_tmpmemctx );
851 
852           return SLAP_CB_CONTINUE;
853 }
854 
855 /*
856 ** When adding a group, we first strip any existing members,
857 ** and add all which match the filters ourselves.
858 */
859 static int
autogroup_add_entry(Operation * op,SlapReply * rs)860 autogroup_add_entry( Operation *op, SlapReply *rs)
861 {
862           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
863           autogroup_info_t    *agi = (autogroup_info_t *)on->on_bi.bi_private;
864           autogroup_def_t               *agd = agi->agi_def;
865           slap_callback       *sc = NULL;
866           ag_addinfo          *aa = NULL;
867 
868           Debug( LDAP_DEBUG_TRACE, "==> autogroup_add_entry <%s>\n",
869                     op->ora_e->e_name.bv_val );
870 
871           sc = op->o_tmpcalloc( sizeof(slap_callback) + sizeof(ag_addinfo), 1, op->o_tmpmemctx );
872           sc->sc_private = (sc+1);
873           sc->sc_response = autogroup_add_entry_cb;
874           aa = sc->sc_private;
875           aa->on = on;
876           aa->e = op->ora_e;
877           sc->sc_next = op->o_callback;
878           op->o_callback = sc;
879 
880           /* Check if it's a group. */
881           for ( ; agd ; agd = agd->agd_next ) {
882                     if ( is_entry_objectclass_or_sub( op->ora_e, agd->agd_oc ) ) {
883                               Modification                  mod;
884                               const char                    *text = NULL;
885                               char                          textbuf[1024];
886 
887                               mod.sm_op = LDAP_MOD_DELETE;
888                               mod.sm_desc = agd->agd_member_ad;
889                               mod.sm_type = agd->agd_member_ad->ad_cname;
890                               mod.sm_values = NULL;
891                               mod.sm_nvalues = NULL;
892 
893                               /* We don't want any member attributes added by the user. */
894                               modify_delete_values( op->ora_e, &mod, /* permissive */ 1, &text, textbuf, sizeof( textbuf ) );
895 
896                               aa->agd = agd;
897 
898                               break;
899                     }
900           }
901 
902           return SLAP_CB_CONTINUE;
903 }
904 
905 /*
906 ** agi    - internal group and attribute definitions list
907 ** e      - the group to remove from the internal list
908 */
909 static int
autogroup_delete_group(autogroup_info_t * agi,autogroup_entry_t * e)910 autogroup_delete_group( autogroup_info_t *agi, autogroup_entry_t *e )
911 {
912           autogroup_entry_t   *age = agi->agi_entry,
913                                         *age_prev = NULL,
914                                         *age_next;
915           int                           rc = 1;
916 
917           Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_group <%s>\n",
918                     age->age_dn.bv_val );
919 
920           for ( age_next = age ; age_next ; age_prev = age, age = age_next ) {
921                     age_next = age->age_next;
922 
923                     if ( age == e ) {
924                               autogroup_filter_t  *agf = age->age_filter,
925                                                                       *agf_next;
926 
927                               if ( age_prev != NULL ) {
928                                         age_prev->age_next = age_next;
929                               } else {
930                                         agi->agi_entry = NULL;
931                               }
932 
933                               ch_free( age->age_dn.bv_val );
934                               ch_free( age->age_ndn.bv_val );
935 
936                               for( agf_next = agf ; agf_next ; agf = agf_next ){
937                                         agf_next = agf->agf_next;
938 
939                                         filter_free( agf->agf_filter );
940                                         ch_free( agf->agf_filterstr.bv_val );
941                                         ch_free( agf->agf_dn.bv_val );
942                                         ch_free( agf->agf_ndn.bv_val );
943                                         anlist_free( agf->agf_anlist, 1, NULL );
944                                         ch_free( agf );
945                               }
946 
947                               ldap_pvt_thread_mutex_unlock( &age->age_mutex );
948                               ldap_pvt_thread_mutex_destroy( &age->age_mutex );
949                               ch_free( age );
950 
951                               rc = 0;
952                               return rc;
953 
954                     }
955           }
956 
957           Debug( LDAP_DEBUG_TRACE, "autogroup_delete_group: group <%s> not found, should not happen\n", age->age_dn.bv_val );
958 
959           return rc;
960 
961 }
962 
963 static int
autogroup_delete_entry(Operation * op,SlapReply * rs)964 autogroup_delete_entry( Operation *op, SlapReply *rs)
965 {
966           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
967           autogroup_info_t    *agi = (autogroup_info_t *)on->on_bi.bi_private;
968           autogroup_entry_t   *age, *age_prev, *age_next;
969           autogroup_filter_t  *agf;
970           Entry                         *e;
971           int                           matched_group = 0, rc = 0;
972           struct berval odn, ondn;
973           OpExtra *oex;
974 
975           LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
976                     if ( oex->oe_key == (void *)&autogroup )
977                               return SLAP_CB_CONTINUE;
978           }
979 
980           Debug( LDAP_DEBUG_TRACE, "==> autogroup_delete_entry <%s>\n", op->o_req_dn.bv_val );
981 
982           ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
983 
984           if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
985                     LDAP_SUCCESS || e == NULL ) {
986                     Debug( LDAP_DEBUG_TRACE, "autogroup_delete_entry: cannot get entry for <%s>\n", op->o_req_dn.bv_val );
987                     ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
988                     return SLAP_CB_CONTINUE;
989           }
990 
991           /* Check if the entry to be deleted is one of our groups. */
992           for ( age_next = agi->agi_entry ; age_next ; age_prev = age ) {
993                     age = age_next;
994                     ldap_pvt_thread_mutex_lock( &age->age_mutex );
995                     age_next = age->age_next;
996 
997                     if ( is_entry_objectclass_or_sub( e, age->age_def->agd_oc ) ) {
998                               int match = 1;
999 
1000                               matched_group = 1;
1001 
1002                               dnMatch( &match, 0, NULL, NULL, &e->e_nname, &age->age_ndn );
1003 
1004                               if ( match == 0 ) {
1005                                         autogroup_delete_group( agi, age );
1006                                         break;
1007                               }
1008                     }
1009 
1010                     ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1011           }
1012 
1013           if ( matched_group == 1 ) {
1014                     overlay_entry_release_ov( op, e, 0, on );
1015                     ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1016                     return SLAP_CB_CONTINUE;
1017           }
1018 
1019           /* Check if the entry matches any of the groups.
1020              If yes, we can delete the entry from that group. */
1021 
1022           odn = op->o_dn;
1023           ondn = op->o_ndn;
1024           op->o_dn = op->o_bd->be_rootdn;
1025           op->o_ndn = op->o_bd->be_rootndn;
1026 
1027           for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1028                     ldap_pvt_thread_mutex_lock( &age->age_mutex );
1029 
1030                     for ( agf = age->age_filter; agf ; agf = agf->agf_next ) {
1031                               if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1032                                         rc = test_filter( op, e, agf->agf_filter );
1033                                         if ( rc == LDAP_COMPARE_TRUE ) {
1034                                                   /* If the attribute is retrieved from the entry, we don't know what to delete
1035                                                   ** So the group must be entirely refreshed
1036                                                   ** But the refresh can't be done now because the entry is not deleted
1037                                                   ** So the group is marked as mustrefresh
1038                                                   */
1039                                                   if ( agf->agf_anlist ) {
1040                                                             age->age_mustrefresh = 1;
1041                                                   } else {
1042                                                             autogroup_delete_member_from_group( op, &e->e_name, &e->e_nname, age );
1043                                                   }
1044                                                   break;
1045                                         }
1046                               }
1047                     }
1048                     ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1049           }
1050           op->o_dn = odn;
1051           op->o_ndn = ondn;
1052 
1053           overlay_entry_release_ov( op, e, 0, on );
1054           ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1055 
1056           return SLAP_CB_CONTINUE;
1057 }
1058 
1059 static int
autogroup_response(Operation * op,SlapReply * rs)1060 autogroup_response( Operation *op, SlapReply *rs )
1061 {
1062           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
1063           autogroup_info_t    *agi = (autogroup_info_t *)on->on_bi.bi_private;
1064           autogroup_def_t               *agd = agi->agi_def;
1065           autogroup_entry_t   *age;
1066           autogroup_filter_t  *agf;
1067           BerValue            new_dn, new_ndn, pdn;
1068           Entry                         *e, *group;
1069           Attribute           *a, *ea, *attrs;
1070           int                           is_olddn, is_newdn, is_value_refresh, dn_equal;
1071           OpExtra *oex;
1072 
1073           LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1074                     if ( oex->oe_key == (void *)&autogroup )
1075                               break;
1076           }
1077 
1078           /* Handle all cases where a refresh of the group is needed */
1079           if ( op->o_tag == LDAP_REQ_DELETE || op->o_tag == LDAP_REQ_MODIFY ) {
1080                     if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
1081 
1082                               ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1083 
1084                               for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1085                                         /* Request detected that the group must be refreshed */
1086 
1087                                         ldap_pvt_thread_mutex_lock( &age->age_mutex );
1088 
1089                                         if ( age->age_mustrefresh ) {
1090                                                   autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1091 
1092                                                   for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1093                                                             autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1094                                                   }
1095                                         }
1096 
1097                                         ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1098                               }
1099 
1100                               ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1101                     }
1102           } else if ( op->o_tag == LDAP_REQ_MODRDN ) {
1103                     if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS && !oex ) {
1104 
1105                               Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODRDN from <%s>\n", op->o_req_dn.bv_val );
1106 
1107                               ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1108 
1109                               if ( op->oq_modrdn.rs_newSup ) {
1110                                         pdn = *op->oq_modrdn.rs_newSup;
1111                               } else {
1112                                         dnParent( &op->o_req_dn, &pdn );
1113                               }
1114                               build_new_dn( &new_dn, &pdn, &op->orr_newrdn, op->o_tmpmemctx );
1115 
1116                               if ( op->oq_modrdn.rs_nnewSup ) {
1117                                         pdn = *op->oq_modrdn.rs_nnewSup;
1118                               } else {
1119                                         dnParent( &op->o_req_ndn, &pdn );
1120                               }
1121                               build_new_dn( &new_ndn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx );
1122 
1123                               Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN to <%s>\n", new_dn.bv_val );
1124 
1125                               dnMatch( &dn_equal, 0, NULL, NULL, &op->o_req_ndn, &new_ndn );
1126 
1127                               if ( overlay_entry_get_ov( op, &new_ndn, NULL, NULL, 0, &e, on ) !=
1128                                         LDAP_SUCCESS || e == NULL ) {
1129                                         Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get entry for <%s>\n", new_dn.bv_val );
1130                                         ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1131                                         return SLAP_CB_CONTINUE;
1132                               }
1133 
1134                               a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1135 
1136 
1137                               if ( a == NULL ) {
1138                                         Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN entry <%s> has no objectClass\n", new_dn.bv_val );
1139                                         overlay_entry_release_ov( op, e, 0, on );
1140                                         ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1141                                         return SLAP_CB_CONTINUE;
1142                               }
1143 
1144 
1145                               /* If a groups DN is modified, just update age_dn/ndn of that group with the new DN. */
1146                               for ( ; agd; agd = agd->agd_next ) {
1147 
1148                                         if ( value_find_ex( slap_schema.si_ad_objectClass,
1149                                                             SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1150                                                             SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1151                                                             a->a_nvals, &agd->agd_oc->soc_cname,
1152                                                             op->o_tmpmemctx ) == 0 )
1153                                         {
1154                                                   for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1155                                                             int match = 1;
1156 
1157                                                             dnMatch( &match, 0, NULL, NULL, &age->age_ndn, &op->o_req_ndn );
1158                                                             if ( match == 0 ) {
1159                                                                       Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN updating group's DN to <%s>\n", new_dn.bv_val );
1160                                                                       ber_dupbv( &age->age_dn, &new_dn );
1161                                                                       ber_dupbv( &age->age_ndn, &new_ndn );
1162 
1163                                                                       op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx  );
1164                                                                       op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1165                                                                       overlay_entry_release_ov( op, e, 0, on );
1166                                                                       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1167                                                                       return SLAP_CB_CONTINUE;
1168                                                             }
1169                                                   }
1170 
1171                                         }
1172                               }
1173 
1174                               /* For each group:
1175                                  1. check if the original entry's DN is in the group.
1176                                  2. check if the any of the group filter's base DN is a suffix of the new DN
1177 
1178                                  If 1 and 2 are both false, we do nothing.
1179                                  If 1 and 2 is true, we remove the old DN from the group, and add the new DN.
1180                                  If 1 is false, and 2 is true, we check the entry against the group's filters,
1181                                         and add it's DN to the group.
1182                                  If 1 is true, and 2 is false, we delete the entry's DN from the group.
1183                               */
1184                               attrs = attrs_dup( e->e_attrs );
1185                               overlay_entry_release_ov( op, e, 0, on );
1186                               for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1187                                         is_olddn = 0;
1188                                         is_newdn = 0;
1189                                         is_value_refresh = 0;
1190 
1191                                         ldap_pvt_thread_mutex_lock( &age->age_mutex );
1192 
1193                                         if ( age->age_filter && age->age_filter->agf_anlist ) {
1194                                                   ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1195                                         }
1196                                         else {
1197                                                   ea = NULL;
1198                                         }
1199 
1200                                         if ( age->age_modrdn_olddnmodified ) {
1201                                                   /* Request already marked this group to be updated */
1202                                                   is_olddn = 1;
1203                                                   is_value_refresh = 1;
1204                                                   age->age_modrdn_olddnmodified = 0;
1205                                         } else {
1206 
1207                                                   if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1208                                                             LDAP_SUCCESS || group == NULL ) {
1209                                                             Debug( LDAP_DEBUG_TRACE, "autogroup_response MODRDN cannot get group entry <%s>\n", age->age_dn.bv_val );
1210 
1211                                                             op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1212                                                             op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1213 
1214                                                             attrs_free( attrs );
1215                                                             ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1216                                                             ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1217                                                             return SLAP_CB_CONTINUE;
1218                                                   }
1219 
1220                                                   a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1221 
1222                                                   if ( a != NULL ) {
1223                                                             if ( value_find_ex( age->age_def->agd_member_ad,
1224                                                                                 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1225                                                                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1226                                                                                 a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1227                                                             {
1228                                                                       is_olddn = 1;
1229                                                             }
1230 
1231                                                   }
1232 
1233                                                   overlay_entry_release_ov( op, group, 0, on );
1234 
1235                                         }
1236 
1237                                         for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1238                                                   if ( dnIsSuffix( &new_ndn, &agf->agf_ndn ) ) {
1239                                                             /* TODO: should retest filter as it could imply conditions on the dn */
1240                                                             is_newdn = 1;
1241                                                             break;
1242                                                   }
1243                                         }
1244 
1245 
1246                                         if ( is_value_refresh ) {
1247                                                   if ( is_olddn != is_newdn ) {
1248                                                             /* group refresh */
1249                                                             autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1250 
1251                                                             for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1252                                                                       autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1253                                                             }
1254                                                   }
1255                                                   ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1256                                                   continue;
1257                                         }
1258                                         if ( is_olddn == 1 && is_newdn == 0 ) {
1259                                                   if ( ea )
1260                                                             autogroup_delete_member_values_from_group( op, &new_dn, age, ea );
1261                                                   else
1262                                                             autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1263                                         } else
1264                                         if ( is_olddn == 0 && is_newdn == 1 ) {
1265                                                   Entry etmp;
1266                                                   struct berval odn, ondn;
1267                                                   etmp.e_name = op->o_req_dn;
1268                                                   etmp.e_nname = op->o_req_ndn;
1269                                                   etmp.e_attrs = attrs;
1270                                                   odn = op->o_dn;
1271                                                   ondn = op->o_ndn;
1272                                                   op->o_dn = op->o_bd->be_rootdn;
1273                                                   op->o_ndn = op->o_bd->be_rootndn;
1274 
1275                                                   for ( agf = age->age_filter; agf; agf = agf->agf_next ) {
1276                                                             if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1277                                                                       if ( ea ) {
1278                                                                                 autogroup_add_member_values_to_group( op, &new_dn, age, ea );
1279                                                                       } else
1280                                                                                 autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1281                                                                       break;
1282                                                             }
1283                                                   }
1284                                                   op->o_dn = odn;
1285                                                   op->o_ndn = ondn;
1286                                         } else
1287                                         if ( is_olddn == 1 && is_newdn == 1 && dn_equal != 0 ) {
1288                                                   if ( ea ) {
1289                                                             /* group refresh */
1290                                                             autogroup_delete_member_from_group( op, NULL, NULL, age) ;
1291 
1292                                                             for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1293                                                                       autogroup_add_members_from_filter( op, NULL, age, agf, 1 );
1294                                                             }
1295                                                   }
1296                                                   else {
1297                                                             autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1298                                                             autogroup_add_member_to_group( op, &new_dn, &new_ndn, age );
1299                                                   }
1300                                         }
1301 
1302                                         ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1303                               }
1304 
1305                               op->o_tmpfree( new_dn.bv_val, op->o_tmpmemctx );
1306                               op->o_tmpfree( new_ndn.bv_val, op->o_tmpmemctx );
1307 
1308                               attrs_free( attrs );
1309 
1310                               ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1311                     }
1312           }
1313 
1314           if ( op->o_tag == LDAP_REQ_MODIFY ) {
1315                     if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS  && !oex ) {
1316                               Entry etmp;
1317                               struct berval odn, ondn;
1318                               Debug( LDAP_DEBUG_TRACE, "==> autogroup_response MODIFY <%s>\n", op->o_req_dn.bv_val );
1319 
1320                               ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1321 
1322                               if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1323                                         LDAP_SUCCESS || e == NULL ) {
1324                                         Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n", op->o_req_dn.bv_val );
1325                                         ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1326                                         return SLAP_CB_CONTINUE;
1327                               }
1328 
1329                               a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1330 
1331 
1332                               if ( a == NULL ) {
1333                                         Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY entry <%s> has no objectClass\n", op->o_req_dn.bv_val );
1334                                         overlay_entry_release_ov( op, e, 0, on );
1335                                         ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1336                                         return SLAP_CB_CONTINUE;
1337                               }
1338 
1339                               /* If we modify a group's memberURL, we have to delete all of it's members,
1340                                  and add them anew, because we cannot tell from which memberURL a member was added. */
1341                               for ( ; agd; agd = agd->agd_next ) {
1342 
1343                                         if ( value_find_ex( slap_schema.si_ad_objectClass,
1344                                                             SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1345                                                             SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1346                                                             a->a_nvals, &agd->agd_oc->soc_cname,
1347                                                             op->o_tmpmemctx ) == 0 )
1348                                         {
1349                                                   Modifications       *m;
1350                                                   int                 match = 1;
1351 
1352                                                   m = op->orm_modlist;
1353 
1354                                                   for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1355                                                             ldap_pvt_thread_mutex_lock( &age->age_mutex );
1356 
1357                                                             dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1358 
1359                                                             if ( match == 0 ) {
1360                                                                       for ( ; m ; m = m->sml_next ) {
1361                                                                                 if ( m->sml_desc == age->age_def->agd_member_url_ad ) {
1362                                                                                           autogroup_def_t     *group_agd = age->age_def;
1363                                                                                           Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY changing memberURL for group <%s>\n",
1364                                                                                                     op->o_req_dn.bv_val );
1365 
1366                                                                                           overlay_entry_release_ov( op, e, 0, on );
1367 
1368                                                                                           autogroup_delete_member_from_group( op, NULL, NULL, age );
1369                                                                                           autogroup_delete_group( agi, age );
1370 
1371                                                                                           autogroup_add_group( op, agi, group_agd, NULL, &op->o_req_ndn, 1, 1);
1372 
1373                                                                                           ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1374                                                                                           return SLAP_CB_CONTINUE;
1375                                                                                 }
1376                                                                       }
1377 
1378                                                                       ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1379                                                                       break;
1380                                                             }
1381 
1382                                                             ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1383                                                   }
1384 
1385                                                   overlay_entry_release_ov( op, e, 0, on );
1386                                                   ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1387                                                   return SLAP_CB_CONTINUE;
1388                                         }
1389                               }
1390 
1391                               /* When modifying any of the attributes of an entry, we must
1392                                  check if the entry is in any of our groups, and if
1393                                  the modified entry matches any of the filters of that group.
1394 
1395                                  If the entry exists in a group, but the modified attributes do
1396                                         not match any of the group's filters, we delete the entry from that group.
1397                                  If the entry doesn't exist in a group, but matches a filter,
1398                                         we add it to that group.
1399                               */
1400                               attrs = attrs_dup( e->e_attrs );
1401                               overlay_entry_release_ov( op, e, 0, on );
1402                               etmp.e_name = op->o_req_dn;
1403                               etmp.e_nname = op->o_req_ndn;
1404                               etmp.e_attrs = attrs;
1405                               odn = op->o_dn;
1406                               ondn = op->o_ndn;
1407                               op->o_dn = op->o_bd->be_rootdn;
1408                               op->o_ndn = op->o_bd->be_rootndn;
1409 
1410                               for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1411                                         is_olddn = 0;
1412                                         is_newdn = 0;
1413 
1414                                         ldap_pvt_thread_mutex_lock( &age->age_mutex );
1415 
1416                                         if ( age->age_filter && age->age_filter->agf_anlist ) {
1417                                                   ea = attrs_find( attrs, age->age_filter->agf_anlist[0].an_desc );
1418                                         }
1419                                         else {
1420                                                   ea = NULL;
1421                                         }
1422 
1423                                         if ( overlay_entry_get_ov( op, &age->age_ndn, NULL, NULL, 0, &group, on ) !=
1424                                                   LDAP_SUCCESS || group == NULL ) {
1425                                                   Debug( LDAP_DEBUG_TRACE, "autogroup_response MODIFY cannot get entry for <%s>\n",
1426                                                             age->age_dn.bv_val );
1427 
1428                                                   attrs_free( attrs );
1429                                                   ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1430                                                   ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1431                                                   op->o_dn = odn;
1432                                                   op->o_ndn = ondn;
1433                                                   return SLAP_CB_CONTINUE;
1434                                         }
1435 
1436                                         a = attrs_find( group->e_attrs, age->age_def->agd_member_ad );
1437 
1438                                         if ( a != NULL ) {
1439                                                   if ( value_find_ex( age->age_def->agd_member_ad,
1440                                                                       SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1441                                                                       SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1442                                                                       a->a_nvals, ea ? ea->a_nvals : &op->o_req_ndn, op->o_tmpmemctx ) == 0 )
1443                                                   {
1444                                                             is_olddn = 1;
1445                                                   }
1446 
1447                                         }
1448 
1449                                         overlay_entry_release_ov( op, group, 0, on );
1450 
1451                                         for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1452                                                   if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1453                                                             if ( test_filter( op, &etmp, agf->agf_filter ) == LDAP_COMPARE_TRUE ) {
1454                                                                       is_newdn = 1;
1455                                                                       break;
1456                                                             }
1457                                                   }
1458                                         }
1459 
1460                                         if ( is_olddn == 1 && is_newdn == 0 ) {
1461                                                   if(ea)
1462                                                             autogroup_delete_member_values_from_group( op, &op->o_req_dn, age, ea );
1463                                                   else
1464                                                             autogroup_delete_member_from_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1465                                         } else
1466                                         if ( is_olddn == 0 && is_newdn == 1 ) {
1467                                                   if(ea)
1468                                                             autogroup_add_member_values_to_group( op, &op->o_req_dn, age, ea );
1469                                                   else
1470                                                             autogroup_add_member_to_group( op, &op->o_req_dn, &op->o_req_ndn, age );
1471                                         }
1472 
1473                                         ldap_pvt_thread_mutex_unlock( &age->age_mutex );
1474                               }
1475 
1476                               op->o_dn = odn;
1477                               op->o_ndn = ondn;
1478                               attrs_free( attrs );
1479 
1480                               ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1481                     }
1482           }
1483 
1484           return SLAP_CB_CONTINUE;
1485 }
1486 
1487 /*
1488 ** Detect if filter contains a memberOf check for dn
1489 */
1490 static int
autogroup_memberOf_filter(Filter * f,BerValue * dn,AttributeDescription * memberof_ad)1491 autogroup_memberOf_filter( Filter *f, BerValue *dn, AttributeDescription *memberof_ad )
1492 {
1493           int result = 0;
1494           if ( f == NULL ) return 0;
1495 
1496           switch ( f->f_choice & SLAPD_FILTER_MASK ) {
1497                     case LDAP_FILTER_AND:
1498                     case LDAP_FILTER_OR:
1499                     case LDAP_FILTER_NOT:
1500                               for ( f = f->f_un.f_un_complex; f && !result; f = f->f_next ) {
1501                                         result = result || autogroup_memberOf_filter( f, dn, memberof_ad );
1502                               }
1503                               break;
1504                     case LDAP_FILTER_EQUALITY:
1505                               result = ( f->f_ava->aa_desc == memberof_ad &&
1506                                          ber_bvcmp( &f->f_ava->aa_value, dn ) == 0 );
1507                               break;
1508                     default:
1509                               break;
1510           }
1511 
1512           return result;
1513 }
1514 
1515 /*
1516 ** When modifying a group, we must deny any modifications to the member attribute,
1517 ** because the group would be inconsistent.
1518 */
1519 static int
autogroup_modify_entry(Operation * op,SlapReply * rs)1520 autogroup_modify_entry( Operation *op, SlapReply *rs)
1521 {
1522           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
1523           autogroup_info_t              *agi = (autogroup_info_t *)on->on_bi.bi_private;
1524           autogroup_def_t               *agd = agi->agi_def;
1525           autogroup_entry_t   *age;
1526           Entry                         *e;
1527           Attribute           *a;
1528           struct berval odn, ondn;
1529           OpExtra *oex;
1530 
1531           LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1532                     if ( oex->oe_key == (void *)&autogroup )
1533                               return SLAP_CB_CONTINUE;
1534           }
1535 
1536           Debug( LDAP_DEBUG_TRACE, "==> autogroup_modify_entry <%s>\n", op->o_req_dn.bv_val );
1537           ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1538 
1539           if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1540                     LDAP_SUCCESS || e == NULL ) {
1541                     Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val );
1542                     ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1543                     return SLAP_CB_CONTINUE;
1544           }
1545 
1546           odn = op->o_dn;
1547           ondn = op->o_ndn;
1548           op->o_dn = op->o_bd->be_rootdn;
1549           op->o_ndn = op->o_bd->be_rootndn;
1550 
1551           /* Must refresh groups if a matching member value is modified OR filter contains memberOf=DN */
1552           for ( age = agi->agi_entry; age ; age = age->age_next ) {
1553                     autogroup_filter_t  *agf;
1554                     for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1555                               if ( agf->agf_anlist ) {
1556                                         Modifications       *m;
1557                                         for ( m = op->orm_modlist ; m ; m = m->sml_next ) {
1558                                                   if ( m->sml_desc == agf->agf_anlist[0].an_desc ) {
1559                                                             if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1560                                                                       int rc = test_filter( op, e, agf->agf_filter );
1561                                                                       if ( rc == LDAP_COMPARE_TRUE ) {
1562                                                                                 age->age_mustrefresh = 1;
1563                                                                       }
1564                                                             }
1565                                                   }
1566                                         }
1567                               }
1568 
1569                               if ( autogroup_memberOf_filter( agf->agf_filter, &op->o_req_ndn, agi->agi_memberof_ad ) ) {
1570                                         age->age_mustrefresh = 1;
1571                               }
1572                     }
1573           }
1574           op->o_dn = odn;
1575           op->o_ndn = ondn;
1576 
1577           a = attrs_find( e->e_attrs, slap_schema.si_ad_objectClass );
1578 
1579           if ( a == NULL ) {
1580                     Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry entry <%s> has no objectClass\n", op->o_req_dn.bv_val );
1581                     ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1582                     return SLAP_CB_CONTINUE;
1583           }
1584 
1585 
1586           for ( ; agd; agd = agd->agd_next ) {
1587 
1588                     if ( value_find_ex( slap_schema.si_ad_objectClass,
1589                                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
1590                                         SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
1591                                         a->a_nvals, &agd->agd_oc->soc_cname,
1592                                         op->o_tmpmemctx ) == 0 )
1593                     {
1594                               Modifications       *m;
1595                               int                 match = 1;
1596 
1597                               m = op->orm_modlist;
1598 
1599                               for ( age = agi->agi_entry ; age ; age = age->age_next ) {
1600                                         dnMatch( &match, 0, NULL, NULL, &op->o_req_ndn, &age->age_ndn );
1601 
1602                                         if ( match == 0 ) {
1603                                                   for ( ; m ; m = m->sml_next ) {
1604                                                             if ( m->sml_desc == age->age_def->agd_member_ad ) {
1605                                                                       overlay_entry_release_ov( op, e, 0, on );
1606                                                                       ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1607                                                                       Debug( LDAP_DEBUG_TRACE, "autogroup_modify_entry attempted to modify group's <%s> member attribute\n", op->o_req_dn.bv_val );
1608                                                                       send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, "attempt to modify dynamic group member attribute");
1609                                                                       return LDAP_CONSTRAINT_VIOLATION;
1610                                                             }
1611                                                   }
1612                                                   break;
1613                                         }
1614                               }
1615 
1616                               /* an entry may only have one dynamic group class */
1617                               break;
1618                     }
1619           }
1620 
1621           overlay_entry_release_ov( op, e, 0, on );
1622           ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1623           return SLAP_CB_CONTINUE;
1624 }
1625 
1626 /*
1627 ** Detect if the olddn is part of a group and so if the group should be refreshed
1628 */
1629 static int
autogroup_modrdn_entry(Operation * op,SlapReply * rs)1630 autogroup_modrdn_entry( Operation *op, SlapReply *rs)
1631 {
1632           slap_overinst                 *on = (slap_overinst *)op->o_bd->bd_info;
1633           autogroup_info_t    *agi = (autogroup_info_t *)on->on_bi.bi_private;
1634           autogroup_entry_t   *age;
1635           Entry                         *e;
1636           struct berval odn, ondn;
1637           OpExtra *oex;
1638 
1639           LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
1640                     if ( oex->oe_key == (void *)&autogroup )
1641                               return SLAP_CB_CONTINUE;
1642           }
1643 
1644           Debug( LDAP_DEBUG_TRACE, "==> autogroup_modrdn_entry <%s>\n", op->o_req_dn.bv_val );
1645           ldap_pvt_thread_mutex_lock( &agi->agi_mutex );
1646 
1647           if ( overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ) !=
1648                     LDAP_SUCCESS || e == NULL ) {
1649                     Debug( LDAP_DEBUG_TRACE, "autogroup_modrdn_entry cannot get entry for <%s>\n", op->o_req_dn.bv_val );
1650                     ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1651                     return SLAP_CB_CONTINUE;
1652           }
1653 
1654           odn = op->o_dn;
1655           ondn = op->o_ndn;
1656           op->o_dn = op->o_bd->be_rootdn;
1657           op->o_ndn = op->o_bd->be_rootndn;
1658 
1659           /* Must check if a dn is modified */
1660           for ( age = agi->agi_entry; age ; age = age->age_next ) {
1661                     autogroup_filter_t  *agf;
1662                     for ( agf = age->age_filter ; agf ; agf = agf->agf_next ) {
1663                               if ( agf->agf_anlist ) {
1664                                         if ( dnIsSuffix( &op->o_req_ndn, &agf->agf_ndn ) ) {
1665                                                   int rc = test_filter( op, e, agf->agf_filter );
1666                                                   if ( rc == LDAP_COMPARE_TRUE ) {
1667                                                             age->age_modrdn_olddnmodified = 1;
1668                                                   }
1669                                         }
1670                               }
1671                     }
1672           }
1673           op->o_dn = odn;
1674           op->o_ndn = ondn;
1675 
1676           overlay_entry_release_ov( op, e, 0, on );
1677           ldap_pvt_thread_mutex_unlock( &agi->agi_mutex );
1678           return SLAP_CB_CONTINUE;
1679 }
1680 
1681 /*
1682 ** Builds a filter for searching for the
1683 ** group entries, according to the objectClass.
1684 */
1685 static int
autogroup_build_def_filter(autogroup_def_t * agd,Operation * op)1686 autogroup_build_def_filter( autogroup_def_t *agd, Operation *op )
1687 {
1688           char      *ptr;
1689 
1690           Debug( LDAP_DEBUG_TRACE, "==> autogroup_build_def_filter\n" );
1691 
1692           op->ors_filterstr.bv_len = STRLENOF( "(=)" )
1693                               + slap_schema.si_ad_objectClass->ad_cname.bv_len
1694                               + agd->agd_oc->soc_cname.bv_len;
1695           ptr = op->ors_filterstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len + 1, op->o_tmpmemctx );
1696           *ptr++ = '(';
1697           ptr = lutil_strcopy( ptr, slap_schema.si_ad_objectClass->ad_cname.bv_val );
1698           *ptr++ = '=';
1699           ptr = lutil_strcopy( ptr, agd->agd_oc->soc_cname.bv_val );
1700           *ptr++ = ')';
1701           *ptr = '\0';
1702 
1703           op->ors_filter = str2filter_x( op, op->ors_filterstr.bv_val );
1704 
1705           assert( op->ors_filterstr.bv_len == ptr - op->ors_filterstr.bv_val );
1706 
1707           return 0;
1708 }
1709 
1710 enum {
1711           AG_ATTRSET = 1,
1712           AG_MEMBER_OF_AD,
1713           AG_LAST
1714 };
1715 
1716 static ConfigDriver ag_cfgen;
1717 
1718 static ConfigTable agcfg[] = {
1719           { "autogroup-attrset", "group-oc> <URL-ad> <member-ad",
1720                     4, 4, 0, ARG_MAGIC|AG_ATTRSET, ag_cfgen,
1721                     "( OLcfgCtAt:2.1 NAME ( 'olcAutoGroupAttrSet' 'olcAGattrSet' ) "
1722                               "DESC 'Automatic groups: <group objectClass>, <URL attributeDescription>, <member attributeDescription>' "
1723                               "EQUALITY caseIgnoreMatch "
1724                               "SYNTAX OMsDirectoryString "
1725                               "X-ORDERED 'VALUES' )",
1726                               NULL, NULL },
1727 
1728           { "autogroup-memberof-ad", "memberOf attribute",
1729                     2, 2, 0, ARG_MAGIC|AG_MEMBER_OF_AD, ag_cfgen,
1730                     "( OLcfgCtAt:2.2 NAME ( 'olcAutoGroupMemberOfAd' 'olcAGmemberOfAd' ) "
1731                               "DESC 'memberOf attribute' "
1732                               "EQUALITY caseIgnoreMatch "
1733                               "SYNTAX OMsDirectoryString SINGLE-VALUE )",
1734                               NULL, NULL },
1735 
1736           { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1737 };
1738 
1739 static ConfigOCs agocs[] = {
1740           { "( OLcfgCtOc:2.1 "
1741                     "NAME 'olcAutoGroupConfig' "
1742                     "DESC 'Automatic groups configuration' "
1743                     "SUP olcOverlayConfig "
1744                     "MAY ( "
1745                               "olcAutoGroupAttrSet "
1746                               "$ olcAutoGroupMemberOfAd "
1747                         ")"
1748             ")",
1749                     Cft_Overlay, agcfg, NULL, NULL },
1750           { NULL, 0, NULL }
1751 };
1752 
1753 
1754 static int
ag_cfgen(ConfigArgs * c)1755 ag_cfgen( ConfigArgs *c )
1756 {
1757           slap_overinst                 *on = (slap_overinst *)c->bi;
1758           autogroup_info_t              *agi = (autogroup_info_t *)on->on_bi.bi_private;
1759           autogroup_def_t               *agd;
1760           autogroup_entry_t   *age;
1761 
1762           int rc = 0, i;
1763 
1764           Debug( LDAP_DEBUG_TRACE, "==> autogroup_cfgen\n" );
1765 
1766           if( agi == NULL ) {
1767                     agi = (autogroup_info_t*)ch_calloc( 1, sizeof(autogroup_info_t) );
1768                     ldap_pvt_thread_mutex_init( &agi->agi_mutex );
1769                     agi->agi_def = NULL;
1770                     agi->agi_entry = NULL;
1771                     on->on_bi.bi_private = (void *)agi;
1772           }
1773 
1774           agd = agi->agi_def;
1775           age = agi->agi_entry;
1776 
1777           if ( c->op == SLAP_CONFIG_EMIT ) {
1778 
1779                     switch( c->type ){
1780                     case AG_ATTRSET:
1781                               for ( i = 0 ; agd ; i++, agd = agd->agd_next ) {
1782                                         struct berval       bv;
1783                                         char                *ptr = c->cr_msg;
1784 
1785                                         assert(agd->agd_oc != NULL);
1786                                         assert(agd->agd_member_url_ad != NULL);
1787                                         assert(agd->agd_member_ad != NULL);
1788 
1789                                         ptr += snprintf( c->cr_msg, sizeof( c->cr_msg ),
1790                                                   SLAP_X_ORDERED_FMT "%s %s %s", i,
1791                                                   agd->agd_oc->soc_cname.bv_val,
1792                                                   agd->agd_member_url_ad->ad_cname.bv_val,
1793                                                   agd->agd_member_ad->ad_cname.bv_val );
1794 
1795                                         bv.bv_val = c->cr_msg;
1796                                         bv.bv_len = ptr - bv.bv_val;
1797                                         value_add_one ( &c->rvalue_vals, &bv );
1798 
1799                               }
1800                               break;
1801 
1802                     case AG_MEMBER_OF_AD:
1803                               if ( agi->agi_memberof_ad != NULL ){
1804                                         value_add_one( &c->rvalue_vals, &agi->agi_memberof_ad->ad_cname );
1805                               }
1806                               break;
1807 
1808                     default:
1809                               assert( 0 );
1810                               return 1;
1811       }
1812 
1813                     return rc;
1814 
1815           }else if ( c->op == LDAP_MOD_DELETE ) {
1816                     if ( c->valx < 0) {
1817                               autogroup_def_t               *agd_next;
1818                               autogroup_entry_t   *age_next;
1819                               autogroup_filter_t  *agf = age->age_filter,
1820                                                             *agf_next;
1821 
1822                               for ( agd_next = agd; agd_next; agd = agd_next ) {
1823                                         agd_next = agd->agd_next;
1824 
1825                                         ch_free( agd );
1826                               }
1827 
1828                               for ( age_next = age ; age_next ; age = age_next ) {
1829                                         age_next = age->age_next;
1830 
1831                                         ch_free( age->age_dn.bv_val );
1832                                         ch_free( age->age_ndn.bv_val );
1833 
1834                                         for( agf_next = agf ; agf_next ; agf = agf_next ){
1835                                                   agf_next = agf->agf_next;
1836 
1837                                                   filter_free( agf->agf_filter );
1838                                                   ch_free( agf->agf_filterstr.bv_val );
1839                                                   ch_free( agf->agf_dn.bv_val );
1840                                                   ch_free( agf->agf_ndn.bv_val );
1841                                                   anlist_free( agf->agf_anlist, 1, NULL );
1842                                                   ch_free( agf );
1843                                         }
1844 
1845                                         ldap_pvt_thread_mutex_init( &age->age_mutex );
1846                                         ch_free( age );
1847                               }
1848 
1849                               ch_free( agi );
1850                               on->on_bi.bi_private = NULL;
1851 
1852                     } else {
1853                               autogroup_def_t               **agdp;
1854                               autogroup_entry_t   *age_next, *age_prev;
1855                               autogroup_filter_t  *agf,
1856                                                             *agf_next;
1857 
1858                               for ( i = 0, agdp = &agi->agi_def;
1859                                         i < c->valx; i++ )
1860                               {
1861                                         if ( *agdp == NULL) {
1862                                                   return 1;
1863                                         }
1864                                         agdp = &(*agdp)->agd_next;
1865                               }
1866 
1867                               agd = *agdp;
1868                               *agdp = agd->agd_next;
1869 
1870                               for ( age_next = age , age_prev = NULL ; age_next ; age_prev = age, age = age_next ) {
1871                                         age_next = age->age_next;
1872 
1873                                         if( age->age_def == agd ) {
1874                                                   agf = age->age_filter;
1875 
1876                                                   ch_free( age->age_dn.bv_val );
1877                                                   ch_free( age->age_ndn.bv_val );
1878 
1879                                                   for ( agf_next = agf; agf_next ; agf = agf_next ) {
1880                                                             agf_next = agf->agf_next;
1881                                                             filter_free( agf->agf_filter );
1882                                                             ch_free( agf->agf_filterstr.bv_val );
1883                                                             ch_free( agf->agf_dn.bv_val );
1884                                                             ch_free( agf->agf_ndn.bv_val );
1885                                                             anlist_free( agf->agf_anlist, 1, NULL );
1886                                                             ch_free( agf );
1887                                                   }
1888 
1889                                                   ldap_pvt_thread_mutex_destroy( &age->age_mutex );
1890                                                   ch_free( age );
1891 
1892                                                   age = age_prev;
1893 
1894                                                   if( age_prev != NULL ) {
1895                                                             age_prev->age_next = age_next;
1896                                                   }
1897                                         }
1898                               }
1899 
1900                               ch_free( agd );
1901                               agd = agi->agi_def;
1902 
1903                     }
1904 
1905                     return rc;
1906           }
1907 
1908           switch(c->type){
1909           case AG_ATTRSET: {
1910                     autogroup_def_t               **agdp,
1911                                                   *agd_next = NULL;
1912                     ObjectClass                   *oc = NULL;
1913                     AttributeDescription          *member_url_ad = NULL,
1914                                                   *member_ad = NULL;
1915                     const char                    *text;
1916 
1917 
1918                     oc = oc_find( c->argv[ 1 ] );
1919                     if( oc == NULL ){
1920                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
1921                                         "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1922                                         "unable to find ObjectClass \"%s\"",
1923                                         c->argv[ 1 ] );
1924                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1925                                         c->log, c->cr_msg );
1926                               return 1;
1927                     }
1928 
1929 
1930                     rc = slap_str2ad( c->argv[ 2 ], &member_url_ad, &text );
1931                     if( rc != LDAP_SUCCESS ) {
1932                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
1933                                         "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1934                                         "unable to find AttributeDescription \"%s\"",
1935                                         c->argv[ 2 ] );
1936                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1937                                         c->log, c->cr_msg );
1938                               return 1;
1939                     }
1940 
1941                     if( !is_at_subtype( member_url_ad->ad_type, slap_schema.si_ad_labeledURI->ad_type ) ) {
1942                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
1943                                         "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1944                                         "AttributeDescription \"%s\" ",
1945                                         "must be of a subtype \"labeledURI\"",
1946                                         c->argv[ 2 ] );
1947                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1948                                         c->log, c->cr_msg );
1949                               return 1;
1950                     }
1951 
1952                     rc = slap_str2ad( c->argv[3], &member_ad, &text );
1953                     if( rc != LDAP_SUCCESS ) {
1954                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
1955                                         "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1956                                         "unable to find AttributeDescription \"%s\"",
1957                                         c->argv[ 3 ] );
1958                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1959                                         c->log, c->cr_msg );
1960                               return 1;
1961                     }
1962 
1963                     for ( agdp = &agi->agi_def ; *agdp ; agdp = &(*agdp)->agd_next ) {
1964                               /* The same URL attribute / member attribute pair
1965                               * cannot be repeated */
1966 
1967                               if ( (*agdp)->agd_member_url_ad == member_url_ad && (*agdp)->agd_member_ad == member_ad ) {
1968                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
1969                                                   "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1970                                                   "URL attributeDescription \"%s\" already mapped",
1971                                                   member_ad->ad_cname.bv_val );
1972                                         Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1973                                                   c->log, c->cr_msg );
1974 /*                                      return 1; //warning*/
1975                               }
1976                     }
1977 
1978                     if ( c->valx > 0 ) {
1979                               int       i;
1980 
1981                               for ( i = 0, agdp = &agi->agi_def ;
1982                                         i < c->valx; i++ )
1983                               {
1984                                         if ( *agdp == NULL ) {
1985                                                   snprintf( c->cr_msg, sizeof( c->cr_msg ),
1986                                                             "\"autogroup-attrset <oc> <URL-ad> <member-ad>\": "
1987                                                             "invalid index {%d}",
1988                                                             c->valx );
1989                                                   Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1990                                                             c->log, c->cr_msg );
1991 
1992                                                   return 1;
1993                                         }
1994                                         agdp = &(*agdp)->agd_next;
1995                               }
1996                               agd_next = *agdp;
1997 
1998                     } else {
1999                               for ( agdp = &agi->agi_def; *agdp;
2000                                         agdp = &(*agdp)->agd_next )
2001                                         /* goto last */;
2002                     }
2003 
2004                     *agdp = (autogroup_def_t *)ch_calloc( 1, sizeof(autogroup_info_t));
2005 
2006                     (*agdp)->agd_oc = oc;
2007                     (*agdp)->agd_member_url_ad = member_url_ad;
2008                     (*agdp)->agd_member_ad = member_ad;
2009                     (*agdp)->agd_next = agd_next;
2010 
2011                     } break;
2012 
2013           case AG_MEMBER_OF_AD: {
2014                     AttributeDescription *memberof_ad = NULL;
2015                     const char     *text;
2016 
2017                     rc = slap_str2ad( c->argv[ 1 ], &memberof_ad, &text );
2018                     if( rc != LDAP_SUCCESS ) {
2019                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
2020                                         "\"autogroup-memberof-ad <memberof-ad>\": "
2021                                         "unable to find AttributeDescription \"%s\"",
2022                                         c->argv[ 1 ] );
2023                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2024                                         c->log, c->cr_msg );
2025                               return 1;
2026                     }
2027 
2028                     if ( !is_at_syntax( memberof_ad->ad_type, SLAPD_DN_SYNTAX )    /* e.g. "member" */
2029                          && !is_at_syntax( memberof_ad->ad_type, SLAPD_NAMEUID_SYNTAX ) )  /* e.g. "uniqueMember" */
2030                     {
2031                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
2032                                         "memberof attribute=\"%s\" must either "
2033                                         "have DN (%s) or nameUID (%s) syntax",
2034                                         c->argv[ 1 ], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX );
2035                               Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
2036                                         c->log, c->cr_msg );
2037                               return 1;
2038                     }
2039 
2040                     agi->agi_memberof_ad = memberof_ad;
2041 
2042                     } break;
2043 
2044           default:
2045                     rc = 1;
2046                     break;
2047           }
2048 
2049           return rc;
2050 }
2051 
2052 extern int slapMode;
2053 
2054 /*
2055 ** Do a search for all the groups in the
2056 ** database, and add them to out internal list.
2057 */
2058 static int
autogroup_db_open(BackendDB * be,ConfigReply * cr)2059 autogroup_db_open(
2060           BackendDB *be,
2061           ConfigReply         *cr )
2062 {
2063           slap_overinst                           *on = (slap_overinst *) be->bd_info;
2064           autogroup_info_t              *agi = on->on_bi.bi_private;
2065           autogroup_def_t               *agd;
2066           autogroup_sc_t                ags;
2067           Operation           *op;
2068           slap_callback                 cb = { 0 };
2069 
2070           void                                    *thrctx = ldap_pvt_thread_pool_context();
2071           Connection                              conn = { 0 };
2072           OperationBuffer     opbuf;
2073 
2074           Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_open\n" );
2075 
2076           if ( agi == NULL || !( slapMode & SLAP_SERVER_MODE )) {
2077                     return 0;
2078           }
2079 
2080           connection_fake_init2( &conn, &opbuf, thrctx, 0 );
2081           op = &opbuf.ob_op;
2082 
2083           op->ors_attrsonly = 0;
2084           op->o_tag = LDAP_REQ_SEARCH;
2085           op->o_dn = be->be_rootdn;
2086           op->o_ndn = be->be_rootndn;
2087 
2088           op->o_req_dn = be->be_suffix[0];
2089           op->o_req_ndn = be->be_nsuffix[0];
2090 
2091           op->ors_scope = LDAP_SCOPE_SUBTREE;
2092           op->ors_deref = LDAP_DEREF_NEVER;
2093           op->ors_limit = NULL;
2094           op->ors_tlimit = SLAP_NO_LIMIT;
2095           op->ors_slimit = SLAP_NO_LIMIT;
2096           op->ors_attrs =  slap_anlist_no_attrs;
2097           op->o_do_not_cache = 1;
2098 
2099           op->o_bd = be;
2100           op->o_bd->bd_info = (BackendInfo *)on->on_info;
2101 
2102           ags.ags_info = agi;
2103           cb.sc_private = &ags;
2104           cb.sc_response = autogroup_group_add_cb;
2105           cb.sc_cleanup = NULL;
2106           cb.sc_next = NULL;
2107 
2108           op->o_callback = &cb;
2109 
2110           for (agd = agi->agi_def ; agd ; agd = agd->agd_next) {
2111                     SlapReply rs = { REP_RESULT };
2112 
2113                     autogroup_build_def_filter(agd, op);
2114 
2115                     ags.ags_def = agd;
2116 
2117                     op->o_bd->be_search( op, &rs );
2118 
2119                     filter_free_x( op, op->ors_filter, 1 );
2120                     op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
2121           }
2122 
2123           if( ! agi->agi_memberof_ad ){
2124                     int                           rc;
2125                     const char                    *text = NULL;
2126 
2127                     rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &agi->agi_memberof_ad, &text );
2128                     if ( rc != LDAP_SUCCESS ) {
2129                               Debug( LDAP_DEBUG_ANY, "autogroup_db_open: "
2130                               "unable to find attribute=\"%s\": %s (%d)\n",
2131                               SLAPD_MEMBEROF_ATTR, text, rc );
2132                               return rc;
2133                     }
2134           }
2135 
2136           return 0;
2137 }
2138 
2139 static int
autogroup_db_close(BackendDB * be,ConfigReply * cr)2140 autogroup_db_close(
2141           BackendDB *be,
2142           ConfigReply         *cr )
2143 {
2144           slap_overinst                           *on = (slap_overinst *) be->bd_info;
2145 
2146           Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_close\n" );
2147 
2148           if ( on->on_bi.bi_private ) {
2149                     autogroup_info_t              *agi = on->on_bi.bi_private;
2150                     autogroup_entry_t   *age = agi->agi_entry,
2151                                                   *age_next;
2152                     autogroup_filter_t  *agf, *agf_next;
2153 
2154                     for ( age_next = age; age_next; age = age_next ) {
2155                               age_next = age->age_next;
2156 
2157                               ch_free( age->age_dn.bv_val );
2158                               ch_free( age->age_ndn.bv_val );
2159 
2160                               agf = age->age_filter;
2161 
2162                               for ( agf_next = agf; agf_next; agf = agf_next ) {
2163                                         agf_next = agf->agf_next;
2164 
2165                                         filter_free( agf->agf_filter );
2166                                         ch_free( agf->agf_filterstr.bv_val );
2167                                         ch_free( agf->agf_dn.bv_val );
2168                                         ch_free( agf->agf_ndn.bv_val );
2169                                         anlist_free( agf->agf_anlist, 1, NULL );
2170                                         ch_free( agf );
2171                               }
2172 
2173                               ldap_pvt_thread_mutex_destroy( &age->age_mutex );
2174                               ch_free( age );
2175                     }
2176           }
2177 
2178           return 0;
2179 }
2180 
2181 static int
autogroup_db_destroy(BackendDB * be,ConfigReply * cr)2182 autogroup_db_destroy(
2183           BackendDB *be,
2184           ConfigReply         *cr )
2185 {
2186           slap_overinst                           *on = (slap_overinst *) be->bd_info;
2187 
2188           Debug( LDAP_DEBUG_TRACE, "==> autogroup_db_destroy\n" );
2189 
2190           if ( on->on_bi.bi_private ) {
2191                     autogroup_info_t              *agi = on->on_bi.bi_private;
2192                     autogroup_def_t               *agd = agi->agi_def,
2193                                                   *agd_next;
2194 
2195                     for ( agd_next = agd; agd_next; agd = agd_next ) {
2196                               agd_next = agd->agd_next;
2197 
2198                               ch_free( agd );
2199                     }
2200 
2201                     ldap_pvt_thread_mutex_destroy( &agi->agi_mutex );
2202                     ch_free( agi );
2203           }
2204 
2205           return 0;
2206 }
2207 
2208 static
2209 int
autogroup_initialize(void)2210 autogroup_initialize(void)
2211 {
2212           int                 rc = 0;
2213           autogroup.on_bi.bi_type = "autogroup";
2214 
2215           autogroup.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
2216           autogroup.on_bi.bi_db_open = autogroup_db_open;
2217           autogroup.on_bi.bi_db_close = autogroup_db_close;
2218           autogroup.on_bi.bi_db_destroy = autogroup_db_destroy;
2219 
2220           autogroup.on_bi.bi_op_add = autogroup_add_entry;
2221           autogroup.on_bi.bi_op_delete = autogroup_delete_entry;
2222           autogroup.on_bi.bi_op_modify = autogroup_modify_entry;
2223           autogroup.on_bi.bi_op_modrdn = autogroup_modrdn_entry;
2224 
2225           autogroup.on_response = autogroup_response;
2226 
2227           autogroup.on_bi.bi_cf_ocs = agocs;
2228 
2229           rc = config_register_schema( agcfg, agocs );
2230           if ( rc ) {
2231                     return rc;
2232           }
2233 
2234           return overlay_register( &autogroup );
2235 }
2236 
2237 int
init_module(int argc,char * argv[])2238 init_module( int argc, char *argv[] )
2239 {
2240           return autogroup_initialize();
2241 }
2242