1 /* unique.c - attribute uniqueness module */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/unique.c,v 1.20.2.9 2008/07/09 23:45:53 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2004,2006-2007 Symas Corporation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Symas Corporation for
19 * inclusion in OpenLDAP Software, with subsequent enhancements by
20 * Matthew Backes at Symas Corporation. This work was sponsored by
26 #ifdef SLAPD_OVER_UNIQUE
30 #include <ac/string.h>
31 #include <ac/socket.h>
36 #define UNIQUE_DEFAULT_URI ("ldap:///??sub")
38 static slap_overinst unique
;
40 typedef struct unique_attrs_s
{
41 struct unique_attrs_s
*next
; /* list of attrs */
42 AttributeDescription
*attr
;
45 typedef struct unique_domain_uri_s
{
46 struct unique_domain_uri_s
*next
;
50 struct unique_attrs_s
*attrs
;
54 typedef struct unique_domain_s
{
55 struct unique_domain_s
*next
;
56 struct berval domain_spec
;
57 struct unique_domain_uri_s
*uri
;
58 char ignore
; /* polarity of attributes */
59 char strict
; /* null considered unique too */
62 typedef struct unique_data_s
{
63 struct unique_domain_s
*domains
;
64 struct unique_domain_s
*legacy
;
65 char legacy_strict_set
;
68 typedef struct unique_counter_s
{
81 static ConfigDriver unique_cf_base
;
82 static ConfigDriver unique_cf_attrs
;
83 static ConfigDriver unique_cf_strict
;
84 static ConfigDriver unique_cf_uri
;
86 static ConfigTable uniquecfg
[] = {
87 { "unique_base", "basedn", 2, 2, 0, ARG_DN
|ARG_MAGIC
|UNIQUE_BASE
,
88 unique_cf_base
, "( OLcfgOvAt:10.1 NAME 'olcUniqueBase' "
89 "DESC 'Subtree for uniqueness searches' "
90 "EQUALITY distinguishedNameMatch "
91 "SYNTAX OMsDN SINGLE-VALUE )", NULL
, NULL
},
92 { "unique_ignore", "attribute...", 2, 0, 0, ARG_MAGIC
|UNIQUE_IGNORE
,
93 unique_cf_attrs
, "( OLcfgOvAt:10.2 NAME 'olcUniqueIgnore' "
94 "DESC 'Attributes for which uniqueness shall not be enforced' "
95 "EQUALITY caseIgnoreMatch "
96 "ORDERING caseIgnoreOrderingMatch "
97 "SUBSTR caseIgnoreSubstringsMatch "
98 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
99 { "unique_attributes", "attribute...", 2, 0, 0, ARG_MAGIC
|UNIQUE_ATTR
,
100 unique_cf_attrs
, "( OLcfgOvAt:10.3 NAME 'olcUniqueAttribute' "
101 "DESC 'Attributes for which uniqueness shall be enforced' "
102 "EQUALITY caseIgnoreMatch "
103 "ORDERING caseIgnoreOrderingMatch "
104 "SUBSTR caseIgnoreSubstringsMatch "
105 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
106 { "unique_strict", "on|off", 1, 2, 0, ARG_MAGIC
|UNIQUE_STRICT
,
107 unique_cf_strict
, "( OLcfgOvAt:10.4 NAME 'olcUniqueStrict' "
108 "DESC 'Enforce uniqueness of null values' "
109 "EQUALITY booleanMatch "
110 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL
, NULL
},
111 { "unique_uri", "ldapuri", 2, 3, 0, ARG_MAGIC
|UNIQUE_URI
,
112 unique_cf_uri
, "( OLcfgOvAt:10.5 NAME 'olcUniqueURI' "
113 "DESC 'List of keywords and LDAP URIs for a uniqueness domain' "
114 "EQUALITY caseExactMatch "
115 "ORDERING caseExactOrderingMatch "
116 "SUBSTR caseExactSubstringsMatch "
117 "SYNTAX OMsDirectoryString )", NULL
, NULL
},
118 { NULL
, NULL
, 0, 0, 0, ARG_IGNORED
}
121 static ConfigOCs uniqueocs
[] = {
122 { "( OLcfgOvOc:10.1 "
123 "NAME 'olcUniqueConfig' "
124 "DESC 'Attribute value uniqueness configuration' "
125 "SUP olcOverlayConfig "
126 "MAY ( olcUniqueBase $ olcUniqueIgnore $ "
127 "olcUniqueAttribute $ olcUniqueStrict $ "
129 Cft_Overlay
, uniquecfg
},
134 unique_free_domain_uri ( unique_domain_uri
*uri
)
136 unique_domain_uri
*next_uri
= NULL
;
137 unique_attrs
*attr
, *next_attr
= NULL
;
140 next_uri
= uri
->next
;
141 ch_free ( uri
->dn
.bv_val
);
142 ch_free ( uri
->ndn
.bv_val
);
143 ch_free ( uri
->filter
.bv_val
);
146 next_attr
= attr
->next
;
155 /* free an entire stack of domains */
157 unique_free_domain ( unique_domain
*domain
)
159 unique_domain
*next_domain
= NULL
;
162 next_domain
= domain
->next
;
163 ch_free ( domain
->domain_spec
.bv_val
);
164 unique_free_domain_uri ( domain
->uri
);
166 domain
= next_domain
;
171 unique_new_domain_uri ( unique_domain_uri
**urip
,
172 const LDAPURLDesc
*url_desc
,
175 int i
, rc
= LDAP_SUCCESS
;
176 unique_domain_uri
*uri
;
177 struct berval bv
= {0, NULL
};
178 BackendDB
*be
= (BackendDB
*)c
->be
;
180 AttributeDescription
* ad
;
183 uri
= ch_calloc ( 1, sizeof ( unique_domain_uri
) );
185 if ( url_desc
->lud_dn
&& url_desc
->lud_dn
[0] ) {
186 ber_str2bv( url_desc
->lud_dn
, 0, 0, &bv
);
187 rc
= dnPrettyNormal( NULL
,
192 if ( rc
!= LDAP_SUCCESS
) {
193 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
194 "<%s> invalid DN %d (%s)",
195 url_desc
->lud_dn
, rc
, ldap_err2string( rc
));
200 if ( !dnIsSuffix ( &uri
->ndn
, &be
->be_nsuffix
[0] ) ) {
201 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
202 "dn <%s> is not a suffix of backend base dn <%s>",
204 be
->be_nsuffix
[0].bv_val
);
210 attr_str
= url_desc
->lud_attrs
;
212 for ( i
=0; attr_str
[i
]; ++i
) {
215 if ( slap_str2ad ( attr_str
[i
], &ad
, &text
)
217 attr
= ch_calloc ( 1,
218 sizeof ( unique_attrs
) );
220 attr
->next
= uri
->attrs
;
223 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
224 "unique: attribute: %s: %s",
232 uri
->scope
= url_desc
->lud_scope
;
234 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
235 "unique: uri with base scope will always be unique");
240 if (url_desc
->lud_filter
) {
241 Filter
*f
= str2filter( url_desc
->lud_filter
);
243 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
244 "unique: bad filter");
248 /* make sure the strfilter is in normal form (ITS#5581) */
249 filter2bv( f
, &uri
->filter
);
256 Debug ( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
257 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
258 unique_free_domain_uri ( uri
);
265 unique_new_domain_uri_basic ( unique_domain_uri
**urip
,
268 LDAPURLDesc
*url_desc
= NULL
;
271 rc
= ldap_url_parse ( UNIQUE_DEFAULT_URI
, &url_desc
);
273 rc
= unique_new_domain_uri ( urip
, url_desc
, c
);
274 ldap_free_urldesc ( url_desc
);
278 /* if *domain is non-null, it's pushed down the stack.
279 * note that the entire stack is freed if there is an error,
280 * so build added domains in a separate stack before adding them
282 * domain_specs look like
284 * [strict ][ignore ]uri[[ uri]...]
285 * e.g. "ldap:///ou=foo,o=bar?uid?sub ldap:///ou=baz,o=bar?uid?sub"
286 * "strict ldap:///ou=accounts,o=bar?uid,uidNumber?one"
289 * so finally strictness is per-domain
290 * but so is ignore-state, and that would be better as a per-url thing
293 unique_new_domain ( unique_domain
**domainp
,
298 int rc
= LDAP_SUCCESS
;
300 unique_domain
* domain
;
301 LDAPURLDesc
*url_desc
, *url_descs
= NULL
;
303 Debug(LDAP_DEBUG_TRACE
, "==> unique_new_domain <%s>\n",
306 domain
= ch_calloc ( 1, sizeof (unique_domain
) );
307 ber_str2bv( domain_spec
, 0, 1, &domain
->domain_spec
);
309 uri_start
= domain_spec
;
310 if ( strncasecmp ( uri_start
, "ignore ",
311 STRLENOF( "ignore " ) ) == 0 ) {
313 uri_start
+= STRLENOF( "ignore " );
315 if ( strncasecmp ( uri_start
, "strict ",
316 STRLENOF( "strict " ) ) == 0 ) {
318 uri_start
+= STRLENOF( "strict " );
320 && strncasecmp ( uri_start
, "ignore ",
321 STRLENOF( "ignore " ) ) == 0 ) {
323 uri_start
+= STRLENOF( "ignore " );
326 rc
= ldap_url_parselist_ext ( &url_descs
, uri_start
, " ", 0 );
328 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
329 "<%s> invalid ldap urilist",
335 for ( url_desc
= url_descs
;
337 url_desc
= url_descs
->lud_next
) {
338 rc
= unique_new_domain_uri ( &domain
->uri
,
349 if ( url_descs
) ldap_free_urldesc ( url_descs
);
350 domain
->next
= *domainp
;
353 Debug ( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
354 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
355 unique_free_domain ( domain
);
362 unique_cf_base( ConfigArgs
*c
)
364 BackendDB
*be
= (BackendDB
*)c
->be
;
365 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
366 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
367 unique_domain
*domains
= private->domains
;
368 unique_domain
*legacy
= private->legacy
;
369 int rc
= ARG_BAD_CONF
;
372 case SLAP_CONFIG_EMIT
:
374 if ( legacy
&& legacy
->uri
&& legacy
->uri
->dn
.bv_val
) {
375 rc
= value_add_one ( &c
->rvalue_vals
,
378 rc
= value_add_one ( &c
->rvalue_nvals
,
383 case LDAP_MOD_DELETE
:
384 assert ( legacy
&& legacy
->uri
&& legacy
->uri
->dn
.bv_val
);
386 ch_free ( legacy
->uri
->dn
.bv_val
);
387 ch_free ( legacy
->uri
->ndn
.bv_val
);
388 BER_BVZERO( &legacy
->uri
->dn
);
389 BER_BVZERO( &legacy
->uri
->ndn
);
390 if ( !legacy
->uri
->attrs
) {
391 unique_free_domain_uri ( legacy
->uri
);
394 if ( !legacy
->uri
&& !private->legacy_strict_set
) {
395 unique_free_domain ( legacy
);
396 private->legacy
= legacy
= NULL
;
400 case SLAP_CONFIG_ADD
:
402 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
403 "cannot set legacy attrs when URIs are present" );
404 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
405 c
->cr_msg
, NULL
, NULL
);
409 if ( !dnIsSuffix ( &c
->value_ndn
,
410 &be
->be_nsuffix
[0] ) ) {
411 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
412 "dn is not a suffix of backend base" );
413 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
414 c
->cr_msg
, NULL
, NULL
);
419 unique_new_domain ( &private->legacy
,
422 legacy
= private->legacy
;
425 unique_new_domain_uri_basic ( &legacy
->uri
, c
);
426 ch_free ( legacy
->uri
->dn
.bv_val
);
427 ch_free ( legacy
->uri
->ndn
.bv_val
);
428 legacy
->uri
->dn
= c
->value_dn
;
429 legacy
->uri
->ndn
= c
->value_ndn
;
440 unique_cf_attrs( ConfigArgs
*c
)
442 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
443 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
444 unique_domain
*domains
= private->domains
;
445 unique_domain
*legacy
= private->legacy
;
446 unique_attrs
*new_attrs
= NULL
;
447 unique_attrs
*attr
, *next_attr
, *reverse_attrs
;
448 unique_attrs
**attrp
;
449 int rc
= ARG_BAD_CONF
;
453 case SLAP_CONFIG_EMIT
:
455 && (c
->type
== UNIQUE_IGNORE
) == legacy
->ignore
457 for ( attr
= legacy
->uri
->attrs
;
460 value_add_one( &c
->rvalue_vals
,
461 &attr
->attr
->ad_cname
);
464 case LDAP_MOD_DELETE
:
466 && (c
->type
== UNIQUE_IGNORE
) == legacy
->ignore
468 && legacy
->uri
->attrs
) {
469 if ( c
->valx
< 0 ) { /* delete all */
470 for ( attr
= legacy
->uri
->attrs
;
473 next_attr
= attr
->next
;
476 legacy
->uri
->attrs
= NULL
;
477 } else { /* delete by index */
478 attrp
= &legacy
->uri
->attrs
;
479 for ( i
=0; i
< c
->valx
; ++i
)
480 attrp
= &(*attrp
)->next
;
485 if ( !legacy
->uri
->attrs
486 && !legacy
->uri
->dn
.bv_val
) {
487 unique_free_domain_uri ( legacy
->uri
);
490 if ( !legacy
->uri
&& !private->legacy_strict_set
) {
491 unique_free_domain ( legacy
);
492 private->legacy
= legacy
= NULL
;
498 case SLAP_CONFIG_ADD
:
500 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
501 "cannot set legacy attrs when URIs are present" );
502 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
503 c
->cr_msg
, NULL
, NULL
);
509 && legacy
->uri
->attrs
510 && (c
->type
== UNIQUE_IGNORE
) != legacy
->ignore
) {
511 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
512 "cannot set both attrs and ignore-attrs" );
513 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
514 c
->cr_msg
, NULL
, NULL
);
519 unique_new_domain ( &private->legacy
,
522 legacy
= private->legacy
;
525 unique_new_domain_uri_basic ( &legacy
->uri
, c
);
527 for ( i
=1; c
->argv
[i
]; ++i
) {
528 AttributeDescription
* ad
= NULL
;
530 if ( slap_str2ad ( c
->argv
[i
], &ad
, &text
)
533 attr
= ch_calloc ( 1,
534 sizeof ( unique_attrs
) );
536 attr
->next
= new_attrs
;
539 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
540 "unique: attribute: %s: %s",
542 for ( attr
= new_attrs
;
545 next_attr
= attr
->next
;
554 /* (nconc legacy->uri->attrs (nreverse new_attrs)) */
555 reverse_attrs
= NULL
;
556 for ( attr
= new_attrs
;
559 next_attr
= attr
->next
;
560 attr
->next
= reverse_attrs
;
561 reverse_attrs
= attr
;
563 for ( attrp
= &legacy
->uri
->attrs
;
565 attrp
= &(*attrp
)->next
) ;
566 *attrp
= reverse_attrs
;
568 legacy
->ignore
= ( c
->type
== UNIQUE_IGNORE
);
575 Debug ( LDAP_DEBUG_CONFIG
|LDAP_DEBUG_NONE
,
576 "%s: %s\n", c
->log
, c
->cr_msg
, 0 );
582 unique_cf_strict( ConfigArgs
*c
)
584 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
585 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
586 unique_domain
*domains
= private->domains
;
587 unique_domain
*legacy
= private->legacy
;
588 int rc
= ARG_BAD_CONF
;
591 case SLAP_CONFIG_EMIT
:
592 /* We process the boolean manually instead of using
593 * ARG_ON_OFF so that we can three-state it;
594 * olcUniqueStrict is either TRUE, FALSE, or missing,
595 * and missing is necessary to add olcUniqueURIs...
597 if ( private->legacy_strict_set
) {
599 bv
.bv_val
= legacy
->strict
? "TRUE" : "FALSE";
600 bv
.bv_len
= legacy
->strict
?
603 value_add_one ( &c
->rvalue_vals
, &bv
);
607 case LDAP_MOD_DELETE
:
610 if ( ! legacy
->uri
) {
611 unique_free_domain ( legacy
);
612 private->legacy
= NULL
;
615 private->legacy_strict_set
= 0;
619 case SLAP_CONFIG_ADD
:
621 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
622 "cannot set legacy attrs when URIs are present" );
623 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
624 c
->cr_msg
, NULL
, NULL
);
629 unique_new_domain ( &private->legacy
,
632 legacy
= private->legacy
;
634 /* ... not using ARG_ON_OFF makes this necessary too */
635 assert ( c
->argc
== 2 );
636 legacy
->strict
= (strcasecmp ( c
->argv
[1], "TRUE" ) == 0);
637 private->legacy_strict_set
= 1;
648 unique_cf_uri( ConfigArgs
*c
)
650 slap_overinst
*on
= (slap_overinst
*)c
->bi
;
651 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
652 unique_domain
*domains
= private->domains
;
653 unique_domain
*legacy
= private->legacy
;
654 unique_domain
*domain
= NULL
, **domainp
= NULL
;
655 int rc
= ARG_BAD_CONF
;
659 case SLAP_CONFIG_EMIT
:
660 for ( domain
= domains
;
662 domain
= domain
->next
) {
663 rc
= value_add_one ( &c
->rvalue_vals
,
664 &domain
->domain_spec
);
668 case LDAP_MOD_DELETE
:
669 if ( c
->valx
< 0 ) { /* delete them all! */
670 unique_free_domain ( domains
);
671 private->domains
= NULL
;
672 } else { /* delete just one */
673 domainp
= &private->domains
;
674 for ( i
=0; i
< c
->valx
&& *domainp
; ++i
)
675 domainp
= &(*domainp
)->next
;
677 /* If *domainp is null, we walked off the end
678 * of the list. This happens when back-config
679 * and the overlay are out-of-sync, like when
680 * rejecting changes before ITS#4752 gets
683 * This should never happen, but will appear
684 * if you backport this version of
685 * slapo-unique without the config-undo fixes
687 * test024 Will hit this case in such a
690 assert (*domainp
!= NULL
);
693 *domainp
= domain
->next
;
695 unique_free_domain ( domain
);
700 case SLAP_CONFIG_ADD
: /* fallthrough */
703 snprintf( c
->cr_msg
, sizeof( c
->cr_msg
),
704 "cannot set Uri when legacy attrs are present" );
705 Debug ( LDAP_DEBUG_CONFIG
, "unique config: %s\n",
706 c
->cr_msg
, NULL
, NULL
);
711 if ( c
->line
) rc
= unique_new_domain ( &domain
, c
->line
, c
);
712 else rc
= unique_new_domain ( &domain
, c
->argv
[1], c
);
714 assert ( domain
->next
== NULL
);
715 for ( domainp
= &private->domains
;
717 domainp
= &(*domainp
)->next
) ;
730 ** allocate new unique_data;
731 ** initialize, copy basedn;
732 ** store in on_bi.bi_private;
742 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
743 unique_data
**privatep
= (unique_data
**) &on
->on_bi
.bi_private
;
745 Debug(LDAP_DEBUG_TRACE
, "==> unique_db_init\n", 0, 0, 0);
747 *privatep
= ch_calloc ( 1, sizeof ( unique_data
) );
758 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
759 unique_data
**privatep
= (unique_data
**) &on
->on_bi
.bi_private
;
760 unique_data
*private = *privatep
;
762 Debug(LDAP_DEBUG_TRACE
, "==> unique_db_destroy\n", 0, 0, 0);
765 unique_domain
*domains
= private->domains
;
766 unique_domain
*legacy
= private->legacy
;
768 unique_free_domain ( domains
);
769 unique_free_domain ( legacy
);
783 Debug(LDAP_DEBUG_TRACE
, "unique_open: overlay initialized\n", 0, 0, 0);
790 ** Leave unique_data but wipe out config
800 slap_overinst
*on
= (slap_overinst
*) be
->bd_info
;
801 unique_data
**privatep
= (unique_data
**) &on
->on_bi
.bi_private
;
802 unique_data
*private = *privatep
;
804 Debug(LDAP_DEBUG_TRACE
, "==> unique_close\n", 0, 0, 0);
807 unique_domain
*domains
= private->domains
;
808 unique_domain
*legacy
= private->legacy
;
810 unique_free_domain ( domains
);
811 unique_free_domain ( legacy
);
812 memset ( private, 0, sizeof ( unique_data
) );
821 ** if this is a REP_SEARCH, count++;
825 static int count_attr_cb(
832 /* because you never know */
833 if(!op
|| !rs
) return(0);
835 /* Only search entries are interesting */
836 if(rs
->sr_type
!= REP_SEARCH
) return(0);
838 uc
= op
->o_callback
->sc_private
;
840 /* Ignore the current entry */
841 if ( dn_match( uc
->ndn
, &rs
->sr_entry
->e_nname
)) return(0);
843 Debug(LDAP_DEBUG_TRACE
, "==> count_attr_cb <%s>\n",
844 rs
->sr_entry
? rs
->sr_entry
->e_name
.bv_val
: "UNKNOWN_DN", 0, 0);
851 /* count the length of one attribute ad
852 * (and all of its values b)
853 * in the proposed filter
857 unique_domain
*domain
,
858 unique_domain_uri
*uri
,
859 AttributeDescription
*ad
,
867 while ( !is_at_operational( ad
->ad_type
) ) {
869 for ( attr
= uri
->attrs
; attr
; attr
= attr
->next
) {
870 if ( ad
== attr
->attr
) {
874 if ( ( domain
->ignore
&& attr
)
875 || (!domain
->ignore
&& !attr
)) {
879 if ( b
&& b
[0].bv_val
) {
880 for (i
= 0; b
[i
].bv_val
; i
++ ) {
881 /* note: make room for filter escaping... */
882 ks
+= ( 3 * b
[i
].bv_len
) + ad
->ad_cname
.bv_len
+ STRLENOF( "(=)" );
884 } else if ( domain
->strict
) {
885 ks
+= ad
->ad_cname
.bv_len
+ STRLENOF( "(=*)" ); /* (attr=*) */
895 unique_domain
*domain
,
896 unique_domain_uri
*uri
,
897 AttributeDescription
*ad
,
907 while ( !is_at_operational( ad
->ad_type
) ) {
909 for ( attr
= uri
->attrs
; attr
; attr
= attr
->next
) {
910 if ( ad
== attr
->attr
) {
914 if ( ( domain
->ignore
&& attr
)
915 || (!domain
->ignore
&& !attr
)) {
919 if ( b
&& b
[0].bv_val
) {
920 for ( i
= 0; b
[i
].bv_val
; i
++ ) {
924 ldap_bv2escaped_filter_value_x( &b
[i
], &bv
, 1, ctx
);
925 len
= snprintf( kp
, ks
, "(%s=%s)", ad
->ad_cname
.bv_val
, bv
.bv_val
);
926 assert( len
>= 0 && len
< ks
);
928 if ( bv
.bv_val
!= b
[i
].bv_val
) {
929 ber_memfree_x( bv
.bv_val
, ctx
);
932 } else if ( domain
->strict
) {
934 len
= snprintf( kp
, ks
, "(%s=*)", ad
->ad_cname
.bv_val
);
935 assert( len
>= 0 && len
< ks
);
953 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
954 SlapReply nrs
= { REP_RESULT
};
955 slap_callback cb
= { NULL
, NULL
, NULL
, NULL
}; /* XXX */
956 unique_counter uq
= { NULL
, 0 };
959 Debug(LDAP_DEBUG_TRACE
, "==> unique_search %s\n", key
, 0, 0);
961 nop
->ors_filter
= str2filter_x(nop
, key
->bv_val
);
962 nop
->ors_filterstr
= *key
;
964 cb
.sc_response
= (slap_response
*)count_attr_cb
;
966 nop
->o_callback
= &cb
;
967 nop
->o_tag
= LDAP_REQ_SEARCH
;
968 nop
->ors_scope
= scope
;
969 nop
->ors_deref
= LDAP_DEREF_NEVER
;
970 nop
->ors_limit
= NULL
;
971 nop
->ors_slimit
= SLAP_NO_LIMIT
;
972 nop
->ors_tlimit
= SLAP_NO_LIMIT
;
973 nop
->ors_attrs
= slap_anlist_no_attrs
;
974 nop
->ors_attrsonly
= 1;
976 uq
.ndn
= &op
->o_req_ndn
;
978 nop
->o_req_ndn
= *dn
;
979 nop
->o_ndn
= op
->o_bd
->be_rootndn
;
981 nop
->o_bd
= on
->on_info
->oi_origdb
;
982 rc
= nop
->o_bd
->be_search(nop
, &nrs
);
983 filter_free_x(nop
, nop
->ors_filter
);
984 op
->o_tmpfree( key
->bv_val
, op
->o_tmpmemctx
);
986 if(rc
!= LDAP_SUCCESS
&& rc
!= LDAP_NO_SUCH_OBJECT
) {
987 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
988 send_ldap_error(op
, rs
, rc
, "unique_search failed");
992 Debug(LDAP_DEBUG_TRACE
, "=> unique_search found %d records\n", uq
.count
, 0, 0);
995 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
996 send_ldap_error(op
, rs
, LDAP_CONSTRAINT_VIOLATION
,
997 "some attributes not unique");
1001 return(SLAP_CB_CONTINUE
);
1010 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
1011 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
1012 unique_domain
*domains
= private->domains
;
1013 unique_domain
*legacy
= private->legacy
;
1014 unique_domain
*domain
;
1015 Operation nop
= *op
;
1018 struct berval bvkey
;
1019 int rc
= SLAP_CB_CONTINUE
;
1021 Debug(LDAP_DEBUG_TRACE
, "==> unique_add <%s>\n",
1022 op
->o_req_dn
.bv_val
, 0, 0);
1024 for ( domain
= legacy
? legacy
: domains
;
1026 domain
= domain
->next
)
1028 unique_domain_uri
*uri
;
1029 int ks
= STRLENOF("(|)");
1031 for ( uri
= domain
->uri
;
1037 if ( uri
->ndn
.bv_val
1038 && !dnIsSuffix( &op
->o_req_ndn
, &uri
->ndn
))
1041 if(!(a
= op
->ora_e
->e_attrs
)) {
1042 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
1043 send_ldap_error(op
, rs
, LDAP_INVALID_SYNTAX
,
1044 "unique_add() got null op.ora_e.e_attrs");
1049 for(; a
; a
= a
->a_next
) {
1050 ks
+= count_filter_len ( domain
,
1057 /* skip this domain-uri if it isn't involved */
1058 if ( !ks
) continue;
1060 /* terminating NUL */
1063 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
)
1064 ks
+= uri
->filter
.bv_len
+ STRLENOF ("(&)");
1065 kp
= key
= op
->o_tmpalloc(ks
, op
->o_tmpmemctx
);
1067 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1068 len
= snprintf (kp
, ks
, "(&%s", uri
->filter
.bv_val
);
1069 assert( len
>= 0 && len
< ks
);
1072 len
= snprintf(kp
, ks
- (kp
- key
), "(|");
1073 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1076 for(a
= op
->ora_e
->e_attrs
; a
; a
= a
->a_next
)
1077 kp
= build_filter(domain
,
1085 len
= snprintf(kp
, ks
- (kp
- key
), ")");
1086 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1088 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1089 len
= snprintf(kp
, ks
- (kp
- key
), ")");
1090 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1094 bvkey
.bv_len
= kp
- key
;
1096 rc
= unique_search ( op
,
1100 &op
->o_bd
->be_nsuffix
[0],
1105 if ( rc
!= SLAP_CB_CONTINUE
) break;
1107 if ( rc
!= SLAP_CB_CONTINUE
) break;
1120 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
1121 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
1122 unique_domain
*domains
= private->domains
;
1123 unique_domain
*legacy
= private->legacy
;
1124 unique_domain
*domain
;
1125 Operation nop
= *op
;
1128 struct berval bvkey
;
1129 int rc
= SLAP_CB_CONTINUE
;
1131 Debug(LDAP_DEBUG_TRACE
, "==> unique_modify <%s>\n",
1132 op
->o_req_dn
.bv_val
, 0, 0);
1134 for ( domain
= legacy
? legacy
: domains
;
1136 domain
= domain
->next
)
1138 unique_domain_uri
*uri
;
1139 int ks
= STRLENOF("(|)");
1141 for ( uri
= domain
->uri
;
1147 if ( uri
->ndn
.bv_val
1148 && !dnIsSuffix( &op
->o_req_ndn
, &uri
->ndn
))
1151 if ( !(m
= op
->orm_modlist
) ) {
1152 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
1153 send_ldap_error(op
, rs
, LDAP_INVALID_SYNTAX
,
1154 "unique_modify() got null op.orm_modlist");
1159 for ( ; m
; m
= m
->sml_next
)
1160 if ( (m
->sml_op
& LDAP_MOD_OP
)
1161 != LDAP_MOD_DELETE
)
1162 ks
+= count_filter_len
1168 /* skip this domain-uri if it isn't involved */
1169 if ( !ks
) continue;
1171 /* terminating NUL */
1174 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
)
1175 ks
+= uri
->filter
.bv_len
+ STRLENOF ("(&)");
1176 kp
= key
= op
->o_tmpalloc(ks
, op
->o_tmpmemctx
);
1178 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1179 len
= snprintf(kp
, ks
, "(&%s", uri
->filter
.bv_val
);
1180 assert( len
>= 0 && len
< ks
);
1183 len
= snprintf(kp
, ks
- (kp
- key
), "(|");
1184 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1187 for(m
= op
->orm_modlist
; m
; m
= m
->sml_next
)
1188 if ( (m
->sml_op
& LDAP_MOD_OP
)
1189 != LDAP_MOD_DELETE
)
1190 kp
= build_filter ( domain
,
1198 len
= snprintf(kp
, ks
- (kp
- key
), ")");
1199 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1201 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1202 len
= snprintf (kp
, ks
- (kp
- key
), ")");
1203 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1207 bvkey
.bv_len
= kp
- key
;
1209 rc
= unique_search ( op
,
1213 &op
->o_bd
->be_nsuffix
[0],
1218 if ( rc
!= SLAP_CB_CONTINUE
) break;
1220 if ( rc
!= SLAP_CB_CONTINUE
) break;
1233 slap_overinst
*on
= (slap_overinst
*) op
->o_bd
->bd_info
;
1234 unique_data
*private = (unique_data
*) on
->on_bi
.bi_private
;
1235 unique_domain
*domains
= private->domains
;
1236 unique_domain
*legacy
= private->legacy
;
1237 unique_domain
*domain
;
1238 Operation nop
= *op
;
1240 struct berval bvkey
;
1242 struct berval bv
[2];
1243 int rc
= SLAP_CB_CONTINUE
;
1245 Debug(LDAP_DEBUG_TRACE
, "==> unique_modrdn <%s> <%s>\n",
1246 op
->o_req_dn
.bv_val
, op
->orr_newrdn
.bv_val
, 0);
1248 for ( domain
= legacy
? legacy
: domains
;
1250 domain
= domain
->next
)
1252 unique_domain_uri
*uri
;
1253 int ks
= STRLENOF("(|)");
1255 for ( uri
= domain
->uri
;
1261 if ( uri
->ndn
.bv_val
1262 && !dnIsSuffix( &op
->o_req_ndn
, &uri
->ndn
)
1263 && (!op
->orr_nnewSup
1264 || !dnIsSuffix( op
->orr_nnewSup
, &uri
->ndn
)))
1267 if ( ldap_bv2rdn_x ( &op
->oq_modrdn
.rs_newrdn
,
1269 (char **)&rs
->sr_text
,
1270 LDAP_DN_FORMAT_LDAP
,
1271 op
->o_tmpmemctx
) ) {
1272 op
->o_bd
->bd_info
= (BackendInfo
*) on
->on_info
;
1273 send_ldap_error(op
, rs
, LDAP_INVALID_SYNTAX
,
1274 "unknown type(s) used in RDN");
1279 rc
= SLAP_CB_CONTINUE
;
1280 for ( i
=0; newrdn
[i
]; i
++) {
1281 AttributeDescription
*ad
= NULL
;
1282 if ( slap_bv2ad( &newrdn
[i
]->la_attr
, &ad
, &rs
->sr_text
)) {
1283 ldap_rdnfree_x( newrdn
, op
->o_tmpmemctx
);
1284 rs
->sr_err
= LDAP_INVALID_SYNTAX
;
1285 send_ldap_result( op
, rs
);
1289 newrdn
[i
]->la_private
= ad
;
1291 if ( rc
!= SLAP_CB_CONTINUE
) break;
1293 bv
[1].bv_val
= NULL
;
1296 for ( i
=0; newrdn
[i
]; i
++ ) {
1297 bv
[0] = newrdn
[i
]->la_value
;
1298 ks
+= count_filter_len ( domain
,
1300 newrdn
[i
]->la_private
,
1304 /* skip this domain if it isn't involved */
1305 if ( !ks
) continue;
1307 /* terminating NUL */
1310 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
)
1311 ks
+= uri
->filter
.bv_len
+ STRLENOF ("(&)");
1312 kp
= key
= op
->o_tmpalloc(ks
, op
->o_tmpmemctx
);
1314 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1315 len
= snprintf(kp
, ks
, "(&%s", uri
->filter
.bv_val
);
1316 assert( len
>= 0 && len
< ks
);
1319 len
= snprintf(kp
, ks
- (kp
- key
), "(|");
1320 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1323 for ( i
=0; newrdn
[i
]; i
++) {
1324 bv
[0] = newrdn
[i
]->la_value
;
1325 kp
= build_filter ( domain
,
1327 newrdn
[i
]->la_private
,
1334 len
= snprintf(kp
, ks
- (kp
- key
), ")");
1335 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1337 if ( uri
->filter
.bv_val
&& uri
->filter
.bv_len
) {
1338 len
= snprintf (kp
, ks
- (kp
- key
), ")");
1339 assert( len
>= 0 && len
< ks
- (kp
- key
) );
1343 bvkey
.bv_len
= kp
- key
;
1345 rc
= unique_search ( op
,
1349 &op
->o_bd
->be_nsuffix
[0],
1354 if ( rc
!= SLAP_CB_CONTINUE
) break;
1356 if ( rc
!= SLAP_CB_CONTINUE
) break;
1363 ** init_module is last so the symbols resolve "for free" --
1364 ** it expects to be called automagically during dynamic module initialization
1372 /* statically declared just after the #includes at top */
1373 memset (&unique
, 0, sizeof(unique
));
1375 unique
.on_bi
.bi_type
= "unique";
1376 unique
.on_bi
.bi_db_init
= unique_db_init
;
1377 unique
.on_bi
.bi_db_destroy
= unique_db_destroy
;
1378 unique
.on_bi
.bi_db_open
= unique_open
;
1379 unique
.on_bi
.bi_db_close
= unique_close
;
1380 unique
.on_bi
.bi_op_add
= unique_add
;
1381 unique
.on_bi
.bi_op_modify
= unique_modify
;
1382 unique
.on_bi
.bi_op_modrdn
= unique_modrdn
;
1384 unique
.on_bi
.bi_cf_ocs
= uniqueocs
;
1385 rc
= config_register_schema( uniquecfg
, uniqueocs
);
1386 if ( rc
) return rc
;
1388 return(overlay_register(&unique
));
1391 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
1392 int init_module(int argc
, char *argv
[]) {
1393 return unique_initialize();
1397 #endif /* SLAPD_OVER_UNIQUE */