Back to index

openldap  2.4.31
unique.c
Go to the documentation of this file.
00001 /* unique.c - attribute uniqueness module */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2004-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2004,2006-2007 Symas Corporation.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS: 
00018  * This work was initially developed by Symas Corporation for
00019  * inclusion in OpenLDAP Software, with subsequent enhancements by
00020  * Matthew Backes at Symas Corporation.  This work was sponsored by
00021  * Hewlett-Packard.
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #ifdef SLAPD_OVER_UNIQUE
00027 
00028 #include <stdio.h>
00029 
00030 #include <ac/string.h>
00031 #include <ac/socket.h>
00032 
00033 #include "slap.h"
00034 #include "config.h"
00035 
00036 #define UNIQUE_DEFAULT_URI ("ldap:///??sub")
00037 
00038 static slap_overinst unique;
00039 
00040 typedef struct unique_attrs_s {
00041        struct unique_attrs_s *next;             /* list of attrs */
00042        AttributeDescription *attr;
00043 } unique_attrs;
00044 
00045 typedef struct unique_domain_uri_s {
00046        struct unique_domain_uri_s *next;
00047        struct berval dn;
00048        struct berval ndn;
00049        struct berval filter;
00050        Filter *f;
00051        struct unique_attrs_s *attrs;
00052        int scope;
00053 } unique_domain_uri;
00054 
00055 typedef struct unique_domain_s {
00056        struct unique_domain_s *next;
00057        struct berval domain_spec;
00058        struct unique_domain_uri_s *uri;
00059        char ignore;                          /* polarity of attributes */
00060        char strict;                          /* null considered unique too */
00061 } unique_domain;
00062 
00063 typedef struct unique_data_s {
00064        struct unique_domain_s *domains;
00065        struct unique_domain_s *legacy;
00066        char legacy_strict_set;
00067 } unique_data;
00068 
00069 typedef struct unique_counter_s {
00070        struct berval *ndn;
00071        int count;
00072 } unique_counter;
00073 
00074 enum {
00075        UNIQUE_BASE = 1,
00076        UNIQUE_IGNORE,
00077        UNIQUE_ATTR,
00078        UNIQUE_STRICT,
00079        UNIQUE_URI
00080 };
00081 
00082 static ConfigDriver unique_cf_base;
00083 static ConfigDriver unique_cf_attrs;
00084 static ConfigDriver unique_cf_strict;
00085 static ConfigDriver unique_cf_uri;
00086 
00087 static ConfigTable uniquecfg[] = {
00088        { "unique_base", "basedn", 2, 2, 0, ARG_DN|ARG_MAGIC|UNIQUE_BASE,
00089          unique_cf_base, "( OLcfgOvAt:10.1 NAME 'olcUniqueBase' "
00090          "DESC 'Subtree for uniqueness searches' "
00091          "EQUALITY distinguishedNameMatch "
00092          "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
00093        { "unique_ignore", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_IGNORE,
00094          unique_cf_attrs, "( OLcfgOvAt:10.2 NAME 'olcUniqueIgnore' "
00095          "DESC 'Attributes for which uniqueness shall not be enforced' "
00096          "EQUALITY caseIgnoreMatch "
00097          "ORDERING caseIgnoreOrderingMatch "
00098          "SUBSTR caseIgnoreSubstringsMatch "
00099          "SYNTAX OMsDirectoryString )", NULL, NULL },
00100        { "unique_attributes", "attribute...", 2, 0, 0, ARG_MAGIC|UNIQUE_ATTR,
00101          unique_cf_attrs, "( OLcfgOvAt:10.3 NAME 'olcUniqueAttribute' "
00102          "DESC 'Attributes for which uniqueness shall be enforced' "
00103          "EQUALITY caseIgnoreMatch "
00104          "ORDERING caseIgnoreOrderingMatch "
00105          "SUBSTR caseIgnoreSubstringsMatch "
00106          "SYNTAX OMsDirectoryString )", NULL, NULL },
00107        { "unique_strict", "on|off", 1, 2, 0, ARG_MAGIC|UNIQUE_STRICT,
00108          unique_cf_strict, "( OLcfgOvAt:10.4 NAME 'olcUniqueStrict' "
00109          "DESC 'Enforce uniqueness of null values' "
00110          "EQUALITY booleanMatch "
00111          "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00112        { "unique_uri", "ldapuri", 2, 3, 0, ARG_MAGIC|UNIQUE_URI,
00113          unique_cf_uri, "( OLcfgOvAt:10.5 NAME 'olcUniqueURI' "
00114          "DESC 'List of keywords and LDAP URIs for a uniqueness domain' "
00115          "EQUALITY caseExactMatch "
00116          "ORDERING caseExactOrderingMatch "
00117          "SUBSTR caseExactSubstringsMatch "
00118          "SYNTAX OMsDirectoryString )", NULL, NULL },
00119        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
00120 };
00121 
00122 static ConfigOCs uniqueocs[] = {
00123        { "( OLcfgOvOc:10.1 "
00124          "NAME 'olcUniqueConfig' "
00125          "DESC 'Attribute value uniqueness configuration' "
00126          "SUP olcOverlayConfig "
00127          "MAY ( olcUniqueBase $ olcUniqueIgnore $ "
00128          "olcUniqueAttribute $ olcUniqueStrict $ "
00129          "olcUniqueURI ) )",
00130          Cft_Overlay, uniquecfg },
00131        { NULL, 0, NULL }
00132 };
00133 
00134 static void
00135 unique_free_domain_uri ( unique_domain_uri *uri )
00136 {
00137        unique_domain_uri *next_uri = NULL;
00138        unique_attrs *attr, *next_attr = NULL;
00139 
00140        while ( uri ) {
00141               next_uri = uri->next;
00142               ch_free ( uri->dn.bv_val );
00143               ch_free ( uri->ndn.bv_val );
00144               ch_free ( uri->filter.bv_val );
00145               filter_free( uri->f );
00146               attr = uri->attrs;
00147               while ( attr ) {
00148                      next_attr = attr->next;
00149                      ch_free (attr);
00150                      attr = next_attr;
00151               }
00152               ch_free ( uri );
00153               uri = next_uri;
00154        }
00155 }
00156 
00157 /* free an entire stack of domains */
00158 static void
00159 unique_free_domain ( unique_domain *domain )
00160 {
00161        unique_domain *next_domain = NULL;
00162 
00163        while ( domain ) {
00164               next_domain = domain->next;
00165               ch_free ( domain->domain_spec.bv_val );
00166               unique_free_domain_uri ( domain->uri );
00167               ch_free ( domain );
00168               domain = next_domain;
00169        }
00170 }
00171 
00172 static int
00173 unique_new_domain_uri ( unique_domain_uri **urip,
00174                      const LDAPURLDesc *url_desc,
00175                      ConfigArgs *c )
00176 {
00177        int i, rc = LDAP_SUCCESS;
00178        unique_domain_uri *uri;
00179        struct berval bv = {0, NULL};
00180        BackendDB *be = (BackendDB *)c->be;
00181        char ** attr_str;
00182        AttributeDescription * ad;
00183        const char * text;
00184 
00185        uri = ch_calloc ( 1, sizeof ( unique_domain_uri ) );
00186 
00187        if ( url_desc->lud_host && url_desc->lud_host[0] ) {
00188               snprintf( c->cr_msg, sizeof( c->cr_msg ),
00189                        "host <%s> not allowed in URI",
00190                        url_desc->lud_host );
00191               rc = ARG_BAD_CONF;
00192               goto exit;
00193        }
00194 
00195        if ( url_desc->lud_dn && url_desc->lud_dn[0] ) {
00196               ber_str2bv( url_desc->lud_dn, 0, 0, &bv );
00197               rc = dnPrettyNormal( NULL,
00198                                  &bv,
00199                                  &uri->dn,
00200                                  &uri->ndn,
00201                                  NULL );
00202               if ( rc != LDAP_SUCCESS ) {
00203                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00204                               "<%s> invalid DN %d (%s)",
00205                               url_desc->lud_dn, rc, ldap_err2string( rc ));
00206                      rc = ARG_BAD_CONF;
00207                      goto exit;
00208               }
00209 
00210               if ( be->be_nsuffix == NULL ) {
00211                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00212                               "suffix must be set" );
00213                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00214                             c->cr_msg, NULL, NULL );
00215                      rc = ARG_BAD_CONF;
00216                      goto exit;
00217               }
00218 
00219               if ( !dnIsSuffix ( &uri->ndn, &be->be_nsuffix[0] ) ) {
00220                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00221                               "dn <%s> is not a suffix of backend base dn <%s>",
00222                               uri->dn.bv_val,
00223                               be->be_nsuffix[0].bv_val );
00224                      rc = ARG_BAD_CONF;
00225                      goto exit;
00226               }
00227 
00228               if ( BER_BVISNULL( &be->be_rootndn ) || BER_BVISEMPTY( &be->be_rootndn ) ) {
00229                      Debug( LDAP_DEBUG_ANY,
00230                             "slapo-unique needs a rootdn; "
00231                             "backend <%s> has none, YMMV.\n",
00232                             be->be_nsuffix[0].bv_val, 0, 0 );
00233               }
00234        }
00235 
00236        attr_str = url_desc->lud_attrs;
00237        if ( attr_str ) {
00238               for ( i=0; attr_str[i]; ++i ) {
00239                      unique_attrs * attr;
00240                      ad = NULL;
00241                      if ( slap_str2ad ( attr_str[i], &ad, &text )
00242                           == LDAP_SUCCESS) {
00243                             attr = ch_calloc ( 1,
00244                                              sizeof ( unique_attrs ) );
00245                             attr->attr = ad;
00246                             attr->next = uri->attrs;
00247                             uri->attrs = attr;
00248                      } else {
00249                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
00250                                      "unique: attribute: %s: %s",
00251                                      attr_str[i], text );
00252                             rc = ARG_BAD_CONF;
00253                             goto exit;
00254                      }
00255               }
00256        }
00257 
00258        uri->scope = url_desc->lud_scope;
00259        if ( !uri->scope ) {
00260               snprintf( c->cr_msg, sizeof( c->cr_msg ),
00261                        "unique: uri with base scope will always be unique");
00262               rc = ARG_BAD_CONF;
00263               goto exit;
00264        }
00265 
00266        if (url_desc->lud_filter) {
00267               char *ptr;
00268               uri->f = str2filter( url_desc->lud_filter );
00269               if ( !uri->f ) {
00270                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00271                               "unique: bad filter");
00272                      rc = ARG_BAD_CONF;
00273                      goto exit;
00274               }
00275               /* make sure the strfilter is in normal form (ITS#5581) */
00276               filter2bv( uri->f, &uri->filter );
00277               ptr = strstr( uri->filter.bv_val, "(?=" /*)*/ );
00278               if ( ptr != NULL && ptr <= ( uri->filter.bv_val - STRLENOF( "(?=" /*)*/ ) + uri->filter.bv_len ) )
00279               {
00280                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00281                               "unique: bad filter");
00282                      rc = ARG_BAD_CONF;
00283                      goto exit;
00284               }
00285        }
00286 exit:
00287        uri->next = *urip;
00288        *urip = uri;
00289        if ( rc ) {
00290               Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
00291                      "%s: %s\n", c->log, c->cr_msg, 0 );
00292               unique_free_domain_uri ( uri );
00293               *urip = NULL;
00294        }
00295        return rc;
00296 }
00297 
00298 static int
00299 unique_new_domain_uri_basic ( unique_domain_uri **urip,
00300                            ConfigArgs *c )
00301 {
00302        LDAPURLDesc *url_desc = NULL;
00303        int rc;
00304 
00305        rc = ldap_url_parse ( UNIQUE_DEFAULT_URI, &url_desc );
00306        if ( rc ) return rc;
00307        rc = unique_new_domain_uri ( urip, url_desc, c );
00308        ldap_free_urldesc ( url_desc );
00309        return rc;
00310 }
00311 
00312 /* if *domain is non-null, it's pushed down the stack.
00313  * note that the entire stack is freed if there is an error,
00314  * so build added domains in a separate stack before adding them
00315  *
00316  * domain_specs look like
00317  *
00318  * [strict ][ignore ]uri[[ uri]...]
00319  * e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
00320  *      "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
00321  *      etc
00322  *
00323  * so finally strictness is per-domain
00324  * but so is ignore-state, and that would be better as a per-url thing
00325  */
00326 static int
00327 unique_new_domain ( unique_domain **domainp,
00328                   char *domain_spec,
00329                   ConfigArgs *c )
00330 {
00331        char *uri_start;
00332        int rc = LDAP_SUCCESS;
00333        int uri_err = 0;
00334        unique_domain * domain;
00335        LDAPURLDesc *url_desc, *url_descs = NULL;
00336 
00337        Debug(LDAP_DEBUG_TRACE, "==> unique_new_domain <%s>\n",
00338              domain_spec, 0, 0);
00339 
00340        domain = ch_calloc ( 1, sizeof (unique_domain) );
00341        ber_str2bv( domain_spec, 0, 1, &domain->domain_spec );
00342 
00343        uri_start = domain_spec;
00344        if ( strncasecmp ( uri_start, "ignore ",
00345                         STRLENOF( "ignore " ) ) == 0 ) {
00346               domain->ignore = 1;
00347               uri_start += STRLENOF( "ignore " );
00348        }
00349        if ( strncasecmp ( uri_start, "strict ",
00350                         STRLENOF( "strict " ) ) == 0 ) {
00351               domain->strict = 1;
00352               uri_start += STRLENOF( "strict " );
00353               if ( !domain->ignore
00354                    && strncasecmp ( uri_start, "ignore ",
00355                                   STRLENOF( "ignore " ) ) == 0 ) {
00356                      domain->ignore = 1;
00357                      uri_start += STRLENOF( "ignore " );
00358               }
00359        }
00360        rc = ldap_url_parselist_ext ( &url_descs, uri_start, " ", 0 );
00361        if ( rc ) {
00362               snprintf( c->cr_msg, sizeof( c->cr_msg ),
00363                        "<%s> invalid ldap urilist",
00364                        uri_start );
00365               rc = ARG_BAD_CONF;
00366               goto exit;
00367        }
00368 
00369        for ( url_desc = url_descs;
00370              url_desc;
00371              url_desc = url_descs->lud_next ) {
00372               rc = unique_new_domain_uri ( &domain->uri,
00373                                         url_desc,
00374                                         c );
00375               if ( rc ) {
00376                      rc = ARG_BAD_CONF;
00377                      uri_err = 1;
00378                      goto exit;
00379               }
00380        }
00381 
00382 exit:
00383        if ( url_descs ) ldap_free_urldesc ( url_descs );
00384        domain->next = *domainp;
00385        *domainp = domain;
00386        if ( rc ) {
00387               Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
00388                      "%s: %s\n", c->log, c->cr_msg, 0 );
00389               unique_free_domain ( domain );
00390               *domainp = NULL;
00391        }
00392        return rc;
00393 }
00394 
00395 static int
00396 unique_cf_base( ConfigArgs *c )
00397 {
00398        BackendDB *be = (BackendDB *)c->be;
00399        slap_overinst *on = (slap_overinst *)c->bi;
00400        unique_data *private = (unique_data *) on->on_bi.bi_private;
00401        unique_domain *domains = private->domains;
00402        unique_domain *legacy = private->legacy;
00403        int rc = ARG_BAD_CONF;
00404 
00405        switch ( c->op ) {
00406        case SLAP_CONFIG_EMIT:
00407               rc = 0;
00408               if ( legacy && legacy->uri && legacy->uri->dn.bv_val ) {
00409                      rc = value_add_one ( &c->rvalue_vals,
00410                                         &legacy->uri->dn );
00411                      if ( rc ) return rc;
00412                      rc = value_add_one ( &c->rvalue_nvals,
00413                                         &legacy->uri->ndn );
00414                      if ( rc ) return rc;
00415               }
00416               break;
00417        case LDAP_MOD_DELETE:
00418               assert ( legacy && legacy->uri && legacy->uri->dn.bv_val );
00419               rc = 0;
00420               ch_free ( legacy->uri->dn.bv_val );
00421               ch_free ( legacy->uri->ndn.bv_val );
00422               BER_BVZERO( &legacy->uri->dn );
00423               BER_BVZERO( &legacy->uri->ndn );
00424               if ( !legacy->uri->attrs ) {
00425                      unique_free_domain_uri ( legacy->uri );
00426                      legacy->uri = NULL;
00427               }
00428               if ( !legacy->uri && !private->legacy_strict_set ) {
00429                      unique_free_domain ( legacy );
00430                      private->legacy = legacy = NULL;
00431               }
00432               break;
00433        case LDAP_MOD_ADD:
00434        case SLAP_CONFIG_ADD:
00435               if ( domains ) {
00436                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00437                               "cannot set legacy attrs when URIs are present" );
00438                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00439                             c->cr_msg, NULL, NULL );
00440                      rc = ARG_BAD_CONF;
00441                      break;
00442               }
00443               if ( be->be_nsuffix == NULL ) {
00444                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00445                               "suffix must be set" );
00446                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00447                             c->cr_msg, NULL, NULL );
00448                      rc = ARG_BAD_CONF;
00449                      break;
00450               }
00451               if ( !dnIsSuffix ( &c->value_ndn,
00452                                &be->be_nsuffix[0] ) ) {
00453                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00454                               "dn is not a suffix of backend base" );
00455                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00456                             c->cr_msg, NULL, NULL );
00457                      rc = ARG_BAD_CONF;
00458                      break;
00459               }
00460               if ( !legacy ) {
00461                      unique_new_domain ( &private->legacy,
00462                                        UNIQUE_DEFAULT_URI,
00463                                        c );
00464                      legacy = private->legacy;
00465               }
00466               if ( !legacy->uri )
00467                      unique_new_domain_uri_basic ( &legacy->uri, c );
00468               ch_free ( legacy->uri->dn.bv_val );
00469               ch_free ( legacy->uri->ndn.bv_val );
00470               legacy->uri->dn = c->value_dn;
00471               legacy->uri->ndn = c->value_ndn;
00472               rc = 0;
00473               break;
00474        default:
00475               abort();
00476        }
00477 
00478        if ( rc ) {
00479               ch_free( c->value_dn.bv_val );
00480               BER_BVZERO( &c->value_dn );
00481               ch_free( c->value_ndn.bv_val );
00482               BER_BVZERO( &c->value_ndn );
00483        }
00484 
00485        return rc;
00486 }
00487 
00488 static int
00489 unique_cf_attrs( ConfigArgs *c )
00490 {
00491        slap_overinst *on = (slap_overinst *)c->bi;
00492        unique_data *private = (unique_data *) on->on_bi.bi_private;
00493        unique_domain *domains = private->domains;
00494        unique_domain *legacy = private->legacy;
00495        unique_attrs *new_attrs = NULL;
00496        unique_attrs *attr, *next_attr, *reverse_attrs;
00497        unique_attrs **attrp;
00498        int rc = ARG_BAD_CONF;
00499        int i;
00500 
00501        switch ( c->op ) {
00502        case SLAP_CONFIG_EMIT:
00503               if ( legacy
00504                    && (c->type == UNIQUE_IGNORE) == legacy->ignore
00505                    && legacy->uri )
00506                      for ( attr = legacy->uri->attrs;
00507                            attr;
00508                            attr = attr->next )
00509                             value_add_one( &c->rvalue_vals,
00510                                           &attr->attr->ad_cname );
00511               rc = 0;
00512               break;
00513        case LDAP_MOD_DELETE:
00514               if ( legacy
00515                    && (c->type == UNIQUE_IGNORE) == legacy->ignore
00516                    && legacy->uri
00517                    && legacy->uri->attrs) {
00518                      if ( c->valx < 0 ) { /* delete all */
00519                             for ( attr = legacy->uri->attrs;
00520                                   attr;
00521                                   attr = next_attr ) {
00522                                    next_attr = attr->next;
00523                                    ch_free ( attr );
00524                             }
00525                             legacy->uri->attrs = NULL;
00526                      } else { /* delete by index */
00527                             attrp = &legacy->uri->attrs;
00528                             for ( i=0; i < c->valx; ++i )
00529                                    attrp = &(*attrp)->next;
00530                             attr = *attrp;
00531                             *attrp = attr->next;
00532                             ch_free (attr);
00533                      }
00534                      if ( !legacy->uri->attrs
00535                           && !legacy->uri->dn.bv_val ) {
00536                             unique_free_domain_uri ( legacy->uri );
00537                             legacy->uri = NULL;
00538                      }
00539                      if ( !legacy->uri && !private->legacy_strict_set ) {
00540                             unique_free_domain ( legacy );
00541                             private->legacy = legacy = NULL;
00542                      }
00543               }
00544               rc = 0;
00545               break;
00546        case LDAP_MOD_ADD:
00547        case SLAP_CONFIG_ADD:
00548               if ( domains ) {
00549                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00550                               "cannot set legacy attrs when URIs are present" );
00551                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00552                             c->cr_msg, NULL, NULL );
00553                      rc = ARG_BAD_CONF;
00554                      break;
00555               }
00556               if ( legacy
00557                    && legacy->uri
00558                    && legacy->uri->attrs
00559                    && (c->type == UNIQUE_IGNORE) != legacy->ignore ) {
00560                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00561                               "cannot set both attrs and ignore-attrs" );
00562                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00563                             c->cr_msg, NULL, NULL );
00564                      rc = ARG_BAD_CONF;
00565                      break;
00566               }
00567               if ( !legacy ) {
00568                      unique_new_domain ( &private->legacy,
00569                                        UNIQUE_DEFAULT_URI,
00570                                        c );
00571                      legacy = private->legacy;
00572               }
00573               if ( !legacy->uri )
00574                      unique_new_domain_uri_basic ( &legacy->uri, c );
00575               rc = 0;
00576               for ( i=1; c->argv[i]; ++i ) {
00577                      AttributeDescription * ad = NULL;
00578                      const char * text;
00579                      if ( slap_str2ad ( c->argv[i], &ad, &text )
00580                           == LDAP_SUCCESS) {
00581 
00582                             attr = ch_calloc ( 1,
00583                                    sizeof ( unique_attrs ) );
00584                             attr->attr = ad;
00585                             attr->next = new_attrs;
00586                             new_attrs = attr;
00587                      } else {
00588                             snprintf( c->cr_msg, sizeof( c->cr_msg ),
00589                                      "unique: attribute: %s: %s",
00590                                      c->argv[i], text );
00591                             for ( attr = new_attrs;
00592                                   attr;
00593                                   attr=next_attr ) {
00594                                    next_attr = attr->next;
00595                                    ch_free ( attr );
00596                             }
00597                             rc = ARG_BAD_CONF;
00598                             break;
00599                      }
00600               }
00601               if ( rc ) break;
00602 
00603               /* (nconc legacy->uri->attrs (nreverse new_attrs)) */
00604               reverse_attrs = NULL;
00605               for ( attr = new_attrs;
00606                     attr;
00607                     attr = next_attr ) {
00608                      next_attr = attr->next;
00609                      attr->next = reverse_attrs;
00610                      reverse_attrs = attr;
00611               }
00612               for ( attrp = &legacy->uri->attrs;
00613                     *attrp;
00614                     attrp = &(*attrp)->next ) ;
00615               *attrp = reverse_attrs;
00616 
00617               legacy->ignore = ( c->type == UNIQUE_IGNORE );
00618               break;
00619        default:
00620               abort();
00621        }
00622 
00623        if ( rc ) {
00624               Debug ( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
00625                      "%s: %s\n", c->log, c->cr_msg, 0 );
00626        }
00627        return rc;
00628 }
00629 
00630 static int
00631 unique_cf_strict( ConfigArgs *c )
00632 {
00633        slap_overinst *on = (slap_overinst *)c->bi;
00634        unique_data *private = (unique_data *) on->on_bi.bi_private;
00635        unique_domain *domains = private->domains;
00636        unique_domain *legacy = private->legacy;
00637        int rc = ARG_BAD_CONF;
00638 
00639        switch ( c->op ) {
00640        case SLAP_CONFIG_EMIT:
00641               /* We process the boolean manually instead of using
00642                * ARG_ON_OFF so that we can three-state it;
00643                * olcUniqueStrict is either TRUE, FALSE, or missing,
00644                * and missing is necessary to add olcUniqueURIs...
00645                */
00646               if ( private->legacy_strict_set ) {
00647                      struct berval bv;
00648                      bv.bv_val = legacy->strict ? "TRUE" : "FALSE";
00649                      bv.bv_len = legacy->strict ?
00650                             STRLENOF("TRUE") :
00651                             STRLENOF("FALSE");
00652                      value_add_one ( &c->rvalue_vals, &bv );
00653               }
00654               rc = 0;
00655               break;
00656        case LDAP_MOD_DELETE:
00657               if ( legacy ) {
00658                      legacy->strict = 0;
00659                      if ( ! legacy->uri ) {
00660                             unique_free_domain ( legacy );
00661                             private->legacy = NULL;
00662                      }
00663               }
00664               private->legacy_strict_set = 0;
00665               rc = 0;
00666               break;
00667        case LDAP_MOD_ADD:
00668        case SLAP_CONFIG_ADD:
00669               if ( domains ) {
00670                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00671                               "cannot set legacy attrs when URIs are present" );
00672                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00673                             c->cr_msg, NULL, NULL );
00674                      rc = ARG_BAD_CONF;
00675                      break;
00676               }
00677               if ( ! legacy ) {
00678                      unique_new_domain ( &private->legacy,
00679                                        UNIQUE_DEFAULT_URI,
00680                                        c );
00681                      legacy = private->legacy;
00682               }
00683               /* ... not using ARG_ON_OFF makes this necessary too */
00684               assert ( c->argc == 2 );
00685               legacy->strict = (strcasecmp ( c->argv[1], "TRUE" ) == 0);
00686               private->legacy_strict_set = 1;
00687               rc = 0;
00688               break;
00689        default:
00690               abort();
00691        }
00692 
00693        return rc;
00694 }
00695 
00696 static int
00697 unique_cf_uri( ConfigArgs *c )
00698 {
00699        slap_overinst *on = (slap_overinst *)c->bi;
00700        unique_data *private = (unique_data *) on->on_bi.bi_private;
00701        unique_domain *domains = private->domains;
00702        unique_domain *legacy = private->legacy;
00703        unique_domain *domain = NULL, **domainp = NULL;
00704        int rc = ARG_BAD_CONF;
00705        int i;
00706 
00707        switch ( c->op ) {
00708        case SLAP_CONFIG_EMIT:
00709               for ( domain = domains;
00710                     domain;
00711                     domain = domain->next ) {
00712                      rc = value_add_one ( &c->rvalue_vals,
00713                                         &domain->domain_spec );
00714                      if ( rc ) break;
00715               }
00716               break;
00717        case LDAP_MOD_DELETE:
00718               if ( c->valx < 0 ) { /* delete them all! */
00719                      unique_free_domain ( domains );
00720                      private->domains = NULL;
00721               } else { /* delete just one */
00722                      domainp = &private->domains;
00723                      for ( i=0; i < c->valx && *domainp; ++i )
00724                             domainp = &(*domainp)->next;
00725 
00726                      /* If *domainp is null, we walked off the end
00727                       * of the list.  This happens when back-config
00728                       * and the overlay are out-of-sync, like when
00729                       * rejecting changes before ITS#4752 gets
00730                       * fixed.
00731                       *
00732                       * This should never happen, but will appear
00733                       * if you backport this version of
00734                       * slapo-unique without the config-undo fixes
00735                       *
00736                       * test024 Will hit this case in such a
00737                       * situation.
00738                       */
00739                      assert (*domainp != NULL);
00740 
00741                      domain = *domainp;
00742                      *domainp = domain->next;
00743                      domain->next = NULL;
00744                      unique_free_domain ( domain );
00745               }
00746               rc = 0;
00747               break;
00748 
00749        case SLAP_CONFIG_ADD: /* fallthrough */
00750        case LDAP_MOD_ADD:
00751               if ( legacy ) {
00752                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00753                               "cannot set Uri when legacy attrs are present" );
00754                      Debug ( LDAP_DEBUG_CONFIG, "unique config: %s\n",
00755                             c->cr_msg, NULL, NULL );
00756                      rc = ARG_BAD_CONF;
00757                      break;
00758               }
00759               rc = 0;
00760               if ( c->line ) rc = unique_new_domain ( &domain, c->line, c );
00761               else rc = unique_new_domain ( &domain, c->argv[1], c );
00762               if ( rc ) break;
00763               assert ( domain->next == NULL );
00764               for ( domainp = &private->domains;
00765                     *domainp;
00766                     domainp = &(*domainp)->next ) ;
00767               *domainp = domain;
00768 
00769               break;
00770 
00771        default:
00772               abort ();
00773        }
00774 
00775        return rc;
00776 }
00777 
00778 /*
00779 ** allocate new unique_data;
00780 ** initialize, copy basedn;
00781 ** store in on_bi.bi_private;
00782 **
00783 */
00784 
00785 static int
00786 unique_db_init(
00787        BackendDB     *be,
00788        ConfigReply   *cr
00789 )
00790 {
00791        slap_overinst *on = (slap_overinst *)be->bd_info;
00792        unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
00793 
00794        Debug(LDAP_DEBUG_TRACE, "==> unique_db_init\n", 0, 0, 0);
00795 
00796        *privatep = ch_calloc ( 1, sizeof ( unique_data ) );
00797 
00798        return 0;
00799 }
00800 
00801 static int
00802 unique_db_destroy(
00803        BackendDB     *be,
00804        ConfigReply   *cr
00805 )
00806 {
00807        slap_overinst *on = (slap_overinst *)be->bd_info;
00808        unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
00809        unique_data *private = *privatep;
00810 
00811        Debug(LDAP_DEBUG_TRACE, "==> unique_db_destroy\n", 0, 0, 0);
00812 
00813        if ( private ) {
00814               unique_domain *domains = private->domains;
00815               unique_domain *legacy = private->legacy;
00816 
00817               unique_free_domain ( domains );
00818               unique_free_domain ( legacy );
00819               ch_free ( private );
00820               *privatep = NULL;
00821        }
00822 
00823        return 0;
00824 }
00825 
00826 static int
00827 unique_open(
00828        BackendDB *be,
00829        ConfigReply *cr
00830 )
00831 {
00832        Debug(LDAP_DEBUG_TRACE, "unique_open: overlay initialized\n", 0, 0, 0);
00833 
00834        return 0;
00835 }
00836 
00837 
00838 /*
00839 ** Leave unique_data but wipe out config
00840 **
00841 */
00842 
00843 static int
00844 unique_close(
00845        BackendDB *be,
00846        ConfigReply *cr
00847 )
00848 {
00849        slap_overinst *on    = (slap_overinst *) be->bd_info;
00850        unique_data **privatep = (unique_data **) &on->on_bi.bi_private;
00851        unique_data *private = *privatep;
00852 
00853        Debug(LDAP_DEBUG_TRACE, "==> unique_close\n", 0, 0, 0);
00854 
00855        if ( private ) {
00856               unique_domain *domains = private->domains;
00857               unique_domain *legacy = private->legacy;
00858 
00859               unique_free_domain ( domains );
00860               unique_free_domain ( legacy );
00861               memset ( private, 0, sizeof ( unique_data ) );
00862        }
00863 
00864        return ( 0 );
00865 }
00866 
00867 
00868 /*
00869 ** search callback
00870 **     if this is a REP_SEARCH, count++;
00871 **
00872 */
00873 
00874 static int count_attr_cb(
00875        Operation *op,
00876        SlapReply *rs
00877 )
00878 {
00879        unique_counter *uc;
00880 
00881        /* because you never know */
00882        if(!op || !rs) return(0);
00883 
00884        /* Only search entries are interesting */
00885        if(rs->sr_type != REP_SEARCH) return(0);
00886 
00887        uc = op->o_callback->sc_private;
00888 
00889        /* Ignore the current entry */
00890        if ( dn_match( uc->ndn, &rs->sr_entry->e_nname )) return(0);
00891 
00892        Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
00893               rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
00894 
00895        uc->count++;
00896 
00897        return(0);
00898 }
00899 
00900 /* count the length of one attribute ad
00901  * (and all of its values b)
00902  * in the proposed filter
00903  */
00904 static int
00905 count_filter_len(
00906        unique_domain *domain,
00907        unique_domain_uri *uri,
00908        AttributeDescription *ad,
00909        BerVarray b
00910 )
00911 {
00912        unique_attrs *attr;
00913        int i;
00914        int ks = 0;
00915 
00916        while ( !is_at_operational( ad->ad_type ) ) {
00917               if ( uri->attrs ) {
00918                      for ( attr = uri->attrs; attr; attr = attr->next ) {
00919                             if ( ad == attr->attr ) {
00920                                    break;
00921                             }
00922                      }
00923                      if ( ( domain->ignore && attr )
00924                           || (!domain->ignore && !attr )) {
00925                             break;
00926                      }
00927               }
00928               if ( b && b[0].bv_val ) {
00929                      for (i = 0; b[i].bv_val; i++ ) {
00930                             /* note: make room for filter escaping... */
00931                             ks += ( 3 * b[i].bv_len ) + ad->ad_cname.bv_len + STRLENOF( "(=)" );
00932                      }
00933               } else if ( domain->strict ) {
00934                      ks += ad->ad_cname.bv_len + STRLENOF( "(=*)" );  /* (attr=*) */
00935               }
00936               break;
00937        }
00938 
00939        return ks;
00940 }
00941 
00942 static char *
00943 build_filter(
00944        unique_domain *domain,
00945        unique_domain_uri *uri,
00946        AttributeDescription *ad,
00947        BerVarray b,
00948        char *kp,
00949        int ks,
00950        void *ctx
00951 )
00952 {
00953        unique_attrs *attr;
00954        int i;
00955 
00956        while ( !is_at_operational( ad->ad_type ) ) {
00957               if ( uri->attrs ) {
00958                      for ( attr = uri->attrs; attr; attr = attr->next ) {
00959                             if ( ad == attr->attr ) {
00960                                    break;
00961                             }
00962                      }
00963                      if ( ( domain->ignore && attr )
00964                           || (!domain->ignore && !attr )) {
00965                             break;
00966                      }
00967               }
00968               if ( b && b[0].bv_val ) {
00969                      for ( i = 0; b[i].bv_val; i++ ) {
00970                             struct berval bv;
00971                             int len;
00972 
00973                             ldap_bv2escaped_filter_value_x( &b[i], &bv, 1, ctx );
00974                             if (!b[i].bv_len)
00975                                    bv.bv_val = b[i].bv_val;
00976                             len = snprintf( kp, ks, "(%s=%s)", ad->ad_cname.bv_val, bv.bv_val );
00977                             assert( len >= 0 && len < ks );
00978                             kp += len;
00979                             if ( bv.bv_val != b[i].bv_val ) {
00980                                    ber_memfree_x( bv.bv_val, ctx );
00981                             }
00982                      }
00983               } else if ( domain->strict ) {
00984                      int len;
00985                      len = snprintf( kp, ks, "(%s=*)", ad->ad_cname.bv_val );
00986                      assert( len >= 0 && len < ks );
00987                      kp += len;
00988               }
00989               break;
00990        }
00991        return kp;
00992 }
00993 
00994 static int
00995 unique_search(
00996        Operation *op,
00997        Operation *nop,
00998        struct berval * dn,
00999        int scope,
01000        SlapReply *rs,
01001        struct berval *key
01002 )
01003 {
01004        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
01005        SlapReply nrs = { REP_RESULT };
01006        slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
01007        unique_counter uq = { NULL, 0 };
01008        int rc;
01009 
01010        Debug(LDAP_DEBUG_TRACE, "==> unique_search %s\n", key->bv_val, 0, 0);
01011 
01012        nop->ors_filter = str2filter_x(nop, key->bv_val);
01013        if(nop->ors_filter == NULL) {
01014               op->o_bd->bd_info = (BackendInfo *) on->on_info;
01015               send_ldap_error(op, rs, LDAP_OTHER,
01016                      "unique_search invalid filter");
01017               return(rs->sr_err);
01018        }
01019 
01020        nop->ors_filterstr = *key;
01021 
01022        cb.sc_response       = (slap_response*)count_attr_cb;
01023        cb.sc_private = &uq;
01024        nop->o_callback      = &cb;
01025        nop->o_tag    = LDAP_REQ_SEARCH;
01026        nop->ors_scope       = scope;
01027        nop->ors_deref       = LDAP_DEREF_NEVER;
01028        nop->ors_limit       = NULL;
01029        nop->ors_slimit      = SLAP_NO_LIMIT;
01030        nop->ors_tlimit      = SLAP_NO_LIMIT;
01031        nop->ors_attrs       = slap_anlist_no_attrs;
01032        nop->ors_attrsonly = 1;
01033 
01034        uq.ndn = &op->o_req_ndn;
01035 
01036        nop->o_req_ndn = *dn;
01037        nop->o_ndn = op->o_bd->be_rootndn;
01038 
01039        nop->o_bd = on->on_info->oi_origdb;
01040        rc = nop->o_bd->be_search(nop, &nrs);
01041        filter_free_x(nop, nop->ors_filter, 1);
01042        op->o_tmpfree( key->bv_val, op->o_tmpmemctx );
01043 
01044        if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
01045               op->o_bd->bd_info = (BackendInfo *) on->on_info;
01046               send_ldap_error(op, rs, rc, "unique_search failed");
01047               return(rs->sr_err);
01048        }
01049 
01050        Debug(LDAP_DEBUG_TRACE, "=> unique_search found %d records\n", uq.count, 0, 0);
01051 
01052        if(uq.count) {
01053               op->o_bd->bd_info = (BackendInfo *) on->on_info;
01054               send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
01055                      "some attributes not unique");
01056               return(rs->sr_err);
01057        }
01058 
01059        return(SLAP_CB_CONTINUE);
01060 }
01061 
01062 static int
01063 unique_add(
01064        Operation *op,
01065        SlapReply *rs
01066 )
01067 {
01068        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
01069        unique_data *private = (unique_data *) on->on_bi.bi_private;
01070        unique_domain *domains = private->domains;
01071        unique_domain *legacy = private->legacy;
01072        unique_domain *domain;
01073        Operation nop = *op;
01074        Attribute *a;
01075        char *key, *kp;
01076        struct berval bvkey;
01077        int rc = SLAP_CB_CONTINUE;
01078 
01079        Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n",
01080              op->o_req_dn.bv_val, 0, 0);
01081 
01082        /* skip the checks if the operation has manageDsaIt control in it
01083         * (for replication) */
01084        if ( op->o_managedsait > SLAP_CONTROL_IGNORED ) {
01085               Debug(LDAP_DEBUG_TRACE, "unique_add: administrative bypass, skipping\n", 0, 0, 0);
01086               return rc;
01087        }
01088 
01089        for ( domain = legacy ? legacy : domains;
01090              domain;
01091              domain = domain->next )
01092        {
01093               unique_domain_uri *uri;
01094 
01095               for ( uri = domain->uri;
01096                     uri;
01097                     uri = uri->next )
01098               {
01099                      int len;
01100                      int ks = 0;
01101 
01102                      if ( uri->ndn.bv_val
01103                           && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
01104                             continue;
01105 
01106                      if ( uri->f ) {
01107                             if ( test_filter( NULL, op->ora_e, uri->f )
01108                                    == LDAP_COMPARE_FALSE )
01109                             {
01110                                    Debug( LDAP_DEBUG_TRACE,
01111                                           "==> unique_add_skip<%s>\n",
01112                                           op->o_req_dn.bv_val, 0, 0 );
01113                                    continue;
01114                             }
01115                      }
01116 
01117                      if(!(a = op->ora_e->e_attrs)) {
01118                             op->o_bd->bd_info = (BackendInfo *) on->on_info;
01119                             send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
01120                                           "unique_add() got null op.ora_e.e_attrs");
01121                             rc = rs->sr_err;
01122                             break;
01123 
01124                      } else {
01125                             for(; a; a = a->a_next) {
01126                                    ks += count_filter_len ( domain,
01127                                                          uri,
01128                                                          a->a_desc,
01129                                                          a->a_vals);
01130                             }
01131                      }
01132 
01133                      /* skip this domain-uri if it isn't involved */
01134                      if ( !ks ) continue;
01135 
01136                      /* terminating NUL */
01137                      ks += sizeof("(|)");
01138 
01139                      if ( uri->filter.bv_val && uri->filter.bv_len )
01140                             ks += uri->filter.bv_len + STRLENOF ("(&)");
01141                      kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
01142 
01143                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01144                             len = snprintf (kp, ks, "(&%s", uri->filter.bv_val);
01145                             assert( len >= 0 && len < ks );
01146                             kp += len;
01147                      }
01148                      len = snprintf(kp, ks - (kp - key), "(|");
01149                      assert( len >= 0 && len < ks - (kp - key) );
01150                      kp += len;
01151 
01152                      for(a = op->ora_e->e_attrs; a; a = a->a_next)
01153                             kp = build_filter(domain,
01154                                             uri,
01155                                             a->a_desc,
01156                                             a->a_vals,
01157                                             kp,
01158                                             ks - ( kp - key ),
01159                                             op->o_tmpmemctx);
01160 
01161                      len = snprintf(kp, ks - (kp - key), ")");
01162                      assert( len >= 0 && len < ks - (kp - key) );
01163                      kp += len;
01164                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01165                             len = snprintf(kp, ks - (kp - key), ")");
01166                             assert( len >= 0 && len < ks - (kp - key) );
01167                             kp += len;
01168                      }
01169                      bvkey.bv_val = key;
01170                      bvkey.bv_len = kp - key;
01171 
01172                      rc = unique_search ( op,
01173                                         &nop,
01174                                         uri->ndn.bv_val ?
01175                                         &uri->ndn :
01176                                         &op->o_bd->be_nsuffix[0],
01177                                         uri->scope,
01178                                         rs,
01179                                         &bvkey);
01180 
01181                      if ( rc != SLAP_CB_CONTINUE ) break;
01182               }
01183               if ( rc != SLAP_CB_CONTINUE ) break;
01184        }
01185 
01186        return rc;
01187 }
01188 
01189 
01190 static int
01191 unique_modify(
01192        Operation *op,
01193        SlapReply *rs
01194 )
01195 {
01196        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
01197        unique_data *private = (unique_data *) on->on_bi.bi_private;
01198        unique_domain *domains = private->domains;
01199        unique_domain *legacy = private->legacy;
01200        unique_domain *domain;
01201        Operation nop = *op;
01202        Modifications *m;
01203        char *key, *kp;
01204        struct berval bvkey;
01205        int rc = SLAP_CB_CONTINUE;
01206 
01207        Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n",
01208              op->o_req_dn.bv_val, 0, 0);
01209 
01210        /* skip the checks if the operation has manageDsaIt control in it
01211         * (for replication) */
01212        if ( op->o_managedsait > SLAP_CONTROL_IGNORED ) {
01213               Debug(LDAP_DEBUG_TRACE, "unique_modify: administrative bypass, skipping\n", 0, 0, 0);
01214               return rc;
01215        }
01216 
01217        for ( domain = legacy ? legacy : domains;
01218              domain;
01219              domain = domain->next )
01220        {
01221               unique_domain_uri *uri;
01222 
01223               for ( uri = domain->uri;
01224                     uri;
01225                     uri = uri->next )
01226               {
01227                      int len;
01228                      int ks = 0;
01229 
01230                      if ( uri->ndn.bv_val
01231                           && !dnIsSuffix( &op->o_req_ndn, &uri->ndn ))
01232                             continue;
01233 
01234                      if ( !(m = op->orm_modlist) ) {
01235                             op->o_bd->bd_info = (BackendInfo *) on->on_info;
01236                             send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
01237                                           "unique_modify() got null op.orm_modlist");
01238                             rc = rs->sr_err;
01239                             break;
01240 
01241                      } else
01242                             for ( ; m; m = m->sml_next)
01243                                    if ( (m->sml_op & LDAP_MOD_OP)
01244                                         != LDAP_MOD_DELETE )
01245                                           ks += count_filter_len
01246                                                  ( domain,
01247                                                    uri,
01248                                                    m->sml_desc,
01249                                                    m->sml_values);
01250 
01251                      /* skip this domain-uri if it isn't involved */
01252                      if ( !ks ) continue;
01253 
01254                      /* terminating NUL */
01255                      ks += sizeof("(|)");
01256 
01257                      if ( uri->filter.bv_val && uri->filter.bv_len )
01258                             ks += uri->filter.bv_len + STRLENOF ("(&)");
01259                      kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
01260 
01261                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01262                             len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
01263                             assert( len >= 0 && len < ks );
01264                             kp += len;
01265                      }
01266                      len = snprintf(kp, ks - (kp - key), "(|");
01267                      assert( len >= 0 && len < ks - (kp - key) );
01268                      kp += len;
01269 
01270                      for(m = op->orm_modlist; m; m = m->sml_next)
01271                             if ( (m->sml_op & LDAP_MOD_OP)
01272                                  != LDAP_MOD_DELETE )
01273                                    kp = build_filter ( domain,
01274                                                      uri,
01275                                                      m->sml_desc,
01276                                                      m->sml_values,
01277                                                      kp,
01278                                                      ks - (kp - key),
01279                                                      op->o_tmpmemctx );
01280 
01281                      len = snprintf(kp, ks - (kp - key), ")");
01282                      assert( len >= 0 && len < ks - (kp - key) );
01283                      kp += len;
01284                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01285                             len = snprintf (kp, ks - (kp - key), ")");
01286                             assert( len >= 0 && len < ks - (kp - key) );
01287                             kp += len;
01288                      }
01289                      bvkey.bv_val = key;
01290                      bvkey.bv_len = kp - key;
01291 
01292                      rc = unique_search ( op,
01293                                         &nop,
01294                                         uri->ndn.bv_val ?
01295                                         &uri->ndn :
01296                                         &op->o_bd->be_nsuffix[0],
01297                                         uri->scope,
01298                                         rs,
01299                                         &bvkey);
01300 
01301                      if ( rc != SLAP_CB_CONTINUE ) break;
01302               }
01303               if ( rc != SLAP_CB_CONTINUE ) break;
01304        }
01305 
01306        return rc;
01307 }
01308 
01309 
01310 static int
01311 unique_modrdn(
01312        Operation *op,
01313        SlapReply *rs
01314 )
01315 {
01316        slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
01317        unique_data *private = (unique_data *) on->on_bi.bi_private;
01318        unique_domain *domains = private->domains;
01319        unique_domain *legacy = private->legacy;
01320        unique_domain *domain;
01321        Operation nop = *op;
01322        char *key, *kp;
01323        struct berval bvkey;
01324        LDAPRDN       newrdn;
01325        struct berval bv[2];
01326        int rc = SLAP_CB_CONTINUE;
01327 
01328        Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
01329               op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
01330 
01331        /* skip the checks if the operation has manageDsaIt control in it
01332         * (for replication) */
01333        if ( op->o_managedsait > SLAP_CONTROL_IGNORED ) {
01334               Debug(LDAP_DEBUG_TRACE, "unique_modrdn: administrative bypass, skipping\n", 0, 0, 0);
01335               return rc;
01336        }
01337 
01338        for ( domain = legacy ? legacy : domains;
01339              domain;
01340              domain = domain->next )
01341        {
01342               unique_domain_uri *uri;
01343 
01344               for ( uri = domain->uri;
01345                     uri;
01346                     uri = uri->next )
01347               {
01348                      int i, len;
01349                      int ks = 0;
01350 
01351                      if ( uri->ndn.bv_val
01352                           && !dnIsSuffix( &op->o_req_ndn, &uri->ndn )
01353                           && (!op->orr_nnewSup
01354                              || !dnIsSuffix( op->orr_nnewSup, &uri->ndn )))
01355                             continue;
01356 
01357                      if ( ldap_bv2rdn_x ( &op->oq_modrdn.rs_newrdn,
01358                                         &newrdn,
01359                                         (char **)&rs->sr_text,
01360                                         LDAP_DN_FORMAT_LDAP,
01361                                         op->o_tmpmemctx ) ) {
01362                             op->o_bd->bd_info = (BackendInfo *) on->on_info;
01363                             send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
01364                                           "unknown type(s) used in RDN");
01365                             rc = rs->sr_err;
01366                             break;
01367                      }
01368 
01369                      rc = SLAP_CB_CONTINUE;
01370                      for ( i=0; newrdn[i]; i++) {
01371                             AttributeDescription *ad = NULL;
01372                             if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
01373                                    ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
01374                                    rs->sr_err = LDAP_INVALID_SYNTAX;
01375                                    send_ldap_result( op, rs );
01376                                    rc = rs->sr_err;
01377                                    break;
01378                             }
01379                             newrdn[i]->la_private = ad;
01380                      }
01381                      if ( rc != SLAP_CB_CONTINUE ) break;
01382 
01383                      bv[1].bv_val = NULL;
01384                      bv[1].bv_len = 0;
01385 
01386                      for ( i=0; newrdn[i]; i++ ) {
01387                             bv[0] = newrdn[i]->la_value;
01388                             ks += count_filter_len ( domain,
01389                                                   uri,
01390                                                   newrdn[i]->la_private,
01391                                                   bv);
01392                      }
01393 
01394                      /* skip this domain if it isn't involved */
01395                      if ( !ks ) continue;
01396 
01397                      /* terminating NUL */
01398                      ks += sizeof("(|)");
01399 
01400                      if ( uri->filter.bv_val && uri->filter.bv_len )
01401                             ks += uri->filter.bv_len + STRLENOF ("(&)");
01402                      kp = key = op->o_tmpalloc(ks, op->o_tmpmemctx);
01403 
01404                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01405                             len = snprintf(kp, ks, "(&%s", uri->filter.bv_val);
01406                             assert( len >= 0 && len < ks );
01407                             kp += len;
01408                      }
01409                      len = snprintf(kp, ks - (kp - key), "(|");
01410                      assert( len >= 0 && len < ks - (kp - key) );
01411                      kp += len;
01412 
01413                      for ( i=0; newrdn[i]; i++) {
01414                             bv[0] = newrdn[i]->la_value;
01415                             kp = build_filter ( domain,
01416                                               uri,
01417                                               newrdn[i]->la_private,
01418                                               bv,
01419                                               kp,
01420                                               ks - (kp - key ),
01421                                               op->o_tmpmemctx);
01422                      }
01423 
01424                      len = snprintf(kp, ks - (kp - key), ")");
01425                      assert( len >= 0 && len < ks - (kp - key) );
01426                      kp += len;
01427                      if ( uri->filter.bv_val && uri->filter.bv_len ) {
01428                             len = snprintf (kp, ks - (kp - key), ")");
01429                             assert( len >= 0 && len < ks - (kp - key) );
01430                             kp += len;
01431                      }
01432                      bvkey.bv_val = key;
01433                      bvkey.bv_len = kp - key;
01434 
01435                      rc = unique_search ( op,
01436                                         &nop,
01437                                         uri->ndn.bv_val ?
01438                                         &uri->ndn :
01439                                         &op->o_bd->be_nsuffix[0],
01440                                         uri->scope,
01441                                         rs,
01442                                         &bvkey);
01443 
01444                      if ( rc != SLAP_CB_CONTINUE ) break;
01445               }
01446               if ( rc != SLAP_CB_CONTINUE ) break;
01447        }
01448 
01449        return rc;
01450 }
01451 
01452 /*
01453 ** init_module is last so the symbols resolve "for free" --
01454 ** it expects to be called automagically during dynamic module initialization
01455 */
01456 
01457 int
01458 unique_initialize()
01459 {
01460        int rc;
01461 
01462        /* statically declared just after the #includes at top */
01463        memset (&unique, 0, sizeof(unique));
01464 
01465        unique.on_bi.bi_type = "unique";
01466        unique.on_bi.bi_db_init = unique_db_init;
01467        unique.on_bi.bi_db_destroy = unique_db_destroy;
01468        unique.on_bi.bi_db_open = unique_open;
01469        unique.on_bi.bi_db_close = unique_close;
01470        unique.on_bi.bi_op_add = unique_add;
01471        unique.on_bi.bi_op_modify = unique_modify;
01472        unique.on_bi.bi_op_modrdn = unique_modrdn;
01473 
01474        unique.on_bi.bi_cf_ocs = uniqueocs;
01475        rc = config_register_schema( uniquecfg, uniqueocs );
01476        if ( rc ) return rc;
01477 
01478        return(overlay_register(&unique));
01479 }
01480 
01481 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
01482 int init_module(int argc, char *argv[]) {
01483        return unique_initialize();
01484 }
01485 #endif
01486 
01487 #endif /* SLAPD_OVER_UNIQUE */