1 /*        $NetBSD: ldifutil.c,v 1.2 2021/08/14 16:14:56 christos Exp $          */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
18  * All rights reserved.
19  */
20 
21 /*
22  * This file contains public API to help with parsing LDIF
23  */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: ldifutil.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 
32 #include <ac/stdlib.h>
33 #include <ac/ctype.h>
34 #include <ac/string.h>
35 #include <ac/unistd.h>
36 #include <ac/socket.h>
37 #include <ac/time.h>
38 
39 #include "ldap-int.h"
40 #include "ldif.h"
41 
42 #define   M_SEP     0x7f
43 
44 /* strings found in LDIF entries */
45 static struct berval BV_VERSION = BER_BVC("version");
46 static struct berval BV_DN = BER_BVC("dn");
47 static struct berval BV_CONTROL = BER_BVC("control");
48 static struct berval BV_CHANGETYPE = BER_BVC("changetype");
49 static struct berval BV_ADDCT = BER_BVC("add");
50 static struct berval BV_MODIFYCT = BER_BVC("modify");
51 static struct berval BV_DELETECT = BER_BVC("delete");
52 static struct berval BV_MODRDNCT = BER_BVC("modrdn");
53 static struct berval BV_MODDNCT = BER_BVC("moddn");
54 static struct berval BV_RENAMECT = BER_BVC("rename");
55 static struct berval BV_MODOPADD = BER_BVC("add");
56 static struct berval BV_MODOPREPLACE = BER_BVC("replace");
57 static struct berval BV_MODOPDELETE = BER_BVC("delete");
58 static struct berval BV_MODOPINCREMENT = BER_BVC("increment");
59 static struct berval BV_NEWRDN = BER_BVC("newrdn");
60 static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn");
61 static struct berval BV_NEWSUP = BER_BVC("newsuperior");
62 
63 #define   BV_CASEMATCH(a, b) \
64           ((a)->bv_len == (b)->bv_len && 0 == strcasecmp((a)->bv_val, (b)->bv_val))
65 
66 static int parse_ldif_control LDAP_P(( struct berval *bval, LDAPControl ***ppctrls ));
67 
68 void
ldap_ldif_record_done(LDIFRecord * lr)69 ldap_ldif_record_done( LDIFRecord *lr )
70 {
71           int i;
72 
73           /* the LDAPControl stuff does not allow the use of memory contexts */
74           if (lr->lr_ctrls != NULL) {
75                     ldap_controls_free( lr->lr_ctrls );
76           }
77           if ( lr->lr_lm != NULL ) {
78                     ber_memfree_x( lr->lr_lm, lr->lr_ctx );
79           }
80           if ( lr->lr_mops != NULL ) {
81                     ber_memfree_x( lr->lr_mops, lr->lr_ctx );
82           }
83           for (i=lr->lr_lines-1; i>=0; i--)
84                     if ( lr->lr_freeval[i] ) ber_memfree_x( lr->lr_vals[i].bv_val, lr->lr_ctx );
85           ber_memfree_x( lr->lr_btype, lr->lr_ctx );
86 
87           memset( lr, 0, sizeof(LDIFRecord) );
88 }
89 
90 /*
91  * ldap_parse_ldif_record_x() will convert an LDIF record read with ldif_read_record()
92  * into an array of LDAPMod* and an array of LDAPControl*, suitable for passing
93  * directly to any other LDAP API function that takes LDAPMod** and LDAPControl**
94  * arguments, such as ldap_modify_s().
95  *
96  * rbuf - the ldif record buffer returned from ldif_read_record - rbuf.bv_val must be
97  *        writable - will use ldif_getline to read from it
98  * linenum - the ldif line number returned from ldif_read_record
99  *         - used for logging errors (e.g. error at line N)
100  * lr - holds the data to return
101  * errstr - a string used for logging (usually the program name e.g. "ldapmodify"
102  * flags - 0 or some combination of LDIF_DEFAULT_ADD LDIF_ENTRIES_ONLY LDIF_NO_CONTROLS
103  * ctx is the memory allocation context - if NULL, use the standard memory allocator
104  */
105 int
ldap_parse_ldif_record_x(struct berval * rbuf,unsigned long linenum,LDIFRecord * lr,const char * errstr,unsigned int flags,void * ctx)106 ldap_parse_ldif_record_x(
107           struct berval *rbuf,
108           unsigned long linenum,
109           LDIFRecord *lr,
110           const char *errstr,
111           unsigned int flags,
112           void *ctx )
113 {
114           char      *line, *dn;
115           int                 rc, modop;
116           int                 expect_modop, expect_sep;
117           int                 ldapadd, new_entry, delete_entry, got_all, no_dn;
118           LDAPMod   **pmods;
119           int version;
120           LDAPControl **pctrls;
121           int i, j, k, idn, nmods;
122           struct berval **bvl, bv;
123 
124           assert( lr != NULL );
125           assert( rbuf != NULL );
126           memset( lr, 0, sizeof(LDIFRecord) );
127           lr->lr_ctx = ctx; /* save memory context for later */
128           ldapadd = flags & LDIF_DEFAULT_ADD;
129           no_dn = flags & LDIF_NO_DN;
130           expect_modop = flags & LDIF_MODS_ONLY;
131           new_entry = ldapadd;
132 
133           rc = got_all = delete_entry = modop = 0;
134           expect_sep = 0;
135           version = 0;
136           pmods = NULL;
137           pctrls = NULL;
138           dn = NULL;
139 
140           lr->lr_lines = ldif_countlines( rbuf->bv_val );
141           lr->lr_btype = ber_memcalloc_x( 1, (lr->lr_lines+1)*2*sizeof(struct berval)+lr->lr_lines, ctx );
142           if ( !lr->lr_btype )
143                     return LDAP_NO_MEMORY;
144 
145           lr->lr_vals = lr->lr_btype+lr->lr_lines+1;
146           lr->lr_freeval = (char *)(lr->lr_vals+lr->lr_lines+1);
147           i = -1;
148 
149           while ( rc == 0 && ( line = ldif_getline( &rbuf->bv_val )) != NULL ) {
150                     int freev;
151 
152                     if ( *line == '\n' || *line == '\0' ) {
153                               break;
154                     }
155 
156                     ++i;
157 
158                     if ( line[0] == '-' && !line[1] ) {
159                               BER_BVZERO( lr->lr_btype+i );
160                               lr->lr_freeval[i] = 0;
161                               continue;
162                     }
163 
164                     if ( ( rc = ldif_parse_line2( line, lr->lr_btype+i, lr->lr_vals+i, &freev ) ) < 0 ) {
165                               fprintf( stderr, _("%s: invalid format (line %lu) entry: \"%s\"\n"),
166                                         errstr, linenum+i, dn == NULL ? "" : dn );
167                               rc = LDAP_PARAM_ERROR;
168                               goto leave;
169                     }
170                     lr->lr_freeval[i] = freev;
171 
172                     if ( dn == NULL && !no_dn ) {
173                               if ( linenum+i == 1 && BV_CASEMATCH( lr->lr_btype+i, &BV_VERSION )) {
174                                         /* lutil_atoi() introduces a dependence of libldap
175                                          * on liblutil; we only allow version 1 by now (ITS#6654)
176                                          */
177 #if 0
178                                         int       v;
179                                         if( lr->lr_vals[i].bv_len == 0 || lutil_atoi( &v, lr->lr_vals[i].bv_val) != 0 || v != 1 )
180 #endif
181                                         static const struct berval version1 = { 1, "1" };
182                                         if ( lr->lr_vals[i].bv_len != version1.bv_len || strncmp( lr->lr_vals[i].bv_val, version1.bv_val, version1.bv_len ) != 0 )
183                                         {
184                                                   fprintf( stderr,
185                                                             _("%s: invalid version %s, line %lu (ignored)\n"),
186                                                             errstr, lr->lr_vals[i].bv_val, linenum );
187                                         }
188                                         version++;
189 
190                               } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) {
191                                         lr->lr_dn = lr->lr_vals[i];
192                                         dn = lr->lr_dn.bv_val; /* primarily for logging */
193                                         idn = i;
194                               }
195                               /* skip all lines until we see "dn:" */
196                     }
197           }
198 
199           /* check to make sure there was a dn: line */
200           if ( !dn && !no_dn ) {
201                     rc = 0;
202                     goto leave;
203           }
204 
205           lr->lr_lines = i+1;
206 
207           if( lr->lr_lines == 0 ) {
208                     rc = 0;
209                     goto leave;
210           }
211 
212           if( version && lr->lr_lines == 1 ) {
213                     rc = 0;
214                     goto leave;
215           }
216 
217           if ( no_dn ) {
218                     i = 0;
219           } else {
220                     i = idn+1;
221                     /* Check for "control" tag after dn and before changetype. */
222                     if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CONTROL )) {
223                               /* Parse and add it to the list of controls */
224                               if ( !( flags & LDIF_NO_CONTROLS ) ) {
225                                         rc = parse_ldif_control( lr->lr_vals+i, &pctrls );
226                                         if (rc != 0) {
227                                                   fprintf( stderr,
228                                                                        _("%s: Error processing %s line, line %lu: %s\n"),
229                                                                        errstr, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) );
230                                         }
231                               }
232                               i++;
233                               if ( i>= lr->lr_lines ) {
234 short_input:
235                                         fprintf( stderr,
236                                                   _("%s: Expecting more input after %s line, line %lu\n"),
237                                                   errstr, lr->lr_btype[i-1].bv_val, linenum+i );
238 
239                                         rc = LDAP_PARAM_ERROR;
240                                         goto leave;
241                               }
242                     }
243           }
244 
245           /* Check for changetype */
246           if ( BV_CASEMATCH( lr->lr_btype+i, &BV_CHANGETYPE )) {
247 #ifdef LIBERAL_CHANGETYPE_MODOP
248                     /* trim trailing spaces (and log warning ...) */
249                     int icnt;
250                     for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) {
251                               if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) {
252                                         break;
253                               }
254                     }
255 
256                     if ( ++icnt != lr->lr_vals[i].bv_len ) {
257                               fprintf( stderr, _("%s: illegal trailing space after"
258                                         " \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"),
259                                         errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn );
260                               lr->lr_vals[i].bv_val[icnt] = '\0';
261                     }
262 #endif /* LIBERAL_CHANGETYPE_MODOP */
263 
264                     /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or
265                        there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */
266                     if ( flags & LDIF_ENTRIES_ONLY ) {
267                               if ( !( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) ) {
268                                         ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
269                                                                                           _("%s: skipping LDIF record beginning at line %lu: "
270                                                                                             "changetype '%.*s' found but entries only was requested\n"),
271                                                                                           errstr, linenum,
272                                                                                           (int)lr->lr_vals[i].bv_len,
273                                                                                           (const char *)lr->lr_vals[i].bv_val );
274                                         goto leave;
275                               }
276                     }
277 
278                     if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODIFYCT )) {
279                               new_entry = 0;
280                               expect_modop = 1;
281                     } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) {
282                               new_entry = 1;
283                               modop = LDAP_MOD_ADD;
284                     } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODRDNCT )
285                               || BV_CASEMATCH( lr->lr_vals+i, &BV_MODDNCT )
286                               || BV_CASEMATCH( lr->lr_vals+i, &BV_RENAMECT ))
287                     {
288                               i++;
289                               if ( i >= lr->lr_lines )
290                                         goto short_input;
291                               if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWRDN )) {
292                                         fprintf( stderr, _("%s: expecting \"%s:\" but saw"
293                                                   " \"%s:\" (line %lu, entry \"%s\")\n"),
294                                                   errstr, BV_NEWRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
295                                         rc = LDAP_PARAM_ERROR;
296                                         goto leave;
297                               }
298                               lr->lrop_newrdn = lr->lr_vals[i];
299                               i++;
300                               if ( i >= lr->lr_lines )
301                                         goto short_input;
302                               if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_DELETEOLDRDN )) {
303                                         fprintf( stderr, _("%s: expecting \"%s:\" but saw"
304                                                   " \"%s:\" (line %lu, entry \"%s\")\n"),
305                                                   errstr, BV_DELETEOLDRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
306                                         rc = LDAP_PARAM_ERROR;
307                                         goto leave;
308                               }
309                               lr->lrop_delold = ( lr->lr_vals[i].bv_val[0] == '0' ) ? 0 : 1;
310                               i++;
311                               if ( i < lr->lr_lines ) {
312                                         if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWSUP )) {
313                                                   fprintf( stderr, _("%s: expecting \"%s:\" but saw"
314                                                             " \"%s:\" (line %lu, entry \"%s\")\n"),
315                                                             errstr, BV_NEWSUP.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn );
316                                                   rc = LDAP_PARAM_ERROR;
317                                                   goto leave;
318                                         }
319                                         lr->lrop_newsup = lr->lr_vals[i];
320                                         i++;
321                               }
322                               got_all = 1;
323                     } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_DELETECT )) {
324                               got_all = delete_entry = 1;
325                     } else {
326                               fprintf( stderr,
327                                         _("%s:  unknown %s \"%s\" (line %lu, entry \"%s\")\n"),
328                                         errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn );
329                               rc = LDAP_PARAM_ERROR;
330                               goto leave;
331                     }
332                     i++;
333           } else if ( ldapadd ) {                 /*  missing changetype => add */
334                     new_entry = 1;
335                     modop = LDAP_MOD_ADD;
336           } else {
337                     /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or
338                        there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */
339                     if ( flags & LDIF_ENTRIES_ONLY ) {
340                               ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug,
341                                                                                 _("%s: skipping LDIF record beginning at line %lu: "
342                                                                                   "no changetype found but entries only was requested and "
343                                                                                   "the default setting for missing changetype is modify\n"),
344                                                                                 errstr, linenum );
345                               goto leave;
346                     }
347                     expect_modop = 1;   /* missing changetype => modify */
348           }
349 
350           if ( got_all ) {
351                     if ( i < lr->lr_lines ) {
352                               fprintf( stderr,
353                                         _("%s: extra lines at end (line %lu, entry \"%s\")\n"),
354                                         errstr, linenum+i, dn );
355                               rc = LDAP_PARAM_ERROR;
356                               goto leave;
357                     }
358                     goto doit;
359           }
360 
361           nmods = lr->lr_lines - i;
362           idn = i;
363 
364           if ( new_entry ) {
365                     int fv;
366 
367                     /* Make sure all attributes with multiple values are contiguous */
368                     for (; i<lr->lr_lines; i++) {
369                               for (j=i+1; j<lr->lr_lines; j++) {
370                                         if ( !lr->lr_btype[j].bv_val ) {
371                                                   fprintf( stderr,
372                                                             _("%s: missing attributeDescription (line %lu, entry \"%s\")\n"),
373                                                             errstr, linenum+j, dn );
374                                                   rc = LDAP_PARAM_ERROR;
375                                                   goto leave;
376                                         }
377                                         if ( BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+j )) {
378                                                   nmods--;
379                                                   /* out of order, move intervening attributes down */
380                                                   if ( j != i+1 ) {
381                                                             bv = lr->lr_vals[j];
382                                                             fv = lr->lr_freeval[j];
383                                                             for (k=j; k>i; k--) {
384                                                                       lr->lr_btype[k] = lr->lr_btype[k-1];
385                                                                       lr->lr_vals[k] = lr->lr_vals[k-1];
386                                                                       lr->lr_freeval[k] = lr->lr_freeval[k-1];
387                                                             }
388                                                             k++;
389                                                             lr->lr_btype[k] = lr->lr_btype[i];
390                                                             lr->lr_vals[k] = bv;
391                                                             lr->lr_freeval[k] = fv;
392                                                   }
393                                                   i++;
394                                         }
395                               }
396                     }
397                     /* Allocate space for array of mods, array of pointers to mods,
398                      * and array of pointers to values, allowing for NULL terminators
399                      * for the pointer arrays...
400                      */
401                     lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) +
402                               (nmods+1) * sizeof(LDAPMod*) +
403                               (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx );
404                     if ( lr->lr_lm == NULL ) {
405                               rc = LDAP_NO_MEMORY;
406                               goto leave;
407                     }
408 
409                     pmods = (LDAPMod **)(lr->lr_lm+nmods);
410                     bvl = (struct berval **)(pmods+nmods+1);
411 
412                     j = 0;
413                     k = -1;
414                     BER_BVZERO(&bv);
415                     for (i=idn; i<lr->lr_lines; i++) {
416                               if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) {
417                                         fprintf( stderr, _("%s: attributeDescription \"%s\":"
418                                                   " (possible missing newline"
419                                                             " after line %lu, entry \"%s\"?)\n"),
420                                                   errstr, lr->lr_btype[i].bv_val, linenum+i - 1, dn );
421                               }
422                               if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
423                                         bvl[k++] = NULL;
424                                         bv = lr->lr_btype[i];
425                                         lr->lr_lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
426                                         lr->lr_lm[j].mod_type = bv.bv_val;
427                                         lr->lr_lm[j].mod_bvalues = bvl+k;
428                                         pmods[j] = lr->lr_lm+j;
429                                         j++;
430                               }
431                               bvl[k++] = lr->lr_vals+i;
432                     }
433                     bvl[k] = NULL;
434                     pmods[j] = NULL;
435                     goto doit;
436           }
437 
438           lr->lr_mops = ber_memalloc_x( lr->lr_lines+1, ctx );
439           if ( lr->lr_mops == NULL ) {
440                     rc = LDAP_NO_MEMORY;
441                     goto leave;
442           }
443 
444           lr->lr_mops[lr->lr_lines] = M_SEP;
445           if ( i > 0 )
446                     lr->lr_mops[i-1] = M_SEP;
447 
448           for ( ; i<lr->lr_lines; i++ ) {
449                     if ( expect_modop ) {
450 #ifdef LIBERAL_CHANGETYPE_MODOP
451                               /* trim trailing spaces (and log warning ...) */
452                         int icnt;
453                         for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) {
454                                         if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) break;
455                               }
456 
457                               if ( ++icnt != lr->lr_vals[i].bv_len ) {
458                                         fprintf( stderr, _("%s: illegal trailing space after"
459                                                   " \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"),
460                                                   errstr, type, lr->lr_vals[i].bv_val, linenum+i, dn );
461                                         lr->lr_vals[i].bv_val[icnt] = '\0';
462                               }
463 #endif /* LIBERAL_CHANGETYPE_MODOP */
464 
465                               expect_modop = 0;
466                               expect_sep = 1;
467                               if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPADD )) {
468                                         modop = LDAP_MOD_ADD;
469                                         lr->lr_mops[i] = M_SEP;
470                                         nmods--;
471                               } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPREPLACE )) {
472                               /* defer handling these since they might have no values.
473                                * Use the BVALUES flag to signal that these were
474                                * deferred. If values are provided later, this
475                                * flag will be switched off.
476                                */
477                                         modop = LDAP_MOD_REPLACE;
478                                         lr->lr_mops[i] = modop | LDAP_MOD_BVALUES;
479                                         lr->lr_btype[i] = lr->lr_vals[i];
480                               } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPDELETE )) {
481                                         modop = LDAP_MOD_DELETE;
482                                         lr->lr_mops[i] = modop | LDAP_MOD_BVALUES;
483                                         lr->lr_btype[i] = lr->lr_vals[i];
484                               } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPINCREMENT )) {
485                                         modop = LDAP_MOD_INCREMENT;
486                                         lr->lr_mops[i] = M_SEP;
487                                         nmods--;
488                               } else {  /* no modify op: invalid LDIF */
489                                         fprintf( stderr, _("%s: modify operation type is missing at"
490                                                   " line %lu, entry \"%s\"\n"),
491                                                   errstr, linenum+i, dn );
492                                         rc = LDAP_PARAM_ERROR;
493                                         goto leave;
494                               }
495                               bv = lr->lr_vals[i];
496                     } else if ( expect_sep && BER_BVISEMPTY( lr->lr_btype+i )) {
497                               lr->lr_mops[i] = M_SEP;
498                               expect_sep = 0;
499                               expect_modop = 1;
500                               nmods--;
501                     } else {
502                               if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
503                                         fprintf( stderr, _("%s: wrong attributeType at"
504                                                   " line %lu, entry \"%s\"\n"),
505                                                   errstr, linenum+i, dn );
506                                         rc = LDAP_PARAM_ERROR;
507                                         goto leave;
508                               }
509                               lr->lr_mops[i] = modop;
510                               /* If prev op was deferred and matches this type,
511                                * clear the flag
512                                */
513                               if ( (lr->lr_mops[i-1] & LDAP_MOD_BVALUES)
514                                         && BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+i-1 ))
515                               {
516                                         lr->lr_mops[i-1] = M_SEP;
517                                         nmods--;
518                               }
519                     }
520           }
521 
522           /* Allocate space for array of mods, array of pointers to mods,
523            * and array of pointers to values, allowing for NULL terminators
524            * for the pointer arrays...
525            */
526           lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) +
527                     (nmods+1) * sizeof(LDAPMod*) +
528                     (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx );
529           if ( lr->lr_lm == NULL ) {
530                     rc = LDAP_NO_MEMORY;
531                     goto leave;
532           }
533 
534           pmods = (LDAPMod **)(lr->lr_lm+nmods);
535           bvl = (struct berval **)(pmods+nmods+1);
536 
537           j = 0;
538           k = -1;
539           BER_BVZERO(&bv);
540           if ( idn > 0 )
541                     lr->lr_mops[idn-1] = M_SEP;
542           for (i=idn; i<lr->lr_lines; i++) {
543                     if ( lr->lr_mops[i] == M_SEP )
544                               continue;
545                     if ( lr->lr_mops[i] != lr->lr_mops[i-1] || !BV_CASEMATCH( lr->lr_btype+i, &bv )) {
546                               bvl[k++] = NULL;
547                               bv = lr->lr_btype[i];
548                               lr->lr_lm[j].mod_op = lr->lr_mops[i] | LDAP_MOD_BVALUES;
549                               lr->lr_lm[j].mod_type = bv.bv_val;
550                               if ( lr->lr_mops[i] & LDAP_MOD_BVALUES ) {
551                                         lr->lr_lm[j].mod_bvalues = NULL;
552                               } else {
553                                         lr->lr_lm[j].mod_bvalues = bvl+k;
554                               }
555                               pmods[j] = lr->lr_lm+j;
556                               j++;
557                     }
558                     bvl[k++] = lr->lr_vals+i;
559           }
560           bvl[k] = NULL;
561           pmods[j] = NULL;
562 
563 doit:
564           /* first, set the common fields */
565           lr->lr_ctrls = pctrls;
566           /* next, set the op */
567           if ( delete_entry ) {
568                     lr->lr_op = LDAP_REQ_DELETE;
569           } else if ( lr->lrop_newrdn.bv_val != NULL ) {
570                     lr->lr_op = LDAP_REQ_MODDN;
571           } else {
572                     /* for now, either add or modify */
573                     lr->lrop_mods = pmods;
574                     if ( new_entry ) {
575                               lr->lr_op = LDAP_REQ_ADD;
576                     } else {
577                               lr->lr_op = LDAP_REQ_MODIFY;
578                     }
579           }
580 
581 leave:
582           if ( rc != LDAP_SUCCESS ) {
583                     ldap_ldif_record_done( lr );
584           }
585 
586           return( rc );
587 }
588 
589 /* Same as ldap_parse_ldif_record_x()
590  * public API does not expose memory context
591  */
592 int
ldap_parse_ldif_record(struct berval * rbuf,unsigned long linenum,LDIFRecord * lr,const char * errstr,unsigned int flags)593 ldap_parse_ldif_record(
594           struct berval *rbuf,
595           unsigned long linenum,
596           LDIFRecord *lr,
597           const char *errstr,
598           unsigned int flags )
599 {
600           return ldap_parse_ldif_record_x( rbuf, linenum, lr, errstr, flags, NULL );
601 }
602 
603 /* Parse an LDIF control line of the form
604       control:  oid  [true/false]  [: value]              or
605       control:  oid  [true/false]  [:: base64-value]      or
606       control:  oid  [true/false]  [:< url]
607    The control is added to the list of controls in *ppctrls.
608 */
609 static int
parse_ldif_control(struct berval * bval,LDAPControl *** ppctrls)610 parse_ldif_control(
611           struct berval *bval,
612           LDAPControl ***ppctrls)
613 {
614           char *oid = NULL;
615           int criticality = 0;   /* Default is false if not present */
616           int i, rc=0;
617           char *s, *oidStart;
618           LDAPControl *newctrl = NULL;
619           LDAPControl **pctrls = NULL;
620           struct berval type, bv = BER_BVNULL;
621           int freeval = 0;
622 
623           if (ppctrls) pctrls = *ppctrls;
624           /* OID should come first. Validate and extract it. */
625           s = bval->bv_val;
626           if (*s == 0) return ( LDAP_PARAM_ERROR );
627           oidStart = s;
628           while (isdigit((unsigned char)*s) || *s == '.') {
629                     s++;                           /* OID should be digits or . */
630           }
631           if (s == oidStart) {
632                     return ( LDAP_PARAM_ERROR );   /* OID was not present */
633           }
634           if (*s) {                          /* End of OID should be space or NULL */
635                     if (!isspace((unsigned char)*s)) {
636                               return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */
637                     }
638                     *s++ = 0;                    /* Replace space with null to terminate */
639           }
640 
641           oid = ber_strdup(oidStart);
642           if (oid == NULL) return ( LDAP_NO_MEMORY );
643 
644           /* Optional Criticality field is next. */
645           while (*s && isspace((unsigned char)*s)) {
646                     s++;                         /* Skip white space before criticality */
647           }
648           if (strncasecmp(s, "true", 4) == 0) {
649                     criticality = 1;
650                     s += 4;
651           }
652           else if (strncasecmp(s, "false", 5) == 0) {
653                     criticality = 0;
654                     s += 5;
655           }
656 
657           /* Optional value field is next */
658           while (*s && isspace((unsigned char)*s)) {
659                     s++;                         /* Skip white space before value */
660           }
661           if (*s) {
662                     if (*s != ':') {           /* If value is present, must start with : */
663                               rc = LDAP_PARAM_ERROR;
664                               goto cleanup;
665                     }
666 
667                     /* Back up so value is in the form
668                          a: value
669                          a:: base64-value
670                          a:< url
671                        Then we can use ldif_parse_line2 to extract and decode the value
672                     */
673                     s--;
674                     *s = 'a';
675 
676                     rc = ldif_parse_line2(s, &type, &bv, &freeval);
677                     if (rc < 0) {
678                               rc = LDAP_PARAM_ERROR;
679                               goto cleanup;
680                     }
681     }
682 
683           /* Create a new LDAPControl structure. */
684           newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl));
685           if ( newctrl == NULL ) {
686                     rc = LDAP_NO_MEMORY;
687                     goto cleanup;
688           }
689           newctrl->ldctl_oid = oid;
690           oid = NULL;
691           newctrl->ldctl_iscritical = criticality;
692           if ( freeval )
693                     newctrl->ldctl_value = bv;
694           else
695                     ber_dupbv( &newctrl->ldctl_value, &bv );
696 
697           /* Add the new control to the passed-in list of controls. */
698           i = 0;
699           if (pctrls) {
700                     while ( pctrls[i] ) {    /* Count the # of controls passed in */
701                               i++;
702                     }
703           }
704           /* Allocate 1 more slot for the new control and 1 for the NULL. */
705           pctrls = (LDAPControl **) ber_memrealloc(pctrls,
706                     (i+2)*(sizeof(LDAPControl *)));
707           if (pctrls == NULL) {
708                     rc = LDAP_NO_MEMORY;
709                     goto cleanup;
710           }
711           pctrls[i] = newctrl;
712           newctrl = NULL;
713           pctrls[i+1] = NULL;
714           *ppctrls = pctrls;
715 
716 cleanup:
717           if (newctrl) {
718                     if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid);
719                     if (newctrl->ldctl_value.bv_val) {
720                               ber_memfree(newctrl->ldctl_value.bv_val);
721                     }
722                     ber_memfree(newctrl);
723           }
724           if (oid) ber_memfree(oid);
725 
726           return( rc );
727 }
728 
729 
730