1 /* $NetBSD: ldifutil.c,v 1.3 2025/09/05 21:16:21 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2024 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.3 2025/09/05 21:16:21 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 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 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 int icnt; 248 for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) { 249 if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) { 250 break; 251 } 252 } 253 254 if ( ++icnt != lr->lr_vals[i].bv_len ) { 255 #ifdef LIBERAL_CHANGETYPE_MODOP 256 /* trim trailing spaces (and log warning ...) */ 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 lr->lr_vals[i].bv_len = icnt; 262 #else /* !LIBERAL_CHANGETYPE_MODOP */ 263 fprintf( stderr, _("%s: illegal trailing space after" 264 " \"%s: %s\" (line %lu, entry \"%s\")\n"), 265 errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn ); 266 rc = LDAP_PARAM_ERROR; 267 goto leave; 268 #endif /* !LIBERAL_CHANGETYPE_MODOP */ 269 } 270 271 /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or 272 there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */ 273 if ( flags & LDIF_ENTRIES_ONLY ) { 274 if ( !( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) ) { 275 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, 276 _("%s: skipping LDIF record beginning at line %lu: " 277 "changetype '%.*s' found but entries only was requested\n"), 278 errstr, linenum, 279 (int)lr->lr_vals[i].bv_len, 280 (const char *)lr->lr_vals[i].bv_val ); 281 goto leave; 282 } 283 } 284 285 if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODIFYCT )) { 286 new_entry = 0; 287 expect_modop = 1; 288 } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_ADDCT )) { 289 new_entry = 1; 290 modop = LDAP_MOD_ADD; 291 } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_MODRDNCT ) 292 || BV_CASEMATCH( lr->lr_vals+i, &BV_MODDNCT ) 293 || BV_CASEMATCH( lr->lr_vals+i, &BV_RENAMECT )) 294 { 295 i++; 296 if ( i >= lr->lr_lines ) 297 goto short_input; 298 if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWRDN )) { 299 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 300 " \"%s:\" (line %lu, entry \"%s\")\n"), 301 errstr, BV_NEWRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); 302 rc = LDAP_PARAM_ERROR; 303 goto leave; 304 } 305 lr->lrop_newrdn = lr->lr_vals[i]; 306 i++; 307 if ( i >= lr->lr_lines ) 308 goto short_input; 309 if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_DELETEOLDRDN )) { 310 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 311 " \"%s:\" (line %lu, entry \"%s\")\n"), 312 errstr, BV_DELETEOLDRDN.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); 313 rc = LDAP_PARAM_ERROR; 314 goto leave; 315 } 316 lr->lrop_delold = ( lr->lr_vals[i].bv_val[0] == '0' ) ? 0 : 1; 317 i++; 318 if ( i < lr->lr_lines ) { 319 if ( !BV_CASEMATCH( lr->lr_btype+i, &BV_NEWSUP )) { 320 fprintf( stderr, _("%s: expecting \"%s:\" but saw" 321 " \"%s:\" (line %lu, entry \"%s\")\n"), 322 errstr, BV_NEWSUP.bv_val, lr->lr_btype[i].bv_val, linenum+i, dn ); 323 rc = LDAP_PARAM_ERROR; 324 goto leave; 325 } 326 lr->lrop_newsup = lr->lr_vals[i]; 327 i++; 328 } 329 got_all = 1; 330 } else if ( BV_CASEMATCH( lr->lr_vals+i, &BV_DELETECT )) { 331 got_all = delete_entry = 1; 332 } else { 333 fprintf( stderr, 334 _("%s: unknown %s \"%s\" (line %lu, entry \"%s\")\n"), 335 errstr, BV_CHANGETYPE.bv_val, lr->lr_vals[i].bv_val, linenum+i, dn ); 336 rc = LDAP_PARAM_ERROR; 337 goto leave; 338 } 339 i++; 340 } else if ( ldapadd ) { /* missing changetype => add */ 341 new_entry = 1; 342 modop = LDAP_MOD_ADD; 343 } else { 344 /* if LDIF_ENTRIES_ONLY, then either the changetype must be add, or 345 there must be no changetype, and the flag LDIF_DEFAULT_ADD must be set */ 346 if ( flags & LDIF_ENTRIES_ONLY ) { 347 ber_pvt_log_printf( LDAP_DEBUG_ANY, ldif_debug, 348 _("%s: skipping LDIF record beginning at line %lu: " 349 "no changetype found but entries only was requested and " 350 "the default setting for missing changetype is modify\n"), 351 errstr, linenum ); 352 goto leave; 353 } 354 expect_modop = 1; /* missing changetype => modify */ 355 } 356 357 if ( got_all ) { 358 if ( i < lr->lr_lines ) { 359 fprintf( stderr, 360 _("%s: extra lines at end (line %lu, entry \"%s\")\n"), 361 errstr, linenum+i, dn ); 362 rc = LDAP_PARAM_ERROR; 363 goto leave; 364 } 365 goto doit; 366 } 367 368 nmods = lr->lr_lines - i; 369 idn = i; 370 371 if ( new_entry ) { 372 int fv; 373 374 /* Make sure all attributes with multiple values are contiguous */ 375 for (; i<lr->lr_lines; i++) { 376 for (j=i+1; j<lr->lr_lines; j++) { 377 if ( !lr->lr_btype[j].bv_val ) { 378 fprintf( stderr, 379 _("%s: missing attributeDescription (line %lu, entry \"%s\")\n"), 380 errstr, linenum+j, dn ); 381 rc = LDAP_PARAM_ERROR; 382 goto leave; 383 } 384 if ( BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+j )) { 385 nmods--; 386 /* out of order, move intervening attributes down */ 387 if ( j != i+1 ) { 388 bv = lr->lr_vals[j]; 389 fv = lr->lr_freeval[j]; 390 for (k=j; k>i; k--) { 391 lr->lr_btype[k] = lr->lr_btype[k-1]; 392 lr->lr_vals[k] = lr->lr_vals[k-1]; 393 lr->lr_freeval[k] = lr->lr_freeval[k-1]; 394 } 395 k++; 396 lr->lr_btype[k] = lr->lr_btype[i]; 397 lr->lr_vals[k] = bv; 398 lr->lr_freeval[k] = fv; 399 } 400 i++; 401 } 402 } 403 } 404 /* Allocate space for array of mods, array of pointers to mods, 405 * and array of pointers to values, allowing for NULL terminators 406 * for the pointer arrays... 407 */ 408 lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) + 409 (nmods+1) * sizeof(LDAPMod*) + 410 (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx ); 411 if ( lr->lr_lm == NULL ) { 412 rc = LDAP_NO_MEMORY; 413 goto leave; 414 } 415 416 pmods = (LDAPMod **)(lr->lr_lm+nmods); 417 bvl = (struct berval **)(pmods+nmods+1); 418 419 j = 0; 420 k = -1; 421 BER_BVZERO(&bv); 422 for (i=idn; i<lr->lr_lines; i++) { 423 if ( BV_CASEMATCH( lr->lr_btype+i, &BV_DN )) { 424 fprintf( stderr, _("%s: attributeDescription \"%s\":" 425 " (possible missing newline" 426 " after line %lu, entry \"%s\"?)\n"), 427 errstr, lr->lr_btype[i].bv_val, linenum+i - 1, dn ); 428 } 429 if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) { 430 bvl[k++] = NULL; 431 bv = lr->lr_btype[i]; 432 lr->lr_lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES; 433 lr->lr_lm[j].mod_type = bv.bv_val; 434 lr->lr_lm[j].mod_bvalues = bvl+k; 435 pmods[j] = lr->lr_lm+j; 436 j++; 437 } 438 bvl[k++] = lr->lr_vals+i; 439 } 440 bvl[k] = NULL; 441 pmods[j] = NULL; 442 goto doit; 443 } 444 445 lr->lr_mops = ber_memalloc_x( lr->lr_lines+1, ctx ); 446 if ( lr->lr_mops == NULL ) { 447 rc = LDAP_NO_MEMORY; 448 goto leave; 449 } 450 451 lr->lr_mops[lr->lr_lines] = M_SEP; 452 if ( i > 0 ) 453 lr->lr_mops[i-1] = M_SEP; 454 455 for ( ; i<lr->lr_lines; i++ ) { 456 if ( expect_modop ) { 457 /* trim trailing spaces (and log warning ...) */ 458 int icnt; 459 for ( icnt = lr->lr_vals[i].bv_len; --icnt > 0; ) { 460 if ( !isspace( (unsigned char) lr->lr_vals[i].bv_val[icnt] ) ) break; 461 } 462 463 if ( ++icnt != lr->lr_vals[i].bv_len ) { 464 #ifdef LIBERAL_CHANGETYPE_MODOP 465 fprintf( stderr, _("%s: illegal trailing space after" 466 " \"%s: %s\" trimmed (line %lu, entry \"%s\")\n"), 467 errstr, lr->lr_btype[i].bv_val, lr->lr_vals[i].bv_val, 468 linenum+i, dn ); 469 lr->lr_vals[i].bv_val[icnt] = '\0'; 470 lr->lr_vals[i].bv_len = icnt; 471 #else /* !LIBERAL_CHANGETYPE_MODOP */ 472 fprintf( stderr, _("%s: illegal trailing space after" 473 " \"%s: %s\" (line %lu, entry \"%s\")\n"), 474 errstr, lr->lr_btype[i].bv_val, lr->lr_vals[i].bv_val, 475 linenum+i, dn ); 476 rc = LDAP_PARAM_ERROR; 477 goto leave; 478 #endif /* !LIBERAL_CHANGETYPE_MODOP */ 479 } 480 481 expect_modop = 0; 482 expect_sep = 1; 483 if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPADD )) { 484 modop = LDAP_MOD_ADD; 485 lr->lr_mops[i] = M_SEP; 486 nmods--; 487 } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPREPLACE )) { 488 /* defer handling these since they might have no values. 489 * Use the BVALUES flag to signal that these were 490 * deferred. If values are provided later, this 491 * flag will be switched off. 492 */ 493 modop = LDAP_MOD_REPLACE; 494 lr->lr_mops[i] = modop | LDAP_MOD_BVALUES; 495 lr->lr_btype[i] = lr->lr_vals[i]; 496 } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPDELETE )) { 497 modop = LDAP_MOD_DELETE; 498 lr->lr_mops[i] = modop | LDAP_MOD_BVALUES; 499 lr->lr_btype[i] = lr->lr_vals[i]; 500 } else if ( BV_CASEMATCH( lr->lr_btype+i, &BV_MODOPINCREMENT )) { 501 modop = LDAP_MOD_INCREMENT; 502 lr->lr_mops[i] = M_SEP; 503 nmods--; 504 } else { /* no modify op: invalid LDIF */ 505 fprintf( stderr, _("%s: modify operation type is missing at" 506 " line %lu, entry \"%s\"\n"), 507 errstr, linenum+i, dn ); 508 rc = LDAP_PARAM_ERROR; 509 goto leave; 510 } 511 bv = lr->lr_vals[i]; 512 } else if ( expect_sep && BER_BVISEMPTY( lr->lr_btype+i )) { 513 lr->lr_mops[i] = M_SEP; 514 expect_sep = 0; 515 expect_modop = 1; 516 nmods--; 517 } else { 518 if ( !BV_CASEMATCH( lr->lr_btype+i, &bv )) { 519 fprintf( stderr, _("%s: wrong attributeType at" 520 " line %lu, entry \"%s\"\n"), 521 errstr, linenum+i, dn ); 522 rc = LDAP_PARAM_ERROR; 523 goto leave; 524 } 525 lr->lr_mops[i] = modop; 526 /* If prev op was deferred and matches this type, 527 * clear the flag 528 */ 529 if ( (lr->lr_mops[i-1] & LDAP_MOD_BVALUES) 530 && BV_CASEMATCH( lr->lr_btype+i, lr->lr_btype+i-1 )) 531 { 532 lr->lr_mops[i-1] = M_SEP; 533 nmods--; 534 } 535 } 536 } 537 538 /* Allocate space for array of mods, array of pointers to mods, 539 * and array of pointers to values, allowing for NULL terminators 540 * for the pointer arrays... 541 */ 542 lr->lr_lm = ber_memalloc_x( nmods * sizeof(LDAPMod) + 543 (nmods+1) * sizeof(LDAPMod*) + 544 (lr->lr_lines + nmods - idn) * sizeof(struct berval *), ctx ); 545 if ( lr->lr_lm == NULL ) { 546 rc = LDAP_NO_MEMORY; 547 goto leave; 548 } 549 550 pmods = (LDAPMod **)(lr->lr_lm+nmods); 551 bvl = (struct berval **)(pmods+nmods+1); 552 553 j = 0; 554 k = -1; 555 BER_BVZERO(&bv); 556 if ( idn > 0 ) 557 lr->lr_mops[idn-1] = M_SEP; 558 for (i=idn; i<lr->lr_lines; i++) { 559 if ( lr->lr_mops[i] == M_SEP ) 560 continue; 561 if ( lr->lr_mops[i] != lr->lr_mops[i-1] || !BV_CASEMATCH( lr->lr_btype+i, &bv )) { 562 bvl[k++] = NULL; 563 bv = lr->lr_btype[i]; 564 lr->lr_lm[j].mod_op = lr->lr_mops[i] | LDAP_MOD_BVALUES; 565 lr->lr_lm[j].mod_type = bv.bv_val; 566 if ( lr->lr_mops[i] & LDAP_MOD_BVALUES ) { 567 lr->lr_lm[j].mod_bvalues = NULL; 568 } else { 569 lr->lr_lm[j].mod_bvalues = bvl+k; 570 } 571 pmods[j] = lr->lr_lm+j; 572 j++; 573 } 574 bvl[k++] = lr->lr_vals+i; 575 } 576 bvl[k] = NULL; 577 pmods[j] = NULL; 578 579 doit: 580 /* first, set the common fields */ 581 lr->lr_ctrls = pctrls; 582 /* next, set the op */ 583 if ( delete_entry ) { 584 lr->lr_op = LDAP_REQ_DELETE; 585 } else if ( lr->lrop_newrdn.bv_val != NULL ) { 586 lr->lr_op = LDAP_REQ_MODDN; 587 } else { 588 /* for now, either add or modify */ 589 lr->lrop_mods = pmods; 590 if ( new_entry ) { 591 lr->lr_op = LDAP_REQ_ADD; 592 } else { 593 lr->lr_op = LDAP_REQ_MODIFY; 594 } 595 } 596 597 leave: 598 if ( rc != LDAP_SUCCESS ) { 599 ldap_ldif_record_done( lr ); 600 } 601 602 return( rc ); 603 } 604 605 /* Same as ldap_parse_ldif_record_x() 606 * public API does not expose memory context 607 */ 608 int 609 ldap_parse_ldif_record( 610 struct berval *rbuf, 611 unsigned long linenum, 612 LDIFRecord *lr, 613 const char *errstr, 614 unsigned int flags ) 615 { 616 return ldap_parse_ldif_record_x( rbuf, linenum, lr, errstr, flags, NULL ); 617 } 618 619 /* Parse an LDIF control line of the form 620 control: oid [true/false] [: value] or 621 control: oid [true/false] [:: base64-value] or 622 control: oid [true/false] [:< url] 623 The control is added to the list of controls in *ppctrls. 624 */ 625 static int 626 parse_ldif_control( 627 struct berval *bval, 628 LDAPControl ***ppctrls) 629 { 630 char *oid = NULL; 631 int criticality = 0; /* Default is false if not present */ 632 int i, rc=0; 633 char *s, *oidStart; 634 LDAPControl *newctrl = NULL; 635 LDAPControl **pctrls = NULL; 636 struct berval type, bv = BER_BVNULL; 637 int freeval = 0; 638 639 if (ppctrls) pctrls = *ppctrls; 640 /* OID should come first. Validate and extract it. */ 641 s = bval->bv_val; 642 if (*s == 0) return ( LDAP_PARAM_ERROR ); 643 oidStart = s; 644 while (isdigit((unsigned char)*s) || *s == '.') { 645 s++; /* OID should be digits or . */ 646 } 647 if (s == oidStart) { 648 return ( LDAP_PARAM_ERROR ); /* OID was not present */ 649 } 650 if (*s) { /* End of OID should be space or NULL */ 651 if (!isspace((unsigned char)*s)) { 652 return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */ 653 } 654 *s++ = 0; /* Replace space with null to terminate */ 655 } 656 657 oid = ber_strdup(oidStart); 658 if (oid == NULL) return ( LDAP_NO_MEMORY ); 659 660 /* Optional Criticality field is next. */ 661 while (*s && isspace((unsigned char)*s)) { 662 s++; /* Skip white space before criticality */ 663 } 664 if (strncasecmp(s, "true", 4) == 0) { 665 criticality = 1; 666 s += 4; 667 } 668 else if (strncasecmp(s, "false", 5) == 0) { 669 criticality = 0; 670 s += 5; 671 } 672 673 /* Optional value field is next */ 674 while (*s && isspace((unsigned char)*s)) { 675 s++; /* Skip white space before value */ 676 } 677 if (*s) { 678 if (*s != ':') { /* If value is present, must start with : */ 679 rc = LDAP_PARAM_ERROR; 680 goto cleanup; 681 } 682 683 /* Back up so value is in the form 684 a: value 685 a:: base64-value 686 a:< url 687 Then we can use ldif_parse_line2 to extract and decode the value 688 */ 689 s--; 690 *s = 'a'; 691 692 rc = ldif_parse_line2(s, &type, &bv, &freeval); 693 if (rc < 0) { 694 rc = LDAP_PARAM_ERROR; 695 goto cleanup; 696 } 697 } 698 699 /* Create a new LDAPControl structure. */ 700 newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl)); 701 if ( newctrl == NULL ) { 702 rc = LDAP_NO_MEMORY; 703 goto cleanup; 704 } 705 newctrl->ldctl_oid = oid; 706 oid = NULL; 707 newctrl->ldctl_iscritical = criticality; 708 if ( freeval ) 709 newctrl->ldctl_value = bv; 710 else 711 ber_dupbv( &newctrl->ldctl_value, &bv ); 712 713 /* Add the new control to the passed-in list of controls. */ 714 i = 0; 715 if (pctrls) { 716 while ( pctrls[i] ) { /* Count the # of controls passed in */ 717 i++; 718 } 719 } 720 /* Allocate 1 more slot for the new control and 1 for the NULL. */ 721 pctrls = (LDAPControl **) ber_memrealloc(pctrls, 722 (i+2)*(sizeof(LDAPControl *))); 723 if (pctrls == NULL) { 724 rc = LDAP_NO_MEMORY; 725 goto cleanup; 726 } 727 pctrls[i] = newctrl; 728 newctrl = NULL; 729 pctrls[i+1] = NULL; 730 *ppctrls = pctrls; 731 732 cleanup: 733 if (newctrl) { 734 if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid); 735 if (newctrl->ldctl_value.bv_val) { 736 ber_memfree(newctrl->ldctl_value.bv_val); 737 } 738 ber_memfree(newctrl); 739 } 740 if (oid) ber_memfree(oid); 741 742 return( rc ); 743 } 744 745 746