1 /*        $NetBSD: unique.c,v 1.3 2021/08/14 16:15:02 christos Exp $  */
2 
3 /* unique.c - attribute uniqueness module */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2004-2021 The OpenLDAP Foundation.
8  * Portions Copyright 2004,2006-2007 Symas Corporation.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by Symas Corporation for
21  * inclusion in OpenLDAP Software, with subsequent enhancements by
22  * Emily Backes at Symas Corporation.  This work was sponsored by
23  * Hewlett-Packard.
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: unique.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
28 
29 #include "portable.h"
30 
31 #ifdef SLAPD_OVER_UNIQUE
32 
33 #include <stdio.h>
34 
35 #include <ac/string.h>
36 #include <ac/socket.h>
37 
38 #include "slap.h"
39 #include "slap-config.h"
40 
41 #define UNIQUE_DEFAULT_URI ("ldap:///??sub")
42 
43 static slap_overinst unique;
44 
45 typedef struct unique_attrs_s {
46           struct unique_attrs_s *next;        /* list of attrs */
47           AttributeDescription *attr;
48 } unique_attrs;
49 
50 typedef struct unique_domain_uri_s {
51           struct unique_domain_uri_s *next;
52           struct berval dn;
53           struct berval ndn;
54           struct berval filter;
55           Filter *f;
56           struct unique_attrs_s *attrs;
57           int scope;
58 } unique_domain_uri;
59 
60 typedef struct unique_domain_s {
61           struct unique_domain_s *next;
62           struct berval domain_spec;
63           struct unique_domain_uri_s *uri;
64           char ignore;                          /* polarity of attributes */
65           char strict;                          /* null considered unique too */
66           char serial;                                                          /* serialize execution */
67 } unique_domain;
68 
69 typedef struct unique_data_s {
70           struct unique_domain_s *domains;
71           struct unique_domain_s *legacy;
72           char legacy_strict_set;
73           ldap_pvt_thread_mutex_t       serial_mutex;
74 } unique_data;
75 
76 typedef struct unique_counter_s {
77           struct berval *ndn;
78           int count;
79 } unique_counter;
80 
81 enum {
82           UNIQUE_BASE = 1,
83           UNIQUE_IGNORE,
84           UNIQUE_ATTR,
85           UNIQUE_STRICT,
86           UNIQUE_URI,
87 };
88 
89 static ConfigDriver unique_cf_base;
90 static ConfigDriver unique_cf_attrs;
91 static ConfigDriver unique_cf_strict;
92 static ConfigDriver unique_cf_uri;
93 
94 static ConfigTable uniquecfg[] = {
95           { "unique_base", "basedn", 2, 2, 0, ARG_DN|ARG_QUOTE|ARG_MAGIC|UNIQUE_BASE,
96             unique_cf_base, "( OLcfgOvAt:10.1 NAME 'olcUniqueBase' "
97             "DESC 'Subtree for uniqueness searches' "
98             "EQUALITY distinguishedNameMatch "
99             "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
100           { "unique_ignore", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_IGNORE,
101             unique_cf_attrs, "( OLcfgOvAt:10.2 NAME 'olcUniqueIgnore' "
102             "DESC 'Attributes for which uniqueness shall not be enforced' "
103             "EQUALITY caseIgnoreMatch "
104             "ORDERING caseIgnoreOrderingMatch "
105             "SUBSTR caseIgnoreSubstringsMatch "
106             "SYNTAX OMsDirectoryString )", NULL, NULL },
107           { "unique_attributes", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_ATTR,
108             unique_cf_attrs, "( OLcfgOvAt:10.3 NAME 'olcUniqueAttribute' "
109             "DESC 'Attributes for which uniqueness shall be enforced' "
110             "EQUALITY caseIgnoreMatch "
111             "ORDERING caseIgnoreOrderingMatch "
112             "SUBSTR caseIgnoreSubstringsMatch "
113             "SYNTAX OMsDirectoryString )", NULL, NULL },
114           { "unique_strict", "on|off", 1, 2, 0, ARG_MAGIC|UNIQUE_STRICT,
115             unique_cf_strict, "( OLcfgOvAt:10.4 NAME 'olcUniqueStrict' "
116             "DESC 'Enforce uniqueness of null values' "
117             "EQUALITY booleanMatch "
118             "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
119           { "unique_uri", "ldapuri", 2, 3, 0, ARG_MAGIC|UNIQUE_URI,
120             unique_cf_uri, "( OLcfgOvAt:10.5 NAME 'olcUniqueURI' "
121             "DESC 'List of keywords and LDAP URIs for a uniqueness domain' "
122             "EQUALITY caseExactMatch "
123             "ORDERING caseExactOrderingMatch "
124             "SUBSTR caseExactSubstringsMatch "
125             "SYNTAX OMsDirectoryString )", NULL, NULL },
126           { NULL, NULL, 0, 0, 0, ARG_IGNORED }
127 };
128 
129 static ConfigOCs uniqueocs[] = {
130           { "( OLcfgOvOc:10.1 "
131             "NAME 'olcUniqueConfig' "
132             "DESC 'Attribute value uniqueness configuration' "
133             "SUP olcOverlayConfig "
134             "MAY ( olcUniqueBase $ olcUniqueIgnore $ "
135             "olcUniqueAttribute $ olcUniqueStrict $ "
136             "olcUniqueURI ) )",
137             Cft_Overlay, uniquecfg },
138           { NULL, 0, NULL }
139 };
140 
141 static void
unique_free_domain_uri(unique_domain_uri * uri)142 unique_free_domain_uri ( unique_domain_uri *uri )
143 {
144           unique_domain_uri *next_uri = NULL;
145           unique_attrs *attr, *next_attr = NULL;
146 
147           while ( uri ) {
148                     next_uri = uri->next;
149                     ch_free ( uri->dn.bv_val );
150                     ch_free ( uri->ndn.bv_val );
151                     ch_free ( uri->filter.bv_val );
152                     filter_free( uri->f );
153                     attr = uri->attrs;
154                     while ( attr ) {
155                               next_attr = attr->next;
156                               ch_free (attr);
157                               attr = next_attr;
158                     }
159                     ch_free ( uri );
160                     uri = next_uri;
161           }
162 }
163 
164 /* free an entire stack of domains */
165 static void
unique_free_domain(unique_domain * domain)166 unique_free_domain ( unique_domain *domain )
167 {
168           unique_domain *next_domain = NULL;
169 
170           while ( domain ) {
171                     next_domain = domain->next;
172                     ch_free ( domain->domain_spec.bv_val );
173                     unique_free_domain_uri ( domain->uri );
174                     ch_free ( domain );
175                     domain = next_domain;
176           }
177 }
178 
179 static int
unique_new_domain_uri(unique_domain_uri ** urip,const LDAPURLDesc * url_desc,ConfigArgs * c)180 unique_new_domain_uri ( unique_domain_uri **urip,
181                               const LDAPURLDesc *url_desc,
182                               ConfigArgs *c )
183 {
184           int i, rc = LDAP_SUCCESS;
185           unique_domain_uri *uri;
186           struct berval bv = {0, NULL};
187           BackendDB *be = (BackendDB *)c->be;
188           char ** attr_str;
189           AttributeDescription * ad;
190           const char * text;
191 
192           uri = ch_calloc ( 1, sizeof ( unique_domain_uri ) );
193 
194           if ( url_desc->lud_host && url_desc->lud_host[0] ) {
195                     snprintf( c->cr_msg, sizeof( c->cr_msg ),
196                                 "host <%s> not allowed in URI",
197                                 url_desc->lud_host );
198                     rc = ARG_BAD_CONF;
199                     goto exit;
200           }
201 
202           if ( url_desc->lud_dn && url_desc->lud_dn[0] ) {
203                     ber_str2bv( url_desc->lud_dn, 0, 0, &bv );
204                     rc = dnPrettyNormal( NULL,
205                                              &bv,
206                                              &uri->dn,
207                                              &uri->ndn,
208                                              NULL );
209                     if ( rc != LDAP_SUCCESS ) {
210                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
211                                           "<%s> invalid DN %d (%s)",
212                                           url_desc->lud_dn, rc, ldap_err2string( rc ));
213                               rc = ARG_BAD_CONF;
214                               goto exit;
215                     }
216 
217                     if ( be->be_nsuffix == NULL ) {
218                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
219                                           "suffix must be set" );
220                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
221                                         c->cr_msg );
222                               rc = ARG_BAD_CONF;
223                               goto exit;
224                     }
225 
226                     if ( !dnIsSuffix ( &uri->ndn, &be->be_nsuffix[0] ) ) {
227                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
228                                           "dn <%s> is not a suffix of backend base dn <%s>",
229                                           uri->dn.bv_val,
230                                           be->be_nsuffix[0].bv_val );
231                               rc = ARG_BAD_CONF;
232                               goto exit;
233                     }
234 
235                     if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
236                               Debug( LDAP_DEBUG_ANY,
237                                         "slapo-unique needs a rootdn; "
238                                         "backend <%s> has none, YMMV.\n",
239                                         be->be_nsuffix[0].bv_val );
240                     }
241           }
242 
243           attr_str = url_desc->lud_attrs;
244           if ( attr_str ) {
245                     for ( i=0; attr_str[i]; ++i ) {
246                               unique_attrs * attr;
247                               ad = NULL;
248                               if ( slap_str2ad ( attr_str[i], &ad, &text )
249                                    == LDAP_SUCCESS) {
250                                         attr = ch_calloc ( 1,
251                                                                sizeof ( unique_attrs ) );
252                                         attr->attr = ad;
253                                         attr->next = uri->attrs;
254                                         uri->attrs = attr;
255                               } else {
256                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
257                                                     "unique: attribute: %s: %s",
258                                                     attr_str[i], text );
259                                         rc = ARG_BAD_CONF;
260                                         goto exit;
261                               }
262                     }
263           }
264 
265           uri->scope = url_desc->lud_scope;
266           if ( !uri->scope ) {
267                     snprintf( c->cr_msg, sizeof( c->cr_msg ),
268                                 "unique: uri with base scope will always be unique");
269                     rc = ARG_BAD_CONF;
270                     goto exit;
271           }
272 
273           if (url_desc->lud_filter) {
274                     char *ptr;
275                     uri->f = str2filter( url_desc->lud_filter );
276                     if ( !uri->f ) {
277                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
278                                           "unique: bad filter");
279                               rc = ARG_BAD_CONF;
280                               goto exit;
281                     }
282                     /* make sure the strfilter is in normal form (ITS#5581) */
283                     filter2bv( uri->f, &uri->filter );
284                     ptr = strstr( uri->filter.bv_val, "(?=" /*)*/ );
285                     if ( ptr != NULL && ptr <= ( uri->filter.bv_val - STRLENOF( "(?=" /*)*/ ) + uri->filter.bv_len ) )
286                     {
287                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
288                                           "unique: bad filter");
289                               rc = ARG_BAD_CONF;
290                               goto exit;
291                     }
292           }
293 exit:
294           uri->next = *urip;
295           *urip = uri;
296           if ( rc ) {
297                     Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
298                               "%s: %s\n", c->log, c->cr_msg );
299                     unique_free_domain_uri ( uri );
300                     *urip = NULL;
301           }
302           return rc;
303 }
304 
305 static int
unique_new_domain_uri_basic(unique_domain_uri ** urip,ConfigArgs * c)306 unique_new_domain_uri_basic ( unique_domain_uri **urip,
307                                     ConfigArgs *c )
308 {
309           LDAPURLDesc *url_desc = NULL;
310           int rc;
311 
312           rc = ldap_url_parse ( UNIQUE_DEFAULT_URI, &url_desc );
313           if ( rc ) return rc;
314           rc = unique_new_domain_uri ( urip, url_desc, c );
315           ldap_free_urldesc ( url_desc );
316           return rc;
317 }
318 
319 /* if *domain is non-null, it's pushed down the stack.
320  * note that the entire stack is freed if there is an error,
321  * so build added domains in a separate stack before adding them
322  *
323  * domain_specs look like
324  *
325  * [strict ][ignore ][serialize ]uri[[ uri]...]
326  * e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
327  *      "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
328  *      etc
329  *
330  * so finally strictness is per-domain
331  * but so is ignore-state, and that would be better as a per-url thing
332  */
333 static int
unique_new_domain(unique_domain ** domainp,char * domain_spec,ConfigArgs * c)334 unique_new_domain ( unique_domain **domainp,
335                         char *domain_spec,
336                         ConfigArgs *c )
337 {
338           char *uri_start;
339           int rc = LDAP_SUCCESS;
340           int uri_err = 0;
341           unique_domain * domain;
342           LDAPURLDesc *url_desc, *url_descs = NULL;
343 
344           Debug(LDAP_DEBUG_TRACE, "==> unique_new_domain <%s>\n",
345                 domain_spec );
346 
347           domain = ch_calloc ( 1, sizeof (unique_domain) );
348           ber_str2bv( domain_spec, 0, 1, &domain->domain_spec );
349 
350           uri_start = domain_spec;
351           if ( strncasecmp ( uri_start, "ignore ",
352                                  STRLENOF( "ignore " ) ) == 0 ) {
353                     domain->ignore = 1;
354                     uri_start += STRLENOF( "ignore " );
355           }
356           if ( strncasecmp ( uri_start, "serialize ",
357                                  STRLENOF( "serialize " ) ) == 0 ) {
358                     domain->serial = 1;
359                     uri_start += STRLENOF( "serialize " );
360           }
361           if ( strncasecmp ( uri_start, "strict ",
362                                  STRLENOF( "strict " ) ) == 0 ) {
363                     domain->strict = 1;
364                     uri_start += STRLENOF( "strict " );
365                     if ( !domain->ignore
366                          && strncasecmp ( uri_start, "ignore ",
367                                               STRLENOF( "ignore " ) ) == 0 ) {
368                               domain->ignore = 1;
369                               uri_start += STRLENOF( "ignore " );
370                     }
371           }
372           rc = ldap_url_parselist_ext ( &url_descs, uri_start, " ", 0 );
373           if ( rc ) {
374                     snprintf( c->cr_msg, sizeof( c->cr_msg ),
375                                 "<%s> invalid ldap urilist",
376                                 uri_start );
377                     rc = ARG_BAD_CONF;
378                     goto exit;
379           }
380 
381           for ( url_desc = url_descs;
382                 url_desc;
383                 url_desc = url_desc->lud_next ) {
384                     rc = unique_new_domain_uri ( &domain->uri,
385                                                        url_desc,
386                                                        c );
387                     if ( rc ) {
388                               rc = ARG_BAD_CONF;
389                               uri_err = 1;
390                               goto exit;
391                     }
392           }
393 
394 exit:
395           if ( url_descs ) ldap_free_urldesc ( url_descs );
396           domain->next = *domainp;
397           *domainp = domain;
398           if ( rc ) {
399                     Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
400                               "%s: %s\n", c->log, c->cr_msg );
401                     unique_free_domain ( domain );
402                     *domainp = NULL;
403           }
404           return rc;
405 }
406 
407 static int
unique_cf_base(ConfigArgs * c)408 unique_cf_base( ConfigArgs *c )
409 {
410           BackendDB *be = (BackendDB *)c->be;
411           slap_overinst *on = (slap_overinst *)c->bi;
412           unique_data *private = (unique_data *) on->on_bi.bi_private;
413           unique_domain *domains = private->domains;
414           unique_domain *legacy = private->legacy;
415           int rc = ARG_BAD_CONF;
416 
417           switch ( c->op ) {
418           case SLAP_CONFIG_EMIT:
419                     rc = 0;
420                     if ( legacy && legacy->uri && legacy->uri->dn.bv_val ) {
421                               rc = value_add_one ( &c->rvalue_vals,
422                                                        &legacy->uri->dn );
423                               if ( rc ) return rc;
424                               rc = value_add_one ( &c->rvalue_nvals,
425                                                        &legacy->uri->ndn );
426                               if ( rc ) return rc;
427                     }
428                     break;
429           case LDAP_MOD_DELETE:
430                     assert ( legacy && legacy->uri && legacy->uri->dn.bv_val );
431                     rc = 0;
432                     ch_free ( legacy->uri->dn.bv_val );
433                     ch_free ( legacy->uri->ndn.bv_val );
434                     BER_BVZERO( &legacy->uri->dn );
435                     BER_BVZERO( &legacy->uri->ndn );
436                     if ( !legacy->uri->attrs ) {
437                               unique_free_domain_uri ( legacy->uri );
438                               legacy->uri = NULL;
439                     }
440                     if ( !legacy->uri && !private->legacy_strict_set ) {
441                               unique_free_domain ( legacy );
442                               private->legacy = legacy = NULL;
443                     }
444                     break;
445           case LDAP_MOD_ADD:
446           case SLAP_CONFIG_ADD:
447                     if ( domains ) {
448                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
449                                           "cannot set legacy attrs when URIs are present" );
450                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
451                                         c->cr_msg );
452                               rc = ARG_BAD_CONF;
453                               break;
454                     }
455                     if ( be->be_nsuffix == NULL ) {
456                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
457                                           "suffix must be set" );
458                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
459                                         c->cr_msg );
460                               rc = ARG_BAD_CONF;
461                               break;
462                     }
463                     if ( !dnIsSuffix ( &c->value_ndn,
464                                            &be->be_nsuffix[0] ) ) {
465                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
466                                           "dn is not a suffix of backend base" );
467                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
468                                         c->cr_msg );
469                               rc = ARG_BAD_CONF;
470                               break;
471                     }
472                     if ( !legacy ) {
473                               unique_new_domain ( &private->legacy,
474                                                       UNIQUE_DEFAULT_URI,
475                                                       c );
476                               legacy = private->legacy;
477                     }
478                     if ( !legacy->uri )
479                               unique_new_domain_uri_basic ( &legacy->uri, c );
480                     ch_free ( legacy->uri->dn.bv_val );
481                     ch_free ( legacy->uri->ndn.bv_val );
482                     legacy->uri->dn = c->value_dn;
483                     legacy->uri->ndn = c->value_ndn;
484                     rc = 0;
485                     break;
486           default:
487                     abort();
488           }
489 
490           if ( rc ) {
491                     ch_free( c->value_dn.bv_val );
492                     BER_BVZERO( &c->value_dn );
493                     ch_free( c->value_ndn.bv_val );
494                     BER_BVZERO( &c->value_ndn );
495           }
496 
497           return rc;
498 }
499 
500 static int
unique_cf_attrs(ConfigArgs * c)501 unique_cf_attrs( ConfigArgs *c )
502 {
503           slap_overinst *on = (slap_overinst *)c->bi;
504           unique_data *private = (unique_data *) on->on_bi.bi_private;
505           unique_domain *domains = private->domains;
506           unique_domain *legacy = private->legacy;
507           unique_attrs *new_attrs = NULL;
508           unique_attrs *attr, *next_attr, *reverse_attrs;
509           unique_attrs **attrp;
510           int rc = ARG_BAD_CONF;
511           int i;
512 
513           switch ( c->op ) {
514           case SLAP_CONFIG_EMIT:
515                     if ( legacy
516                          && (c->type == UNIQUE_IGNORE) == legacy->ignore
517                          && legacy->uri )
518                               for ( attr = legacy->uri->attrs;
519                                     attr;
520                                     attr = attr->next )
521                                         value_add_one( &c->rvalue_vals,
522                                                          &attr->attr->ad_cname );
523                     rc = 0;
524                     break;
525           case LDAP_MOD_DELETE:
526                     if ( legacy
527                          && (c->type == UNIQUE_IGNORE) == legacy->ignore
528                          && legacy->uri
529                          && legacy->uri->attrs) {
530                               if ( c->valx < 0 ) { /* delete all */
531                                         for ( attr = legacy->uri->attrs;
532                                               attr;
533                                               attr = next_attr ) {
534                                                   next_attr = attr->next;
535                                                   ch_free ( attr );
536                                         }
537                                         legacy->uri->attrs = NULL;
538                               } else { /* delete by index */
539                                         attrp = &legacy->uri->attrs;
540                                         for ( i=0; i < c->valx; ++i )
541                                                   attrp = &(*attrp)->next;
542                                         attr = *attrp;
543                                         *attrp = attr->next;
544                                         ch_free (attr);
545                               }
546                               if ( !legacy->uri->attrs
547                                    && !legacy->uri->dn.bv_val ) {
548                                         unique_free_domain_uri ( legacy->uri );
549                                         legacy->uri = NULL;
550                               }
551                               if ( !legacy->uri && !private->legacy_strict_set ) {
552                                         unique_free_domain ( legacy );
553                                         private->legacy = legacy = NULL;
554                               }
555                     }
556                     rc = 0;
557                     break;
558           case LDAP_MOD_ADD:
559           case SLAP_CONFIG_ADD:
560                     if ( domains ) {
561                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
562                                           "cannot set legacy attrs when URIs are present" );
563                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
564                                         c->cr_msg );
565                               rc = ARG_BAD_CONF;
566                               break;
567                     }
568                     if ( legacy
569                          && legacy->uri
570                          && legacy->uri->attrs
571                          && (c->type == UNIQUE_IGNORE) != legacy->ignore ) {
572                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
573                                           "cannot set both attrs and ignore-attrs" );
574                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
575                                         c->cr_msg );
576                               rc = ARG_BAD_CONF;
577                               break;
578                     }
579                     if ( !legacy ) {
580                               unique_new_domain ( &private->legacy,
581                                                       UNIQUE_DEFAULT_URI,
582                                                       c );
583                               legacy = private->legacy;
584                     }
585                     if ( !legacy->uri )
586                               unique_new_domain_uri_basic ( &legacy->uri, c );
587                     rc = 0;
588                     for ( i=1; c->argv[i]; ++i ) {
589                               AttributeDescription * ad = NULL;
590                               const char * text;
591                               if ( slap_str2ad ( c->argv[i], &ad, &text )
592                                    == LDAP_SUCCESS) {
593 
594                                         attr = ch_calloc ( 1,
595                                                   sizeof ( unique_attrs ) );
596                                         attr->attr = ad;
597                                         attr->next = new_attrs;
598                                         new_attrs = attr;
599                               } else {
600                                         snprintf( c->cr_msg, sizeof( c->cr_msg ),
601                                                     "unique: attribute: %s: %s",
602                                                     c->argv[i], text );
603                                         for ( attr = new_attrs;
604                                               attr;
605                                               attr=next_attr ) {
606                                                   next_attr = attr->next;
607                                                   ch_free ( attr );
608                                         }
609                                         rc = ARG_BAD_CONF;
610                                         break;
611                               }
612                     }
613                     if ( rc ) break;
614 
615                     /* (nconc legacy->uri->attrs (nreverse new_attrs)) */
616                     reverse_attrs = NULL;
617                     for ( attr = new_attrs;
618                           attr;
619                           attr = next_attr ) {
620                               next_attr = attr->next;
621                               attr->next = reverse_attrs;
622                               reverse_attrs = attr;
623                     }
624                     for ( attrp = &legacy->uri->attrs;
625                           *attrp;
626                           attrp = &(*attrp)->next ) ;
627                     *attrp = reverse_attrs;
628 
629                     legacy->ignore = ( c->type == UNIQUE_IGNORE );
630                     break;
631           default:
632                     abort();
633           }
634 
635           if ( rc ) {
636                     Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
637                               "%s: %s\n", c->log, c->cr_msg );
638           }
639           return rc;
640 }
641 
642 static int
unique_cf_strict(ConfigArgs * c)643 unique_cf_strict( ConfigArgs *c )
644 {
645           slap_overinst *on = (slap_overinst *)c->bi;
646           unique_data *private = (unique_data *) on->on_bi.bi_private;
647           unique_domain *domains = private->domains;
648           unique_domain *legacy = private->legacy;
649           int rc = ARG_BAD_CONF;
650 
651           switch ( c->op ) {
652           case SLAP_CONFIG_EMIT:
653                     /* We process the boolean manually instead of using
654                      * ARG_ON_OFF so that we can three-state it;
655                      * olcUniqueStrict is either TRUE, FALSE, or missing,
656                      * and missing is necessary to add olcUniqueURIs...
657                      */
658                     if ( private->legacy_strict_set ) {
659                               struct berval bv = legacy->strict ? slap_true_bv : slap_false_bv;
660                               value_add_one ( &c->rvalue_vals, &bv );
661                     }
662                     rc = 0;
663                     break;
664           case LDAP_MOD_DELETE:
665                     if ( legacy ) {
666                               legacy->strict = 0;
667                               if ( ! legacy->uri ) {
668                                         unique_free_domain ( legacy );
669                                         private->legacy = NULL;
670                               }
671                     }
672                     private->legacy_strict_set = 0;
673                     rc = 0;
674                     break;
675           case LDAP_MOD_ADD:
676           case SLAP_CONFIG_ADD:
677                     if ( domains ) {
678                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
679                                           "cannot set legacy attrs when URIs are present" );
680                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
681                                         c->cr_msg );
682                               rc = ARG_BAD_CONF;
683                               break;
684                     }
685                     if ( ! legacy ) {
686                               unique_new_domain ( &private->legacy,
687                                                       UNIQUE_DEFAULT_URI,
688                                                       c );
689                               legacy = private->legacy;
690                     }
691                     /* ... not using ARG_ON_OFF makes this necessary too */
692                     assert ( c->argc == 2 );
693                     legacy->strict = (strcasecmp ( c->argv[1], "TRUE" ) == 0);
694                     private->legacy_strict_set = 1;
695                     rc = 0;
696                     break;
697           default:
698                     abort();
699           }
700 
701           return rc;
702 }
703 
704 static int
unique_cf_uri(ConfigArgs * c)705 unique_cf_uri( ConfigArgs *c )
706 {
707           slap_overinst *on = (slap_overinst *)c->bi;
708           unique_data *private = (unique_data *) on->on_bi.bi_private;
709           unique_domain *domains = private->domains;
710           unique_domain *legacy = private->legacy;
711           unique_domain *domain = NULL, **domainp = NULL;
712           int rc = ARG_BAD_CONF;
713           int i;
714 
715           switch ( c->op ) {
716           case SLAP_CONFIG_EMIT:
717                     for ( domain = domains;
718                           domain;
719                           domain = domain->next ) {
720                               rc = value_add_one ( &c->rvalue_vals,
721                                                        &domain->domain_spec );
722                               if ( rc ) break;
723                     }
724                     break;
725           case LDAP_MOD_DELETE:
726                     if ( c->valx < 0 ) { /* delete them all! */
727                               unique_free_domain ( domains );
728                               private->domains = NULL;
729                     } else { /* delete just one */
730                               domainp = &private->domains;
731                               for ( i=0; i < c->valx && *domainp; ++i )
732                                         domainp = &(*domainp)->next;
733 
734                               /* If *domainp is null, we walked off the end
735                                * of the list.  This happens when back-config
736                                * and the overlay are out-of-sync, like when
737                                * rejecting changes before ITS#4752 gets
738                                * fixed.
739                                *
740                                * This should never happen, but will appear
741                                * if you backport this version of
742                                * slapo-unique without the config-undo fixes
743                                *
744                                * test024 Will hit this case in such a
745                                * situation.
746                                */
747                               assert (*domainp != NULL);
748 
749                               domain = *domainp;
750                               *domainp = domain->next;
751                               domain->next = NULL;
752                               unique_free_domain ( domain );
753                     }
754                     rc = 0;
755                     break;
756 
757           case SLAP_CONFIG_ADD: /* fallthru */
758           case LDAP_MOD_ADD:
759                     if ( legacy ) {
760                               snprintf( c->cr_msg, sizeof( c->cr_msg ),
761                                           "cannot set Uri when legacy attrs are present" );
762                               Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
763                                         c->cr_msg );
764                               rc = ARG_BAD_CONF;
765                               break;
766                     }
767                     rc = 0;
768                     if ( c->line ) rc = unique_new_domain ( &domain, c->line, c );
769                     else rc = unique_new_domain ( &domain, c->argv[1], c );
770                     if ( rc ) break;
771                     assert ( domain->next == NULL );
772                     for ( domainp = &private->domains;
773                           *domainp;
774                           domainp = &(*domainp)->next ) ;
775                     *domainp = domain;
776 
777                     break;
778 
779           default:
780                     abort ();
781           }
782 
783           return rc;
784 }
785 
786 /*
787 ** allocate new unique_data;
788 ** initialize, copy basedn;
789 ** store in on_bi.bi_private;
790 **
791 */
792 
793 static int
unique_db_init(BackendDB * be,ConfigReply * cr)794 unique_db_init(
795           BackendDB *be,
796           ConfigReply         *cr
797 )
798 {
799           slap_overinst *on = (slap_overinst *)be->bd_info;
800           unique_data *private;
801 
802           Debug(LDAP_DEBUG_TRACE, "==> unique_db_init\n" );
803 
804           private = ch_calloc ( 1, sizeof ( unique_data ) );
805           ldap_pvt_thread_mutex_init( &private->serial_mutex );
806           on->on_bi.bi_private = private;
807 
808           return 0;
809 }
810 
811 static int
unique_db_destroy(BackendDB * be,ConfigReply * cr)812 unique_db_destroy(
813           BackendDB *be,
814           ConfigReply         *cr
815 )
816 {
817           slap_overinst *on = (slap_overinst *)be->bd_info;
818           unique_data *private = on->on_bi.bi_private;
819 
820           Debug(LDAP_DEBUG_TRACE, "==> unique_db_destroy\n" );
821 
822           if ( private ) {
823                     unique_domain *domains = private->domains;
824                     unique_domain *legacy = private->legacy;
825 
826                     unique_free_domain ( domains );
827                     unique_free_domain ( legacy );
828                     ldap_pvt_thread_mutex_destroy( &private->serial_mutex );
829                     ch_free ( private );
830                     on->on_bi.bi_private = NULL;
831           }
832 
833           return 0;
834 }
835 
836 
837 /*
838 ** search callback
839 **        if this is a REP_SEARCH, count++;
840 **
841 */
842 
count_attr_cb(Operation * op,SlapReply * rs)843 static int count_attr_cb(
844           Operation *op,
845           SlapReply *rs
846 )
847 {
848           unique_counter *uc;
849 
850           /* because you never know */
851           if(!op || !rs) return(0);
852 
853           /* Only search entries are interesting */
854           if(rs->sr_type != REP_SEARCH) return(0);
855 
856           uc = op->o_callback->sc_private;
857 
858           /* Ignore the current entry */
859           if ( dn_match( uc->ndn, &rs->sr_entry->e_nname )) return(0);
860 
861           Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
862                     rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN" );
863 
864           uc->count++;
865 
866           return(0);
867 }
868 
869 /* count the length of one attribute ad
870  * (and all of its values b)
871  * in the proposed filter
872  */
873 static int
count_filter_len(unique_domain * domain,unique_domain_uri * uri,AttributeDescription * ad,BerVarray b)874 count_filter_len(
875           unique_domain *domain,
876           unique_domain_uri *uri,
877           AttributeDescription *ad,
878           BerVarray b
879 )
880 {
881           unique_attrs *attr;
882           int i;
883           int ks = 0;
884 
885           while ( !is_at_operational( ad->ad_type ) ) {
886                     if ( uri->attrs ) {
887                               for ( attr = uri->attrs; attr; attr = attr->next ) {
888                                         if ( ad == attr->attr ) {
889                                                   break;
890                                         }
891                               }
892                               if ( ( domain->ignore && attr )
893                                    || (!domain->ignore && !attr )) {
894                                         break;
895                               }
896                     }
897                     if ( b && b[0].bv_val ) {
898                               for (i = 0; b[i].bv_val; i++ ) {
899                                         /* note: make room for filter escaping... */
900                                         ks += ( 3 * b[i].bv_len ) + ad->ad_cname.bv_len + STRLENOF( "(=)" );
901                               }
902                     } else if ( domain->strict ) {
903                               ks += ad->ad_cname.bv_len + STRLENOF( "(=*)" );   /* (attr=*) */
904                     }
905                     break;
906           }
907 
908           return ks;
909 }
910 
911 static char *
build_filter(unique_domain * domain,unique_domain_uri * uri,AttributeDescription * ad,BerVarray b,char * kp,int ks,void * ctx)912 build_filter(
913           unique_domain *domain,
914           unique_domain_uri *uri,
915           AttributeDescription *ad,
916           BerVarray b,
917           char *kp,
918           int ks,
919           void *ctx
920 )
921 {
922           unique_attrs *attr;
923           int i;
924 
925           while ( !is_at_operational( ad->ad_type ) ) {
926                     if ( uri->attrs ) {
927                               for ( attr = uri->attrs; attr; attr = attr->next ) {
928                                         if ( ad == attr->attr ) {
929                                                   break;
930                                         }
931                               }
932                               if ( ( domain->ignore && attr )
933                                    || (!domain->ignore && !attr )) {
934                                         break;
935                               }
936                     }
937                     if ( b && b[0].bv_val ) {
938                               for ( i = 0; b[i].bv_val; i++ ) {
939                                         struct berval       bv;
940                                         int len;
941 
942                                         ldap_bv2escaped_filter_value_x( &b[i], &bv, 1, ctx );
943                                         if (!b[i].bv_len)
944                                                   bv.bv_val = b[i].bv_val;
945                                         len = snprintf( kp, ks, "(%s=%s)", ad->ad_cname.bv_val, bv.bv_val );
946                                         assert( len >= 0 && len < ks );
947                                         kp += len;
948                                         if ( bv.bv_val != b[i].bv_val ) {
949                                                   ber_memfree_x( bv.bv_val, ctx );
950                                         }
951                               }
952                     } else if ( domain->strict ) {
953                               int len;
954                               len = snprintf( kp, ks, "(%s=*)", ad->ad_cname.bv_val );
955                               assert( len >= 0 && len < ks );
956                               kp += len;
957                     }
958                     break;
959           }
960           return kp;
961 }
962 
963 static int
unique_search(Operation * op,Operation * nop,struct berval * dn,int scope,SlapReply * rs,struct berval * key)964 unique_search(
965           Operation *op,
966           Operation *nop,
967           struct berval * dn,
968           int scope,
969           SlapReply *rs,
970           struct berval *key
971 )
972 {
973           slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
974           SlapReply nrs = { REP_RESULT };
975           slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
976           unique_counter uq = { NULL, 0 };
977           int rc;
978           char *errmsg;
979           int errmsgsize;
980 
981           Debug(LDAP_DEBUG_TRACE, "==> unique_search %s\n", key->bv_val );
982 
983           nop->ors_filter = str2filter_x(nop, key->bv_val);
984           if(nop->ors_filter == NULL) {
985                     op->o_bd->bd_info = (BackendInfo *) on->on_info;
986                     send_ldap_error(op, rs, LDAP_OTHER,
987                               "unique_search invalid filter");
988                     return(rs->sr_err);
989           }
990 
991           nop->ors_filterstr = *key;
992 
993           cb.sc_response      = (slap_response*)count_attr_cb;
994           cb.sc_private       = &uq;
995           nop->o_callback     = &cb;
996           nop->o_tag          = LDAP_REQ_SEARCH;
997           nop->ors_scope      = scope;
998           nop->ors_deref      = LDAP_DEREF_NEVER;
999           nop->ors_limit      = NULL;
1000           nop->ors_slimit     = SLAP_NO_LIMIT;
1001           nop->ors_tlimit     = SLAP_NO_LIMIT;
1002           nop->ors_attrs      = slap_anlist_no_attrs;
1003           nop->ors_attrsonly = 1;
1004 
1005           uq.ndn = &op->o_req_ndn;
1006 
1007           nop->o_req_ndn = *dn;
1008           nop->o_ndn = op->o_bd->be_rootndn;
1009 
1010           nop->o_bd = on->on_info->oi_origdb;
1011           rc = nop->o_bd->be_search(nop, &nrs);
1012           filter_free_x(nop, nop->ors_filter, 1);
1013 
1014           if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
1015                     op->o_bd->bd_info = (BackendInfo *) on->on_info;
1016                     send_ldap_error(op, rs, rc, "unique_search failed");
1017                     rc = rs->sr_err;
1018           } else if(uq.count) {
1019                     Debug(LDAP_DEBUG_TRACE, "=> unique_search found %d records\n", uq.count );
1020 
1021                     errmsgsize = sizeof("non-unique attributes found with ") + key->bv_len;
1022                     errmsg = op->o_tmpalloc(errmsgsize, op->o_tmpmemctx);
1023                     snprintf( errmsg, errmsgsize, "non-unique attributes found with %s", key->bv_val );
1024                     op->o_bd->bd_info = (BackendInfo *) on->on_info;
1025                     send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, errmsg);
1026                     op->o_tmpfree(errmsg, op->o_tmpmemctx);
1027                     rc = rs->sr_err;
1028           } else {
1029                     Debug(LDAP_DEBUG_TRACE, "=> unique_search found no records\n" );
1030                     rc = SLAP_CB_CONTINUE;
1031           }
1032 
1033           op->o_tmpfree( key->bv_val, op->o_tmpmemctx );
1034 
1035           return(rc);
1036 }
1037 
1038 static int
unique_unlock(Operation * op,SlapReply * rs)1039 unique_unlock(
1040           Operation *op,
1041           SlapReply *rs
1042 )
1043 {
1044           slap_callback *sc = op->o_callback;
1045           unique_data *private = sc->sc_private;
1046 
1047           ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1048           op->o_callback = sc->sc_next;
1049           op->o_tmpfree( sc, op->o_tmpmemctx );
1050           return 0;
1051 }
1052 
1053 static int
unique_add(Operation * op,SlapReply * rs)1054 unique_add(
1055           Operation *op,
1056           SlapReply *rs
1057 )
1058 {
1059           slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1060           unique_data *private = (unique_data *) on->on_bi.bi_private;
1061           unique_domain *domains = private->domains;
1062           unique_domain *legacy = private->legacy;
1063           unique_domain *domain;
1064           Operation nop = *op;
1065           Attribute *a;
1066           char *key, *kp;
1067           struct berval bvkey;
1068           int rc = SLAP_CB_CONTINUE;
1069           int locked = 0;
1070 
1071           Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n",
1072                 op->o_req_dn.bv_val );
1073 
1074           if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1075                               get_relax(op) > SLAP_CONTROL_IGNORED
1076                               && access_allowed( op, op->ora_e,
1077                                         slap_schema.si_ad_entry, NULL,
1078                                         ACL_MANAGE, NULL ) ) ) {
1079                     return rc;
1080           }
1081 
1082           for ( domain = legacy ? legacy : domains;
1083                 domain;
1084                 domain = domain->next )
1085           {
1086                     unique_domain_uri *uri;
1087 
1088                     for ( uri = domain->uri;
1089                           uri;
1090                           uri = uri->next )
1091                     {
1092                               int len;
1093                               int ks = 0;
1094 
1095                               if ( uri->ndn.bv_val
1096                                    && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
1097                                         continue;
1098 
1099                               if ( uri->f ) {
1100                                         if ( test_filter( NULL, op->ora_e, uri->f )
1101                                                   == LDAP_COMPARE_FALSE )
1102                                         {
1103                                                   Debug( LDAP_DEBUG_TRACE,
1104                                                             "==> unique_add_skip<%s>\n",
1105                                                             op->o_req_dn.bv_val );
1106                                                   continue;
1107                                         }
1108                               }
1109 
1110                               if(!(a = op->ora_e->e_attrs)) {
1111                                         op->o_bd->bd_info = (BackendInfo *) on->on_info;
1112                                         send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
1113                                                             "unique_add() got null op.ora_e.e_attrs");
1114                                         rc = rs->sr_err;
1115                                         break;
1116 
1117                               } else {
1118                                         for(; a; a = a->a_next) {
1119                                                   ks += count_filter_len ( domain,
1120                                                                                  uri,
1121                                                                                  a->a_desc,
1122                                                                                  a->a_vals);
1123                                         }
1124                               }
1125 
1126                               /* skip this domain-uri if it isn't involved */
1127                               if ( !ks ) continue;
1128 
1129                               if ( domain->serial && !locked ) {
1130                                         ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1131                                         locked = 1;
1132                               }
1133 
1134                               /* terminating NUL */
1135                               ks += sizeof("(|)");
1136 
1137                               if ( uri->filter.bv_val && uri->filter.bv_len )
1138                                         ks += uri->filter.bv_len + STRLENOF ("(&)");
1139                               kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1140 
1141                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1142                                         len = snprintf (kp, ks, "(&%s", uri->filter.bv_val);
1143                                         assert( len >= 0 && len < ks );
1144                                         kp += len;
1145                               }
1146                               len = snprintf(kp, ks - (kp - key), "(|");
1147                               assert( len >= 0 && len < ks - (kp - key) );
1148                               kp += len;
1149 
1150                               for(a = op->ora_e->e_attrs; a; a = a->a_next)
1151                                         kp = build_filter(domain,
1152                                                               uri,
1153                                                               a->a_desc,
1154                                                               a->a_vals,
1155                                                               kp,
1156                                                               ks - ( kp - key ),
1157                                                               op->o_tmpmemctx);
1158 
1159                               len = snprintf(kp, ks - (kp - key), ")");
1160                               assert( len >= 0 && len < ks - (kp - key) );
1161                               kp += len;
1162                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1163                                         len = snprintf(kp, ks - (kp - key), ")");
1164                                         assert( len >= 0 && len < ks - (kp - key) );
1165                                         kp += len;
1166                               }
1167                               bvkey.bv_val = key;
1168                               bvkey.bv_len = kp - key;
1169 
1170                               rc = unique_search ( op,
1171                                                        &nop,
1172                                                        uri->ndn.bv_val ?
1173                                                        &uri->ndn :
1174                                                        &op->o_bd->be_nsuffix[0],
1175                                                        uri->scope,
1176                                                        rs,
1177                                                        &bvkey);
1178 
1179                               if ( rc != SLAP_CB_CONTINUE ) break;
1180                     }
1181                     if ( rc != SLAP_CB_CONTINUE ) break;
1182           }
1183 
1184           if ( locked ) {
1185                     if ( rc != SLAP_CB_CONTINUE ) {
1186                               ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1187                     } else {
1188                               slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1189                               cb->sc_cleanup = unique_unlock;
1190                               cb->sc_private = private;
1191                               cb->sc_next = op->o_callback;
1192                               op->o_callback = cb;
1193                     }
1194           }
1195           return rc;
1196 }
1197 
1198 
1199 static int
unique_modify(Operation * op,SlapReply * rs)1200 unique_modify(
1201           Operation *op,
1202           SlapReply *rs
1203 )
1204 {
1205           slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1206           unique_data *private = (unique_data *) on->on_bi.bi_private;
1207           unique_domain *domains = private->domains;
1208           unique_domain *legacy = private->legacy;
1209           unique_domain *domain;
1210           Operation nop = *op;
1211           Modifications *m;
1212           Entry *e = NULL;
1213           char *key, *kp;
1214           struct berval bvkey;
1215           int rc = SLAP_CB_CONTINUE;
1216           int locked = 0;
1217 
1218           Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n",
1219                 op->o_req_dn.bv_val );
1220 
1221           if ( !op->orm_modlist ) {
1222                     Debug(LDAP_DEBUG_TRACE, "unique_modify: got empty modify op\n" );
1223                     return rc;
1224           }
1225 
1226           if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1227                               get_relax(op) > SLAP_CONTROL_IGNORED
1228                               && overlay_entry_get_ov(op, &op->o_req_ndn, NULL, NULL, 0, &e, on) == LDAP_SUCCESS
1229                               && e
1230                               && access_allowed( op, e,
1231                                         slap_schema.si_ad_entry, NULL,
1232                                         ACL_MANAGE, NULL ) ) ) {
1233                     overlay_entry_release_ov( op, e, 0, on );
1234                     return rc;
1235           }
1236           if ( e ) {
1237                     overlay_entry_release_ov( op, e, 0, on );
1238           }
1239 
1240           for ( domain = legacy ? legacy : domains;
1241                 domain;
1242                 domain = domain->next )
1243           {
1244                     unique_domain_uri *uri;
1245 
1246                     for ( uri = domain->uri;
1247                           uri;
1248                           uri = uri->next )
1249                     {
1250                               int len;
1251                               int ks = 0;
1252 
1253                               if ( uri->ndn.bv_val
1254                                    && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
1255                                         continue;
1256 
1257                               for ( m = op->orm_modlist; m; m = m->sml_next)
1258                                         if ( (m->sml_op & LDAP_MOD_OP)
1259                                              != LDAP_MOD_DELETE )
1260                                                   ks += count_filter_len
1261                                                             ( domain,
1262                                                               uri,
1263                                                               m->sml_desc,
1264                                                               m->sml_values);
1265 
1266                               /* skip this domain-uri if it isn't involved */
1267                               if ( !ks ) continue;
1268 
1269                               if ( domain->serial && !locked ) {
1270                                         ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1271                                         locked = 1;
1272                               }
1273 
1274                               /* terminating NUL */
1275                               ks += sizeof("(|)");
1276 
1277                               if ( uri->filter.bv_val && uri->filter.bv_len )
1278                                         ks += uri->filter.bv_len + STRLENOF ("(&)");
1279                               kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1280 
1281                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1282                                         len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
1283                                         assert( len >= 0 && len < ks );
1284                                         kp += len;
1285                               }
1286                               len = snprintf(kp, ks - (kp - key), "(|");
1287                               assert( len >= 0 && len < ks - (kp - key) );
1288                               kp += len;
1289 
1290                               for(m = op->orm_modlist; m; m = m->sml_next)
1291                                         if ( (m->sml_op & LDAP_MOD_OP)
1292                                              != LDAP_MOD_DELETE )
1293                                                   kp = build_filter ( domain,
1294                                                                           uri,
1295                                                                           m->sml_desc,
1296                                                                           m->sml_values,
1297                                                                           kp,
1298                                                                           ks - (kp - key),
1299                                                                           op->o_tmpmemctx );
1300 
1301                               len = snprintf(kp, ks - (kp - key), ")");
1302                               assert( len >= 0 && len < ks - (kp - key) );
1303                               kp += len;
1304                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1305                                         len = snprintf (kp, ks - (kp - key), ")");
1306                                         assert( len >= 0 && len < ks - (kp - key) );
1307                                         kp += len;
1308                               }
1309                               bvkey.bv_val = key;
1310                               bvkey.bv_len = kp - key;
1311 
1312                               rc = unique_search ( op,
1313                                                        &nop,
1314                                                        uri->ndn.bv_val ?
1315                                                        &uri->ndn :
1316                                                        &op->o_bd->be_nsuffix[0],
1317                                                        uri->scope,
1318                                                        rs,
1319                                                        &bvkey);
1320 
1321                               if ( rc != SLAP_CB_CONTINUE ) break;
1322                     }
1323                     if ( rc != SLAP_CB_CONTINUE ) break;
1324           }
1325 
1326           if ( locked ) {
1327                     if ( rc != SLAP_CB_CONTINUE ) {
1328                               ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1329                     } else {
1330                               slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1331                               cb->sc_cleanup = unique_unlock;
1332                               cb->sc_private = private;
1333                               cb->sc_next = op->o_callback;
1334                               op->o_callback = cb;
1335                     }
1336           }
1337           return rc;
1338 }
1339 
1340 
1341 static int
unique_modrdn(Operation * op,SlapReply * rs)1342 unique_modrdn(
1343           Operation *op,
1344           SlapReply *rs
1345 )
1346 {
1347           slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1348           unique_data *private = (unique_data *) on->on_bi.bi_private;
1349           unique_domain *domains = private->domains;
1350           unique_domain *legacy = private->legacy;
1351           unique_domain *domain;
1352           Operation nop = *op;
1353           Entry *e = NULL;
1354           char *key, *kp;
1355           struct berval bvkey;
1356           LDAPRDN   newrdn;
1357           struct berval bv[2];
1358           int rc = SLAP_CB_CONTINUE;
1359           int locked = 0;
1360 
1361           Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
1362                     op->o_req_dn.bv_val, op->orr_newrdn.bv_val );
1363 
1364           if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) || (
1365                               get_relax(op) > SLAP_CONTROL_IGNORED
1366                               && overlay_entry_get_ov(op, &op->o_req_ndn, NULL, NULL, 0, &e, on) == LDAP_SUCCESS
1367                               && e
1368                               && access_allowed( op, e,
1369                                         slap_schema.si_ad_entry, NULL,
1370                                         ACL_MANAGE, NULL ) ) ) {
1371                     overlay_entry_release_ov( op, e, 0, on );
1372                     return rc;
1373           }
1374           if ( e ) {
1375                     overlay_entry_release_ov( op, e, 0, on );
1376           }
1377 
1378           for ( domain = legacy ? legacy : domains;
1379                 domain;
1380                 domain = domain->next )
1381           {
1382                     unique_domain_uri *uri;
1383 
1384                     for ( uri = domain->uri;
1385                           uri;
1386                           uri = uri->next )
1387                     {
1388                               int i, len;
1389                               int ks = 0;
1390 
1391                               if ( uri->ndn.bv_val
1392                                    && !dnIsSuffix( &op->o_req_ndn, &uri->ndn )
1393                                    && (!op->orr_nnewSup
1394                                          || !dnIsSuffix( op->orr_nnewSup, &uri->ndn )))
1395                                         continue;
1396 
1397                               if ( ldap_bv2rdn_x ( &op->oq_modrdn.rs_newrdn,
1398                                                        &newrdn,
1399                                                        (char **)&rs->sr_text,
1400                                                        LDAP_DN_FORMAT_LDAP,
1401                                                        op->o_tmpmemctx ) ) {
1402                                         op->o_bd->bd_info = (BackendInfo *) on->on_info;
1403                                         send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
1404                                                             "unknown type(s) used in RDN");
1405                                         rc = rs->sr_err;
1406                                         break;
1407                               }
1408 
1409                               rc = SLAP_CB_CONTINUE;
1410                               for ( i=0; newrdn[i]; i++) {
1411                                         AttributeDescription *ad = NULL;
1412                                         if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
1413                                                   ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
1414                                                   rs->sr_err = LDAP_INVALID_SYNTAX;
1415                                                   send_ldap_result( op, rs );
1416                                                   rc = rs->sr_err;
1417                                                   break;
1418                                         }
1419                                         newrdn[i]->la_private = ad;
1420                               }
1421                               if ( rc != SLAP_CB_CONTINUE ) break;
1422 
1423                               bv[1].bv_val = NULL;
1424                               bv[1].bv_len = 0;
1425 
1426                               for ( i=0; newrdn[i]; i++ ) {
1427                                         bv[0] = newrdn[i]->la_value;
1428                                         ks += count_filter_len ( domain,
1429                                                                        uri,
1430                                                                        newrdn[i]->la_private,
1431                                                                        bv);
1432                               }
1433 
1434                               /* skip this domain if it isn't involved */
1435                               if ( !ks ) continue;
1436 
1437                               if ( domain->serial && !locked ) {
1438                                         ldap_pvt_thread_mutex_lock( &private->serial_mutex );
1439                                         locked = 1;
1440                               }
1441 
1442                               /* terminating NUL */
1443                               ks += sizeof("(|)");
1444 
1445                               if ( uri->filter.bv_val && uri->filter.bv_len )
1446                                         ks += uri->filter.bv_len + STRLENOF ("(&)");
1447                               kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
1448 
1449                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1450                                         len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
1451                                         assert( len >= 0 && len < ks );
1452                                         kp += len;
1453                               }
1454                               len = snprintf(kp, ks - (kp - key), "(|");
1455                               assert( len >= 0 && len < ks - (kp - key) );
1456                               kp += len;
1457 
1458                               for ( i=0; newrdn[i]; i++) {
1459                                         bv[0] = newrdn[i]->la_value;
1460                                         kp = build_filter ( domain,
1461                                                                 uri,
1462                                                                 newrdn[i]->la_private,
1463                                                                 bv,
1464                                                                 kp,
1465                                                                 ks - (kp - key ),
1466                                                                 op->o_tmpmemctx);
1467                               }
1468 
1469                               len = snprintf(kp, ks - (kp - key), ")");
1470                               assert( len >= 0 && len < ks - (kp - key) );
1471                               kp += len;
1472                               if ( uri->filter.bv_val && uri->filter.bv_len ) {
1473                                         len = snprintf (kp, ks - (kp - key), ")");
1474                                         assert( len >= 0 && len < ks - (kp - key) );
1475                                         kp += len;
1476                               }
1477                               bvkey.bv_val = key;
1478                               bvkey.bv_len = kp - key;
1479 
1480                               rc = unique_search ( op,
1481                                                        &nop,
1482                                                        uri->ndn.bv_val ?
1483                                                        &uri->ndn :
1484                                                        &op->o_bd->be_nsuffix[0],
1485                                                        uri->scope,
1486                                                        rs,
1487                                                        &bvkey);
1488 
1489                               if ( rc != SLAP_CB_CONTINUE ) break;
1490                     }
1491                     if ( rc != SLAP_CB_CONTINUE ) break;
1492           }
1493 
1494           if ( locked ) {
1495                     if ( rc != SLAP_CB_CONTINUE ) {
1496                               ldap_pvt_thread_mutex_unlock( &private->serial_mutex );
1497                     } else {
1498                               slap_callback *cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
1499                               cb->sc_cleanup = unique_unlock;
1500                               cb->sc_private = private;
1501                               cb->sc_next = op->o_callback;
1502                               op->o_callback = cb;
1503                     }
1504           }
1505           return rc;
1506 }
1507 
1508 /*
1509 ** init_module is last so the symbols resolve "for free" --
1510 ** it expects to be called automagically during dynamic module initialization
1511 */
1512 
1513 int
unique_initialize()1514 unique_initialize()
1515 {
1516           int rc;
1517 
1518           /* statically declared just after the #includes at top */
1519           memset (&unique, 0, sizeof(unique));
1520 
1521           unique.on_bi.bi_type = "unique";
1522           unique.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
1523           unique.on_bi.bi_db_init = unique_db_init;
1524           unique.on_bi.bi_db_destroy = unique_db_destroy;
1525           unique.on_bi.bi_op_add = unique_add;
1526           unique.on_bi.bi_op_modify = unique_modify;
1527           unique.on_bi.bi_op_modrdn = unique_modrdn;
1528 
1529           unique.on_bi.bi_cf_ocs = uniqueocs;
1530           rc = config_register_schema( uniquecfg, uniqueocs );
1531           if ( rc ) return rc;
1532 
1533           return(overlay_register(&unique));
1534 }
1535 
1536 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
init_module(int argc,char * argv[])1537 int init_module(int argc, char *argv[]) {
1538           return unique_initialize();
1539 }
1540 #endif
1541 
1542 #endif /* SLAPD_OVER_UNIQUE */
1543