2 * Copyright (c) 1990 Regents of the University of Michigan.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of Michigan at Ann Arbor. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
15 #include <quipu/commonarg.h>
16 #include <quipu/attrvalue.h>
17 #include <quipu/ds_error.h>
18 #include <quipu/modify.h>
19 #include <quipu/dap2.h>
20 #include <quipu/dua.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
27 static CommonArgs common = default_common_args;
29 extern short ldap_photo_syntax;
30 extern short ldap_jpeg_syntax;
31 extern short ldap_jpeg_nonfile_syntax;
32 extern short ldap_audio_syntax;
33 extern short ldap_dn_syntax;
34 extern short ldap_postaladdress_syntax;
35 extern short ldap_acl_syntax;
36 extern short ldap_mtai_syntax;
37 extern short ldap_rts_cred_syntax;
38 extern short ldap_rtl_syntax;
39 extern short ldap_octetstring_syntax;
43 extern int ldap_compat;
44 #define MODTAG (ldap_compat == 20 ? OLD_LDAP_RES_MODIFY : LDAP_RES_MODIFY)
46 #define MODTAG LDAP_RES_MODIFY
59 unsigned long tag, len;
60 LDAPMod *mods, *modtail;
61 struct ds_read_arg ra;
62 extern DN ldap_str2dn();
64 Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
67 * Parse the modify request. It looks like this:
68 * ModifyRequest := [APPLICATION 6] SEQUENCE {
69 * name DistinguishedName,
70 * mods SEQUENCE OF SEQUENCE {
71 * operation ENUMERATED {
76 * modification SEQUENCE {
78 * values SET OF AttributeValue
82 * We then have to initiate a read of the entry to be modified.
83 * The actual modification is done by do_modify2(), after the
87 #if ISODEPACKAGE == IC
89 DAS_ReadArgument_INIT( &ra );
93 if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
94 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
95 send_ldap_msgresult( clientsb, MODTAG, m,
96 LDAP_PROTOCOL_ERROR, NULL, "" );
100 Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
102 ra.rda_object = ldap_str2dn( dn );
104 if ( ra.rda_object == NULLDN ) {
105 Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
106 send_ldap_msgresult( clientsb, MODTAG, m,
107 LDAP_INVALID_DN_SYNTAX, NULL, "" );
110 ra.rda_eis.eis_allattributes = TRUE;
111 ra.rda_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
112 ra.rda_eis.eis_select = NULLATTR;
114 /* collect modifications & save for later */
115 mods = modtail = NULL;
116 for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
117 tag = ber_next_element( ber, &len, last ) ) {
120 if ( (tmp = (LDAPMod *) calloc( 1, sizeof(LDAPMod) ))
122 send_ldap_msgresult( clientsb, MODTAG, m,
123 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
127 if ( ber_scanf( ber, "{i{a[V]}}", &tmp->mod_op, &tmp->mod_type,
128 &tmp->mod_bvalues ) == LBER_ERROR ) {
129 send_ldap_msgresult( clientsb, MODTAG, m,
130 LDAP_PROTOCOL_ERROR, NULL, "" );
134 if ( mods == NULL ) {
137 modtail->mod_next = tmp;
143 ra.rda_common = common; /* struct copy */
145 rc = initiate_dap_operation( OP_READ, m, &ra );
147 dn_free( ra.rda_object );
150 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
161 struct ds_read_result *rr
164 struct ds_modifyentry_arg ma;
165 struct entrymod *changetail = NULLMOD;
169 Debug( LDAP_DEBUG_TRACE, "do_modify2\n", 0, 0, 0 );
171 #if ISODEPACKAGE == IC
173 DAS_ModifyEntryArgument_INIT( &ma );
177 ma.mea_changes = NULLMOD;
178 for ( mods = m->m_mods; mods != NULL; mods = mods->mod_next ) {
180 Attr_Sequence as, new, get_as();
182 if ( (em = (struct entrymod *) calloc( 1,
183 sizeof(struct entrymod) )) == NULLMOD ) {
184 send_ldap_msgresult( clientsb, MODTAG, m,
185 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
188 em->em_next = NULLMOD;
190 if ( (new = get_as( clientsb, MODTAG, m,
191 mods->mod_type, mods->mod_bvalues )) == NULLATTR )
195 for ( as = rr->rdr_entry.ent_attr; as != NULLATTR;
196 as = as->attr_link ) {
197 if ( AttrT_cmp( new->attr_type, as->attr_type ) == 0 )
201 if ( new->attr_value == NULLAV &&
202 mods->mod_op != LDAP_MOD_DELETE ) {
203 send_ldap_msgresult( clientsb, MODTAG, m,
204 LDAP_INVALID_SYNTAX, NULL, "No values specified" );
208 switch ( mods->mod_op ) {
210 Debug( LDAP_DEBUG_ARGS, "ADD:\n", 0, 0, 0 );
212 if ( as == NULLATTR ) {
213 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
215 em->em_type = EM_ADDATTRIBUTE;
217 Debug( LDAP_DEBUG_ARGS, "\tvalues\n", 0, 0, 0 );
218 em->em_type = EM_ADDVALUES;
222 case LDAP_MOD_DELETE:
223 Debug( LDAP_DEBUG_ARGS, "DELETE:\n", 0, 0, 0 );
225 if ( as == NULLATTR ) {
226 Debug( LDAP_DEBUG_ARGS,
227 "\tno existing attribute\n", 0, 0, 0 );
228 send_ldap_msgresult( clientsb, MODTAG,
229 m, LDAP_NO_SUCH_ATTRIBUTE, NULL, "" );
233 if ( new->attr_value == NULLAV ) {
234 Debug( LDAP_DEBUG_ARGS, "\tattribute\n",
236 em->em_type = EM_REMOVEATTRIBUTE;
238 if ( avs_cmp( new->attr_value,
239 as->attr_value ) == 0 ) {
240 Debug( LDAP_DEBUG_ARGS,
241 "\tattribute\n", 0, 0, 0 );
245 Debug( LDAP_DEBUG_ARGS,
246 "\tvalues\n", 0, 0, 0 );
247 em->em_type = EM_REMOVEVALUES;
253 case LDAP_MOD_REPLACE:
254 Debug( LDAP_DEBUG_ARGS, "REPLACE:\n", 0, 0, 0 );
256 if ( as == NULLATTR ) {
257 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
259 em->em_type = EM_ADDATTRIBUTE;
261 if ( replace_mod( em, as, new ) < 0 ) {
268 Debug( LDAP_DEBUG_ARGS, "UNKNOWN MOD:\n", 0, 0, 0 );
270 send_ldap_msgresult( clientsb, MODTAG, m,
271 LDAP_PROTOCOL_ERROR, NULL, "" );
276 if ( em->em_what == NULL ) { /* ignore this mod */
279 if ( ma.mea_changes == NULLMOD ) {
282 changetail->em_next = em;
284 changetail = em->em_next == NULLMOD ? em : em->em_next;
289 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
295 ps = ps_alloc( std_open );
296 std_setup( ps, stderr );
298 fprintf( stderr, "Modify changes are:\n");
299 for (e = ma.mea_changes; e; e = e->em_next) {
300 switch (e->em_type) {
301 case EM_ADDATTRIBUTE:
302 fprintf( stderr, "\tADD ATTRIBUTE\n");
304 case EM_REMOVEATTRIBUTE:
305 fprintf( stderr, "\tREMOVE ATTRIBUTE\n");
308 fprintf( stderr, "\tADD VALUES\n");
310 case EM_REMOVEVALUES:
311 fprintf( stderr, "\tREMOVE VALUES\n");
314 fprintf( stderr, "\tUNKNOWN\n");
319 fprintf( stderr, "\t\ttype (" );
320 AttrT_print( ps, as->attr_type, EDBOUT );
321 fprintf( stderr, ")" );
322 if ( e->em_type == EM_REMOVEATTRIBUTE ) {
323 fprintf( stderr, "\n" );
326 fprintf( stderr, " values" );
327 for (val = as->attr_value; val; val = val->avseq_next) {
328 ps_print( ps, " (" );
329 AttrV_print( ps, &val->avseq_av, EDBOUT );
332 fprintf( stderr, "\n" );
338 if ( ma.mea_changes == NULLMOD ) { /* nothing to do */
339 send_ldap_msgresult( clientsb, MODTAG, m,
340 LDAP_SUCCESS, NULL, "" );
344 ma.mea_object = rr->rdr_entry.ent_dn;
345 ma.mea_common = common; /* struct copy */
347 rc = initiate_dap_operation( OP_MODIFYENTRY, m, &ma );
349 ems_free( ma.mea_changes );
352 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
365 struct berval **bvals
372 Debug( LDAP_DEBUG_TRACE, "get_as\n", 0, 0, 0 );
374 if ( (as = as_comp_new( NULLAttrT, NULLAV, NULLACL_INFO ))
376 send_ldap_msgresult( clientsb, op, m,
377 LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
380 as->attr_link = NULLATTR;
381 as->attr_value = NULLAV;
382 as->attr_acl = NULLACL_INFO;
384 if ( (as->attr_type = str2AttrT( type )) == NULLAttrT ) {
385 send_ldap_msgresult( clientsb, op, m, LDAP_UNDEFINED_TYPE,
393 syntax = as->attr_type->oa_syntax;
394 for ( i = 0; bvals[i] != NULL; i++ ) {
397 char *sval, *s, *news, *n;
398 extern IFP merge_acl;
399 extern AttributeValue bv_asn2AttrV(), ldap_strdn2AttrV();
400 extern AttributeValue ldap_str_at2AttrV(), bv_octet2AttrV();
402 if ( syntax == ldap_jpeg_syntax ||
403 syntax == ldap_jpeg_nonfile_syntax ||
404 syntax == ldap_octetstring_syntax ||
405 syntax == ldap_audio_syntax ) {
406 if (( av = bv_octet2AttrV( bvals[i] )) == NULLAttrV ) {
407 send_ldap_msgresult( clientsb, op, m,
408 LDAP_INVALID_SYNTAX, NULL, type );
412 } else if ( syntax == ldap_photo_syntax ) {
413 if (( av = bv_asn2AttrV( bvals[i] )) == NULLAttrV ) {
414 send_ldap_msgresult( clientsb, op, m,
415 LDAP_INVALID_SYNTAX, NULL, type );
421 if (( sval = malloc( bvals[i]->bv_len + 1 )) == NULL ) {
422 send_ldap_msgresult( clientsb, op, m,
423 LDAP_OPERATIONS_ERROR, NULL,
427 SAFEMEMCPY( sval, bvals[i]->bv_val, bvals[i]->bv_len );
428 sval[ bvals[i]->bv_len ] = '\0';
430 /* dang quipu - there's no need for this! */
431 if ( syntax == ldap_postaladdress_syntax ) {
434 for ( s = sval; *s; s++ ) {
439 #define ist61(c) (!isascii(c) || !isalnum(c) \
440 && c != 047 && c != '(' && c != ')' \
441 && c != '+' && c != '-' && c != '.' && c != ',' \
442 && c != '/' && c != ':' && c != '=' && c != '?' \
447 #define T61MARK "{T.61}"
450 news = malloc( strlen(sval) +
451 ncomp * T61MARKLEN + 1 );
452 strcpy( news, T61MARK );
453 for ( n = news + T61MARKLEN, s = sval;
457 strcpy( ++n, T61MARK );
466 av = str_at2AttrV( sval, as->attr_type );
467 } else if ( syntax == ldap_dn_syntax ) {
468 av = ldap_strdn2AttrV( sval );
469 } else if ( i != 0 && syntax == ldap_acl_syntax ) {
470 (void) (*merge_acl)( as->attr_value, sval );
474 av = ldap_str_at2AttrV( sval, as->attr_type );
477 if ( av == NULLAttrV ) {
478 send_ldap_msgresult( clientsb, op, m,
479 LDAP_INVALID_SYNTAX, NULL, sval );
487 as->attr_value = avs_merge( as->attr_value,
488 avs_comp_new( av ) );
495 modify_result( Sockbuf *sb, struct msg *m )
497 send_ldap_msgresult( sb, MODTAG, m, LDAP_SUCCESS, NULL, "" );
503 modlist_free( LDAPMod *mods )
505 LDAPMod *next = NULL;
507 for ( ; mods != NULL; mods = next ) {
508 free( mods->mod_type );
509 if ( mods->mod_bvalues != NULL )
510 ber_bvecfree( mods->mod_bvalues );
516 * called when mod is replace to optimize by only deleting old values
517 * that are not in the new set and by only adding what isn't in old set
522 struct entrymod *rem,
527 AV_Sequence oavs, navs, davs, prev_navs, tmp;
531 ps = ps_alloc( std_open );
532 std_setup( ps, stderr );
534 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
535 ps_print( ps, "replace_mod(" );
536 AttrT_print( ps, oas->attr_type, EDBOUT );
537 ps_print( ps, ")\n" );
542 for ( oavs = oas->attr_value; oavs != NULL; oavs = oavs->avseq_next ) {
544 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
545 ps_print( ps, "old value " );
546 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
547 ps_print( ps, "\n" );
552 for ( navs = nas->attr_value; navs != NULL;
553 prev_navs = navs, navs = navs->avseq_next ) {
555 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
556 ps_print( ps, "\tnew value " );
557 AttrV_print( ps, &navs->avseq_av, EDBOUT );
558 ps_print( ps, "\n" );
561 if ( AttrV_cmp( &oavs->avseq_av, &navs->avseq_av)
567 if ( navs == NULL ) { /* value to delete */
569 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
570 ps_print( ps, "value to delete " );
571 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
572 ps_print( ps, "\n" );
575 if ( davs == NULL ) {
576 davs = avs_comp_cpy( oavs );
578 tmp = avs_comp_cpy( oavs );
579 tmp->avseq_next = davs;
582 } else { /* value to keep */
584 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
585 ps_print( ps, "value to leave alone " );
586 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
587 ps_print( ps, "\n" );
590 if ( prev_navs == NULL ) {
591 nas->attr_value = navs->avseq_next;
593 prev_navs->avseq_next = navs->avseq_next;
595 avs_comp_free( navs );
599 if ( davs == NULL && nas->attr_value == NULL ) {
601 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
602 ps_print( ps, " nothing to do" );
607 /* Must add new values before removing old values.
608 * Otherwise, removing all existing values causes the
609 * attribute to be removed such that subsequent add values
612 if ( nas->attr_value != NULL ) { /* add new values */
614 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
615 AttrT_print( ps, nas->attr_type, EDBOUT );
616 ps_print( ps, ": some to add\n" );
619 rem->em_type = EM_ADDVALUES;
621 rem->em_next = NULLMOD;
624 if ( davs != NULL ) { /* delete old values */
626 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
627 AttrT_print( ps, nas->attr_type, EDBOUT );
628 ps_print( ps, ": some to delete\n" );
631 if ( nas->attr_value != NULL ) {
632 rem->em_next = (struct entrymod *) calloc( 1,
633 sizeof(struct entrymod) );
636 rem->em_type = EM_REMOVEVALUES;
637 rem->em_what = as_comp_new( NULLAttrT, NULLAV,
639 rem->em_what->attr_type = AttrT_cpy( nas->attr_type );
640 rem->em_what->attr_value = davs;