]> git.sur5r.net Git - openldap/blob - servers/slapd/mods.c
Cast away const
[openldap] / servers / slapd / mods.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 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 #include "lutil.h"
32
33 int
34 modify_add_values(
35         Entry           *e,
36         Modification    *mod,
37         int             permissive,
38         const char      **text,
39         char            *textbuf,
40         size_t          textlen )
41 {
42         int             rc;
43         const char      *op;
44         Attribute       *a;
45         Modification    pmod = *mod;
46
47         switch ( mod->sm_op ) {
48         case LDAP_MOD_ADD:
49                 op = "add";
50                 break;
51         case LDAP_MOD_REPLACE:
52                 op = "replace";
53                 break;
54         default:
55                 op = "?";
56                 assert( 0 );
57         }
58
59         /* check if values to add exist in attribute */
60         a = attr_find( e->e_attrs, mod->sm_desc );
61         if ( a != NULL ) {
62                 int             rc, i, j, p;
63                 MatchingRule    *mr;
64
65                 mr = mod->sm_desc->ad_type->sat_equality;
66                 if( mr == NULL || !mr->smr_match ) {
67                         /* do not allow add of additional attribute
68                                 if no equality rule exists */
69                         *text = textbuf;
70                         snprintf( textbuf, textlen,
71                                 "modify/%s: %s: no equality matching rule",
72                                 op, mod->sm_desc->ad_cname.bv_val );
73                         return LDAP_INAPPROPRIATE_MATCHING;
74                 }
75
76                 if ( permissive ) {
77                         for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
78                                 /* EMPTY -- just counting 'em */;
79                         }
80
81                         pmod.sm_values = (BerVarray)ch_malloc(
82                                 (i + 1) * sizeof( struct berval ));
83                         if ( pmod.sm_nvalues != NULL ) {
84                                 pmod.sm_nvalues = (BerVarray)ch_malloc(
85                                         (i + 1) * sizeof( struct berval ));
86                         }
87                 }
88
89                 /* no normalization is done in this routine nor
90                  * in the matching routines called by this routine. 
91                  * values are now normalized once on input to the
92                  * server (whether from LDAP or from the underlying
93                  * database).
94                  */
95                 for ( p = i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
96                         int     match;
97
98                         assert( a->a_vals[0].bv_val != NULL );
99                         for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) {
100                                 if ( mod->sm_nvalues ) {
101                                         rc = ordered_value_match( &match, mod->sm_desc, mr,
102                                                 SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
103                                                         | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
104                                                         | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
105                                                 &a->a_nvals[j], &mod->sm_nvalues[i], text );
106                                 } else {
107                                         rc = ordered_value_match( &match, mod->sm_desc, mr,
108                                                 SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
109                                                 &a->a_vals[j], &mod->sm_values[i], text );
110                                 }
111
112                                 if ( rc == LDAP_SUCCESS && match == 0 ) {
113                                         /* value already exists */
114                                         if ( permissive ) break;
115
116                                         *text = textbuf;
117                                         snprintf( textbuf, textlen,
118                                                 "modify/%s: %s: value #%d already exists",
119                                                 op, mod->sm_desc->ad_cname.bv_val, i );
120                                         return LDAP_TYPE_OR_VALUE_EXISTS;
121
122                                 } else if ( rc != LDAP_SUCCESS ) {
123                                         return rc;
124                                 }
125                         }
126
127                         if ( permissive && match != 0 ) {
128                                 if ( pmod.sm_nvalues ) {
129                                         pmod.sm_nvalues[p] = mod->sm_nvalues[i];
130                                 }
131                                 pmod.sm_values[p++] = mod->sm_values[i];
132                         }
133                 }
134
135                 if ( permissive ) {
136                         if ( p == 0 ) {
137                                 /* all new values match exist */
138                                 ch_free( pmod.sm_values );
139                                 if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues );
140                                 return LDAP_SUCCESS;
141                         }
142
143                         BER_BVZERO( &pmod.sm_values[p] );
144                         if ( pmod.sm_nvalues ) {
145                                 BER_BVZERO( &pmod.sm_nvalues[p] );
146                         }
147                 }
148         }
149
150         /* no - add them */
151         if ( mod->sm_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) {
152                 rc = ordered_value_add( e, mod->sm_desc, a,
153                         pmod.sm_values, pmod.sm_nvalues );
154         } else {
155                 rc = attr_merge( e, mod->sm_desc, pmod.sm_values, pmod.sm_nvalues );
156         }
157
158         if ( a != NULL && permissive ) {
159                 ch_free( pmod.sm_values );
160                 if ( pmod.sm_nvalues ) ch_free( pmod.sm_nvalues );
161         }
162
163         if ( rc != 0 ) {
164                 /* this should return result of attr_merge */
165                 *text = textbuf;
166                 snprintf( textbuf, textlen,
167                         "modify/%s: %s: merge error",
168                         op, mod->sm_desc->ad_cname.bv_val );
169                 return LDAP_OTHER;
170         }
171
172         return LDAP_SUCCESS;
173 }
174
175 int
176 modify_delete_values(
177         Entry   *e,
178         Modification    *m,
179         int     perm,
180         const char      **text,
181         char *textbuf, size_t textlen )
182 {
183         return modify_delete_vindex( e, m, perm, text, textbuf, textlen, NULL );
184 }
185
186 int
187 modify_delete_vindex(
188         Entry   *e,
189         Modification    *mod,
190         int     permissive,
191         const char      **text,
192         char *textbuf, size_t textlen,
193         int *idx )
194 {
195         int             i, j, k, rc = LDAP_SUCCESS;
196         Attribute       *a;
197         MatchingRule    *mr = mod->sm_desc->ad_type->sat_equality;
198         char            dummy = '\0';
199         int             match = 0;
200
201         /*
202          * If permissive is set, then the non-existence of an 
203          * attribute is not treated as an error.
204          */
205
206         /* delete the entire attribute */
207         if ( mod->sm_values == NULL ) {
208                 rc = attr_delete( &e->e_attrs, mod->sm_desc );
209
210                 if( permissive ) {
211                         rc = LDAP_SUCCESS;
212                 } else if( rc != LDAP_SUCCESS ) {
213                         *text = textbuf;
214                         snprintf( textbuf, textlen,
215                                 "modify/delete: %s: no such attribute",
216                                 mod->sm_desc->ad_cname.bv_val );
217                         rc = LDAP_NO_SUCH_ATTRIBUTE;
218                 }
219                 return rc;
220         }
221
222         if( mr == NULL || !mr->smr_match ) {
223                 /* disallow specific attributes from being deleted if
224                         no equality rule */
225                 *text = textbuf;
226                 snprintf( textbuf, textlen,
227                         "modify/delete: %s: no equality matching rule",
228                         mod->sm_desc->ad_cname.bv_val );
229                 return LDAP_INAPPROPRIATE_MATCHING;
230         }
231
232         /* delete specific values - find the attribute first */
233         if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
234                 if( permissive ) {
235                         return LDAP_SUCCESS;
236                 }
237                 *text = textbuf;
238                 snprintf( textbuf, textlen,
239                         "modify/delete: %s: no such attribute",
240                         mod->sm_desc->ad_cname.bv_val );
241                 return LDAP_NO_SUCH_ATTRIBUTE;
242         }
243
244         for ( i = 0; !BER_BVISNULL( &mod->sm_values[i] ); i++ ) {
245                 int     found = 0;
246                 for ( j = 0; !BER_BVISNULL( &a->a_vals[j] ); j++ ) {
247                         /* skip already deleted values */
248                         if ( a->a_vals[j].bv_val == &dummy ) {
249                                 continue;
250                         }
251
252                         if( mod->sm_nvalues ) {
253                                 assert( a->a_nvals != NULL );
254                                 rc = ordered_value_match( &match, a->a_desc, mr,
255                                         SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
256                                                 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
257                                                 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
258                                         &a->a_nvals[j], &mod->sm_nvalues[i], text );
259                         } else {
260 #if 0
261                                 assert( a->a_nvals == NULL );
262 #endif
263                                 rc = ordered_value_match( &match, a->a_desc, mr,
264                                         SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
265                                         &a->a_vals[j], &mod->sm_values[i], text );
266                         }
267
268                         if ( rc != LDAP_SUCCESS ) {
269                                 *text = textbuf;
270                                 snprintf( textbuf, textlen,
271                                         "%s: matching rule failed",
272                                         mod->sm_desc->ad_cname.bv_val );
273                                 break;
274                         }
275
276                         if ( match != 0 ) {
277                                 continue;
278                         }
279
280                         found = 1;
281
282                         if ( idx )
283                                 idx[i] = j;
284
285                         /* delete value and mark it as dummy */
286                         free( a->a_vals[j].bv_val );
287                         a->a_vals[j].bv_val = &dummy;
288                         if( a->a_nvals != a->a_vals ) {
289                                 free( a->a_nvals[j].bv_val );
290                                 a->a_nvals[j].bv_val = &dummy;
291                         }
292                         a->a_numvals--;
293
294                         break;
295                 }
296
297                 if ( found == 0 ) {
298                         *text = textbuf;
299                         snprintf( textbuf, textlen,
300                                 "modify/delete: %s: no such value",
301                                 mod->sm_desc->ad_cname.bv_val );
302                         rc = LDAP_NO_SUCH_ATTRIBUTE;
303                         if ( i > 0 ) {
304                                 break;
305                         } else {
306                                 goto return_results;
307                         }
308                 }
309         }
310
311         /* compact array skipping dummies */
312         for ( k = 0, j = 0; !BER_BVISNULL( &a->a_vals[k] ); k++ ) {
313                 /* skip dummies */
314                 if( a->a_vals[k].bv_val == &dummy ) {
315                         assert( a->a_nvals[k].bv_val == &dummy );
316                         continue;
317                 }
318                 if ( j != k ) {
319                         a->a_vals[ j ] = a->a_vals[ k ];
320                         if (a->a_nvals != a->a_vals) {
321                                 a->a_nvals[ j ] = a->a_nvals[ k ];
322                         }
323                 }
324
325                 j++;
326         }
327
328         BER_BVZERO( &a->a_vals[j] );
329         if (a->a_nvals != a->a_vals) {
330                 BER_BVZERO( &a->a_nvals[j] );
331         }
332
333         /* if no values remain, delete the entire attribute */
334         if ( BER_BVISNULL( &a->a_vals[0] ) ) {
335                 if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
336                         *text = textbuf;
337                         snprintf( textbuf, textlen,
338                                 "modify/delete: %s: no such attribute",
339                                 mod->sm_desc->ad_cname.bv_val );
340                         rc = LDAP_NO_SUCH_ATTRIBUTE;
341                 }
342         } else if ( a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED_VAL ) {
343                 /* For an ordered attribute, renumber the value indices */
344                 ordered_value_sort( a, 1 );
345         }
346
347 return_results:;
348
349         return rc;
350 }
351
352 int
353 modify_replace_values(
354         Entry   *e,
355         Modification    *mod,
356         int             permissive,
357         const char      **text,
358         char *textbuf, size_t textlen )
359 {
360         (void) attr_delete( &e->e_attrs, mod->sm_desc );
361
362         if ( mod->sm_values ) {
363                 return modify_add_values( e, mod, permissive, text, textbuf, textlen );
364         }
365
366         return LDAP_SUCCESS;
367 }
368
369 int
370 modify_increment_values(
371         Entry   *e,
372         Modification    *mod,
373         int     permissive,
374         const char      **text,
375         char *textbuf, size_t textlen )
376 {
377         Attribute *a;
378
379         a = attr_find( e->e_attrs, mod->sm_desc );
380         if( a == NULL ) {
381                 if ( permissive ) {
382                         Modification modReplace = *mod;
383
384                         modReplace.sm_op = LDAP_MOD_REPLACE;
385
386                         return modify_add_values(e, &modReplace, permissive, text, textbuf, textlen);
387                 } else {
388                         *text = textbuf;
389                         snprintf( textbuf, textlen,
390                                 "modify/increment: %s: no such attribute",
391                                 mod->sm_desc->ad_cname.bv_val );
392                         return LDAP_NO_SUCH_ATTRIBUTE;
393                 }
394         }
395
396         if ( !strcmp( a->a_desc->ad_type->sat_syntax_oid, SLAPD_INTEGER_SYNTAX )) {
397                 int i;
398                 char str[sizeof(long)*3 + 2]; /* overly long */
399                 long incr;
400
401                 if ( lutil_atol( &incr, mod->sm_values[0].bv_val ) != 0 ) {
402                         *text = "modify/increment: invalid syntax of increment";
403                         return LDAP_INVALID_SYNTAX;
404                 }
405
406                 /* treat zero and errors as a no-op */
407                 if( incr == 0 ) {
408                         return LDAP_SUCCESS;
409                 }
410
411                 for( i = 0; !BER_BVISNULL( &a->a_nvals[i] ); i++ ) {
412                         char *tmp;
413                         long value;
414                         size_t strln;
415                         if ( lutil_atol( &value, a->a_nvals[i].bv_val ) != 0 ) {
416                                 *text = "modify/increment: invalid syntax of original value";
417                                 return LDAP_INVALID_SYNTAX;
418                         }
419                         strln = snprintf( str, sizeof(str), "%ld", value+incr );
420
421                         tmp = SLAP_REALLOC( a->a_nvals[i].bv_val, strln+1 );
422                         if( tmp == NULL ) {
423                                 *text = "modify/increment: reallocation error";
424                                 return LDAP_OTHER;
425                         }
426                         a->a_nvals[i].bv_val = tmp;
427                         a->a_nvals[i].bv_len = strln;
428
429                         AC_MEMCPY( a->a_nvals[i].bv_val, str, strln+1 );
430                 }
431
432         } else {
433                 snprintf( textbuf, textlen,
434                         "modify/increment: %s: increment not supported for value syntax %s",
435                         mod->sm_desc->ad_cname.bv_val,
436                         a->a_desc->ad_type->sat_syntax_oid );
437                 return LDAP_CONSTRAINT_VIOLATION;
438         }
439
440         return LDAP_SUCCESS;
441 }
442
443 void
444 slap_mod_free(
445         Modification    *mod,
446         int                             freeit )
447 {
448         if ( mod->sm_values != NULL ) ber_bvarray_free( mod->sm_values );
449         mod->sm_values = NULL;
450
451         if ( mod->sm_nvalues != NULL ) ber_bvarray_free( mod->sm_nvalues );
452         mod->sm_nvalues = NULL;
453
454         if( freeit ) free( mod );
455 }
456
457 void
458 slap_mods_free(
459     Modifications       *ml,
460     int                 freevals )
461 {
462         Modifications *next;
463
464         for ( ; ml != NULL; ml = next ) {
465                 next = ml->sml_next;
466
467                 if ( freevals )
468                         slap_mod_free( &ml->sml_mod, 0 );
469                 free( ml );
470         }
471 }
472