]> git.sur5r.net Git - openldap/blob - servers/slapd/mods.c
filter_candidate tweaks, search_stack tweaks
[openldap] / servers / slapd / mods.c
1 /*
2  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /*
6  * Copyright (c) 1995 Regents of the University of Michigan.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that this notice is preserved and that due credit is given
11  * to the University of Michigan at Ann Arbor. The name of the University
12  * may not be used to endorse or promote products derived from this
13  * software without specific prior written permission. This software
14  * is provided ``as is'' without express or implied warranty.
15  */
16
17 #include "portable.h"
18
19 #include "slap.h"
20
21 int
22 modify_check_duplicates(
23         AttributeDescription    *ad,
24         MatchingRule            *mr,
25         BerVarray               vals,
26         BerVarray               mods,
27         int                     permissive,
28         const char      **text,
29         char *textbuf, size_t textlen )
30 {
31         int             i, j, numvals = 0, nummods,
32                         rc = LDAP_SUCCESS, matched;
33         /* this function is no longer used */
34         return rc;
35 }
36
37 int
38 modify_add_values(
39         Entry   *e,
40         Modification    *mod,
41         int     permissive,
42         const char      **text,
43         char *textbuf, size_t textlen
44 )
45 {
46         int             i, j;
47         int             matched;
48         Attribute       *a;
49         MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
50         const char *op;
51
52         switch( mod->sm_op ) {
53         case LDAP_MOD_ADD:
54                 op = "add";
55                 break;
56         case LDAP_MOD_REPLACE:
57                 op = "replace";
58                 break;
59         default:
60                 op = "?";
61                 assert( 0 );
62         }
63
64         a = attr_find( e->e_attrs, mod->sm_desc );
65
66         /*
67          * With permissive set, as long as the attribute being added
68          * has the same value(s?) as the existing attribute, then the
69          * modify will succeed.
70          */
71
72         /* check if the values we're adding already exist */
73         if( mr == NULL || !mr->smr_match ) {
74                 if ( a != NULL ) {
75                         /* do not allow add of additional attribute
76                                 if no equality rule exists */
77                         *text = textbuf;
78                         snprintf( textbuf, textlen,
79                                 "modify/%s: %s: no equality matching rule",
80                                 op, mod->sm_desc->ad_cname.bv_val );
81                         return LDAP_INAPPROPRIATE_MATCHING;
82                 }
83
84                 for ( i = 0; mod->sm_bvalues[i].bv_val != NULL; i++ ) {
85                         /* test asserted values against existing values */
86                         if( a ) {
87                                 for( matched = 0, j = 0; a->a_vals[j].bv_val != NULL; j++ ) {
88                                         if ( bvmatch( &mod->sm_bvalues[i], &a->a_vals[j] ) ) {
89                                                 if ( permissive ) {
90                                                         matched++;
91                                                         continue;
92                                                 }
93                                                 /* value exists already */
94                                                 *text = textbuf;
95                                                 snprintf( textbuf, textlen,
96                                                         "modify/%s: %s: value #%i already exists",
97                                                         op, mod->sm_desc->ad_cname.bv_val, j );
98                                                 return LDAP_TYPE_OR_VALUE_EXISTS;
99                                         }
100                                 }
101                                 if ( permissive && matched == j ) {
102                                         /* values already exist; do nothing */
103                                         return LDAP_SUCCESS;
104                                 }
105                         }
106
107                         /* test asserted values against themselves */
108                         for( j = 0; j < i; j++ ) {
109                                 if ( bvmatch( &mod->sm_bvalues[i], &mod->sm_bvalues[j] ) ) {
110                                         /* value exists already */
111                                         *text = textbuf;
112                                         snprintf( textbuf, textlen,
113                                                 "modify/%s: %s: value #%i already exists",
114                                                 op, mod->sm_desc->ad_cname.bv_val, j );
115                                         return LDAP_TYPE_OR_VALUE_EXISTS;
116                                 }
117                         }
118                 }
119
120         } else {
121                 /* no normalization is done in this routine nor
122                  * in the matching routines called by this routine. 
123                  * values are now normalized once on input to the
124                  * server (whether from LDAP or from the underlying
125                  * database).
126                  * This should outperform the old code.  No numbers
127                  * are available yet.
128                  */
129
130                 int             rc;
131
132                 if ( mod->sm_bvalues[1].bv_val == 0 ) {
133                         if ( a != NULL ) {
134                                 int             i;
135
136                                 for ( matched = 0, i = 0; a->a_vals[ i ].bv_val; i++ ) {
137                                         int     match;
138
139                                         if( mod->sm_nvalues ) {
140                                                 rc = value_match( &match, mod->sm_desc, mr,
141                                                         SLAP_MR_EQUALITY
142                                                                 | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
143                                                                 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
144                                                                 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
145                                                         &a->a_nvals[i],
146                                                         &mod->sm_nvalues[0],
147                                                         text );
148
149                                         } else {
150                                                 rc = value_match( &match, mod->sm_desc, mr,
151                                                         SLAP_MR_EQUALITY
152                                                                 | SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
153                                                         &a->a_vals[i],
154                                                         &mod->sm_values[0],
155                                                         text );
156                                         }
157
158
159                                         if( rc == LDAP_SUCCESS && match == 0 ) {
160                                                 if ( permissive ) {
161                                                         matched++;
162                                                         continue;
163                                                 }
164                                                 *text = textbuf;
165                                                 snprintf( textbuf, textlen,
166                                                         "modify/%s: %s: value #0 already exists",
167                                                         op, mod->sm_desc->ad_cname.bv_val, 0 );
168                                                 return LDAP_TYPE_OR_VALUE_EXISTS;
169                                         }
170                                 }
171                                 if ( permissive && matched == i ) {
172                                         /* values already exist; do nothing */
173                                         return LDAP_SUCCESS;
174                                 }
175                         }
176
177                 } else {
178                         rc = modify_check_duplicates( mod->sm_desc, mr,
179                                         a ? a->a_vals : NULL, mod->sm_bvalues,
180                                         permissive, text, textbuf, textlen );
181
182                         if ( permissive && rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
183                                 return LDAP_SUCCESS;
184                         }
185
186                         if ( rc != LDAP_SUCCESS ) {
187                                 return rc;
188                         }
189                 }
190         }
191
192         /* no - add them */
193         if( attr_merge( e, mod->sm_desc, mod->sm_values, mod->sm_nvalues ) != 0 )
194         {
195                 /* this should return result of attr_merge */
196                 *text = textbuf;
197                 snprintf( textbuf, textlen,
198                         "modify/%s: %s: merge error",
199                         op, mod->sm_desc->ad_cname.bv_val );
200                 return LDAP_OTHER;
201         }
202
203         return LDAP_SUCCESS;
204 }
205
206 int
207 modify_delete_values(
208         Entry   *e,
209         Modification    *mod,
210         int     permissive,
211         const char      **text,
212         char *textbuf, size_t textlen
213 )
214 {
215         int             i, j, k, rc = LDAP_SUCCESS;
216         Attribute       *a;
217         MatchingRule    *mr = mod->sm_desc->ad_type->sat_equality;
218         char            dummy = '\0';
219
220         /*
221          * If permissive is set, then the non-existence of an 
222          * attribute is not treated as an error.
223          */
224
225         /* delete the entire attribute */
226         if ( mod->sm_bvalues == NULL ) {
227                 rc = attr_delete( &e->e_attrs, mod->sm_desc );
228
229                 if( permissive ) {
230                         rc = LDAP_SUCCESS;
231                 } else if( rc != LDAP_SUCCESS ) {
232                         *text = textbuf;
233                         snprintf( textbuf, textlen,
234                                 "modify/delete: %s: no such attribute",
235                                 mod->sm_desc->ad_cname.bv_val );
236                         rc = LDAP_NO_SUCH_ATTRIBUTE;
237                 }
238                 return rc;
239         }
240
241         if( mr == NULL || !mr->smr_match ) {
242                 /* disallow specific attributes from being deleted if
243                         no equality rule */
244                 *text = textbuf;
245                 snprintf( textbuf, textlen,
246                         "modify/delete: %s: no equality matching rule",
247                         mod->sm_desc->ad_cname.bv_val );
248                 return LDAP_INAPPROPRIATE_MATCHING;
249         }
250
251         /* delete specific values - find the attribute first */
252         if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
253                 if( permissive ) {
254                         return LDAP_SUCCESS;
255                 }
256                 *text = textbuf;
257                 snprintf( textbuf, textlen,
258                         "modify/delete: %s: no such attribute",
259                         mod->sm_desc->ad_cname.bv_val );
260                 return LDAP_NO_SUCH_ATTRIBUTE;
261         }
262
263
264         for ( i = 0; mod->sm_values[i].bv_val != NULL; i++ ) {
265                 int     found = 0;
266                 for ( j = 0; a->a_vals[j].bv_val != NULL; j++ )
267                 {
268                         int match;
269
270                         if( mod->sm_nvalues ) {
271                                 assert( a->a_nvals );
272                                 rc = (*mr->smr_match)( &match,
273                                         SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
274                                                 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
275                                                 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
276                                         a->a_desc->ad_type->sat_syntax,
277                                         mr, &a->a_nvals[j],
278                                         &mod->sm_nvalues[i] );
279                         } else {
280 #if 0
281                                 assert( a->a_nvals == NULL );
282 #endif
283                                 rc = (*mr->smr_match)( &match,
284                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
285                                         a->a_desc->ad_type->sat_syntax,
286                                         mr, &a->a_vals[j],
287                                         &mod->sm_values[i] );
288                         }
289
290                         if ( rc != LDAP_SUCCESS ) {
291                                 *text = textbuf;
292                                 snprintf( textbuf, textlen,
293                                         "%s: matching rule failed",
294                                         mod->sm_desc->ad_cname.bv_val );
295                                 goto return_results;
296                         }
297
298                         if ( match != 0 ) {
299                                 continue;
300                         }
301
302                         found = 1;
303
304                         /* delete value and mark it as dummy */
305                         free( a->a_vals[j].bv_val );
306                         a->a_vals[j].bv_val = &dummy;
307                         if( a->a_nvals != a->a_vals ) {
308                                 free( a->a_nvals[j].bv_val );
309                                 a->a_nvals[j].bv_val = &dummy;
310                         }
311
312                         break;
313                 }
314
315
316                 if ( found == 0 ) {
317                         *text = textbuf;
318                         snprintf( textbuf, textlen,
319                                 "modify/delete: %s: no such value",
320                                 mod->sm_desc->ad_cname.bv_val );
321                         rc = LDAP_NO_SUCH_ATTRIBUTE;
322                         goto return_results;
323                 }
324         }
325
326         /* compact array skipping dummies */
327         for ( k = 0, j = 0; a->a_vals[k].bv_val != NULL; k++ )
328         {
329                 /* skip dummies */
330                 if( a->a_vals[k].bv_val == &dummy ) {
331                         assert( a->a_nvals == NULL || a->a_nvals[k].bv_val == &dummy );
332                         continue;
333                 }
334                 if ( j != k ) {
335                         a->a_vals[ j ] = a->a_vals[ k ];
336                         if (a->a_nvals != a->a_vals) {
337                                 a->a_nvals[ j ] = a->a_nvals[ k ];
338                         }
339                 }
340
341                 j++;
342         }
343
344         a->a_vals[j].bv_val = NULL;
345         if (a->a_nvals != a->a_vals) a->a_nvals[j].bv_val = NULL;
346
347         /* if no values remain, delete the entire attribute */
348         if ( a->a_vals[0].bv_val == NULL ) {
349                 if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
350                         *text = textbuf;
351                         snprintf( textbuf, textlen,
352                                 "modify/delete: %s: no such attribute",
353                                 mod->sm_desc->ad_cname.bv_val );
354                         rc = LDAP_NO_SUCH_ATTRIBUTE;
355                 }
356         }
357
358 return_results:;
359
360         return rc;
361 }
362
363 int
364 modify_replace_values(
365         Entry   *e,
366         Modification    *mod,
367         int             permissive,
368         const char      **text,
369         char *textbuf, size_t textlen
370 )
371 {
372         (void) attr_delete( &e->e_attrs, mod->sm_desc );
373
374         if ( mod->sm_bvalues ) {
375                 return modify_add_values( e, mod, permissive, text, textbuf, textlen );
376         }
377
378         return LDAP_SUCCESS;
379 }
380
381 void
382 slap_mod_free(
383         Modification    *mod,
384         int                             freeit
385 )
386 {
387         if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values );
388         mod->sm_values = NULL;
389
390         if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues );
391         mod->sm_nvalues = NULL;
392
393         if( freeit ) free( mod );
394 }
395
396 void
397 slap_mods_free(
398     Modifications       *ml
399 )
400 {
401         Modifications *next;
402
403         for ( ; ml != NULL; ml = next ) {
404                 next = ml->sml_next;
405
406                 slap_mod_free( &ml->sml_mod, 0 );
407                 free( ml );
408         }
409 }
410