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