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, &timestamp );
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