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 */ 45static struct berval BV_VERSION = BER_BVC("version"); 46static struct berval BV_DN = BER_BVC("dn"); 47static struct berval BV_CONTROL = BER_BVC("control"); 48static struct berval BV_CHANGETYPE = BER_BVC("changetype"); 49static struct berval BV_ADDCT = BER_BVC("add"); 50static struct berval BV_MODIFYCT = BER_BVC("modify"); 51static struct berval BV_DELETECT = BER_BVC("delete"); 52static struct berval BV_MODRDNCT = BER_BVC("modrdn"); 53static struct berval BV_MODDNCT = BER_BVC("moddn"); 54static struct berval BV_RENAMECT = BER_BVC("rename"); 55static struct berval BV_MODOPADD = BER_BVC("add"); 56static struct berval BV_MODOPREPLACE = BER_BVC("replace"); 57static struct berval BV_MODOPDELETE = BER_BVC("delete"); 58static struct berval BV_MODOPINCREMENT = BER_BVC("increment"); 59static struct berval BV_NEWRDN = BER_BVC("newrdn"); 60static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn"); 61static 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 66static int parse_ldif_control LDAP_P(( struct berval *bval, LDAPControl ***ppctrls )); 67 68void 69ldap_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 */ 105int 106ldap_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 ) { 234short_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 563doit: 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 581leave: 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 */ 592int 593ldap_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*/ 609static int 610parse_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 716cleanup: 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