]> git.sur5r.net Git - openldap/blob - servers/ldapd/modify.c
Some gcc -W... cleanup
[openldap] / servers / ldapd / modify.c
1 /*
2  * Copyright (c) 1990 Regents of the University of Michigan.
3  * All rights reserved.
4  *
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.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/ctype.h>
18 #include <ac/socket.h>
19 #include <ac/string.h>          /* get SAFEMEMCPY */
20
21 #include <quipu/commonarg.h>
22 #include <quipu/attrvalue.h>
23 #include <quipu/ds_error.h>
24 #include <quipu/modify.h>
25 #include <quipu/dap2.h>
26 #include <quipu/dua.h>
27
28 #include "lber.h"
29 #include "ldap.h"
30 #include "common.h"
31
32 static CommonArgs       common = default_common_args;
33
34 extern short    ldap_photo_syntax;
35 extern short    ldap_jpeg_syntax;
36 extern short    ldap_jpeg_nonfile_syntax;
37 extern short    ldap_audio_syntax;
38 extern short    ldap_dn_syntax;
39 extern short    ldap_postaladdress_syntax;
40 extern short    ldap_acl_syntax;
41 extern short    ldap_mtai_syntax;
42 extern short    ldap_rts_cred_syntax;
43 extern short    ldap_rtl_syntax;
44 extern short    ldap_octetstring_syntax;
45
46 static int replace_mod( struct entrymod *, Attr_Sequence, Attr_Sequence );
47
48 #ifdef LDAP_COMPAT20
49 extern int      ldap_compat;
50 #define MODTAG  (ldap_compat == 20 ? OLD_LDAP_RES_MODIFY : LDAP_RES_MODIFY)
51 #else
52 #define MODTAG  LDAP_RES_MODIFY
53 #endif
54
55 int
56 do_modify(
57     Sockbuf     *clientsb,
58     struct msg  *m,
59     BerElement  *ber
60 )
61 {
62         char                    *dn;
63         char                    *last;
64         int                     rc;
65         unsigned long           tag, len;
66         LDAPMod                 *mods, *modtail;
67         struct ds_read_arg      ra;
68         extern DN               ldap_str2dn();
69
70         Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
71
72         /*
73          * Parse the modify request.  It looks like this:
74          *      ModifyRequest := [APPLICATION 6] SEQUENCE {
75          *              name    DistinguishedName,
76          *              mods    SEQUENCE OF SEQUENCE {
77          *                      operation       ENUMERATED {
78          *                              add     (0),
79          *                              delete  (1),
80          *                              replace (2)
81          *                      },
82          *                      modification    SEQUENCE {
83          *                              type    AttributeType,
84          *                              values  SET OF AttributeValue
85          *                      }
86          *              }
87          *      }
88          * We then have to initiate a read of the entry to be modified.
89          * The actual modification is done by do_modify2(), after the
90          * read completes.
91          */
92
93 #if ISODEPACKAGE == IC
94 #if ICRELEASE > 2
95         DAS_ReadArgument_INIT( &ra );
96 #endif
97 #endif
98
99         if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
100                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
101                 send_ldap_msgresult( clientsb, MODTAG, m,
102                     LDAP_PROTOCOL_ERROR, NULL, "" );
103                 return( 0 );
104         }
105
106         Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
107
108         ra.rda_object = ldap_str2dn( dn );
109         free( dn );
110         if ( ra.rda_object == NULLDN ) {
111                 Debug( LDAP_DEBUG_ANY, "ldap_str2dn failed\n", 0, 0, 0 );
112                 send_ldap_msgresult( clientsb, MODTAG, m,
113                     LDAP_INVALID_DN_SYNTAX, NULL, "" );
114                 return( 0 );
115         }
116         ra.rda_eis.eis_allattributes = TRUE;
117         ra.rda_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
118         ra.rda_eis.eis_select = NULLATTR;
119
120         /* collect modifications & save for later */
121         mods = modtail = NULL;
122         for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
123             tag = ber_next_element( ber, &len, last ) ) {
124                 LDAPMod *tmp;
125
126                 if ( (tmp = (LDAPMod *) calloc( 1, sizeof(LDAPMod) ))
127                     == NULL ) {
128                         send_ldap_msgresult( clientsb, MODTAG, m,
129                             LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
130                         return( 0 );
131                 }
132                         
133                 if ( ber_scanf( ber, "{i{a[V]}}", &tmp->mod_op, &tmp->mod_type,
134                     &tmp->mod_bvalues ) == LBER_ERROR ) {
135                         send_ldap_msgresult( clientsb, MODTAG, m,
136                             LDAP_PROTOCOL_ERROR, NULL, "" );
137                         return( 0 );
138                 }
139
140                 if ( mods == NULL ) {
141                         mods = tmp;
142                 } else {
143                         modtail->mod_next = tmp;
144                 }
145                 modtail = tmp;
146         }
147         m->m_mods = mods;
148
149         ra.rda_common = common; /* struct copy */
150
151         rc = initiate_dap_operation( OP_READ, m, &ra );
152
153         dn_free( ra.rda_object );
154
155         if ( rc != 0 ) {
156                 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
157                 return( 0 );
158         }
159
160         return( 1 );
161 }
162
163 int
164 do_modify2(
165     Sockbuf                     *clientsb,
166     struct msg                  *m,
167     struct ds_read_result       *rr
168 )
169 {
170         struct ds_modifyentry_arg       ma;
171         struct entrymod                 *changetail = NULLMOD;
172         int                             rc;
173         LDAPMod                         *mods;
174
175         Debug( LDAP_DEBUG_TRACE, "do_modify2\n", 0, 0, 0 );
176
177 #if ISODEPACKAGE == IC
178 #if ICRELEASE > 2
179         DAS_ModifyEntryArgument_INIT( &ma );
180 #endif
181 #endif
182
183         ma.mea_changes = NULLMOD;
184         for ( mods = m->m_mods; mods != NULL; mods = mods->mod_next ) {
185                 struct entrymod *em;
186                 Attr_Sequence   as, new, get_as();
187
188                 if ( (em = (struct entrymod *) calloc( 1,
189                     sizeof(struct entrymod) )) == NULLMOD ) {
190                         send_ldap_msgresult( clientsb, MODTAG, m,
191                             LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
192                         return( 0 );
193                 }
194                 em->em_next = NULLMOD;
195
196                 if ( (new = get_as( clientsb, MODTAG, m,
197                     mods->mod_type, mods->mod_bvalues )) == NULLATTR )
198                         return( 0 );
199                 em->em_what = new;
200
201                 for ( as = rr->rdr_entry.ent_attr; as != NULLATTR;
202                     as = as->attr_link ) {
203                         if ( AttrT_cmp( new->attr_type, as->attr_type ) == 0 )
204                                 break;
205                 }
206
207                 if ( new->attr_value == NULLAV &&
208                     mods->mod_op != LDAP_MOD_DELETE ) {
209                         send_ldap_msgresult( clientsb, MODTAG, m,
210                             LDAP_INVALID_SYNTAX, NULL, "No values specified" );
211                         return( 0 );
212                 }
213
214                 switch ( mods->mod_op ) {
215                 case LDAP_MOD_ADD:
216                         Debug( LDAP_DEBUG_ARGS, "ADD:\n", 0, 0, 0 );
217
218                         if ( as == NULLATTR ) {
219                                 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
220                                     0 );
221                                 em->em_type = EM_ADDATTRIBUTE;
222                         } else {
223                                 Debug( LDAP_DEBUG_ARGS, "\tvalues\n", 0, 0, 0 );
224                                 em->em_type = EM_ADDVALUES;
225                         }
226                         break;
227
228                 case LDAP_MOD_DELETE:
229                         Debug( LDAP_DEBUG_ARGS, "DELETE:\n", 0, 0, 0 );
230
231                         if ( as == NULLATTR ) {
232                                 Debug( LDAP_DEBUG_ARGS,
233                                     "\tno existing attribute\n", 0, 0, 0 );
234                                 send_ldap_msgresult( clientsb, MODTAG,
235                                     m, LDAP_NO_SUCH_ATTRIBUTE, NULL, "" );
236                                 ems_free( em );
237                                 return( 0 );
238                         } else {
239                                 if ( new->attr_value == NULLAV ) {
240                                         Debug( LDAP_DEBUG_ARGS, "\tattribute\n",
241                                             0, 0, 0 );
242                                         em->em_type = EM_REMOVEATTRIBUTE;
243                                 } else {
244                                         if ( avs_cmp( new->attr_value,
245                                             as->attr_value ) == 0 ) {
246                                                 Debug( LDAP_DEBUG_ARGS,
247                                                     "\tattribute\n", 0, 0, 0 );
248                                                 em->em_type =
249                                                     EM_REMOVEATTRIBUTE;
250                                         } else {
251                                                 Debug( LDAP_DEBUG_ARGS,
252                                                     "\tvalues\n", 0, 0, 0 );
253                                                 em->em_type = EM_REMOVEVALUES;
254                                         }
255                                 }
256                         }
257                         break;
258
259                 case LDAP_MOD_REPLACE:
260                         Debug( LDAP_DEBUG_ARGS, "REPLACE:\n", 0, 0, 0 );
261
262                         if ( as == NULLATTR ) {
263                                 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
264                                     0 );
265                                 em->em_type = EM_ADDATTRIBUTE;
266                         } else {
267                                 if ( replace_mod( em, as, new ) < 0 ) {
268                                         return( 0 );
269                                 }
270                         }
271                         break;
272
273                 default:
274                         Debug( LDAP_DEBUG_ARGS, "UNKNOWN MOD:\n", 0, 0, 0 );
275
276                         send_ldap_msgresult( clientsb, MODTAG, m,
277                             LDAP_PROTOCOL_ERROR, NULL, "" );
278                         return( 0 );
279                         break;
280                 }
281
282                 if ( em->em_what == NULL ) {    /* ignore this mod */
283                         free( em );
284                 } else {
285                         if ( ma.mea_changes == NULLMOD ) {
286                                 ma.mea_changes = em;
287                         } else {
288                                 changetail->em_next = em;
289                         }
290                         changetail = em->em_next == NULLMOD ? em : em->em_next;
291                 }
292         }
293
294 #ifdef LDAP_DEBUG
295         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
296                 struct entrymod *e;
297                 Attr_Sequence   as;
298                 AV_Sequence     val;
299                 PS              ps;
300
301                 ps = ps_alloc( std_open );
302                 std_setup( ps, stderr );
303
304                 fprintf( stderr, "Modify changes are:\n");
305                 for (e = ma.mea_changes; e; e = e->em_next) {
306                         switch (e->em_type) {
307                         case EM_ADDATTRIBUTE:
308                                 fprintf( stderr, "\tADD ATTRIBUTE\n");
309                                 break;
310                         case EM_REMOVEATTRIBUTE:
311                                 fprintf( stderr, "\tREMOVE ATTRIBUTE\n");
312                                 break;
313                         case EM_ADDVALUES:
314                                 fprintf( stderr, "\tADD VALUES\n");
315                                 break;
316                         case EM_REMOVEVALUES:
317                                 fprintf( stderr, "\tREMOVE VALUES\n");
318                                 break;
319                         default:
320                                 fprintf( stderr, "\tUNKNOWN\n");
321                                 break;
322                         }
323
324                         as = e->em_what;
325                         fprintf( stderr, "\t\ttype (" );
326                         AttrT_print( ps, as->attr_type, EDBOUT );
327                         fprintf( stderr, ")" );
328                         if ( e->em_type == EM_REMOVEATTRIBUTE ) {
329                                 fprintf( stderr, "\n" );
330                                 continue;
331                         }
332                         fprintf( stderr, " values" );
333                         for (val = as->attr_value; val; val = val->avseq_next) {
334                                 ps_print( ps, " (" );
335                                 AttrV_print( ps, &val->avseq_av, EDBOUT );
336                                 ps_print( ps, ")" );
337                         }
338                         fprintf( stderr, "\n" );
339                 }
340                 ps_free( ps );
341         }
342 #endif
343
344         if ( ma.mea_changes == NULLMOD ) {      /* nothing to do */
345                 send_ldap_msgresult( clientsb, MODTAG, m,
346                     LDAP_SUCCESS, NULL, "" );
347                 return( 0 );
348         }
349
350         ma.mea_object = rr->rdr_entry.ent_dn;
351         ma.mea_common = common; /* struct copy */
352
353         rc = initiate_dap_operation( OP_MODIFYENTRY, m, &ma );
354
355         ems_free( ma.mea_changes );
356
357         if ( rc != 0 ) {
358                 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
359                 return( 0 );
360         }
361
362         return( 1 );
363 }
364
365 Attr_Sequence
366 get_as(
367     Sockbuf             *clientsb,
368     unsigned long       op,
369     struct msg          *m,
370     char                *type,
371     struct berval       **bvals
372 )
373 {
374         Attr_Sequence   as;
375         int             i;
376         short           syntax;
377
378         Debug( LDAP_DEBUG_TRACE, "get_as\n", 0, 0, 0 );
379
380         if ( (as = as_comp_new( NULLAttrT, NULLAV, NULLACL_INFO ))
381             == NULLATTR ) {
382                 send_ldap_msgresult( clientsb, op, m,
383                     LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
384                 return( NULLATTR );
385         }
386         as->attr_link = NULLATTR;
387         as->attr_value = NULLAV;
388         as->attr_acl = NULLACL_INFO;
389
390         if ( (as->attr_type = str2AttrT( type )) == NULLAttrT ) {
391               send_ldap_msgresult( clientsb, op, m, LDAP_UNDEFINED_TYPE,
392                   NULL, type );
393                 return( NULLATTR );
394         }
395
396         if ( bvals == NULL )
397                 return( as );
398
399         syntax = as->attr_type->oa_syntax;
400         for ( i = 0; bvals[i] != NULL; i++ ) {
401                 AttributeValue  av;
402                 int             t61str, ncomp;
403                 char            *sval, *s, *news, *n;
404                 extern IFP      merge_acl;
405                 extern AttributeValue   bv_asn2AttrV(), ldap_strdn2AttrV();
406                 extern AttributeValue   ldap_str_at2AttrV(), bv_octet2AttrV();
407
408                 if ( syntax == ldap_jpeg_syntax ||
409                     syntax == ldap_jpeg_nonfile_syntax ||
410                     syntax == ldap_octetstring_syntax ||
411                     syntax == ldap_audio_syntax ) {
412                         if (( av = bv_octet2AttrV( bvals[i] )) == NULLAttrV ) {
413                                 send_ldap_msgresult( clientsb, op, m,
414                                     LDAP_INVALID_SYNTAX, NULL, type );
415                                 as_free( as );
416                                 return( NULLATTR );
417                         }
418                 } else if ( syntax == ldap_photo_syntax ) {
419                         if (( av = bv_asn2AttrV( bvals[i] )) == NULLAttrV ) {
420                                 send_ldap_msgresult( clientsb, op, m,
421                                     LDAP_INVALID_SYNTAX, NULL, type );
422                                 as_free( as );
423                                 return( NULLATTR );
424                         }
425                 } else {
426
427                         if (( sval = malloc( bvals[i]->bv_len + 1 )) == NULL ) {
428                                 send_ldap_msgresult( clientsb, op, m,
429                                     LDAP_OPERATIONS_ERROR, NULL,
430                                   "Malloc error" );
431                                 return( NULLATTR );
432                         }
433                         SAFEMEMCPY( sval, bvals[i]->bv_val, bvals[i]->bv_len );
434                         sval[ bvals[i]->bv_len ] = '\0';
435
436                         /* dang quipu - there's no need for this! */
437                         if ( syntax == ldap_postaladdress_syntax ) {
438                                 t61str = 0;
439                                 ncomp = 1;
440                                 for ( s = sval; *s; s++ ) {
441                                         if ( *s == '$' ) {
442                                                 ncomp++;
443                                                 continue;
444                                         }
445 #define ist61(c)  (!isascii(c) || !isalnum(c) \
446                           && c != 047 && c != '(' && c != ')' \
447                           && c != '+' && c != '-' && c != '.' && c != ',' \
448                           && c != '/' && c != ':' && c != '=' && c != '?' \
449                           && c != ' ')
450                                         if ( ist61( *s ) )
451                                                 t61str = 1;
452                                 }
453 #define T61MARK         "{T.61}"
454 #define T61MARKLEN      6
455                                 if ( t61str ) {
456                                         news = malloc( strlen(sval) +
457                                             ncomp * T61MARKLEN + 1 );
458                                         strcpy( news, T61MARK );
459                                         for ( n = news + T61MARKLEN, s = sval;
460                                             *s; n++, s++ ) {
461                                                 *n = *s;
462                                                 if ( *s == '$' ) {
463                                                         strcpy( ++n, T61MARK );
464                                                         n += T61MARKLEN - 1;
465                                                 }
466                                         }
467                                         *n = '\0';
468                                         free( sval );
469                                         sval = news;
470                                 }
471
472                                 av = str_at2AttrV( sval, as->attr_type );
473                         } else if ( syntax == ldap_dn_syntax ) {
474                                 av = ldap_strdn2AttrV( sval );
475                         } else if ( i != 0 && syntax == ldap_acl_syntax ) {
476                                 (void) (*merge_acl)( as->attr_value, sval );
477                                 free( sval );
478                                 continue;
479                         } else {
480                                 av = ldap_str_at2AttrV( sval, as->attr_type );
481                         }
482
483                         if ( av == NULLAttrV ) {
484                                 send_ldap_msgresult( clientsb, op, m,
485                                     LDAP_INVALID_SYNTAX, NULL, sval );
486                                 free( sval );
487                                 as_free( as );
488                                 return( NULLATTR );
489                         }
490
491                         free( sval );
492                 }
493                 as->attr_value = avs_merge( as->attr_value,
494                     avs_comp_new( av ) );
495         }
496
497         return( as );
498 }
499
500 void
501 modify_result( Sockbuf *sb, struct msg *m )
502 {
503         send_ldap_msgresult( sb, MODTAG, m, LDAP_SUCCESS, NULL, "" );
504
505         return;
506 }
507
508 void
509 modlist_free( LDAPMod *mods )
510 {
511         LDAPMod *next = NULL;
512
513         for ( ; mods != NULL; mods = next ) {
514                 free( mods->mod_type );
515                 if ( mods->mod_bvalues != NULL )
516                         ber_bvecfree( mods->mod_bvalues );
517                 free( mods );
518         }
519 }
520
521 /*
522  * called when mod is replace to optimize by only deleting old values
523  * that are not in the new set and by only adding what isn't in old set
524  */
525
526 static int
527 replace_mod(
528     struct entrymod     *rem,
529     Attr_Sequence       oas,
530     Attr_Sequence       nas
531 )
532 {
533         AV_Sequence     oavs, navs, davs, prev_navs, tmp;
534 #ifdef LDAP_DEBUG
535         PS              ps;
536
537         ps = ps_alloc( std_open );
538         std_setup( ps, stderr );
539
540         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
541                 ps_print( ps, "replace_mod(" );
542                 AttrT_print( ps, oas->attr_type, EDBOUT );
543                 ps_print( ps, ")\n" );
544         }
545 #endif
546
547         davs = NULL;
548         for ( oavs = oas->attr_value; oavs != NULL; oavs = oavs->avseq_next ) {
549 #ifdef LDAP_DEBUG
550                 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
551                         ps_print( ps, "old value " );
552                         AttrV_print( ps, &oavs->avseq_av, EDBOUT );
553                         ps_print( ps, "\n" );
554                 }
555 #endif
556
557                 prev_navs = NULL;
558                 for ( navs = nas->attr_value; navs != NULL;
559                     prev_navs = navs, navs = navs->avseq_next ) {
560 #ifdef LDAP_DEBUG
561                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
562                                 ps_print( ps, "\tnew value " );
563                                 AttrV_print( ps, &navs->avseq_av, EDBOUT );
564                                 ps_print( ps, "\n" );
565                         }
566 #endif
567                         if ( AttrV_cmp( &oavs->avseq_av, &navs->avseq_av)
568                             == 0) {
569                                 break;
570                         }
571                 }
572
573                 if ( navs == NULL ) {   /* value to delete */
574 #ifdef LDAP_DEBUG
575                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
576                                 ps_print( ps, "value to delete " );
577                                 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
578                                 ps_print( ps, "\n" );
579                         }
580 #endif
581                         if ( davs == NULL ) {
582                             davs = avs_comp_cpy( oavs );
583                         } else {
584                             tmp = avs_comp_cpy( oavs );
585                             tmp->avseq_next = davs;
586                             davs = tmp;
587                         }
588                 } else {                /* value to keep */
589 #ifdef LDAP_DEBUG
590                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
591                                 ps_print( ps, "value to leave alone " );
592                                 AttrV_print( ps, &oavs->avseq_av, EDBOUT );
593                                 ps_print( ps, "\n" );
594                         }
595 #endif
596                         if ( prev_navs == NULL ) {
597                             nas->attr_value = navs->avseq_next;
598                         } else {
599                             prev_navs->avseq_next = navs->avseq_next;
600                         }
601                         avs_comp_free( navs );
602                 }
603         }
604
605         if ( davs == NULL && nas->attr_value == NULL ) {
606 #ifdef LDAP_DEBUG
607                 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
608                         ps_print( ps, "  nothing to do" );
609                 }
610 #endif
611                 rem->em_what = NULL;
612         } else {
613             /*  Must add new values before removing old values.
614              *  Otherwise, removing all existing values causes the
615              *  attribute to be removed such that subsequent add values
616              *  fail.
617              */
618                 if ( nas->attr_value != NULL ) {        /* add new values */
619 #ifdef LDAP_DEBUG
620                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
621                                 AttrT_print( ps, nas->attr_type, EDBOUT );
622                                 ps_print( ps, ": some to add\n" );
623                         }
624 #endif
625                         rem->em_type = EM_ADDVALUES;
626                         rem->em_what = nas;
627                         rem->em_next = NULLMOD;
628                 }
629
630                 if ( davs != NULL ) {   /* delete old values */
631 #ifdef LDAP_DEBUG
632                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
633                                 AttrT_print( ps, nas->attr_type, EDBOUT );
634                                 ps_print( ps, ": some to delete\n" );
635                         }
636 #endif
637                         if ( nas->attr_value != NULL ) {
638                                 rem->em_next = (struct entrymod *) calloc( 1,
639                                     sizeof(struct entrymod) );
640                                 rem = rem->em_next;
641                         }
642                         rem->em_type = EM_REMOVEVALUES;
643                         rem->em_what = as_comp_new( NULLAttrT, NULLAV,
644                             NULLACL_INFO );
645                         rem->em_what->attr_type = AttrT_cpy( nas->attr_type );
646                         rem->em_what->attr_value = davs;
647                 }
648         }
649
650         return( 0 );
651 }