modify.c revision 1.1.1.6 1 /* $NetBSD: modify.c,v 1.1.1.6 2018/02/06 01:53:14 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2017 The OpenLDAP Foundation.
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 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms are permitted
21 * provided that this notice is preserved and that due credit is given
22 * to the University of Michigan at Ann Arbor. The name of the University
23 * may not be used to endorse or promote products derived from this
24 * software without specific prior written permission. This software
25 * is provided ``as is'' without express or implied warranty.
26 */
27
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: modify.c,v 1.1.1.6 2018/02/06 01:53:14 christos Exp $");
30
31 #include "portable.h"
32
33 #include <stdio.h>
34
35 #include <ac/socket.h>
36 #include <ac/string.h>
37 #include <ac/time.h>
38
39 #include "slap.h"
40 #include "lutil.h"
41
42
43 int
44 do_modify(
45 Operation *op,
46 SlapReply *rs )
47 {
48 struct berval dn = BER_BVNULL;
49 char textbuf[ SLAP_TEXT_BUFLEN ];
50 size_t textlen = sizeof( textbuf );
51 #ifdef LDAP_DEBUG
52 Modifications *tmp;
53 #endif
54
55 Debug( LDAP_DEBUG_TRACE, "%s do_modify\n",
56 op->o_log_prefix, 0, 0 );
57 /*
58 * Parse the modify request. It looks like this:
59 *
60 * ModifyRequest := [APPLICATION 6] SEQUENCE {
61 * name DistinguishedName,
62 * mods SEQUENCE OF SEQUENCE {
63 * operation ENUMERATED {
64 * add (0),
65 * delete (1),
66 * replace (2)
67 * },
68 * modification SEQUENCE {
69 * type AttributeType,
70 * values SET OF AttributeValue
71 * }
72 * }
73 * }
74 */
75
76 if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
77 Debug( LDAP_DEBUG_ANY, "%s do_modify: ber_scanf failed\n",
78 op->o_log_prefix, 0, 0 );
79 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
80 return SLAPD_DISCONNECT;
81 }
82
83 Debug( LDAP_DEBUG_ARGS, "%s do_modify: dn (%s)\n",
84 op->o_log_prefix, dn.bv_val, 0 );
85
86 rs->sr_err = slap_parse_modlist( op, rs, op->o_ber, &op->oq_modify );
87 if ( rs->sr_err != LDAP_SUCCESS ) {
88 Debug( LDAP_DEBUG_ANY, "%s do_modify: slap_parse_modlist failed err=%d msg=%s\n",
89 op->o_log_prefix, rs->sr_err, rs->sr_text );
90 send_ldap_result( op, rs );
91 goto cleanup;
92 }
93
94 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
95 Debug( LDAP_DEBUG_ANY, "%s do_modify: get_ctrls failed\n",
96 op->o_log_prefix, 0, 0 );
97 /* get_ctrls has sent results. Now clean up. */
98 goto cleanup;
99 }
100
101 rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
102 op->o_tmpmemctx );
103 if( rs->sr_err != LDAP_SUCCESS ) {
104 Debug( LDAP_DEBUG_ANY, "%s do_modify: invalid dn (%s)\n",
105 op->o_log_prefix, dn.bv_val, 0 );
106 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
107 goto cleanup;
108 }
109
110 op->orm_no_opattrs = 0;
111
112 #ifdef LDAP_DEBUG
113 Debug( LDAP_DEBUG_ARGS, "%s modifications:\n",
114 op->o_log_prefix, 0, 0 );
115
116 for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
117 Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
118 tmp->sml_op == LDAP_MOD_ADD ? "add" :
119 (tmp->sml_op == LDAP_MOD_INCREMENT ? "increment" :
120 (tmp->sml_op == LDAP_MOD_DELETE ? "delete" :
121 "replace")), tmp->sml_type.bv_val, 0 );
122
123 if ( tmp->sml_values == NULL ) {
124 Debug( LDAP_DEBUG_ARGS, "%s\n",
125 "\t\tno values", NULL, NULL );
126 } else if ( BER_BVISNULL( &tmp->sml_values[ 0 ] ) ) {
127 Debug( LDAP_DEBUG_ARGS, "%s\n",
128 "\t\tzero values", NULL, NULL );
129 } else if ( BER_BVISNULL( &tmp->sml_values[ 1 ] ) ) {
130 Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
131 "\t\tone value", (long) tmp->sml_values[0].bv_len, NULL );
132 } else {
133 Debug( LDAP_DEBUG_ARGS, "%s\n",
134 "\t\tmultiple values", NULL, NULL );
135 }
136 }
137
138 if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
139 char abuf[BUFSIZ/2], *ptr = abuf;
140 int len = 0;
141
142 Statslog( LDAP_DEBUG_STATS, "%s MOD dn=\"%s\"\n",
143 op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
144
145 for ( tmp = op->orm_modlist; tmp != NULL; tmp = tmp->sml_next ) {
146 if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
147 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
148 op->o_log_prefix, abuf, 0, 0, 0 );
149
150 len = 0;
151 ptr = abuf;
152
153 if( 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
154 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
155 op->o_log_prefix, tmp->sml_type.bv_val, 0, 0, 0 );
156 continue;
157 }
158 }
159 if (len) {
160 *ptr++ = ' ';
161 len++;
162 }
163 ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val);
164 len += tmp->sml_type.bv_len;
165 }
166 if (len) {
167 Statslog( LDAP_DEBUG_STATS, "%s MOD attr=%s\n",
168 op->o_log_prefix, abuf, 0, 0, 0 );
169 }
170 }
171 #endif /* LDAP_DEBUG */
172
173 rs->sr_err = slap_mods_check( op, op->orm_modlist,
174 &rs->sr_text, textbuf, textlen, NULL );
175
176 if ( rs->sr_err != LDAP_SUCCESS ) {
177 send_ldap_result( op, rs );
178 goto cleanup;
179 }
180
181 op->o_bd = frontendDB;
182 rs->sr_err = frontendDB->be_modify( op, rs );
183
184 #ifdef LDAP_X_TXN
185 if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) {
186 /* skip cleanup */
187 return rs->sr_err;
188 }
189 #endif
190
191 cleanup:
192 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
193 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
194 if ( op->orm_modlist != NULL ) slap_mods_free( op->orm_modlist, 1 );
195
196 return rs->sr_err;
197 }
198
199 int
200 fe_op_modify( Operation *op, SlapReply *rs )
201 {
202 BackendDB *op_be, *bd = op->o_bd;
203 char textbuf[ SLAP_TEXT_BUFLEN ];
204 size_t textlen = sizeof( textbuf );
205
206 if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
207 Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n",
208 op->o_log_prefix, 0, 0 );
209 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
210 "modify upon the root DSE not supported" );
211 goto cleanup;
212
213 } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
214 Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n",
215 op->o_log_prefix, 0, 0 );
216 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
217 "modification of subschema subentry not supported" );
218 goto cleanup;
219 }
220
221 /*
222 * We could be serving multiple database backends. Select the
223 * appropriate one, or send a referral to our "referral server"
224 * if we don't hold it.
225 */
226 op->o_bd = select_backend( &op->o_req_ndn, 1 );
227 if ( op->o_bd == NULL ) {
228 op->o_bd = bd;
229 rs->sr_ref = referral_rewrite( default_referral,
230 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
231 if ( !rs->sr_ref ) {
232 rs->sr_ref = default_referral;
233 }
234
235 if ( rs->sr_ref != NULL ) {
236 rs->sr_err = LDAP_REFERRAL;
237 send_ldap_result( op, rs );
238
239 if ( rs->sr_ref != default_referral ) {
240 ber_bvarray_free( rs->sr_ref );
241 }
242
243 } else {
244 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
245 "no global superior knowledge" );
246 }
247 goto cleanup;
248 }
249
250 /* If we've got a glued backend, check the real backend */
251 op_be = op->o_bd;
252 if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
253 op->o_bd = select_backend( &op->o_req_ndn, 0 );
254 }
255
256 /* check restrictions */
257 if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
258 send_ldap_result( op, rs );
259 goto cleanup;
260 }
261
262 /* check for referrals */
263 if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
264 goto cleanup;
265 }
266
267 rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist,
268 &rs->sr_text, textbuf, textlen );
269 if ( rs->sr_err != LDAP_SUCCESS ) {
270 send_ldap_result( op, rs );
271 goto cleanup;
272 }
273
274 /* check for modify/increment support */
275 if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) {
276 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
277 "modify/increment not supported in context" );
278 goto cleanup;
279 }
280
281 /*
282 * do the modify if 1 && (2 || 3)
283 * 1) there is a modify function implemented in this backend;
284 * 2) this backend is master for what it holds;
285 * 3) it's a replica and the dn supplied is the update_ndn.
286 */
287 if ( op->o_bd->be_modify ) {
288 /* do the update here */
289 int repl_user = be_isupdate( op );
290
291 /*
292 * Multimaster slapd does not have to check for replicator dn
293 * because it accepts each modify request
294 */
295 if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
296 int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
297
298 op->o_bd = op_be;
299
300 if ( !update ) {
301 rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist,
302 &rs->sr_text, textbuf, textlen );
303 if ( rs->sr_err != LDAP_SUCCESS ) {
304 send_ldap_result( op, rs );
305 goto cleanup;
306 }
307 }
308 op->o_bd->be_modify( op, rs );
309
310 } else { /* send a referral */
311 BerVarray defref = op->o_bd->be_update_refs
312 ? op->o_bd->be_update_refs : default_referral;
313 if ( defref != NULL ) {
314 rs->sr_ref = referral_rewrite( defref,
315 NULL, &op->o_req_dn,
316 LDAP_SCOPE_DEFAULT );
317 if ( rs->sr_ref == NULL ) {
318 /* FIXME: must duplicate, because
319 * overlays may muck with it */
320 rs->sr_ref = defref;
321 }
322 rs->sr_err = LDAP_REFERRAL;
323 send_ldap_result( op, rs );
324 if ( rs->sr_ref != defref ) {
325 ber_bvarray_free( rs->sr_ref );
326 }
327
328 } else {
329 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
330 "shadow context; no update referral" );
331 }
332 }
333
334 } else {
335 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
336 "operation not supported within namingContext" );
337 }
338
339 cleanup:;
340 op->o_bd = bd;
341 return rs->sr_err;
342 }
343
344 /*
345 * Obsolete constraint checking.
346 */
347 int
348 slap_mods_obsolete_check(
349 Operation *op,
350 Modifications *ml,
351 const char **text,
352 char *textbuf,
353 size_t textlen )
354 {
355 if( get_relax( op ) ) return LDAP_SUCCESS;
356
357 for ( ; ml != NULL; ml = ml->sml_next ) {
358 if ( is_at_obsolete( ml->sml_desc->ad_type ) &&
359 (( ml->sml_op != LDAP_MOD_REPLACE &&
360 ml->sml_op != LDAP_MOD_DELETE ) ||
361 ml->sml_values != NULL ))
362 {
363 /*
364 * attribute is obsolete,
365 * only allow replace/delete with no values
366 */
367 snprintf( textbuf, textlen,
368 "%s: attribute is obsolete",
369 ml->sml_type.bv_val );
370 *text = textbuf;
371 return LDAP_CONSTRAINT_VIOLATION;
372 }
373 }
374
375 return LDAP_SUCCESS;
376 }
377
378 /*
379 * No-user-modification constraint checking.
380 */
381 int
382 slap_mods_no_user_mod_check(
383 Operation *op,
384 Modifications *ml,
385 const char **text,
386 char *textbuf,
387 size_t textlen )
388 {
389 for ( ; ml != NULL; ml = ml->sml_next ) {
390 if ( !is_at_no_user_mod( ml->sml_desc->ad_type ) ) {
391 continue;
392 }
393
394 if ( ml->sml_flags & SLAP_MOD_INTERNAL ) {
395 continue;
396 }
397
398 if ( get_relax( op ) ) {
399 if ( ml->sml_desc->ad_type->sat_flags & SLAP_AT_MANAGEABLE ) {
400 ml->sml_flags |= SLAP_MOD_MANAGING;
401 continue;
402 }
403
404 /* attribute not manageable */
405 snprintf( textbuf, textlen,
406 "%s: no-user-modification attribute not manageable",
407 ml->sml_type.bv_val );
408
409 } else {
410 /* user modification disallowed */
411 snprintf( textbuf, textlen,
412 "%s: no user modification allowed",
413 ml->sml_type.bv_val );
414 }
415
416 *text = textbuf;
417 return LDAP_CONSTRAINT_VIOLATION;
418 }
419
420 return LDAP_SUCCESS;
421 }
422
423 int
424 slap_mods_no_repl_user_mod_check(
425 Operation *op,
426 Modifications *ml,
427 const char **text,
428 char *textbuf,
429 size_t textlen )
430 {
431 Modifications *mods;
432 Modifications *modp;
433
434 for ( mods = ml; mods != NULL; mods = mods->sml_next ) {
435 assert( mods->sml_op == LDAP_MOD_ADD );
436
437 /* check doesn't already appear */
438 for ( modp = ml; modp != NULL; modp = modp->sml_next ) {
439 if ( mods->sml_desc == modp->sml_desc && mods != modp ) {
440 snprintf( textbuf, textlen,
441 "attribute '%s' provided more than once",
442 mods->sml_desc->ad_cname.bv_val );
443 *text = textbuf;
444 return LDAP_TYPE_OR_VALUE_EXISTS;
445 }
446 }
447 }
448
449 return LDAP_SUCCESS;
450 }
451
452 /*
453 * Do basic attribute type checking and syntax validation.
454 */
455 int slap_mods_check(
456 Operation *op,
457 Modifications *ml,
458 const char **text,
459 char *textbuf,
460 size_t textlen,
461 void *ctx )
462 {
463 int rc;
464
465 for( ; ml != NULL; ml = ml->sml_next ) {
466 AttributeDescription *ad = NULL;
467
468 /* convert to attribute description */
469 if ( ml->sml_desc == NULL ) {
470 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
471 if( rc != LDAP_SUCCESS ) {
472 if ( get_no_schema_check( op )) {
473 rc = slap_bv2undef_ad( &ml->sml_type, &ml->sml_desc,
474 text, 0 );
475 }
476 }
477 if( rc != LDAP_SUCCESS ) {
478 snprintf( textbuf, textlen, "%s: %s",
479 ml->sml_type.bv_val, *text );
480 *text = textbuf;
481 return rc;
482 }
483 }
484
485 ad = ml->sml_desc;
486
487 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
488 && !slap_ad_is_binary( ad ))
489 {
490 /* attribute requires binary transfer */
491 snprintf( textbuf, textlen,
492 "%s: requires ;binary transfer",
493 ml->sml_type.bv_val );
494 *text = textbuf;
495 return LDAP_UNDEFINED_TYPE;
496 }
497
498 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
499 && slap_ad_is_binary( ad ))
500 {
501 /* attribute does not require binary transfer */
502 snprintf( textbuf, textlen,
503 "%s: disallows ;binary transfer",
504 ml->sml_type.bv_val );
505 *text = textbuf;
506 return LDAP_UNDEFINED_TYPE;
507 }
508
509 if( slap_ad_is_tag_range( ad )) {
510 /* attribute requires binary transfer */
511 snprintf( textbuf, textlen,
512 "%s: inappropriate use of tag range option",
513 ml->sml_type.bv_val );
514 *text = textbuf;
515 return LDAP_UNDEFINED_TYPE;
516 }
517
518 #if 0
519 if ( is_at_obsolete( ad->ad_type ) &&
520 (( ml->sml_op != LDAP_MOD_REPLACE &&
521 ml->sml_op != LDAP_MOD_DELETE ) ||
522 ml->sml_values != NULL ))
523 {
524 /*
525 * attribute is obsolete,
526 * only allow replace/delete with no values
527 */
528 snprintf( textbuf, textlen,
529 "%s: attribute is obsolete",
530 ml->sml_type.bv_val );
531 *text = textbuf;
532 return LDAP_CONSTRAINT_VIOLATION;
533 }
534 #endif
535
536 if ( ml->sml_op == LDAP_MOD_INCREMENT &&
537 #ifdef SLAPD_REAL_SYNTAX
538 !is_at_syntax( ad->ad_type, SLAPD_REAL_SYNTAX ) &&
539 #endif
540 !is_at_syntax( ad->ad_type, SLAPD_INTEGER_SYNTAX ) )
541 {
542 /*
543 * attribute values must be INTEGER or REAL
544 */
545 snprintf( textbuf, textlen,
546 "%s: attribute syntax inappropriate for increment",
547 ml->sml_type.bv_val );
548 *text = textbuf;
549 return LDAP_CONSTRAINT_VIOLATION;
550 }
551
552 /*
553 * check values
554 */
555 if( ml->sml_values != NULL ) {
556 ber_len_t nvals;
557 slap_syntax_validate_func *validate =
558 ad->ad_type->sat_syntax->ssyn_validate;
559 slap_syntax_transform_func *pretty =
560 ad->ad_type->sat_syntax->ssyn_pretty;
561
562 if( !pretty && !validate ) {
563 *text = "no validator for syntax";
564 snprintf( textbuf, textlen,
565 "%s: no validator for syntax %s",
566 ml->sml_type.bv_val,
567 ad->ad_type->sat_syntax->ssyn_oid );
568 *text = textbuf;
569 return LDAP_INVALID_SYNTAX;
570 }
571
572 /*
573 * check that each value is valid per syntax
574 * and pretty if appropriate
575 */
576 for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
577 struct berval pval;
578
579 if ( pretty ) {
580 rc = ordered_value_pretty( ad,
581 &ml->sml_values[nvals], &pval, ctx );
582 } else {
583 rc = ordered_value_validate( ad,
584 &ml->sml_values[nvals], ml->sml_op );
585 }
586
587 if( rc != 0 ) {
588 snprintf( textbuf, textlen,
589 "%s: value #%ld invalid per syntax",
590 ml->sml_type.bv_val, (long) nvals );
591 *text = textbuf;
592 return LDAP_INVALID_SYNTAX;
593 }
594
595 if( pretty ) {
596 ber_memfree_x( ml->sml_values[nvals].bv_val, ctx );
597 ml->sml_values[nvals] = pval;
598 }
599 }
600 ml->sml_values[nvals].bv_len = 0;
601 ml->sml_numvals = nvals;
602
603 /*
604 * a rough single value check... an additional check is needed
605 * to catch add of single value to existing single valued attribute
606 */
607 if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
608 && nvals > 1 && is_at_single_value( ad->ad_type ))
609 {
610 snprintf( textbuf, textlen,
611 "%s: multiple values provided",
612 ml->sml_type.bv_val );
613 *text = textbuf;
614 return LDAP_CONSTRAINT_VIOLATION;
615 }
616
617 /* if the type has a normalizer, generate the
618 * normalized values. otherwise leave them NULL.
619 *
620 * this is different from the rule for attributes
621 * in an entry - in an attribute list, the normalized
622 * value is set equal to the non-normalized value
623 * when there is no normalizer.
624 */
625 if( nvals && ad->ad_type->sat_equality &&
626 ad->ad_type->sat_equality->smr_normalize )
627 {
628 ml->sml_nvalues = ber_memalloc_x(
629 (nvals+1)*sizeof(struct berval), ctx );
630
631 for ( nvals = 0; !BER_BVISNULL( &ml->sml_values[nvals] ); nvals++ ) {
632 rc = ordered_value_normalize(
633 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
634 ad,
635 ad->ad_type->sat_equality,
636 &ml->sml_values[nvals], &ml->sml_nvalues[nvals], ctx );
637 if ( rc ) {
638 Debug( LDAP_DEBUG_ANY,
639 "<= str2entry NULL (ssyn_normalize %d)\n",
640 rc, 0, 0 );
641 snprintf( textbuf, textlen,
642 "%s: value #%ld normalization failed",
643 ml->sml_type.bv_val, (long) nvals );
644 *text = textbuf;
645 BER_BVZERO( &ml->sml_nvalues[nvals] );
646 return rc;
647 }
648 }
649
650 BER_BVZERO( &ml->sml_nvalues[nvals] );
651 }
652
653 /* check for duplicates, but ignore Deletes.
654 */
655 if( nvals > 1 && ml->sml_op != LDAP_MOD_DELETE ) {
656 int i;
657 rc = slap_sort_vals( ml, text, &i, ctx );
658 if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
659 /* value exists already */
660 snprintf( textbuf, textlen,
661 "%s: value #%d provided more than once",
662 ml->sml_desc->ad_cname.bv_val, i );
663 *text = textbuf;
664 }
665 if ( rc )
666 return rc;
667 }
668 } else {
669 ml->sml_numvals = 0;
670 }
671 }
672
673 return LDAP_SUCCESS;
674 }
675
676 /* Sort a set of values. An (Attribute *) may be used interchangeably here
677 * instead of a (Modifications *) structure.
678 *
679 * Uses Quicksort + Insertion sort for small arrays
680 */
681
682 int
683 slap_sort_vals(
684 Modifications *ml,
685 const char **text,
686 int *dup,
687 void *ctx )
688 {
689 AttributeDescription *ad;
690 MatchingRule *mr;
691 int istack[sizeof(int)*16];
692 int i, j, k, l, ir, jstack, match, *ix, itmp, nvals, rc = LDAP_SUCCESS;
693 int is_norm;
694 struct berval a, *cv;
695
696 #define SMALL 8
697 #define SWAP(a,b,tmp) tmp=(a);(a)=(b);(b)=tmp
698 #define COMP(a,b) match=0; rc = ordered_value_match( &match, \
699 ad, mr, SLAP_MR_EQUALITY \
700 | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX \
701 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH \
702 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, \
703 &(a), &(b), text );
704
705 #define IX(x) ix[x]
706 #define EXCH(x,y) SWAP(ix[x],ix[y],itmp)
707 #define SETA(x) itmp = ix[x]; a = cv[itmp]
708 #define GETA(x) ix[x] = itmp;
709 #define SET(x,y) ix[x] = ix[y]
710
711 ad = ml->sml_desc;
712 nvals = ml->sml_numvals;
713 if ( nvals <= 1 )
714 goto ret;
715
716 /* For Modifications, sml_nvalues is NULL if normalization wasn't needed.
717 * For Attributes, sml_nvalues == sml_values when normalization isn't needed.
718 */
719 if ( ml->sml_nvalues && ml->sml_nvalues != ml->sml_values ) {
720 cv = ml->sml_nvalues;
721 is_norm = 1;
722 } else {
723 cv = ml->sml_values;
724 is_norm = 0;
725 }
726
727 if ( ad == slap_schema.si_ad_objectClass )
728 mr = NULL; /* shortcut matching */
729 else
730 mr = ad->ad_type->sat_equality;
731
732 /* record indices to preserve input ordering */
733 ix = slap_sl_malloc( nvals * sizeof(int), ctx );
734 for (i=0; i<nvals; i++) ix[i] = i;
735
736 ir = nvals-1;
737 l = 0;
738 jstack = 0;
739
740 for(;;) {
741 if (ir - l < SMALL) { /* Insertion sort */
742 match=1;
743 for (j=l+1;j<=ir;j++) {
744 SETA(j);
745 for (i=j-1;i>=0;i--) {
746 COMP(cv[IX(i)], a);
747 if ( match <= 0 )
748 break;
749 SET(i+1,i);
750 }
751 GETA(i+1);
752 if ( match == 0 ) goto done;
753 }
754 if ( jstack == 0 ) break;
755 ir = istack[jstack--];
756 l = istack[jstack--];
757 } else {
758 k = (l + ir) >> 1; /* Choose median of left, center, right */
759 EXCH(k, l+1);
760 COMP( cv[IX(l)], cv[IX(ir)] );
761 if ( match > 0 ) {
762 EXCH(l, ir);
763 } else if ( match == 0 ) {
764 i = ir;
765 break;
766 }
767 COMP( cv[IX(l+1)], cv[IX(ir)] );
768 if ( match > 0 ) {
769 EXCH(l+1, ir);
770 } else if ( match == 0 ) {
771 i = ir;
772 break;
773 }
774 COMP( cv[IX(l)], cv[IX(l+1)] );
775 if ( match > 0 ) {
776 EXCH(l, l+1);
777 } else if ( match == 0 ) {
778 i = l;
779 break;
780 }
781 i = l+1;
782 j = ir;
783 a = cv[IX(i)];
784 for(;;) {
785 do {
786 i++;
787 COMP( cv[IX(i)], a );
788 } while( match < 0 );
789 while( match > 0 ) {
790 j--;
791 COMP( cv[IX(j)], a );
792 }
793 if (j < i) {
794 match = 1;
795 break;
796 }
797 if ( match == 0 ) {
798 i = l+1;
799 break;
800 }
801 EXCH(i,j);
802 }
803 if ( match == 0 )
804 break;
805 EXCH(l+1,j);
806 jstack += 2;
807 if (ir-i+1 > j-l) {
808 istack[jstack] = ir;
809 istack[jstack-1] = i;
810 ir = j;
811 } else {
812 istack[jstack] = j;
813 istack[jstack-1] = l;
814 l = i;
815 }
816 }
817 }
818 done:
819 if ( match == 0 && i >= 0 )
820 *dup = ix[i];
821
822 /* For sorted attributes, put the values in index order */
823 if ( rc == LDAP_SUCCESS && match &&
824 ( ad->ad_type->sat_flags & SLAP_AT_SORTED_VAL )) {
825 BerVarray tmpv = slap_sl_malloc( sizeof( struct berval ) * nvals, ctx );
826 for ( i = 0; i<nvals; i++ )
827 tmpv[i] = cv[ix[i]];
828 for ( i = 0; i<nvals; i++ )
829 cv[i] = tmpv[i];
830 /* Check if the non-normalized array needs to move too */
831 if ( is_norm ) {
832 cv = ml->sml_values;
833 for ( i = 0; i<nvals; i++ )
834 tmpv[i] = cv[ix[i]];
835 for ( i = 0; i<nvals; i++ )
836 cv[i] = tmpv[i];
837 }
838 slap_sl_free( tmpv, ctx );
839 }
840
841 slap_sl_free( ix, ctx );
842
843 if ( rc == LDAP_SUCCESS && match == 0 ) {
844 /* value exists already */
845 assert( i >= 0 );
846 assert( i < nvals );
847 rc = LDAP_TYPE_OR_VALUE_EXISTS;
848 }
849 ret:
850 return rc;
851 }
852
853 /* Enter with bv->bv_len = sizeof buffer, returns with
854 * actual length of string
855 */
856 void slap_timestamp( time_t *tm, struct berval *bv )
857 {
858 struct tm ltm;
859
860 ldap_pvt_gmtime( tm, <m );
861
862 bv->bv_len = lutil_gentime( bv->bv_val, bv->bv_len, <m );
863 }
864
865 /* Called for all modify and modrdn ops. If the current op was replicated
866 * from elsewhere, all of the attrs should already be present.
867 */
868 void slap_mods_opattrs(
869 Operation *op,
870 Modifications **modsp,
871 int manage_ctxcsn )
872 {
873 struct berval name, timestamp, csn = BER_BVNULL;
874 struct berval nname;
875 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
876 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
877 Modifications *mod, **modtail, *modlast;
878 int gotcsn = 0, gotmname = 0, gotmtime = 0;
879
880 if ( SLAP_LASTMOD( op->o_bd ) && !op->orm_no_opattrs ) {
881 char *ptr;
882 timestamp.bv_val = timebuf;
883 for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) {
884 if ( (*modtail)->sml_op != LDAP_MOD_ADD &&
885 (*modtail)->sml_op != SLAP_MOD_SOFTADD &&
886 (*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT &&
887 (*modtail)->sml_op != LDAP_MOD_REPLACE )
888 {
889 continue;
890 }
891
892 if ( (*modtail)->sml_desc == slap_schema.si_ad_entryCSN )
893 {
894 csn = (*modtail)->sml_values[0];
895 gotcsn = 1;
896
897 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifiersName )
898 {
899 gotmname = 1;
900
901 } else if ( (*modtail)->sml_desc == slap_schema.si_ad_modifyTimestamp )
902 {
903 gotmtime = 1;
904 }
905 }
906
907 if ( BER_BVISEMPTY( &op->o_csn )) {
908 if ( !gotcsn ) {
909 csn.bv_val = csnbuf;
910 csn.bv_len = sizeof( csnbuf );
911 slap_get_csn( op, &csn, manage_ctxcsn );
912
913 } else {
914 if ( manage_ctxcsn ) {
915 slap_queue_csn( op, &csn );
916 }
917 }
918
919 } else {
920 csn = op->o_csn;
921 }
922
923 ptr = ber_bvchr( &csn, '#' );
924 if ( ptr ) {
925 timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
926 AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len );
927 timebuf[timestamp.bv_len-1] = 'Z';
928 timebuf[timestamp.bv_len] = '\0';
929
930 } else {
931 time_t now = slap_get_time();
932
933 timestamp.bv_len = sizeof(timebuf);
934
935 slap_timestamp( &now, ×tamp );
936 }
937
938 if ( BER_BVISEMPTY( &op->o_dn ) ) {
939 BER_BVSTR( &name, SLAPD_ANONYMOUS );
940 nname = name;
941
942 } else {
943 name = op->o_dn;
944 nname = op->o_ndn;
945 }
946
947 if ( !gotcsn ) {
948 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
949 mod->sml_op = LDAP_MOD_REPLACE;
950 mod->sml_flags = SLAP_MOD_INTERNAL;
951 mod->sml_next = NULL;
952 BER_BVZERO( &mod->sml_type );
953 mod->sml_desc = slap_schema.si_ad_entryCSN;
954 mod->sml_numvals = 1;
955 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
956 ber_dupbv( &mod->sml_values[0], &csn );
957 BER_BVZERO( &mod->sml_values[1] );
958 assert( !BER_BVISNULL( &mod->sml_values[0] ) );
959 mod->sml_nvalues = NULL;
960 *modtail = mod;
961 modlast = mod;
962 modtail = &mod->sml_next;
963 }
964
965 if ( !gotmname ) {
966 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
967 mod->sml_op = LDAP_MOD_REPLACE;
968 mod->sml_flags = SLAP_MOD_INTERNAL;
969 mod->sml_next = NULL;
970 BER_BVZERO( &mod->sml_type );
971 mod->sml_desc = slap_schema.si_ad_modifiersName;
972 mod->sml_numvals = 1;
973 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
974 ber_dupbv( &mod->sml_values[0], &name );
975 BER_BVZERO( &mod->sml_values[1] );
976 assert( !BER_BVISNULL( &mod->sml_values[0] ) );
977 mod->sml_nvalues =
978 (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
979 ber_dupbv( &mod->sml_nvalues[0], &nname );
980 BER_BVZERO( &mod->sml_nvalues[1] );
981 assert( !BER_BVISNULL( &mod->sml_nvalues[0] ) );
982 *modtail = mod;
983 modtail = &mod->sml_next;
984 }
985
986 if ( !gotmtime ) {
987 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
988 mod->sml_op = LDAP_MOD_REPLACE;
989 mod->sml_flags = SLAP_MOD_INTERNAL;
990 mod->sml_next = NULL;
991 BER_BVZERO( &mod->sml_type );
992 mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
993 mod->sml_numvals = 1;
994 mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
995 ber_dupbv( &mod->sml_values[0], ×tamp );
996 BER_BVZERO( &mod->sml_values[1] );
997 assert( !BER_BVISNULL( &mod->sml_values[0] ) );
998 mod->sml_nvalues = NULL;
999 *modtail = mod;
1000 modtail = &mod->sml_next;
1001 }
1002 }
1003 }
1004
1005 int
1006 slap_parse_modlist(
1007 Operation *op,
1008 SlapReply *rs,
1009 BerElement *ber,
1010 req_modify_s *ms )
1011 {
1012 ber_tag_t tag;
1013 ber_len_t len;
1014 char *last;
1015 Modifications **modtail = &ms->rs_mods.rs_modlist;
1016
1017 ms->rs_mods.rs_modlist = NULL;
1018 ms->rs_increment = 0;
1019
1020 rs->sr_err = LDAP_SUCCESS;
1021
1022 /* collect modifications & save for later */
1023 for ( tag = ber_first_element( ber, &len, &last );
1024 tag != LBER_DEFAULT;
1025 tag = ber_next_element( ber, &len, last ) )
1026 {
1027 ber_int_t mop;
1028 Modifications tmp, *mod;
1029
1030 tmp.sml_nvalues = NULL;
1031
1032 if ( ber_scanf( ber, "{e{m[W]}}", &mop,
1033 &tmp.sml_type, &tmp.sml_values ) == LBER_ERROR )
1034 {
1035 rs->sr_text = "decoding modlist error";
1036 rs->sr_err = LDAP_PROTOCOL_ERROR;
1037 goto done;
1038 }
1039
1040 mod = (Modifications *) ch_malloc( sizeof(Modifications) );
1041 mod->sml_op = mop;
1042 mod->sml_flags = 0;
1043 mod->sml_type = tmp.sml_type;
1044 mod->sml_values = tmp.sml_values;
1045 mod->sml_nvalues = NULL;
1046 mod->sml_desc = NULL;
1047 mod->sml_next = NULL;
1048 *modtail = mod;
1049
1050 switch( mop ) {
1051 case LDAP_MOD_ADD:
1052 if ( mod->sml_values == NULL ) {
1053 rs->sr_text = "modify/add operation requires values";
1054 rs->sr_err = LDAP_PROTOCOL_ERROR;
1055 goto done;
1056 }
1057
1058 /* fall through */
1059
1060 case LDAP_MOD_DELETE:
1061 case LDAP_MOD_REPLACE:
1062 break;
1063
1064 case LDAP_MOD_INCREMENT:
1065 if( op->o_protocol >= LDAP_VERSION3 ) {
1066 ms->rs_increment++;
1067 if ( mod->sml_values == NULL ) {
1068 rs->sr_text = "modify/increment operation requires value";
1069 rs->sr_err = LDAP_PROTOCOL_ERROR;
1070 goto done;
1071 }
1072
1073 if ( !BER_BVISNULL( &mod->sml_values[ 1 ] ) ) {
1074 rs->sr_text = "modify/increment operation requires single value";
1075 rs->sr_err = LDAP_PROTOCOL_ERROR;
1076 goto done;
1077 }
1078
1079 break;
1080 }
1081 /* fall thru */
1082
1083 default:
1084 rs->sr_text = "unrecognized modify operation";
1085 rs->sr_err = LDAP_PROTOCOL_ERROR;
1086 goto done;
1087 }
1088
1089 modtail = &mod->sml_next;
1090 }
1091 *modtail = NULL;
1092
1093 done:
1094 if ( rs->sr_err != LDAP_SUCCESS ) {
1095 slap_mods_free( ms->rs_mods.rs_modlist, 1 );
1096 ms->rs_mods.rs_modlist = NULL;
1097 ms->rs_increment = 0;
1098 }
1099
1100 return rs->sr_err;
1101 }
1102
1103