1 /* $OpenLDAP: pkg/ldap/servers/slapd/mods.c,v 1.59.2.5 2008/02/11 23:26:44 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
15 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
16 * All rights reserved.
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.
28 #include <ac/string.h>
45 Modification pmod
= *mod
;
47 switch ( mod
->sm_op
) {
51 case LDAP_MOD_REPLACE
:
59 /* FIXME: Catch old code that doesn't set sm_numvals.
61 if ( !BER_BVISNULL( &mod
->sm_values
[mod
->sm_numvals
] )) {
63 for ( i
= 0; !BER_BVISNULL( &mod
->sm_values
[i
] ); i
++ );
64 assert( mod
->sm_numvals
== i
);
67 /* check if values to add exist in attribute */
68 a
= attr_find( e
->e_attrs
, mod
->sm_desc
);
75 mr
= mod
->sm_desc
->ad_type
->sat_equality
;
76 if( mr
== NULL
|| !mr
->smr_match
) {
77 /* do not allow add of additional attribute
78 if no equality rule exists */
80 snprintf( textbuf
, textlen
,
81 "modify/%s: %s: no equality matching rule",
82 op
, mod
->sm_desc
->ad_cname
.bv_val
);
83 return LDAP_INAPPROPRIATE_MATCHING
;
88 pmod
.sm_values
= (BerVarray
)ch_malloc(
89 (i
+ 1) * sizeof( struct berval
));
90 if ( pmod
.sm_nvalues
!= NULL
) {
91 pmod
.sm_nvalues
= (BerVarray
)ch_malloc(
92 (i
+ 1) * sizeof( struct berval
));
96 /* no normalization is done in this routine nor
97 * in the matching routines called by this routine.
98 * values are now normalized once on input to the
99 * server (whether from LDAP or from the underlying
102 flags
= SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
;
103 if ( mod
->sm_nvalues
) {
104 flags
|= SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
|
105 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
;
106 cvals
= mod
->sm_nvalues
;
108 cvals
= mod
->sm_values
;
110 for ( p
= i
= 0; i
< mod
->sm_numvals
; i
++ ) {
113 rc
= attr_valfind( a
, flags
, &cvals
[i
], &slot
, NULL
);
114 if ( rc
== LDAP_SUCCESS
) {
116 /* value already exists */
118 snprintf( textbuf
, textlen
,
119 "modify/%s: %s: value #%d already exists",
120 op
, mod
->sm_desc
->ad_cname
.bv_val
, i
);
121 return LDAP_TYPE_OR_VALUE_EXISTS
;
123 } else if ( rc
!= LDAP_NO_SUCH_ATTRIBUTE
) {
127 if ( permissive
&& rc
) {
128 if ( pmod
.sm_nvalues
) {
129 pmod
.sm_nvalues
[p
] = mod
->sm_nvalues
[i
];
131 pmod
.sm_values
[p
++] = mod
->sm_values
[i
];
137 /* all new values match exist */
138 ch_free( pmod
.sm_values
);
139 if ( pmod
.sm_nvalues
) ch_free( pmod
.sm_nvalues
);
143 BER_BVZERO( &pmod
.sm_values
[p
] );
144 if ( pmod
.sm_nvalues
) {
145 BER_BVZERO( &pmod
.sm_nvalues
[p
] );
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
);
155 rc
= attr_merge( e
, mod
->sm_desc
, pmod
.sm_values
, pmod
.sm_nvalues
);
158 if ( a
!= NULL
&& permissive
) {
159 ch_free( pmod
.sm_values
);
160 if ( pmod
.sm_nvalues
) ch_free( pmod
.sm_nvalues
);
164 /* this should return result of attr_merge */
166 snprintf( textbuf
, textlen
,
167 "modify/%s: %s: merge error (%d)",
168 op
, mod
->sm_desc
->ad_cname
.bv_val
, rc
);
176 modify_delete_values(
181 char *textbuf
, size_t textlen
)
183 return modify_delete_vindex( e
, m
, perm
, text
, textbuf
, textlen
, NULL
);
187 modify_delete_vindex(
192 char *textbuf
, size_t textlen
,
196 MatchingRule
*mr
= mod
->sm_desc
->ad_type
->sat_equality
;
197 struct berval
*cvals
;
204 * If permissive is set, then the non-existence of an
205 * attribute is not treated as an error.
208 /* delete the entire attribute */
209 if ( mod
->sm_values
== NULL
) {
210 rc
= attr_delete( &e
->e_attrs
, mod
->sm_desc
);
214 } else if( rc
!= LDAP_SUCCESS
) {
216 snprintf( textbuf
, textlen
,
217 "modify/delete: %s: no such attribute",
218 mod
->sm_desc
->ad_cname
.bv_val
);
219 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
224 /* FIXME: Catch old code that doesn't set sm_numvals.
226 if ( !BER_BVISNULL( &mod
->sm_values
[mod
->sm_numvals
] )) {
227 for ( i
= 0; !BER_BVISNULL( &mod
->sm_values
[i
] ); i
++ );
228 assert( mod
->sm_numvals
== i
);
231 id2
= ch_malloc( mod
->sm_numvals
* sizeof( int ));
235 if( mr
== NULL
|| !mr
->smr_match
) {
236 /* disallow specific attributes from being deleted if
239 snprintf( textbuf
, textlen
,
240 "modify/delete: %s: no equality matching rule",
241 mod
->sm_desc
->ad_cname
.bv_val
);
242 rc
= LDAP_INAPPROPRIATE_MATCHING
;
246 /* delete specific values - find the attribute first */
247 if ( (a
= attr_find( e
->e_attrs
, mod
->sm_desc
)) == NULL
) {
253 snprintf( textbuf
, textlen
,
254 "modify/delete: %s: no such attribute",
255 mod
->sm_desc
->ad_cname
.bv_val
);
256 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
260 if ( mod
->sm_nvalues
) {
261 flags
= SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
262 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
263 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
;
264 cvals
= mod
->sm_nvalues
;
266 flags
= SLAP_MR_EQUALITY
| SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
;
267 cvals
= mod
->sm_values
;
270 /* Locate values to delete */
271 for ( i
= 0; !BER_BVISNULL( &mod
->sm_values
[i
] ); i
++ ) {
273 rc
= attr_valfind( a
, flags
, &cvals
[i
], &sort
, NULL
);
274 if ( rc
== LDAP_SUCCESS
) {
276 } else if ( rc
== LDAP_NO_SUCH_ATTRIBUTE
) {
282 snprintf( textbuf
, textlen
,
283 "modify/delete: %s: no such value",
284 mod
->sm_desc
->ad_cname
.bv_val
);
288 snprintf( textbuf
, textlen
,
289 "modify/delete: %s: matching rule failed",
290 mod
->sm_desc
->ad_cname
.bv_val
);
295 /* Delete the values */
296 for ( i
= 0; i
< mod
->sm_numvals
; i
++ ) {
297 /* Skip permissive values that weren't found */
300 /* Skip duplicate delete specs */
301 if ( a
->a_vals
[idx
[i
]].bv_val
== &dummy
)
303 /* delete value and mark it as gone */
304 free( a
->a_vals
[idx
[i
]].bv_val
);
305 a
->a_vals
[idx
[i
]].bv_val
= &dummy
;
306 if( a
->a_nvals
!= a
->a_vals
) {
307 free( a
->a_nvals
[idx
[i
]].bv_val
);
308 a
->a_nvals
[idx
[i
]].bv_val
= &dummy
;
313 /* compact array skipping dummies */
314 for ( i
= 0, j
= 0; !BER_BVISNULL( &a
->a_vals
[i
] ); i
++ ) {
316 if( a
->a_vals
[i
].bv_val
== &dummy
) {
317 assert( a
->a_nvals
[i
].bv_val
== &dummy
);
321 a
->a_vals
[ j
] = a
->a_vals
[ i
];
322 if (a
->a_nvals
!= a
->a_vals
) {
323 a
->a_nvals
[ j
] = a
->a_nvals
[ i
];
329 BER_BVZERO( &a
->a_vals
[j
] );
330 if (a
->a_nvals
!= a
->a_vals
) {
331 BER_BVZERO( &a
->a_nvals
[j
] );
334 /* if no values remain, delete the entire attribute */
335 if ( !a
->a_numvals
) {
336 if ( attr_delete( &e
->e_attrs
, mod
->sm_desc
) ) {
337 /* Can never happen */
339 snprintf( textbuf
, textlen
,
340 "modify/delete: %s: no such attribute",
341 mod
->sm_desc
->ad_cname
.bv_val
);
342 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
344 } else if ( a
->a_desc
->ad_type
->sat_flags
& SLAP_AT_ORDERED_VAL
) {
345 /* For an ordered attribute, renumber the value indices */
346 ordered_value_sort( a
, 1 );
355 modify_replace_values(
360 char *textbuf
, size_t textlen
)
362 (void) attr_delete( &e
->e_attrs
, mod
->sm_desc
);
364 if ( mod
->sm_values
) {
365 return modify_add_values( e
, mod
, permissive
, text
, textbuf
, textlen
);
372 modify_increment_values(
377 char *textbuf
, size_t textlen
)
381 a
= attr_find( e
->e_attrs
, mod
->sm_desc
);
384 Modification modReplace
= *mod
;
386 modReplace
.sm_op
= LDAP_MOD_REPLACE
;
388 return modify_add_values(e
, &modReplace
, permissive
, text
, textbuf
, textlen
);
391 snprintf( textbuf
, textlen
,
392 "modify/increment: %s: no such attribute",
393 mod
->sm_desc
->ad_cname
.bv_val
);
394 return LDAP_NO_SUCH_ATTRIBUTE
;
398 if ( !strcmp( a
->a_desc
->ad_type
->sat_syntax_oid
, SLAPD_INTEGER_SYNTAX
)) {
400 char str
[sizeof(long)*3 + 2]; /* overly long */
403 if ( lutil_atol( &incr
, mod
->sm_values
[0].bv_val
) != 0 ) {
404 *text
= "modify/increment: invalid syntax of increment";
405 return LDAP_INVALID_SYNTAX
;
408 /* treat zero and errors as a no-op */
413 for( i
= 0; !BER_BVISNULL( &a
->a_nvals
[i
] ); i
++ ) {
417 if ( lutil_atol( &value
, a
->a_nvals
[i
].bv_val
) != 0 ) {
418 *text
= "modify/increment: invalid syntax of original value";
419 return LDAP_INVALID_SYNTAX
;
421 strln
= snprintf( str
, sizeof(str
), "%ld", value
+incr
);
423 tmp
= SLAP_REALLOC( a
->a_nvals
[i
].bv_val
, strln
+1 );
425 *text
= "modify/increment: reallocation error";
428 a
->a_nvals
[i
].bv_val
= tmp
;
429 a
->a_nvals
[i
].bv_len
= strln
;
431 AC_MEMCPY( a
->a_nvals
[i
].bv_val
, str
, strln
+1 );
435 snprintf( textbuf
, textlen
,
436 "modify/increment: %s: increment not supported for value syntax %s",
437 mod
->sm_desc
->ad_cname
.bv_val
,
438 a
->a_desc
->ad_type
->sat_syntax_oid
);
439 return LDAP_CONSTRAINT_VIOLATION
;
450 if ( mod
->sm_values
!= NULL
) ber_bvarray_free( mod
->sm_values
);
451 mod
->sm_values
= NULL
;
453 if ( mod
->sm_nvalues
!= NULL
) ber_bvarray_free( mod
->sm_nvalues
);
454 mod
->sm_nvalues
= NULL
;
456 if( freeit
) free( mod
);
466 for ( ; ml
!= NULL
; ml
= next
) {
470 slap_mod_free( &ml
->sml_mod
, 0 );