]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/unique.c
Fix cancel cleanup
[openldap] / servers / slapd / overlays / unique.c
1 /* unique.c - attribute uniqueness module */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2004-2005 The OpenLDAP Foundation.
6  * Portions Copyright 2004 Symas Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Symas Corp. for inclusion in
19  * OpenLDAP Software.  This work was sponsored by Hewlett-Packard.
20  */
21
22 #include "portable.h"
23
24 #ifdef SLAPD_OVER_UNIQUE
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/socket.h>
30
31 #include "slap.h"
32
33 static slap_overinst unique;
34
35 typedef struct unique_attrs_s {
36         struct unique_attrs_s *next;            /* list of attrs */
37         AttributeDescription *attr;
38 } unique_attrs;
39
40 typedef struct unique_data_s {
41         const char *message;                    /* breadcrumbs */
42         struct unique_attrs_s *attrs;           /* list of known attrs */
43         struct unique_attrs_s *ignore;          /* list of ignored attrs */
44         BerValue dn;                            /* base of "unique tree" */
45         char strict;                            /* null considered unique too */
46 } unique_data;
47
48 typedef struct unique_counter_s {
49         int count;
50 } unique_counter;
51
52 /*
53 ** allocate new unique_data;
54 ** initialize, copy basedn;
55 ** store in on_bi.bi_private;
56 **
57 */
58
59 static int unique_db_init(
60         BackendDB       *be
61 )
62 {
63         slap_overinst *on = (slap_overinst *)be->bd_info;
64         unique_data *ud   = ch_malloc(sizeof(unique_data));
65
66         /* Debug(LDAP_DEBUG_TRACE, "==> unique_init\n", 0, 0, 0); */
67
68         ud->message     = "_init";
69         ud->attrs       = NULL;
70         ud->ignore      = NULL;
71         ud->strict      = 0;
72
73         /* default to the base of our configured database */
74         ber_dupbv(&ud->dn, &be->be_nsuffix[0]);
75         on->on_bi.bi_private = ud;
76
77         return 0;
78 }
79
80
81 /*
82 ** if command = attributes:
83 **      foreach argument:
84 **              convert to attribute;
85 **              add to configured attribute list;
86 ** elseif command = base:
87 **      set our basedn to argument;
88 ** else complain about invalid directive;
89 **
90 */
91
92 static int unique_config(
93         BackendDB       *be,
94         const char      *fname,
95         int             lineno,
96         int             argc,
97         char            **argv
98 )
99 {
100         slap_overinst *on = (slap_overinst *) be->bd_info;
101         unique_data *ud   = on->on_bi.bi_private;
102         unique_attrs *up;
103         const char *text;
104         AttributeDescription *ad;
105         int i;
106
107         ud->message = "_config";
108         Debug(LDAP_DEBUG_TRACE, "==> unique_config\n", 0, 0, 0);
109
110         if(!strcasecmp(*argv, "unique_attributes") ||
111            !strcasecmp(*argv, "unique_ignore")) {
112                 for(i = 1; i < argc; i++) {
113                         for(up = ud->attrs; up; up = up->next)
114                             if(!strcmp(argv[i], up->attr->ad_cname.bv_val)) {
115                                 Debug(LDAP_DEBUG_ANY,
116                                         "%s: line %d: duplicate attribute <%s>, ignored\n",
117                                         fname, lineno, argv[i]);
118                                 continue;
119                         }
120                         ad = NULL;
121                         if(slap_str2ad(argv[i], &ad, &text) != LDAP_SUCCESS) {
122                                 Debug(LDAP_DEBUG_ANY,
123                                         "%s: line %d: bad attribute <%s>, ignored\n",
124                                         fname, lineno, text);
125                                 continue;               /* XXX */
126                         } else if(ad->ad_next) {
127                                 Debug(LDAP_DEBUG_ANY,
128                                         "%s: line %d: multiple attributes match <%s>, ignored\n",
129                                         fname, lineno, argv[i]);
130                                 continue;
131                         }
132                         up = ch_malloc(sizeof(unique_attrs));
133                         up->attr = ad;
134                         if(!strcasecmp(*argv, "unique_ignore")) {
135                                 up->next = ud->ignore;
136                                 ud->ignore = up;
137                         } else {
138                                 up->next = ud->attrs;
139                                 ud->attrs = up;
140                         }
141                         Debug(LDAP_DEBUG_ANY, "%s: line %d: new attribute <%s>\n",
142                                 fname, lineno, argv[i]);
143                 }
144         } else if(!strcasecmp(*argv, "unique_strict")) {
145                 ud->strict = 1;
146         } else if(!strcasecmp(*argv, "unique_base")) {
147                 struct berval bv;
148                 ber_str2bv( argv[1], 0, 0, &bv );
149                 ch_free(ud->dn.bv_val);
150                 dnNormalize(0, NULL, NULL, &bv, &ud->dn, NULL);
151                 Debug(LDAP_DEBUG_ANY, "%s: line %d: new base dn <%s>\n",
152                         fname, lineno, argv[1]);
153         } else {
154                 return(SLAP_CONF_UNKNOWN);
155         }
156
157         return(0);
158 }
159
160
161 /*
162 ** mostly, just print the init message;
163 **
164 */
165
166 static int
167 unique_open(
168         BackendDB *be
169 )
170 {
171         slap_overinst *on       = (slap_overinst *)be->bd_info;
172         unique_data *ud         = on->on_bi.bi_private;
173         ud->message             = "_open";
174
175         Debug(LDAP_DEBUG_TRACE, "unique_open: overlay initialized\n", 0, 0, 0);
176
177         return(0);
178 }
179
180
181 /*
182 ** foreach configured attribute:
183 **      free it;
184 ** free our basedn;
185 ** (do not) free ud->message;
186 ** reset on_bi.bi_private;
187 ** free our config data;
188 **
189 */
190
191 static int
192 unique_close(
193         BackendDB *be
194 )
195 {
196         slap_overinst *on       = (slap_overinst *) be->bd_info;
197         unique_data *ud         = on->on_bi.bi_private;
198         unique_attrs *ii, *ij;
199         ud->message             = "_close";
200
201         Debug(LDAP_DEBUG_TRACE, "==> unique_close\n", 0, 0, 0);
202
203         for(ii = ud->attrs; ii; ii = ij) {
204                 ij = ii->next;
205                 ch_free(ii);
206         }
207
208         for(ii = ud->ignore; ii; ii = ij) {
209                 ij = ii->next;
210                 ch_free(ii);
211         }
212
213         ch_free(ud->dn.bv_val);
214
215         on->on_bi.bi_private = NULL;    /* XXX */
216
217         ch_free(ud);
218
219         return(0);
220 }
221
222
223 /*
224 ** search callback
225 **      if this is a REP_SEARCH, count++;
226 **
227 */
228
229 static int count_attr_cb(
230         Operation *op,
231         SlapReply *rs
232 )
233 {
234         /* because you never know */
235         if(!op || !rs) return(0);
236
237         /* Only search entries are interesting */
238         if(rs->sr_type != REP_SEARCH) return(0);
239
240         Debug(LDAP_DEBUG_TRACE, "==> count_attr_cb <%s>\n",
241                 rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
242
243         ((unique_counter*)op->o_callback->sc_private)->count++;
244
245         return(0);
246 }
247
248 static int count_filter_len(
249         unique_data *ud,
250         AttributeDescription *ad,
251         BerVarray b,
252         int ks
253 )
254 {
255         unique_attrs *up;
256         int i;
257
258         while(!is_at_operational(ad->ad_type)) {
259                 if(ud->ignore) {
260                         for(up = ud->ignore; up; up = up->next)
261                                 if(ad == up->attr) break;
262                         if(up) break;
263                 }
264                 if(ud->attrs) {
265                         for(up = ud->attrs; up; up = up->next)
266                                 if(ad == up->attr) break;
267                         if(!up) break;
268                 }
269                 if(b && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
270                         ks += b[i].bv_len + ad->ad_cname.bv_len + STRLENOF( "(=)" );
271                 else if(ud->strict)
272                         ks += ad->ad_cname.bv_len + STRLENOF( "(=*)" ); /* (attr=*) */
273                 break;
274         }
275         return ks;
276 }
277
278 static char *build_filter(
279         unique_data *ud,
280         AttributeDescription *ad,
281         BerVarray b,
282         char *kp
283 )
284 {
285         unique_attrs *up;
286         int i;
287
288         while(!is_at_operational(ad->ad_type)) {
289                 if(ud->ignore) {
290                         for(up = ud->ignore; up; up = up->next)
291                                 if(ad == up->attr) break;
292                         if(up) break;
293                 }
294                 if(ud->attrs) {
295                         for(up = ud->attrs; up; up = up->next)
296                                 if(ad == up->attr) break;
297                         if(!up) break;
298                 }
299                 if(b && b[0].bv_val) for(i = 0; b[i].bv_val; i++)
300                         kp += sprintf(kp, "(%s=%s)", ad->ad_cname.bv_val, b[i].bv_val);
301                 else if(ud->strict)
302                         kp += sprintf(kp, "(%s=*)", ad->ad_cname.bv_val);
303                 break;
304         }
305         return kp;
306 }
307
308 static int unique_search(
309         Operation *op,
310         Operation *nop,
311         SlapReply *rs,
312         char *key
313 )
314 {
315         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
316         unique_data *ud = on->on_bi.bi_private;
317         SlapReply nrs = { REP_RESULT };
318         slap_callback cb = { NULL, NULL, NULL, NULL }; /* XXX */
319         unique_counter uq = { 0 };
320         int rc;
321
322         nop->ors_filter = str2filter_x(nop, key);
323         ber_str2bv(key, 0, 0, &nop->ors_filterstr);
324
325         cb.sc_response  = (slap_response*)count_attr_cb;
326         cb.sc_private   = &uq;
327         nop->o_callback = &cb;
328         nop->o_tag      = LDAP_REQ_SEARCH;
329         nop->ors_scope  = LDAP_SCOPE_SUBTREE;
330         nop->ors_deref  = LDAP_DEREF_NEVER;
331         nop->ors_limit  = NULL;
332         nop->ors_slimit = SLAP_NO_LIMIT;
333         nop->ors_tlimit = SLAP_NO_LIMIT;
334         nop->ors_attrs  = slap_anlist_no_attrs;
335         nop->ors_attrsonly = 1;
336
337         nop->o_req_ndn  = ud->dn;
338         nop->o_ndn = op->o_bd->be_rootndn;
339
340         rc = nop->o_bd->be_search(nop, &nrs);
341         filter_free_x(nop, nop->ors_filter);
342         ch_free( key );
343
344         if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
345                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
346                 send_ldap_error(op, rs, rc, "unique_search failed");
347                 return(rs->sr_err);
348         }
349
350         Debug(LDAP_DEBUG_TRACE, "=> unique_search found %d records\n", uq.count, 0, 0);
351
352         if(uq.count) {
353                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
354                 send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION,
355                         "some attributes not unique");
356                 return(rs->sr_err);
357         }
358
359         return(SLAP_CB_CONTINUE);
360 }
361
362 static int unique_add(
363         Operation *op,
364         SlapReply *rs
365 )
366 {
367         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
368         unique_data *ud = on->on_bi.bi_private;
369         Operation nop = *op;
370
371         Attribute *a;
372         char *key, *kp;
373         int ks = 16;
374
375         Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n", op->o_req_dn.bv_val, 0, 0);
376
377         /* validate backend. Should have already been done, but whatever */
378         nop.o_bd = select_backend(&ud->dn, 0, 1);
379         if(nop.o_bd) {
380                 if (!nop.o_bd->be_search) {
381                         op->o_bd->bd_info = (BackendInfo *) on->on_info;
382                         send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
383                         "backend missing search function");
384                         return(rs->sr_err);
385                 }
386         } else {
387                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
388                 send_ldap_error(op, rs, LDAP_OTHER,
389                         "no known backend? this shouldn't be happening!");
390                 return(rs->sr_err);
391         }
392
393 /*
394 ** count everything first;
395 ** allocate some memory;
396 ** write the search key;
397 **
398 */
399
400         if(!(a = op->ora_e->e_attrs)) {
401                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
402                 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
403                         "unique_add() got null op.ora_e.e_attrs");
404                 return(rs->sr_err);
405         } else for(; a; a = a->a_next) {
406                 ks = count_filter_len(ud, a->a_desc, a->a_vals, ks);
407         }
408
409         key = ch_malloc(ks);
410
411         kp = key + sprintf(key, "(|");
412
413         for(a = op->ora_e->e_attrs; a; a = a->a_next) {
414                 kp = build_filter(ud, a->a_desc, a->a_vals, kp);
415         }
416
417         sprintf(kp, ")");
418
419         Debug(LDAP_DEBUG_TRACE, "=> unique_add %s\n", key, 0, 0);
420
421         return unique_search(op, &nop, rs, key);
422 }
423
424
425 static int unique_modify(
426         Operation *op,
427         SlapReply *rs
428 )
429 {
430         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
431         unique_data *ud = on->on_bi.bi_private;
432         Operation nop = *op;
433
434         Modifications *m;
435         char *key, *kp;
436         int ks = 16;            /* a handful of extra bytes */
437
438         Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n", op->o_req_dn.bv_val, 0, 0);
439
440         nop.o_bd = select_backend(&ud->dn, 0, 1);
441         if(nop.o_bd) {
442                 if (!nop.o_bd->be_search) {
443                         op->o_bd->bd_info = (BackendInfo *) on->on_info;
444                         send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
445                         "backend missing search function");
446                         return(rs->sr_err);
447                 }
448         } else {
449                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
450                 send_ldap_error(op, rs, LDAP_OTHER,
451                         "no known backend? this shouldn't be happening!");
452                 return(rs->sr_err);
453         }
454
455 /*
456 ** count everything first;
457 ** allocate some memory;
458 ** write the search key;
459 **
460 */
461
462         if(!(m = op->orm_modlist)) {
463                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
464                 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
465                         "unique_modify() got null op.orm_modlist");
466                 return(rs->sr_err);
467         } else for(; m; m = m->sml_next) {
468                 if ((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE) continue;
469                 ks = count_filter_len(ud, m->sml_desc, m->sml_values, ks);
470         }
471
472         key = ch_malloc(ks);
473
474         kp = key + sprintf(key, "(|");
475
476         for(m = op->orm_modlist; m; m = m->sml_next) {
477                 if ((m->sml_op & LDAP_MOD_OP) == LDAP_MOD_DELETE) continue;
478                 kp = build_filter(ud, m->sml_desc, m->sml_values, kp);
479         }
480
481         sprintf(kp, ")");
482
483         Debug(LDAP_DEBUG_TRACE, "=> unique_modify %s\n", key, 0, 0);
484
485         return unique_search(op, &nop, rs, key);
486 }
487
488
489 static int unique_modrdn(
490         Operation *op,
491         SlapReply *rs
492 )
493 {
494         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
495         unique_data *ud = on->on_bi.bi_private;
496         Operation nop = *op;
497
498         char *key, *kp;
499         int i, rc, ks = 16;             /* a handful of extra bytes */
500         LDAPRDN newrdn;
501         struct berval bv[2];
502
503         Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n",
504                 op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0);
505
506         nop.o_bd = select_backend(&ud->dn, 0, 1);
507         if(nop.o_bd) {
508                 if (!nop.o_bd->be_search) {
509                         op->o_bd->bd_info = (BackendInfo *) on->on_info;
510                         send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM,
511                         "backend missing search function");
512                         return(rs->sr_err);
513                 }
514         } else {
515                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
516                 send_ldap_error(op, rs, LDAP_OTHER,
517                         "no known backend? this shouldn't be happening!");
518                 return(rs->sr_err);
519         }
520
521         if(ldap_bv2rdn_x(&op->oq_modrdn.rs_newrdn, &newrdn,
522                 (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx )) {
523                 op->o_bd->bd_info = (BackendInfo *) on->on_info;
524                 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
525                         "unknown type(s) used in RDN");
526                 return(rs->sr_err);
527         }
528         for(i = 0; newrdn[i]; i++) {
529                 AttributeDescription *ad = NULL;
530                 if ( slap_bv2ad( &newrdn[i]->la_attr, &ad, &rs->sr_text )) {
531                         ldap_rdnfree_x( newrdn, op->o_tmpmemctx );
532                         rs->sr_err = LDAP_INVALID_SYNTAX;
533                         send_ldap_result( op, rs );
534                         return(rs->sr_err);
535                 }
536                 newrdn[i]->la_private = ad;
537         }
538
539         bv[1].bv_val = NULL;
540         bv[1].bv_len = 0;
541
542         for(i = 0; newrdn[i]; i++) {
543                 bv[0] = newrdn[i]->la_value;
544                 ks = count_filter_len(ud, newrdn[i]->la_private, bv, ks);
545         }
546
547         key = ch_malloc(ks);
548         kp = key + sprintf(key, "(|");
549
550         for(i = 0; newrdn[i]; i++) {
551                 bv[0] = newrdn[i]->la_value;
552                 kp = build_filter(ud, newrdn[i]->la_private, bv, kp);
553         }
554
555         sprintf(kp, ")");
556
557         Debug(LDAP_DEBUG_TRACE, "=> unique_modrdn %s\n", key, 0, 0);
558
559         return unique_search(op, &nop, rs, key);
560 }
561
562 /*
563 ** init_module is last so the symbols resolve "for free" --
564 ** it expects to be called automagically during dynamic module initialization
565 */
566
567 int unique_init() {
568
569         /* statically declared just after the #includes at top */
570         unique.on_bi.bi_type = "unique";
571         unique.on_bi.bi_db_init = unique_db_init;
572         unique.on_bi.bi_db_config = unique_config;
573         unique.on_bi.bi_db_open = unique_open;
574         unique.on_bi.bi_db_close = unique_close;
575         unique.on_bi.bi_op_add = unique_add;
576         unique.on_bi.bi_op_modify = unique_modify;
577         unique.on_bi.bi_op_modrdn = unique_modrdn;
578         unique.on_bi.bi_op_delete = NULL;
579
580         return(overlay_register(&unique));
581 }
582
583 #if SLAPD_OVER_UNIQUE == SLAPD_MOD_DYNAMIC && defined(PIC)
584 int init_module(int argc, char *argv[]) {
585         return unique_init();
586 }
587 #endif
588
589 #endif /* SLAPD_OVER_UNIQUE */