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