1 /* $NetBSD: slapadd.c,v 1.1.1.4 2014/05/28 09:58:48 tron Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2014 The OpenLDAP Foundation. 7 * Portions Copyright 1998-2003 Kurt D. Zeilenga. 8 * Portions Copyright 2003 IBM Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Kurt Zeilenga for inclusion 21 * in OpenLDAP Software. Additional signficant contributors include 22 * Jong Hyuk Choi 23 * Pierangelo Masarati 24 */ 25 26 #include "portable.h" 27 28 #include <stdio.h> 29 30 #include <ac/stdlib.h> 31 32 #include <ac/ctype.h> 33 #include <ac/string.h> 34 #include <ac/socket.h> 35 #include <ac/unistd.h> 36 37 #include <lber.h> 38 #include <ldif.h> 39 #include <lutil.h> 40 #include <lutil_meter.h> 41 #include <sys/stat.h> 42 43 #include "slapcommon.h" 44 45 extern int slap_DN_strict; /* dn.c */ 46 47 static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 48 49 typedef struct Erec { 50 Entry *e; 51 unsigned long lineno; 52 unsigned long nextline; 53 } Erec; 54 55 typedef struct Trec { 56 Entry *e; 57 unsigned long lineno; 58 unsigned long nextline; 59 int rc; 60 int ready; 61 } Trec; 62 63 static Trec trec; 64 static unsigned long sid = SLAP_SYNC_SID_MAX + 1; 65 static int checkvals; 66 static int enable_meter; 67 static lutil_meter_t meter; 68 static const char *progname = "slapadd"; 69 static OperationBuffer opbuf; 70 static char *buf; 71 static int lmax; 72 73 static ldap_pvt_thread_mutex_t add_mutex; 74 static ldap_pvt_thread_cond_t add_cond; 75 static int add_stop; 76 77 /* returns: 78 * 1: got a record 79 * 0: EOF 80 * -1: read failure 81 * -2: parse failure 82 */ 83 static int 84 getrec0(Erec *erec) 85 { 86 const char *text; 87 int ldifrc; 88 char textbuf[SLAP_TEXT_BUFLEN] = { '\0' }; 89 size_t textlen = sizeof textbuf; 90 struct berval csn; 91 Operation *op = &opbuf.ob_op; 92 op->o_hdr = &opbuf.ob_hdr; 93 94 again: 95 erec->lineno = erec->nextline+1; 96 /* nextline is the line number of the end of the current entry */ 97 ldifrc = ldif_read_record( ldiffp, &erec->nextline, &buf, &lmax ); 98 if (ldifrc < 1) 99 return ldifrc < 0 ? -1 : 0; 100 { 101 BackendDB *bd; 102 Entry *e; 103 int prev_DN_strict; 104 105 if ( erec->lineno < jumpline ) 106 goto again; 107 108 if ( !dbnum ) { 109 prev_DN_strict = slap_DN_strict; 110 slap_DN_strict = 0; 111 } 112 e = str2entry2( buf, checkvals ); 113 if ( !dbnum ) { 114 slap_DN_strict = prev_DN_strict; 115 } 116 117 if ( enable_meter ) 118 lutil_meter_update( &meter, 119 ftell( ldiffp->fp ), 120 0); 121 122 if( e == NULL ) { 123 fprintf( stderr, "%s: could not parse entry (line=%lu)\n", 124 progname, erec->lineno ); 125 return -2; 126 } 127 128 /* make sure the DN is not empty */ 129 if( BER_BVISEMPTY( &e->e_nname ) && 130 !BER_BVISEMPTY( be->be_nsuffix )) 131 { 132 fprintf( stderr, "%s: line %lu: " 133 "cannot add entry with empty dn=\"%s\"", 134 progname, erec->lineno, e->e_dn ); 135 bd = select_backend( &e->e_nname, nosubordinates ); 136 if ( bd ) { 137 BackendDB *bdtmp; 138 int dbidx = 0; 139 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) { 140 if ( bdtmp == bd ) break; 141 dbidx++; 142 } 143 144 assert( bdtmp != NULL ); 145 146 fprintf( stderr, "; did you mean to use database #%d (%s)?", 147 dbidx, 148 bd->be_suffix[0].bv_val ); 149 150 } 151 fprintf( stderr, "\n" ); 152 entry_free( e ); 153 return -2; 154 } 155 156 /* check backend */ 157 bd = select_backend( &e->e_nname, nosubordinates ); 158 if ( bd != be ) { 159 fprintf( stderr, "%s: line %lu: " 160 "database #%d (%s) not configured to hold \"%s\"", 161 progname, erec->lineno, 162 dbnum, 163 be->be_suffix[0].bv_val, 164 e->e_dn ); 165 if ( bd ) { 166 BackendDB *bdtmp; 167 int dbidx = 0; 168 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) { 169 if ( bdtmp == bd ) break; 170 dbidx++; 171 } 172 173 assert( bdtmp != NULL ); 174 175 fprintf( stderr, "; did you mean to use database #%d (%s)?", 176 dbidx, 177 bd->be_suffix[0].bv_val ); 178 179 } else { 180 fprintf( stderr, "; no database configured for that naming context" ); 181 } 182 fprintf( stderr, "\n" ); 183 entry_free( e ); 184 return -2; 185 } 186 187 if ( slap_tool_entry_check( progname, op, e, erec->lineno, &text, textbuf, textlen ) != 188 LDAP_SUCCESS ) { 189 entry_free( e ); 190 return -2; 191 } 192 193 if ( SLAP_LASTMOD(be) ) { 194 time_t now = slap_get_time(); 195 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ]; 196 struct berval vals[ 2 ]; 197 198 struct berval name, timestamp; 199 200 struct berval nvals[ 2 ]; 201 struct berval nname; 202 char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 203 204 enum { 205 GOT_NONE = 0x0, 206 GOT_CSN = 0x1, 207 GOT_UUID = 0x2, 208 GOT_ALL = (GOT_CSN|GOT_UUID) 209 } got = GOT_ALL; 210 211 vals[1].bv_len = 0; 212 vals[1].bv_val = NULL; 213 214 nvals[1].bv_len = 0; 215 nvals[1].bv_val = NULL; 216 217 csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 ); 218 csn.bv_val = csnbuf; 219 220 timestamp.bv_val = timebuf; 221 timestamp.bv_len = sizeof(timebuf); 222 223 slap_timestamp( &now, ×tamp ); 224 225 if ( BER_BVISEMPTY( &be->be_rootndn ) ) { 226 BER_BVSTR( &name, SLAPD_ANONYMOUS ); 227 nname = name; 228 } else { 229 name = be->be_rootdn; 230 nname = be->be_rootndn; 231 } 232 233 if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ) 234 == NULL ) 235 { 236 got &= ~GOT_UUID; 237 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) ); 238 vals[0].bv_val = uuidbuf; 239 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL ); 240 } 241 242 if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName ) 243 == NULL ) 244 { 245 vals[0] = name; 246 nvals[0] = nname; 247 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals ); 248 } 249 250 if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp ) 251 == NULL ) 252 { 253 vals[0] = timestamp; 254 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL ); 255 } 256 257 if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ) 258 == NULL ) 259 { 260 got &= ~GOT_CSN; 261 vals[0] = csn; 262 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL ); 263 } 264 265 if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName ) 266 == NULL ) 267 { 268 vals[0] = name; 269 nvals[0] = nname; 270 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals ); 271 } 272 273 if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp ) 274 == NULL ) 275 { 276 vals[0] = timestamp; 277 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL ); 278 } 279 280 if ( SLAP_SINGLE_SHADOW(be) && got != GOT_ALL ) { 281 char buf[SLAP_TEXT_BUFLEN]; 282 283 snprintf( buf, sizeof(buf), 284 "%s%s%s", 285 ( !(got & GOT_UUID) ? slap_schema.si_ad_entryUUID->ad_cname.bv_val : "" ), 286 ( !(got & GOT_CSN) ? "," : "" ), 287 ( !(got & GOT_CSN) ? slap_schema.si_ad_entryCSN->ad_cname.bv_val : "" ) ); 288 289 Debug( LDAP_DEBUG_ANY, "%s: warning, missing attrs %s from entry dn=\"%s\"\n", 290 progname, buf, e->e_name.bv_val ); 291 } 292 293 sid = slap_tool_update_ctxcsn_check( progname, e ); 294 } 295 erec->e = e; 296 } 297 return 1; 298 } 299 300 static void * 301 getrec_thr(void *ctx) 302 { 303 ldap_pvt_thread_mutex_lock( &add_mutex ); 304 while (!add_stop) { 305 trec.rc = getrec0((Erec *)&trec); 306 trec.ready = 1; 307 while (trec.ready) 308 ldap_pvt_thread_cond_wait( &add_cond, &add_mutex ); 309 /* eof or read failure */ 310 if ( trec.rc == 0 || trec.rc == -1 ) 311 break; 312 } 313 ldap_pvt_thread_mutex_unlock( &add_mutex ); 314 return NULL; 315 } 316 317 static int ldif_threaded; 318 319 static int 320 getrec(Erec *erec) 321 { 322 int rc; 323 if ( !ldif_threaded ) 324 return getrec0(erec); 325 326 while (!trec.ready) 327 ldap_pvt_thread_yield(); 328 erec->e = trec.e; 329 erec->lineno = trec.lineno; 330 erec->nextline = trec.nextline; 331 trec.ready = 0; 332 rc = trec.rc; 333 ldap_pvt_thread_mutex_lock( &add_mutex ); 334 ldap_pvt_thread_mutex_unlock( &add_mutex ); 335 ldap_pvt_thread_cond_signal( &add_cond ); 336 return rc; 337 } 338 339 int 340 slapadd( int argc, char **argv ) 341 { 342 char textbuf[SLAP_TEXT_BUFLEN] = { '\0' }; 343 size_t textlen = sizeof textbuf; 344 Erec erec; 345 struct berval bvtext; 346 ldap_pvt_thread_t thr; 347 ID id; 348 Entry *prev = NULL; 349 350 int ldifrc; 351 int rc = EXIT_SUCCESS; 352 353 struct stat stat_buf; 354 355 /* default "000" */ 356 csnsid = 0; 357 358 if ( isatty (2) ) enable_meter = 1; 359 slap_tool_init( progname, SLAPADD, argc, argv ); 360 361 if( !be->be_entry_open || 362 !be->be_entry_close || 363 !be->be_entry_put || 364 (update_ctxcsn && 365 (!be->be_dn2id_get || 366 !be->be_entry_get || 367 !be->be_entry_modify)) ) 368 { 369 fprintf( stderr, "%s: database doesn't support necessary operations.\n", 370 progname ); 371 if ( dryrun ) { 372 fprintf( stderr, "\t(dry) continuing...\n" ); 373 374 } else { 375 exit( EXIT_FAILURE ); 376 } 377 } 378 379 checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1; 380 381 /* do not check values in quick mode */ 382 if ( slapMode & SLAP_TOOL_QUICK ) { 383 if ( slapMode & SLAP_TOOL_VALUE_CHECK ) { 384 fprintf( stderr, "%s: value-check incompatible with quick mode; disabled.\n", progname ); 385 slapMode &= ~SLAP_TOOL_VALUE_CHECK; 386 } 387 } 388 389 /* enforce schema checking unless not disabled */ 390 if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) { 391 SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK); 392 } 393 394 if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) { 395 fprintf( stderr, "%s: could not open database.\n", 396 progname ); 397 exit( EXIT_FAILURE ); 398 } 399 400 (void)slap_tool_update_ctxcsn_init(); 401 402 if ( enable_meter 403 #ifdef LDAP_DEBUG 404 /* tools default to "none" */ 405 && slap_debug == LDAP_DEBUG_NONE 406 #endif 407 && !fstat ( fileno ( ldiffp->fp ), &stat_buf ) 408 && S_ISREG(stat_buf.st_mode) ) { 409 enable_meter = !lutil_meter_open( 410 &meter, 411 &lutil_meter_text_display, 412 &lutil_meter_linear_estimator, 413 stat_buf.st_size); 414 } else { 415 enable_meter = 0; 416 } 417 418 if ( slap_tool_thread_max > 1 ) { 419 ldap_pvt_thread_mutex_init( &add_mutex ); 420 ldap_pvt_thread_cond_init( &add_cond ); 421 ldap_pvt_thread_create( &thr, 0, getrec_thr, NULL ); 422 ldif_threaded = 1; 423 } 424 425 erec.nextline = 0; 426 erec.e = NULL; 427 428 for (;;) { 429 ldifrc = getrec( &erec ); 430 if ( ldifrc < 1 ) { 431 if ( ldifrc == -2 && continuemode ) 432 continue; 433 break; 434 } 435 436 if ( !dryrun ) { 437 /* 438 * Initialize text buffer 439 */ 440 bvtext.bv_len = textlen; 441 bvtext.bv_val = textbuf; 442 bvtext.bv_val[0] = '\0'; 443 444 id = be->be_entry_put( be, erec.e, &bvtext ); 445 if( id == NOID ) { 446 fprintf( stderr, "%s: could not add entry dn=\"%s\" " 447 "(line=%lu): %s\n", progname, erec.e->e_dn, 448 erec.lineno, bvtext.bv_val ); 449 rc = EXIT_FAILURE; 450 if( continuemode ) { 451 if ( prev ) entry_free( prev ); 452 prev = erec.e; 453 continue; 454 } 455 break; 456 } 457 if ( verbose ) 458 fprintf( stderr, "added: \"%s\" (%08lx)\n", 459 erec.e->e_dn, (long) id ); 460 } else { 461 if ( verbose ) 462 fprintf( stderr, "added: \"%s\"\n", 463 erec.e->e_dn ); 464 } 465 466 if ( prev ) entry_free( prev ); 467 prev = erec.e; 468 } 469 470 if ( ldif_threaded ) { 471 ldap_pvt_thread_mutex_lock( &add_mutex ); 472 add_stop = 1; 473 trec.ready = 0; 474 ldap_pvt_thread_cond_signal( &add_cond ); 475 ldap_pvt_thread_mutex_unlock( &add_mutex ); 476 ldap_pvt_thread_join( thr, NULL ); 477 } 478 if ( erec.e ) entry_free( erec.e ); 479 480 if ( ldifrc < 0 ) 481 rc = EXIT_FAILURE; 482 483 bvtext.bv_len = textlen; 484 bvtext.bv_val = textbuf; 485 bvtext.bv_val[0] = '\0'; 486 487 if ( enable_meter ) { 488 lutil_meter_update( &meter, ftell( ldiffp->fp ), 1); 489 lutil_meter_close( &meter ); 490 } 491 492 if ( rc == EXIT_SUCCESS ) { 493 rc = slap_tool_update_ctxcsn( progname, sid, &bvtext ); 494 } 495 496 ch_free( buf ); 497 498 if ( !dryrun ) { 499 if ( enable_meter ) { 500 fprintf( stderr, "Closing DB..." ); 501 } 502 if( be->be_entry_close( be ) ) { 503 rc = EXIT_FAILURE; 504 } 505 506 if( be->be_sync ) { 507 be->be_sync( be ); 508 } 509 if ( enable_meter ) { 510 fprintf( stderr, "\n" ); 511 } 512 } 513 514 if ( slap_tool_destroy()) 515 rc = EXIT_FAILURE; 516 517 return rc; 518 } 519 520