]> git.sur5r.net Git - openldap/blob - servers/ldapd/modify.c
LDAPworldP21: SLAPD Memory leak/error in filterentry.c
[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 <stdio.h>
14 #include <ctype.h>
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>
23 #include "lber.h"
24 #include "ldap.h"
25 #include "common.h"
26
27 static CommonArgs       common = default_common_args;
28
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;
40
41
42 #ifdef COMPAT20
43 extern int      ldap_compat;
44 #define MODTAG  (ldap_compat == 20 ? OLD_LDAP_RES_MODIFY : LDAP_RES_MODIFY)
45 #else
46 #define MODTAG  LDAP_RES_MODIFY
47 #endif
48
49 int
50 do_modify(
51     Sockbuf     *clientsb,
52     struct msg  *m,
53     BerElement  *ber
54 )
55 {
56         char                    *dn;
57         char                    *last;
58         int                     rc;
59         unsigned long           tag, len;
60         LDAPMod                 *mods, *modtail;
61         struct ds_read_arg      ra;
62         extern DN               ldap_str2dn();
63
64         Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
65
66         /*
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 {
72          *                              add     (0),
73          *                              delete  (1),
74          *                              replace (2)
75          *                      },
76          *                      modification    SEQUENCE {
77          *                              type    AttributeType,
78          *                              values  SET OF AttributeValue
79          *                      }
80          *              }
81          *      }
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
84          * read completes.
85          */
86
87 #if ISODEPACKAGE == IC
88 #if ICRELEASE > 2
89         DAS_ReadArgument_INIT( &ra );
90 #endif
91 #endif
92
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, "" );
97                 return( 0 );
98         }
99
100         Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
101
102         ra.rda_object = ldap_str2dn( dn );
103         free( 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, "" );
108                 return( 0 );
109         }
110         ra.rda_eis.eis_allattributes = TRUE;
111         ra.rda_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
112         ra.rda_eis.eis_select = NULLATTR;
113
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 ) ) {
118                 LDAPMod *tmp;
119
120                 if ( (tmp = (LDAPMod *) calloc( 1, sizeof(LDAPMod) ))
121                     == NULL ) {
122                         send_ldap_msgresult( clientsb, MODTAG, m,
123                             LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
124                         return( 0 );
125                 }
126                         
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, "" );
131                         return( 0 );
132                 }
133
134                 if ( mods == NULL ) {
135                         mods = tmp;
136                 } else {
137                         modtail->mod_next = tmp;
138                 }
139                 modtail = tmp;
140         }
141         m->m_mods = mods;
142
143         ra.rda_common = common; /* struct copy */
144
145         rc = initiate_dap_operation( OP_READ, m, &ra );
146
147         dn_free( ra.rda_object );
148
149         if ( rc != 0 ) {
150                 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
151                 return( 0 );
152         }
153
154         return( 1 );
155 }
156
157 int
158 do_modify2(
159     Sockbuf                     *clientsb,
160     struct msg                  *m,
161     struct ds_read_result       *rr
162 )
163 {
164         struct ds_modifyentry_arg       ma;
165         struct entrymod                 *changetail = NULLMOD;
166         int                             rc;
167         LDAPMod                         *mods;
168
169         Debug( LDAP_DEBUG_TRACE, "do_modify2\n", 0, 0, 0 );
170
171 #if ISODEPACKAGE == IC
172 #if ICRELEASE > 2
173         DAS_ModifyEntryArgument_INIT( &ma );
174 #endif
175 #endif
176
177         ma.mea_changes = NULLMOD;
178         for ( mods = m->m_mods; mods != NULL; mods = mods->mod_next ) {
179                 struct entrymod *em;
180                 Attr_Sequence   as, new, get_as();
181
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" );
186                         return( 0 );
187                 }
188                 em->em_next = NULLMOD;
189
190                 if ( (new = get_as( clientsb, MODTAG, m,
191                     mods->mod_type, mods->mod_bvalues )) == NULLATTR )
192                         return( 0 );
193                 em->em_what = new;
194
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 )
198                                 break;
199                 }
200
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" );
205                         return( 0 );
206                 }
207
208                 switch ( mods->mod_op ) {
209                 case LDAP_MOD_ADD:
210                         Debug( LDAP_DEBUG_ARGS, "ADD:\n", 0, 0, 0 );
211
212                         if ( as == NULLATTR ) {
213                                 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
214                                     0 );
215                                 em->em_type = EM_ADDATTRIBUTE;
216                         } else {
217                                 Debug( LDAP_DEBUG_ARGS, "\tvalues\n", 0, 0, 0 );
218                                 em->em_type = EM_ADDVALUES;
219                         }
220                         break;
221
222                 case LDAP_MOD_DELETE:
223                         Debug( LDAP_DEBUG_ARGS, "DELETE:\n", 0, 0, 0 );
224
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, "" );
230                                 ems_free( em );
231                                 return( 0 );
232                         } else {
233                                 if ( new->attr_value == NULLAV ) {
234                                         Debug( LDAP_DEBUG_ARGS, "\tattribute\n",
235                                             0, 0, 0 );
236                                         em->em_type = EM_REMOVEATTRIBUTE;
237                                 } else {
238                                         if ( avs_cmp( new->attr_value,
239                                             as->attr_value ) == 0 ) {
240                                                 Debug( LDAP_DEBUG_ARGS,
241                                                     "\tattribute\n", 0, 0, 0 );
242                                                 em->em_type =
243                                                     EM_REMOVEATTRIBUTE;
244                                         } else {
245                                                 Debug( LDAP_DEBUG_ARGS,
246                                                     "\tvalues\n", 0, 0, 0 );
247                                                 em->em_type = EM_REMOVEVALUES;
248                                         }
249                                 }
250                         }
251                         break;
252
253                 case LDAP_MOD_REPLACE:
254                         Debug( LDAP_DEBUG_ARGS, "REPLACE:\n", 0, 0, 0 );
255
256                         if ( as == NULLATTR ) {
257                                 Debug( LDAP_DEBUG_ARGS, "\tattribute\n", 0, 0,
258                                     0 );
259                                 em->em_type = EM_ADDATTRIBUTE;
260                         } else {
261                                 if ( replace_mod( em, as, new ) < 0 ) {
262                                         return( 0 );
263                                 }
264                         }
265                         break;
266
267                 default:
268                         Debug( LDAP_DEBUG_ARGS, "UNKNOWN MOD:\n", 0, 0, 0 );
269
270                         send_ldap_msgresult( clientsb, MODTAG, m,
271                             LDAP_PROTOCOL_ERROR, NULL, "" );
272                         return( 0 );
273                         break;
274                 }
275
276                 if ( em->em_what == NULL ) {    /* ignore this mod */
277                         free( em );
278                 } else {
279                         if ( ma.mea_changes == NULLMOD ) {
280                                 ma.mea_changes = em;
281                         } else {
282                                 changetail->em_next = em;
283                         }
284                         changetail = em->em_next == NULLMOD ? em : em->em_next;
285                 }
286         }
287
288 #ifdef LDAP_DEBUG
289         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
290                 struct entrymod *e;
291                 Attr_Sequence   as;
292                 AV_Sequence     val;
293                 PS              ps;
294
295                 ps = ps_alloc( std_open );
296                 std_setup( ps, stderr );
297
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");
303                                 break;
304                         case EM_REMOVEATTRIBUTE:
305                                 fprintf( stderr, "\tREMOVE ATTRIBUTE\n");
306                                 break;
307                         case EM_ADDVALUES:
308                                 fprintf( stderr, "\tADD VALUES\n");
309                                 break;
310                         case EM_REMOVEVALUES:
311                                 fprintf( stderr, "\tREMOVE VALUES\n");
312                                 break;
313                         default:
314                                 fprintf( stderr, "\tUNKNOWN\n");
315                                 break;
316                         }
317
318                         as = e->em_what;
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" );
324                                 continue;
325                         }
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 );
330                                 ps_print( ps, ")" );
331                         }
332                         fprintf( stderr, "\n" );
333                 }
334                 ps_free( ps );
335         }
336 #endif
337
338         if ( ma.mea_changes == NULLMOD ) {      /* nothing to do */
339                 send_ldap_msgresult( clientsb, MODTAG, m,
340                     LDAP_SUCCESS, NULL, "" );
341                 return( 0 );
342         }
343
344         ma.mea_object = rr->rdr_entry.ent_dn;
345         ma.mea_common = common; /* struct copy */
346
347         rc = initiate_dap_operation( OP_MODIFYENTRY, m, &ma );
348
349         ems_free( ma.mea_changes );
350
351         if ( rc != 0 ) {
352                 send_ldap_msgresult( clientsb, MODTAG, m, rc, NULL, "" );
353                 return( 0 );
354         }
355
356         return( 1 );
357 }
358
359 Attr_Sequence
360 get_as(
361     Sockbuf             *clientsb,
362     unsigned long       op,
363     struct msg          *m,
364     char                *type,
365     struct berval       **bvals
366 )
367 {
368         Attr_Sequence   as;
369         int             i;
370         short           syntax;
371
372         Debug( LDAP_DEBUG_TRACE, "get_as\n", 0, 0, 0 );
373
374         if ( (as = as_comp_new( NULLAttrT, NULLAV, NULLACL_INFO ))
375             == NULLATTR ) {
376                 send_ldap_msgresult( clientsb, op, m,
377                     LDAP_OPERATIONS_ERROR, NULL, "Malloc error" );
378                 return( NULLATTR );
379         }
380         as->attr_link = NULLATTR;
381         as->attr_value = NULLAV;
382         as->attr_acl = NULLACL_INFO;
383
384         if ( (as->attr_type = str2AttrT( type )) == NULLAttrT ) {
385               send_ldap_msgresult( clientsb, op, m, LDAP_UNDEFINED_TYPE,
386                   NULL, type );
387                 return( NULLATTR );
388         }
389
390         if ( bvals == NULL )
391                 return( as );
392
393         syntax = as->attr_type->oa_syntax;
394         for ( i = 0; bvals[i] != NULL; i++ ) {
395                 AttributeValue  av;
396                 int             t61str, ncomp;
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();
401
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 );
409                                 as_free( as );
410                                 return( NULLATTR );
411                         }
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 );
416                                 as_free( as );
417                                 return( NULLATTR );
418                         }
419                 } else {
420
421                         if (( sval = malloc( bvals[i]->bv_len + 1 )) == NULL ) {
422                                 send_ldap_msgresult( clientsb, op, m,
423                                     LDAP_OPERATIONS_ERROR, NULL,
424                                   "Malloc error" );
425                                 return( NULLATTR );
426                         }
427                         SAFEMEMCPY( sval, bvals[i]->bv_val, bvals[i]->bv_len );
428                         sval[ bvals[i]->bv_len ] = '\0';
429
430                         /* dang quipu - there's no need for this! */
431                         if ( syntax == ldap_postaladdress_syntax ) {
432                                 t61str = 0;
433                                 ncomp = 1;
434                                 for ( s = sval; *s; s++ ) {
435                                         if ( *s == '$' ) {
436                                                 ncomp++;
437                                                 continue;
438                                         }
439 #define ist61(c)  (!isascii(c) || !isalnum(c) \
440                           && c != 047 && c != '(' && c != ')' \
441                           && c != '+' && c != '-' && c != '.' && c != ',' \
442                           && c != '/' && c != ':' && c != '=' && c != '?' \
443                           && c != ' ')
444                                         if ( ist61( *s ) )
445                                                 t61str = 1;
446                                 }
447 #define T61MARK         "{T.61}"
448 #define T61MARKLEN      6
449                                 if ( t61str ) {
450                                         news = malloc( strlen(sval) +
451                                             ncomp * T61MARKLEN + 1 );
452                                         strcpy( news, T61MARK );
453                                         for ( n = news + T61MARKLEN, s = sval;
454                                             *s; n++, s++ ) {
455                                                 *n = *s;
456                                                 if ( *s == '$' ) {
457                                                         strcpy( ++n, T61MARK );
458                                                         n += T61MARKLEN - 1;
459                                                 }
460                                         }
461                                         *n = '\0';
462                                         free( sval );
463                                         sval = news;
464                                 }
465
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 );
471                                 free( sval );
472                                 continue;
473                         } else {
474                                 av = ldap_str_at2AttrV( sval, as->attr_type );
475                         }
476
477                         if ( av == NULLAttrV ) {
478                                 send_ldap_msgresult( clientsb, op, m,
479                                     LDAP_INVALID_SYNTAX, NULL, sval );
480                                 free( sval );
481                                 as_free( as );
482                                 return( NULLATTR );
483                         }
484
485                         free( sval );
486                 }
487                 as->attr_value = avs_merge( as->attr_value,
488                     avs_comp_new( av ) );
489         }
490
491         return( as );
492 }
493
494 void
495 modify_result( Sockbuf *sb, struct msg *m )
496 {
497         send_ldap_msgresult( sb, MODTAG, m, LDAP_SUCCESS, NULL, "" );
498
499         return;
500 }
501
502 void
503 modlist_free( LDAPMod *mods )
504 {
505         LDAPMod *next = NULL;
506
507         for ( ; mods != NULL; mods = next ) {
508                 free( mods->mod_type );
509                 if ( mods->mod_bvalues != NULL )
510                         ber_bvecfree( mods->mod_bvalues );
511                 free( mods );
512         }
513 }
514
515 /*
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
518  */
519
520 int
521 replace_mod(
522     struct entrymod     *rem,
523     Attr_Sequence       oas,
524     Attr_Sequence       nas
525 )
526 {
527         AV_Sequence     oavs, navs, davs, prev_navs, tmp;
528 #ifdef LDAP_DEBUG
529         PS              ps;
530
531         ps = ps_alloc( std_open );
532         std_setup( ps, stderr );
533
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" );
538         }
539 #endif
540
541         davs = NULL;
542         for ( oavs = oas->attr_value; oavs != NULL; oavs = oavs->avseq_next ) {
543 #ifdef LDAP_DEBUG
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" );
548                 }
549 #endif
550
551                 prev_navs = NULL;
552                 for ( navs = nas->attr_value; navs != NULL;
553                     prev_navs = navs, navs = navs->avseq_next ) {
554 #ifdef LDAP_DEBUG
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" );
559                         }
560 #endif
561                         if ( AttrV_cmp( &oavs->avseq_av, &navs->avseq_av)
562                             == 0) {
563                                 break;
564                         }
565                 }
566
567                 if ( navs == NULL ) {   /* value to delete */
568 #ifdef LDAP_DEBUG
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" );
573                         }
574 #endif
575                         if ( davs == NULL ) {
576                             davs = avs_comp_cpy( oavs );
577                         } else {
578                             tmp = avs_comp_cpy( oavs );
579                             tmp->avseq_next = davs;
580                             davs = tmp;
581                         }
582                 } else {                /* value to keep */
583 #ifdef LDAP_DEBUG
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" );
588                         }
589 #endif
590                         if ( prev_navs == NULL ) {
591                             nas->attr_value = navs->avseq_next;
592                         } else {
593                             prev_navs->avseq_next = navs->avseq_next;
594                         }
595                         avs_comp_free( navs );
596                 }
597         }
598
599         if ( davs == NULL && nas->attr_value == NULL ) {
600 #ifdef LDAP_DEBUG
601                 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
602                         ps_print( ps, "  nothing to do" );
603                 }
604 #endif
605                 rem->em_what = NULL;
606         } else {
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
610              *  fail.
611              */
612                 if ( nas->attr_value != NULL ) {        /* add new values */
613 #ifdef LDAP_DEBUG
614                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
615                                 AttrT_print( ps, nas->attr_type, EDBOUT );
616                                 ps_print( ps, ": some to add\n" );
617                         }
618 #endif
619                         rem->em_type = EM_ADDVALUES;
620                         rem->em_what = nas;
621                         rem->em_next = NULLMOD;
622                 }
623
624                 if ( davs != NULL ) {   /* delete old values */
625 #ifdef LDAP_DEBUG
626                         if ( ldap_debug & LDAP_DEBUG_ARGS ) {
627                                 AttrT_print( ps, nas->attr_type, EDBOUT );
628                                 ps_print( ps, ": some to delete\n" );
629                         }
630 #endif
631                         if ( nas->attr_value != NULL ) {
632                                 rem->em_next = (struct entrymod *) calloc( 1,
633                                     sizeof(struct entrymod) );
634                                 rem = rem->em_next;
635                         }
636                         rem->em_type = EM_REMOVEVALUES;
637                         rem->em_what = as_comp_new( NULLAttrT, NULLAV,
638                             NULLACL_INFO );
639                         rem->em_what->attr_type = AttrT_cpy( nas->attr_type );
640                         rem->em_what->attr_value = davs;
641                 }
642         }
643
644         return( 0 );
645 }