3 * Copyright (c) 1990 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
19 #include <ac/socket.h>
20 #include <ac/string.h> /* get SAFEMEMCPY */
22 #include <quipu/commonarg.h>
23 #include <quipu/attrvalue.h>
24 #include <quipu/ds_error.h>
25 #include <quipu/modify.h>
26 #include <quipu/dap2.h>
27 #include <quipu/dua.h>
34 static CommonArgs common = default_common_args;
36 static int replace_mod( struct entrymod *, Attr_Sequence, Attr_Sequence );
39 #define MODTAG (ldap_compat == 20 ? OLD_LDAP_RES_MODIFY : LDAP_RES_MODIFY)
41 #define MODTAG LDAP_RES_MODIFY
54 unsigned long tag, len;
55 LDAPModList *mods, *modtail;
56 struct ds_read_arg ra;
58 Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
61 * Parse the modify request. It looks like this:
62 * ModifyRequest := [APPLICATION 6] SEQUENCE {
63 * name DistinguishedName,
64 * mods SEQUENCE OF SEQUENCE {
65 * operation ENUMERATED {
70 * modification SEQUENCE {
72 * values SET OF AttributeValue
76 * We then have to initiate a read of the entry to be modified.
77 * The actual modification is done by do_modify2(), after the
81 #if ISODEPACKAGE == IC
83 DAS_ReadArgument_INIT( &ra );
87 if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
88 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
89 send_ldap_msgresult( clientsb, MODTAG, m,
90 LDAP_PROTOCOL_ERROR, NULL, "" );
94 Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
96 ra.rda_object = ldap_str2dn( dn );
98 if ( ra.rda_object == NULLDN ) {
99 Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
100 send_ldap_msgresult( clientsb, MODTAG, m,
101 LDAP_INVALID_DN_SYNTAX, NULL, "" );
104 ra.rda_eis.eis_allattributes = TRUE;
105 ra.rda_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
106 ra.rda_eis.eis_select = NULLATTR;
108 /* collect modifications & save for later */
109 mods = modtail = NULL;
110 for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
111 tag = ber_next_element( ber, &len, last ) ) {
114 if ( (tmp = (LDAPModList *) calloc( 1, sizeof(LDAPModList) ))
116 send_ldap_msgresult( clientsb, MODTAG, m,
117 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
121 if ( ber_scanf( ber, "{i{a[V]}}", &tmp->m.mod_op,
122 &tmp->m.mod_type, &tmp->m.mod_bvalues ) == LBER_ERROR ) {
123 send_ldap_msgresult( clientsb, MODTAG, m,
124 LDAP_PROTOCOL_ERROR, NULL, "" );
128 if ( mods == NULL ) {
131 modtail->mod_next = tmp;
137 ra.rda_common = common; /* struct copy */
139 rc = initiate_dap_operation( OP_READ, m, &ra );
141 dn_free( ra.rda_object );
144 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
155 struct ds_read_result *rr
158 struct ds_modifyentry_arg ma;
159 struct entrymod *changetail = NULLMOD;
163 Debug( LDAP_DEBUG_TRACE, "do_modify2\n", 0, 0, 0 );
165 #if ISODEPACKAGE == IC
167 DAS_ModifyEntryArgument_INIT( &ma );
171 ma.mea_changes = NULLMOD;
172 for ( mods = m->m_mods; mods != NULL; mods = mods->mod_next ) {
174 Attr_Sequence as, new;
176 if ( (em = (struct entrymod *) calloc( 1,
177 sizeof(struct entrymod) )) == NULLMOD ) {
178 send_ldap_msgresult( clientsb, MODTAG, m,
179 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
182 em->em_next = NULLMOD;
184 if ( (new = get_as( clientsb, MODTAG, m,
185 mods->m.mod_type, mods->m.mod_bvalues )) == NULLATTR )
189 for ( as = rr->rdr_entry.ent_attr; as != NULLATTR;
190 as = as->attr_link ) {
191 if ( AttrT_cmp( new->attr_type, as->attr_type ) == 0 )
195 if ( new->attr_value == NULLAV &&
196 mods->m.mod_op != LDAP_MOD_DELETE ) {
197 send_ldap_msgresult( clientsb, MODTAG, m,
198 LDAP_INVALID_SYNTAX, NULL, "No values specified" );
202 switch ( mods->m.mod_op ) {
204 Debug( LDAP_DEBUG_ARGS, "ADD:\n", 0, 0, 0 );
206 if ( as == NULLATTR ) {
207 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
209 em->em_type = EM_ADDATTRIBUTE;
211 Debug( LDAP_DEBUG_ARGS, "\tvalues\n", 0, 0, 0 );
212 em->em_type = EM_ADDVALUES;
216 case LDAP_MOD_DELETE:
217 Debug( LDAP_DEBUG_ARGS, "DELETE:\n", 0, 0, 0 );
219 if ( as == NULLATTR ) {
220 Debug( LDAP_DEBUG_ARGS,
221 "\tno existing attribute\n", 0, 0, 0 );
222 send_ldap_msgresult( clientsb, MODTAG,
223 m, LDAP_NO_SUCH_ATTRIBUTE, NULL, "" );
227 if ( new->attr_value == NULLAV ) {
228 Debug( LDAP_DEBUG_ARGS, "\tattribute\n",
230 em->em_type = EM_REMOVEATTRIBUTE;
232 if ( avs_cmp( new->attr_value,
233 as->attr_value ) == 0 ) {
234 Debug( LDAP_DEBUG_ARGS,
235 "\tattribute\n", 0, 0, 0 );
239 Debug( LDAP_DEBUG_ARGS,
240 "\tvalues\n", 0, 0, 0 );
241 em->em_type = EM_REMOVEVALUES;
247 case LDAP_MOD_REPLACE:
248 Debug( LDAP_DEBUG_ARGS, "REPLACE:\n", 0, 0, 0 );
250 if ( as == NULLATTR ) {
251 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
253 em->em_type = EM_ADDATTRIBUTE;
255 if ( replace_mod( em, as, new ) < 0 ) {
262 Debug( LDAP_DEBUG_ARGS, "UNKNOWN MOD:\n", 0, 0, 0 );
264 send_ldap_msgresult( clientsb, MODTAG, m,
265 LDAP_PROTOCOL_ERROR, NULL, "" );
270 if ( em->em_what == NULL ) { /* ignore this mod */
273 if ( ma.mea_changes == NULLMOD ) {
276 changetail->em_next = em;
278 changetail = em->em_next == NULLMOD ? em : em->em_next;
283 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
289 ps = ps_alloc( std_open );
290 std_setup( ps, stderr );
292 fprintf( stderr, "Modify changes are:\n");
293 for (e = ma.mea_changes; e; e = e->em_next) {
294 switch (e->em_type) {
295 case EM_ADDATTRIBUTE:
296 fprintf( stderr, "\tADD ATTRIBUTE\n");
298 case EM_REMOVEATTRIBUTE:
299 fprintf( stderr, "\tREMOVE ATTRIBUTE\n");
302 fprintf( stderr, "\tADD VALUES\n");
304 case EM_REMOVEVALUES:
305 fprintf( stderr, "\tREMOVE VALUES\n");
308 fprintf( stderr, "\tUNKNOWN\n");
313 fprintf( stderr, "\t\ttype (" );
314 AttrT_print( ps, as->attr_type, EDBOUT );
315 fprintf( stderr, ")" );
316 if ( e->em_type == EM_REMOVEATTRIBUTE ) {
317 fprintf( stderr, "\n" );
320 fprintf( stderr, " values" );
321 for (val = as->attr_value; val; val = val->avseq_next) {
322 ps_print( ps, " (" );
323 AttrV_print( ps, &val->avseq_av, EDBOUT );
326 fprintf( stderr, "\n" );
332 if ( ma.mea_changes == NULLMOD ) { /* nothing to do */
333 send_ldap_msgresult( clientsb, MODTAG, m,
334 LDAP_SUCCESS, NULL, "" );
338 ma.mea_object = rr->rdr_entry.ent_dn;
339 ma.mea_common = common; /* struct copy */
341 rc = initiate_dap_operation( OP_MODIFYENTRY, m, &ma );
343 ems_free( ma.mea_changes );
346 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
359 struct berval **bvals
366 Debug( LDAP_DEBUG_TRACE, "get_as\n", 0, 0, 0 );
368 if ( (as = as_comp_new( NULLAttrT, NULLAV, NULLACL_INFO ))
370 send_ldap_msgresult( clientsb, op, m,
371 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
374 as->attr_link = NULLATTR;
375 as->attr_value = NULLAV;
376 as->attr_acl = NULLACL_INFO;
378 if ( (as->attr_type = str2AttrT( type )) == NULLAttrT ) {
379 send_ldap_msgresult( clientsb, op, m, LDAP_UNDEFINED_TYPE,
387 syntax = as->attr_type->oa_syntax;
388 for ( i = 0; bvals[i] != NULL; i++ ) {
391 char *sval, *s, *news, *n;
393 if ( syntax == ldap_jpeg_syntax ||
394 syntax == ldap_jpeg_nonfile_syntax ||
395 syntax == ldap_octetstring_syntax ||
396 syntax == ldap_audio_syntax ) {
397 if (( av = bv_octet2AttrV( bvals[i] )) == NULLAttrV ) {
398 send_ldap_msgresult( clientsb, op, m,
399 LDAP_INVALID_SYNTAX, NULL, type );
403 } else if ( syntax == ldap_photo_syntax ) {
404 if (( av = bv_asn2AttrV( bvals[i] )) == NULLAttrV ) {
405 send_ldap_msgresult( clientsb, op, m,
406 LDAP_INVALID_SYNTAX, NULL, type );
412 if (( sval = malloc( bvals[i]->bv_len + 1 )) == NULL ) {
413 send_ldap_msgresult( clientsb, op, m,
414 LDAP_OPERATIONS_ERROR, NULL,
418 SAFEMEMCPY( sval, bvals[i]->bv_val, bvals[i]->bv_len );
419 sval[ bvals[i]->bv_len ] = '\0';
421 /* dang quipu - there's no need for this! */
422 if ( syntax == ldap_postaladdress_syntax ) {
425 for ( s = sval; *s; s++ ) {
430 #define ist61(c) (!isascii(c) || !isalnum(c) \
431 && c != 047 && c != '(' && c != ')' \
432 && c != '+' && c != '-' && c != '.' && c != ',' \
433 && c != '/' && c != ':' && c != '=' && c != '?' \
438 #define T61MARK "{T.61}"
441 news = malloc( strlen(sval) +
442 ncomp * T61MARKLEN + 1 );
443 strcpy( news, T61MARK );
444 for ( n = news + T61MARKLEN, s = sval;
448 strcpy( ++n, T61MARK );
457 av = str_at2AttrV( sval, as->attr_type );
458 } else if ( syntax == ldap_dn_syntax ) {
459 av = ldap_strdn2AttrV( sval );
460 } else if ( i != 0 && syntax == ldap_acl_syntax ) {
461 (void) (*merge_acl)( as->attr_value, sval );
465 av = ldap_str_at2AttrV( sval, as->attr_type );
468 if ( av == NULLAttrV ) {
469 send_ldap_msgresult( clientsb, op, m,
470 LDAP_INVALID_SYNTAX, NULL, sval );
478 as->attr_value = avs_merge( as->attr_value,
479 avs_comp_new( av ) );
486 modify_result( Sockbuf *sb, struct msg *m )
488 send_ldap_msgresult( sb, MODTAG, m, LDAP_SUCCESS, NULL, "" );
494 modlist_free( LDAPModList *mods )
498 for ( ; mods != NULL; mods = next ) {
499 free( mods->m.mod_type );
500 if ( mods->m.mod_bvalues != NULL )
501 ber_bvecfree( mods->m.mod_bvalues );
502 next = mods->mod_next;
508 * called when mod is replace to optimize by only deleting old values
509 * that are not in the new set and by only adding what isn't in old set
514 struct entrymod *rem,
519 AV_Sequence oavs, navs, davs, prev_navs, tmp;
523 ps = ps_alloc( std_open );
524 std_setup( ps, stderr );
526 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
527 ps_print( ps, "replace_mod(" );
528 AttrT_print( ps, oas->attr_type, EDBOUT );
529 ps_print( ps, ")\n" );
534 for ( oavs = oas->attr_value; oavs != NULL; oavs = oavs->avseq_next ) {
536 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
537 ps_print( ps, "old value " );
538 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
539 ps_print( ps, "\n" );
544 for ( navs = nas->attr_value; navs != NULL;
545 prev_navs = navs, navs = navs->avseq_next ) {
547 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
548 ps_print( ps, "\tnew value " );
549 AttrV_print( ps, &navs->avseq_av, EDBOUT );
550 ps_print( ps, "\n" );
553 if ( AttrV_cmp( &oavs->avseq_av, &navs->avseq_av)
559 if ( navs == NULL ) { /* value to delete */
561 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
562 ps_print( ps, "value to delete " );
563 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
564 ps_print( ps, "\n" );
567 if ( davs == NULL ) {
568 davs = avs_comp_cpy( oavs );
570 tmp = avs_comp_cpy( oavs );
571 tmp->avseq_next = davs;
574 } else { /* value to keep */
576 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
577 ps_print( ps, "value to leave alone " );
578 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
579 ps_print( ps, "\n" );
582 if ( prev_navs == NULL ) {
583 nas->attr_value = navs->avseq_next;
585 prev_navs->avseq_next = navs->avseq_next;
587 avs_comp_free( navs );
591 if ( davs == NULL && nas->attr_value == NULL ) {
593 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
594 ps_print( ps, " nothing to do" );
599 /* Must add new values before removing old values.
600 * Otherwise, removing all existing values causes the
601 * attribute to be removed such that subsequent add values
604 if ( nas->attr_value != NULL ) { /* add new values */
606 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
607 AttrT_print( ps, nas->attr_type, EDBOUT );
608 ps_print( ps, ": some to add\n" );
611 rem->em_type = EM_ADDVALUES;
613 rem->em_next = NULLMOD;
616 if ( davs != NULL ) { /* delete old values */
618 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
619 AttrT_print( ps, nas->attr_type, EDBOUT );
620 ps_print( ps, ": some to delete\n" );
623 if ( nas->attr_value != NULL ) {
624 rem->em_next = (struct entrymod *) calloc( 1,
625 sizeof(struct entrymod) );
628 rem->em_type = EM_REMOVEVALUES;
629 rem->em_what = as_comp_new( NULLAttrT, NULLAV,
631 rem->em_what->attr_type = AttrT_cpy( nas->attr_type );
632 rem->em_what->attr_value = davs;