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