3 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1995 Regents of the University of Michigan.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that this notice is preserved and that due credit is given
12 * to the University of Michigan at Ann Arbor. The name of the University
13 * may not be used to endorse or promote products derived from this
14 * software without specific prior written permission. This software
15 * is provided ``as is'' without express or implied warranty.
19 #include "slapi_common.h"
23 #include <ac/socket.h>
24 #include <ac/string.h>
34 static LDAPMod **Modifications2LDAPMods (Modifications **modlist);
35 static Modifications *LDAPMods2Modifications (LDAPMod **mods);
36 static void FreeLDAPMods (LDAPMod **mods);
37 #endif /* LDAP_SLAPI */
44 struct berval dn = { 0, NULL };
45 struct berval pdn = { 0, NULL };
46 struct berval ndn = { 0, NULL };
50 Modifications *modlist = NULL;
51 Modifications **modtail = &modlist;
53 LDAPMod **modv = NULL;
62 Slapi_PBlock *pb = op->o_pb;
65 LDAP_LOG( OPERATION, ENTRY, "do_modify: enter\n", 0, 0, 0 );
67 Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
71 * Parse the modify request. It looks like this:
73 * ModifyRequest := [APPLICATION 6] SEQUENCE {
74 * name DistinguishedName,
75 * mods SEQUENCE OF SEQUENCE {
76 * operation ENUMERATED {
81 * modification SEQUENCE {
83 * values SET OF AttributeValue
89 if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
91 LDAP_LOG( OPERATION, ERR, "do_modify: ber_scanf failed\n", 0, 0, 0 );
93 Debug( LDAP_DEBUG_ANY, "do_modify: ber_scanf failed\n", 0, 0, 0 );
96 send_ldap_disconnect( conn, op,
97 LDAP_PROTOCOL_ERROR, "decoding error" );
98 return SLAPD_DISCONNECT;
102 LDAP_LOG( OPERATION, ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
104 Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
108 /* collect modifications & save for later */
110 for ( tag = ber_first_element( op->o_ber, &len, &last );
112 tag = ber_next_element( op->o_ber, &len, last ) )
115 Modifications tmp, *mod;
118 if ( ber_scanf( op->o_ber, "{i{m[W]}}", &mop,
119 &tmp.sml_type, &tmp.sml_bvalues )
122 send_ldap_disconnect( conn, op,
123 LDAP_PROTOCOL_ERROR, "decoding modlist error" );
124 rc = SLAPD_DISCONNECT;
128 mod = (Modifications *) ch_malloc( sizeof(Modifications) );
130 mod->sml_type = tmp.sml_type;
131 mod->sml_bvalues = tmp.sml_bvalues;
132 mod->sml_desc = NULL;
133 mod->sml_next = NULL;
138 if ( mod->sml_bvalues == NULL ) {
140 LDAP_LOG( OPERATION, ERR,
141 "do_modify: modify/add operation (%ld) requires values\n",
144 Debug( LDAP_DEBUG_ANY,
145 "do_modify: modify/add operation (%ld) requires values\n",
149 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
150 NULL, "modify/add operation requires values",
152 rc = LDAP_PROTOCOL_ERROR;
158 case LDAP_MOD_DELETE:
159 case LDAP_MOD_REPLACE:
164 LDAP_LOG( OPERATION, ERR,
165 "do_modify: invalid modify operation (%ld)\n", (long)mop, 0, 0 );
167 Debug( LDAP_DEBUG_ANY,
168 "do_modify: invalid modify operation (%ld)\n",
172 send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
173 NULL, "unrecognized modify operation", NULL, NULL );
174 rc = LDAP_PROTOCOL_ERROR;
179 modtail = &mod->sml_next;
183 if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
185 LDAP_LOG( OPERATION, ERR, "do_modify: get_ctrls failed\n", 0, 0, 0 );
187 Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
193 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn );
194 if( rc != LDAP_SUCCESS ) {
196 LDAP_LOG( OPERATION, INFO, "do_modify: conn %d invalid dn (%s)\n",
197 conn->c_connid, dn.bv_val, 0 );
199 Debug( LDAP_DEBUG_ANY,
200 "do_modify: invalid dn (%s)\n", dn.bv_val, 0, 0 );
202 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
203 "invalid DN", NULL, NULL );
207 if( ndn.bv_len == 0 ) {
209 LDAP_LOG( OPERATION, ERR,
210 "do_modify: attempt to modify root DSE.\n",0, 0, 0 );
212 Debug( LDAP_DEBUG_ANY, "do_modify: root dse!\n", 0, 0, 0 );
215 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
216 NULL, "modify upon the root DSE not supported", NULL, NULL );
219 } else if ( bvmatch( &ndn, &global_schemandn ) ) {
221 LDAP_LOG( OPERATION, ERR,
222 "do_modify: attempt to modify subschema subentry.\n" , 0, 0, 0 );
224 Debug( LDAP_DEBUG_ANY, "do_modify: subschema subentry!\n", 0, 0, 0 );
227 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
228 NULL, "modification of subschema subentry not supported",
235 LDAP_LOG( OPERATION, DETAIL1, "do_modify: modifications:\n", 0, 0, 0 );
237 Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
240 for ( tmp = modlist; tmp != NULL; tmp = tmp->sml_next ) {
242 LDAP_LOG( OPERATION, DETAIL1, "\t%s: %s\n",
243 tmp->sml_op == LDAP_MOD_ADD ?
244 "add" : (tmp->sml_op == LDAP_MOD_DELETE ?
245 "delete" : "replace"), tmp->sml_type.bv_val, 0 );
247 if ( tmp->sml_bvalues == NULL ) {
248 LDAP_LOG( OPERATION, DETAIL1, "\t\tno values", 0, 0, 0 );
249 } else if ( tmp->sml_bvalues[0].bv_val == NULL ) {
250 LDAP_LOG( OPERATION, DETAIL1, "\t\tzero values", 0, 0, 0 );
251 } else if ( tmp->sml_bvalues[1].bv_val == NULL ) {
252 LDAP_LOG( OPERATION, DETAIL1, "\t\tone value", 0, 0, 0 );
254 LDAP_LOG( OPERATION, DETAIL1, "\t\tmultiple values", 0, 0, 0 );
258 Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
259 tmp->sml_op == LDAP_MOD_ADD
260 ? "add" : (tmp->sml_op == LDAP_MOD_DELETE
261 ? "delete" : "replace"), tmp->sml_type.bv_val, 0 );
263 if ( tmp->sml_bvalues == NULL ) {
264 Debug( LDAP_DEBUG_ARGS, "%s\n",
265 "\t\tno values", NULL, NULL );
266 } else if ( tmp->sml_bvalues[0].bv_val == NULL ) {
267 Debug( LDAP_DEBUG_ARGS, "%s\n",
268 "\t\tzero values", NULL, NULL );
269 } else if ( tmp->sml_bvalues[1].bv_val == NULL ) {
270 Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
271 "\t\tone value", (long) tmp->sml_bvalues[0].bv_len, NULL );
273 Debug( LDAP_DEBUG_ARGS, "%s\n",
274 "\t\tmultiple values", NULL, NULL );
280 if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
281 char abuf[BUFSIZ/2], *ptr = abuf;
284 Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD dn=\"%s\"\n",
285 op->o_connid, op->o_opid, dn.bv_val, 0, 0 );
287 for ( tmp = modlist; tmp != NULL; tmp = tmp->sml_next ) {
288 if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
289 Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD attr=%s\n",
290 op->o_connid, op->o_opid, abuf, 0, 0 );
298 ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val);
299 len += tmp->sml_type.bv_len;
302 Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD attr=%s\n",
303 op->o_connid, op->o_opid, abuf, 0, 0 );
307 manageDSAit = get_manageDSAit( op );
310 * We could be serving multiple database backends. Select the
311 * appropriate one, or send a referral to our "referral server"
312 * if we don't hold it.
314 if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) {
315 BerVarray ref = referral_rewrite( default_referral,
316 NULL, &pdn, LDAP_SCOPE_DEFAULT );
318 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
319 NULL, NULL, ref ? ref : default_referral, NULL );
321 ber_bvarray_free( ref );
325 /* check restrictions */
326 rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
327 if( rc != LDAP_SUCCESS ) {
328 send_ldap_result( conn, op, rc,
329 NULL, text, NULL, NULL );
333 /* check for referrals */
334 rc = backend_check_referrals( be, conn, op, &pdn, &ndn );
335 if ( rc != LDAP_SUCCESS ) {
339 /* deref suffix alias if appropriate */
340 suffix_alias( be, &ndn );
342 #if defined( LDAP_SLAPI )
343 slapi_x_backend_set_pb( pb, be );
344 slapi_x_connection_set_pb( pb, conn );
345 slapi_x_operation_set_pb( pb, op );
346 slapi_pblock_set( pb, SLAPI_MODIFY_TARGET, (void *)dn.bv_val );
347 slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)(1) );
348 modv = Modifications2LDAPMods( &modlist );
349 slapi_pblock_set( pb, SLAPI_MODIFY_MODS, (void *)modv );
351 rc = doPluginFNs( be, SLAPI_PLUGIN_PRE_MODIFY_FN, pb );
354 * A preoperation plugin failure will abort the
358 LDAP_LOG( OPERATION, INFO, "do_modify: modify preoperation plugin "
359 "failed\n", 0, 0, 0 );
361 Debug(LDAP_DEBUG_TRACE, "do_modify: modify preoperation plugin failed.\n",
364 if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0) {
367 ldap_mods_free( modv, 1 );
373 * It's possible that the preoperation plugin changed the
374 * modification array, so we need to convert it back to
375 * a Modification list.
377 * Calling Modifications2LDAPMods() destroyed modlist so
378 * we don't need to free it.
380 slapi_pblock_get( pb, SLAPI_MODIFY_MODS, (void **)&modv );
381 modlist = LDAPMods2Modifications( modv );
382 #endif /* defined( LDAP_SLAPI ) */
385 * do the modify if 1 && (2 || 3)
386 * 1) there is a modify function implemented in this backend;
387 * 2) this backend is master for what it holds;
388 * 3) it's a replica and the dn supplied is the update_ndn.
390 if ( be->be_modify ) {
391 /* do the update here */
392 int repl_user = be_isupdate( be, &op->o_ndn );
393 #ifndef SLAPD_MULTIMASTER
394 /* Multimaster slapd does not have to check for replicator dn
395 * because it accepts each modify request
397 if ( !be->be_update_ndn.bv_len || repl_user )
400 int update = be->be_update_ndn.bv_len;
402 char textbuf[SLAP_TEXT_BUFLEN];
403 size_t textlen = sizeof textbuf;
405 rc = slap_mods_check( modlist, update, &text,
408 if( rc != LDAP_SUCCESS ) {
409 send_ldap_result( conn, op, rc,
410 NULL, text, NULL, NULL );
415 for( modtail = &modlist;
417 modtail = &(*modtail)->sml_next )
422 rc = slap_mods_opattrs( be, op, modlist, modtail, &text,
424 if( rc != LDAP_SUCCESS ) {
425 send_ldap_result( conn, op, rc,
432 if ( (*be->be_modify)( be, conn, op, &pdn, &ndn, modlist ) == 0
433 #ifdef SLAPD_MULTIMASTER
437 /* but we log only the ones not from a replicator user */
438 replog( be, op, &pdn, &ndn, modlist );
441 #ifndef SLAPD_MULTIMASTER
442 /* send a referral */
444 BerVarray defref = be->be_update_refs
445 ? be->be_update_refs : default_referral;
446 BerVarray ref = referral_rewrite( defref,
447 NULL, &pdn, LDAP_SCOPE_DEFAULT );
449 send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
450 ref ? ref : defref, NULL );
452 ber_bvarray_free( ref );
456 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
457 NULL, "operation not supported within namingContext",
461 #if defined( LDAP_SLAPI )
462 if ( doPluginFNs( be, SLAPI_PLUGIN_POST_MODIFY_FN, pb ) != 0 ) {
464 LDAP_LOG( OPERATION, INFO, "do_modify: modify postoperation plugins "
465 "failed\n", 0, 0, 0 );
467 Debug(LDAP_DEBUG_TRACE, "do_modify: modify postoperation plugins "
468 "failed.\n", 0, 0, 0);
471 #endif /* defined( LDAP_SLAPI ) */
476 if ( modlist != NULL ) slap_mods_free( modlist );
477 #if defined( LDAP_SLAPI )
478 if ( modv != NULL ) FreeLDAPMods( modv );
484 * Do basic attribute type checking and syntax validation.
495 for( ; ml != NULL; ml = ml->sml_next ) {
496 AttributeDescription *ad = NULL;
498 /* convert to attribute description */
499 rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
501 if( rc != LDAP_SUCCESS ) {
502 snprintf( textbuf, textlen, "%s: %s",
503 ml->sml_type.bv_val, *text );
510 if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
511 && !slap_ad_is_binary( ad ))
513 /* attribute requires binary transfer */
514 snprintf( textbuf, textlen,
515 "%s: requires ;binary transfer",
516 ml->sml_type.bv_val );
518 return LDAP_UNDEFINED_TYPE;
521 if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
522 && slap_ad_is_binary( ad ))
524 /* attribute requires binary transfer */
525 snprintf( textbuf, textlen,
526 "%s: disallows ;binary transfer",
527 ml->sml_type.bv_val );
529 return LDAP_UNDEFINED_TYPE;
532 if( slap_ad_is_tag_range( ad )) {
533 /* attribute requires binary transfer */
534 snprintf( textbuf, textlen,
535 "%s: inappropriate use of tag range option",
536 ml->sml_type.bv_val );
538 return LDAP_UNDEFINED_TYPE;
541 if (!update && is_at_no_user_mod( ad->ad_type )) {
542 /* user modification disallowed */
543 snprintf( textbuf, textlen,
544 "%s: no user modification allowed",
545 ml->sml_type.bv_val );
547 return LDAP_CONSTRAINT_VIOLATION;
550 if ( is_at_obsolete( ad->ad_type ) &&
551 ( ml->sml_op == LDAP_MOD_ADD || ml->sml_bvalues != NULL ) )
554 * attribute is obsolete,
555 * only allow replace/delete with no values
557 snprintf( textbuf, textlen,
558 "%s: attribute is obsolete",
559 ml->sml_type.bv_val );
561 return LDAP_CONSTRAINT_VIOLATION;
567 if( ml->sml_bvalues != NULL ) {
569 slap_syntax_validate_func *validate =
570 ad->ad_type->sat_syntax->ssyn_validate;
571 slap_syntax_transform_func *pretty =
572 ad->ad_type->sat_syntax->ssyn_pretty;
574 if( !pretty && !validate ) {
575 *text = "no validator for syntax";
576 snprintf( textbuf, textlen,
577 "%s: no validator for syntax %s",
579 ad->ad_type->sat_syntax->ssyn_oid );
581 return LDAP_INVALID_SYNTAX;
585 * check that each value is valid per syntax
586 * and pretty if appropriate
588 for( nvals = 0; ml->sml_bvalues[nvals].bv_val; nvals++ ) {
591 rc = pretty( ad->ad_type->sat_syntax,
592 &ml->sml_bvalues[nvals], &pval );
594 rc = validate( ad->ad_type->sat_syntax,
595 &ml->sml_bvalues[nvals] );
599 snprintf( textbuf, textlen,
600 "%s: value #%ld invalid per syntax",
601 ml->sml_type.bv_val, (long) nvals );
603 return LDAP_INVALID_SYNTAX;
607 ber_memfree( ml->sml_bvalues[nvals].bv_val );
608 ml->sml_bvalues[nvals] = pval;
613 * a rough single value check... an additional check is needed
614 * to catch add of single value to existing single valued attribute
616 if( ( ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE )
617 && nvals > 1 && is_at_single_value( ad->ad_type ))
619 snprintf( textbuf, textlen,
620 "%s: multiple value provided",
621 ml->sml_type.bv_val );
623 return LDAP_CONSTRAINT_VIOLATION;
631 int slap_mods_opattrs(
635 Modifications **modtail,
637 char *textbuf, size_t textlen )
639 struct berval name, timestamp, csn;
640 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
641 char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
644 int mop = op->o_tag == LDAP_REQ_ADD
645 ? LDAP_MOD_ADD : LDAP_MOD_REPLACE;
647 assert( modtail != NULL );
648 assert( *modtail == NULL );
650 if( SLAP_LASTMOD(be) ) {
652 time_t now = slap_get_time();
654 ldap_pvt_thread_mutex_lock( &gmtime_mutex );
655 ltm = gmtime( &now );
656 lutil_gentime( timebuf, sizeof(timebuf), ltm );
658 csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
659 ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
662 timestamp.bv_val = timebuf;
663 timestamp.bv_len = strlen(timebuf);
665 if( op->o_dn.bv_len == 0 ) {
666 name.bv_val = SLAPD_ANONYMOUS;
667 name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
673 if( op->o_tag == LDAP_REQ_ADD ) {
674 struct berval tmpval;
676 if( global_schemacheck ) {
677 int rc = mods_structural_class( mods, &tmpval,
678 text, textbuf, textlen );
679 if( rc != LDAP_SUCCESS ) {
683 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
685 mod->sml_type.bv_val = NULL;
686 mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
687 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
688 ber_dupbv( &mod->sml_bvalues[0], &tmpval );
689 mod->sml_bvalues[1].bv_val = NULL;
690 assert( mod->sml_bvalues[0].bv_val );
692 modtail = &mod->sml_next;
695 if( SLAP_LASTMOD(be) ) {
696 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
698 tmpval.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
699 tmpval.bv_val = uuidbuf;
701 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
703 mod->sml_type.bv_val = NULL;
704 mod->sml_desc = slap_schema.si_ad_entryUUID;
705 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
706 ber_dupbv( &mod->sml_bvalues[0], &tmpval );
707 mod->sml_bvalues[1].bv_val = NULL;
708 assert( mod->sml_bvalues[0].bv_val );
710 modtail = &mod->sml_next;
712 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
714 mod->sml_type.bv_val = NULL;
715 mod->sml_desc = slap_schema.si_ad_creatorsName;
716 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
717 ber_dupbv( &mod->sml_bvalues[0], &name );
718 mod->sml_bvalues[1].bv_val = NULL;
719 assert( mod->sml_bvalues[0].bv_val );
721 modtail = &mod->sml_next;
723 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
725 mod->sml_type.bv_val = NULL;
726 mod->sml_desc = slap_schema.si_ad_createTimestamp;
727 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
728 ber_dupbv( &mod->sml_bvalues[0], ×tamp );
729 mod->sml_bvalues[1].bv_val = NULL;
730 assert( mod->sml_bvalues[0].bv_val );
732 modtail = &mod->sml_next;
736 if( SLAP_LASTMOD(be) ) {
737 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
739 mod->sml_type.bv_val = NULL;
740 mod->sml_desc = slap_schema.si_ad_entryCSN;
741 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
742 ber_dupbv( &mod->sml_bvalues[0], &csn );
743 mod->sml_bvalues[1].bv_val = NULL;
744 assert( mod->sml_bvalues[0].bv_val );
746 modtail = &mod->sml_next;
748 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
750 mod->sml_type.bv_val = NULL;
751 mod->sml_desc = slap_schema.si_ad_modifiersName;
752 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
753 ber_dupbv( &mod->sml_bvalues[0], &name );
754 mod->sml_bvalues[1].bv_val = NULL;
755 assert( mod->sml_bvalues[0].bv_val );
757 modtail = &mod->sml_next;
759 mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
761 mod->sml_type.bv_val = NULL;
762 mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
763 mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
764 ber_dupbv( &mod->sml_bvalues[0], ×tamp );
765 mod->sml_bvalues[1].bv_val = NULL;
766 assert( mod->sml_bvalues[0].bv_val );
768 modtail = &mod->sml_next;
777 * Synthesise an LDAPMod array from a Modifications list to pass
778 * to SLAPI. This synthesis is destructive and as such the
779 * Modifications list may not be used after calling this
782 * This function must also be called before slap_mods_check().
784 static LDAPMod **Modifications2LDAPMods(Modifications **pmodlist)
786 Modifications *ml, *modlist;
787 LDAPMod **mods, *modp;
792 for( i = 0, ml = modlist; ml != NULL; i++, ml = ml->sml_next )
795 mods = (LDAPMod **)ch_malloc( (i + 1) * sizeof(LDAPMod *) );
797 for( i = 0, ml = modlist; ml != NULL; ml = ml->sml_next ) {
799 modp->mod_op = ml->sml_op | LDAP_MOD_BVALUES;
801 /* Take ownership of original type. */
802 modp->mod_type = ml->sml_type.bv_val;
803 ml->sml_type.bv_val = NULL;
805 if ( ml->sml_bvalues != NULL ) {
806 for( j = 0; ml->sml_bvalues[j].bv_val != NULL; j++ )
808 modp->mod_bvalues = (struct berval **)ch_malloc( (j + 1) *
809 sizeof(struct berval *) );
810 for( j = 0; ml->sml_bvalues[j].bv_val != NULL; j++ ) {
811 /* Take ownership of original values. */
812 modp->mod_bvalues[j] = (struct berval *)ch_malloc( sizeof(struct berval) );
813 modp->mod_bvalues[j]->bv_len = ml->sml_bvalues[j].bv_len;
814 modp->mod_bvalues[j]->bv_val = ml->sml_bvalues[j].bv_val;
815 ml->sml_bvalues[j].bv_len = 0;
816 ml->sml_bvalues[j].bv_val = NULL;
818 modp->mod_bvalues[j] = NULL;
820 modp->mod_bvalues = NULL;
827 slap_mods_free( modlist );
834 * Convert a potentially modified array of LDAPMods back to a
837 * The returned Modification list contains pointers into the
838 * LDAPMods array; the latter MUST be freed with FreeLDAPMods()
841 static Modifications *LDAPMods2Modifications (LDAPMod **mods)
843 Modifications *modlist, **modtail;
848 for( modp = mods; *modp != NULL; modp++ ) {
854 mod = (Modifications *) ch_malloc( sizeof(Modifications) );
855 mod->sml_op = (*modp)->mod_op & (~LDAP_MOD_BVALUES);
856 mod->sml_type.bv_val = (*modp)->mod_type;
857 mod->sml_type.bv_len = strlen( mod->sml_type.bv_val );
858 mod->sml_desc = NULL;
859 mod->sml_next = NULL;
861 if ( (*modp)->mod_op & LDAP_MOD_BVALUES ) {
862 for( i = 0, bvp = (*modp)->mod_bvalues; *bvp != NULL; bvp++, i++ )
865 for( i = 0, p = (*modp)->mod_values; *p != NULL; p++, i++ )
869 mod->sml_bvalues = (BerVarray) ch_malloc( (i + 1) * sizeof(struct berval) );
871 /* NB: This implicitly trusts a plugin to return valid modifications. */
872 if ( (*modp)->mod_op & LDAP_MOD_BVALUES ) {
873 for( i = 0, bvp = (*modp)->mod_bvalues; *bvp != NULL; bvp++, i++ ) {
874 mod->sml_bvalues[i].bv_val = (*bvp)->bv_val;
875 mod->sml_bvalues[i].bv_len = (*bvp)->bv_len;
878 for( i = 0, p = (*modp)->mod_values; *p != NULL; p++, i++ ) {
879 mod->sml_bvalues[i].bv_val = *p;
880 mod->sml_bvalues[i].bv_len = strlen( *p );
883 mod->sml_bvalues[i].bv_val = NULL;
886 modtail = &mod->sml_next;
893 * This function only frees the parts of the mods array that
894 * are not shared with the Modification list that was created
895 * by LDAPMods2Modifications.
898 static void FreeLDAPMods (LDAPMod **mods)
905 for ( i = 0; mods[i] != NULL; i++ ) {
907 * Don't free values themselves; they're owned by the
908 * Modification list. Do free the containing array.
910 if ( mods[i]->mod_op & LDAP_MOD_BVALUES ) {
911 for ( j = 0; mods[i]->mod_bvalues[j] != NULL; j++ ) {
912 ch_free( mods[i]->mod_bvalues[j] );
914 ch_free( mods[i]->mod_bvalues );
916 ch_free( mods[i]->mod_values );
918 /* Don't free type, for same reasons. */
924 #endif /* LDAP_SLAPI */