xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldapmodify.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /* ldapmodify.c - generic program to modify or add entries using LDAP */
2 /* $OpenLDAP: pkg/ldap/clients/tools/ldapmodify.c,v 1.186.2.7 2008/02/11 23:26:38 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * Portions Copyright 2006 Howard Chu.
7  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
8  * Portions Copyright 1998-2001 Net Boolean Incorporated.
9  * Portions Copyright 2001-2003 IBM Corporation.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms are permitted
24  * provided that this notice is preserved and that due credit is given
25  * to the University of Michigan at Ann Arbor.  The name of the
26  * University may not be used to endorse or promote products derived
27  * from this software without specific prior written permission.  This
28  * software is provided ``as is'' without express or implied warranty.
29  */
30 /* ACKNOWLEDGEMENTS:
31  * This work was originally developed by the University of Michigan
32  * (as part of U-MICH LDAP).  Additional significant contributors
33  * include:
34  *   Kurt D. Zeilenga
35  *   Norbert Klasen
36  *   Howard Chu
37  */
38 
39 #include "portable.h"
40 
41 #include <stdio.h>
42 
43 #include <ac/stdlib.h>
44 #include <ac/ctype.h>
45 #include <ac/string.h>
46 #include <ac/unistd.h>
47 #include <ac/socket.h>
48 #include <ac/time.h>
49 
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
53 
54 #ifdef HAVE_SYS_FILE_H
55 #include <sys/file.h>
56 #endif
57 #ifdef HAVE_FCNTL_H
58 #include <fcntl.h>
59 #endif
60 
61 #include <ldap.h>
62 
63 #include "lutil.h"
64 #include "lutil_ldap.h"
65 #include "ldif.h"
66 #include "ldap_defaults.h"
67 #include "ldap_log.h"
68 #include "ldap_pvt.h"
69 #include "lber_pvt.h"
70 
71 #include "common.h"
72 
73 static int	ldapadd;
74 static char *rejfile = NULL;
75 static LDAP	*ld = NULL;
76 
77 #define	M_SEP	0x7f
78 
79 /* strings found in LDIF entries */
80 static struct berval BV_VERSION = BER_BVC("version");
81 static struct berval BV_DN = BER_BVC("dn");
82 static struct berval BV_CONTROL = BER_BVC("control");
83 static struct berval BV_CHANGETYPE = BER_BVC("changetype");
84 static struct berval BV_ADDCT = BER_BVC("add");
85 static struct berval BV_MODIFYCT = BER_BVC("modify");
86 static struct berval BV_DELETECT = BER_BVC("delete");
87 static struct berval BV_MODRDNCT = BER_BVC("modrdn");
88 static struct berval BV_MODDNCT = BER_BVC("moddn");
89 static struct berval BV_RENAMECT = BER_BVC("rename");
90 static struct berval BV_MODOPADD = BER_BVC("add");
91 static struct berval BV_MODOPREPLACE = BER_BVC("replace");
92 static struct berval BV_MODOPDELETE = BER_BVC("delete");
93 static struct berval BV_MODOPINCREMENT = BER_BVC("increment");
94 static struct berval BV_NEWRDN = BER_BVC("newrdn");
95 static struct berval BV_DELETEOLDRDN = BER_BVC("deleteoldrdn");
96 static struct berval BV_NEWSUP = BER_BVC("newsuperior");
97 
98 #define	BVICMP(a,b)	((a)->bv_len != (b)->bv_len ? \
99 	(a)->bv_len - (b)->bv_len : strcasecmp((a)->bv_val, (b)->bv_val))
100 
101 static int process_ldif_rec LDAP_P(( char *rbuf, int lineno ));
102 static int parse_ldif_control LDAP_P(( struct berval *val, LDAPControl ***pctrls ));
103 static int domodify LDAP_P((
104 	const char *dn,
105 	LDAPMod **pmods,
106 	LDAPControl **pctrls,
107 	int newentry ));
108 static int dodelete LDAP_P((
109 	const char *dn,
110 	LDAPControl **pctrls ));
111 static int dorename LDAP_P((
112 	const char *dn,
113 	const char *newrdn,
114 	const char *newsup,
115 	int deleteoldrdn,
116 	LDAPControl **pctrls ));
117 static int process_response(
118 	LDAP *ld,
119 	int msgid,
120 	int res,
121 	const char *dn );
122 
123 #ifdef LDAP_X_TXN
124 static int txn = 0;
125 static int txnabort = 0;
126 struct berval *txn_id = NULL;
127 #endif
128 
129 void
130 usage( void )
131 {
132 	fprintf( stderr, _("Add or modify entries from an LDAP server\n\n"));
133 	fprintf( stderr, _("usage: %s [options]\n"), prog);
134 	fprintf( stderr, _("	The list of desired operations are read from stdin"
135 		" or from the file\n"));
136 	fprintf( stderr, _("	specified by \"-f file\".\n"));
137 	fprintf( stderr, _("Add or modify options:\n"));
138 	fprintf( stderr, _("  -a         add values (%s)\n"),
139 		(ldapadd ? _("default") : _("default is to replace")));
140 	fprintf( stderr, _("  -E [!]ext=extparam	modify extensions"
141 		" (! indicate s criticality)\n"));
142 #ifdef LDAP_X_TXN
143  	fprintf( stderr,
144 		_("             [!]txn=<commit|abort>         (transaction)\n"));
145 #endif
146 	fprintf( stderr, _("  -S file    write skipped modifications to `file'\n"));
147 
148 	tool_common_usage();
149 	exit( EXIT_FAILURE );
150 }
151 
152 
153 const char options[] = "aE:rS:"
154 	"cd:D:e:f:h:H:IMnO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
155 
156 int
157 handle_private_option( int i )
158 {
159 	char	*control, *cvalue;
160 	int		crit;
161 
162 	switch ( i ) {
163 	case 'E': /* modify extensions */
164 		if( protocol == LDAP_VERSION2 ) {
165 			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
166 				prog, protocol );
167 			exit( EXIT_FAILURE );
168 		}
169 
170 		/* should be extended to support comma separated list of
171 		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
172 		 */
173 
174 		crit = 0;
175 		cvalue = NULL;
176 		if( optarg[0] == '!' ) {
177 			crit = 1;
178 			optarg++;
179 		}
180 
181 		control = ber_strdup( optarg );
182 		if ( (cvalue = strchr( control, '=' )) != NULL ) {
183 			*cvalue++ = '\0';
184 		}
185 
186 #ifdef LDAP_X_TXN
187 		if( strcasecmp( control, "txn" ) == 0 ) {
188 			/* Transaction */
189 			if( txn ) {
190 				fprintf( stderr,
191 					_("txn control previously specified\n"));
192 				exit( EXIT_FAILURE );
193 			}
194 			if( cvalue != NULL ) {
195 				if( strcasecmp( cvalue, "abort" ) == 0 ) {
196 					txnabort=1;
197 				} else if( strcasecmp( cvalue, "commit" ) != 0 ) {
198 					fprintf( stderr, _("Invalid value for txn control, %s\n"),
199 						cvalue );
200 					exit( EXIT_FAILURE );
201 				}
202 			}
203 
204 			txn = 1 + crit;
205 		} else
206 #endif
207 		{
208 			fprintf( stderr, _("Invalid modify extension name: %s\n"),
209 				control );
210 			usage();
211 		}
212 		break;
213 
214 	case 'a':	/* add */
215 		ldapadd = 1;
216 		break;
217 
218 	case 'r':	/* replace (obsolete) */
219 		break;
220 
221 	case 'S':	/* skipped modifications to file */
222 		if( rejfile != NULL ) {
223 			fprintf( stderr, _("%s: -S previously specified\n"), prog );
224 			exit( EXIT_FAILURE );
225 		}
226 		rejfile = ber_strdup( optarg );
227 		break;
228 
229 	default:
230 		return 0;
231 	}
232 	return 1;
233 }
234 
235 
236 int
237 main( int argc, char **argv )
238 {
239 	char		*rbuf = NULL, *rejbuf = NULL;
240 	FILE		*rejfp;
241 	struct LDIFFP *ldiffp, ldifdummy = {0};
242 	char		*matched_msg, *error_msg;
243 	int		rc, retval;
244 	int		len;
245 	int		i = 0;
246 	int		lineno, nextline = 0, lmax = 0;
247 	LDAPControl	c[1];
248 
249 	prog = lutil_progname( "ldapmodify", argc, argv );
250 
251 	/* strncmp instead of strcmp since NT binaries carry .exe extension */
252 	ldapadd = ( strncasecmp( prog, "ldapadd", sizeof("ldapadd")-1 ) == 0 );
253 
254 	tool_init( ldapadd ? TOOL_ADD : TOOL_MODIFY );
255 
256 	tool_args( argc, argv );
257 
258 	if ( argc != optind ) usage();
259 
260 	if ( rejfile != NULL ) {
261 		if (( rejfp = fopen( rejfile, "w" )) == NULL ) {
262 			perror( rejfile );
263 			return( EXIT_FAILURE );
264 		}
265 	} else {
266 		rejfp = NULL;
267 	}
268 
269 	if ( infile != NULL ) {
270 		if (( ldiffp = ldif_open( infile, "r" )) == NULL ) {
271 			perror( infile );
272 			return( EXIT_FAILURE );
273 		}
274 	} else {
275 		ldifdummy.fp = stdin;
276 		ldiffp = &ldifdummy;
277 	}
278 
279 	if ( debug ) ldif_debug = debug;
280 
281 	ld = tool_conn_setup( dont, 0 );
282 
283 	if ( !dont ) {
284 		if ( pw_file || want_bindpw ) {
285 			if ( pw_file ) {
286 				rc = lutil_get_filed_password( pw_file, &passwd );
287 				if( rc ) return EXIT_FAILURE;
288 			} else {
289 				passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
290 				passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
291 			}
292 		}
293 		tool_bind( ld );
294 	}
295 
296 #ifdef LDAP_X_TXN
297 	if( txn ) {
298 		/* start transaction */
299 		rc = ldap_txn_start_s( ld, NULL, NULL, &txn_id );
300 		if( rc != LDAP_SUCCESS ) {
301 			tool_perror( "ldap_txn_start_s", rc, NULL, NULL, NULL, NULL );
302 			if( txn > 1 ) return EXIT_FAILURE;
303 			txn = 0;
304 		}
305 	}
306 #endif
307 
308 	if ( 0
309 #ifdef LDAP_X_TXN
310 		|| txn
311 #endif
312 		)
313 	{
314 #ifdef LDAP_X_TXN
315 		if( txn ) {
316 			c[i].ldctl_oid = LDAP_CONTROL_X_TXN_SPEC;
317 			c[i].ldctl_value = *txn_id;
318 			c[i].ldctl_iscritical = 1;
319 			i++;
320 		}
321 #endif
322 	}
323 
324 	tool_server_controls( ld, c, i );
325 
326 	rc = 0;
327 	retval = 0;
328 	lineno = 1;
329 	while (( rc == 0 || contoper ) && ldif_read_record( ldiffp, &nextline,
330 		&rbuf, &lmax ))
331 	{
332 		if ( rejfp ) {
333 			len = strlen( rbuf );
334 			if (( rejbuf = (char *)ber_memalloc( len+1 )) == NULL ) {
335 				perror( "malloc" );
336 				exit( EXIT_FAILURE );
337 			}
338 			memcpy( rejbuf, rbuf, len+1 );
339 		}
340 
341 		rc = process_ldif_rec( rbuf, lineno );
342 		lineno = nextline+1;
343 
344 		if ( rc ) retval = rc;
345 		if ( rc && rejfp ) {
346 			fprintf(rejfp, _("# Error: %s (%d)"), ldap_err2string(rc), rc);
347 
348 			matched_msg = NULL;
349 			ldap_get_option(ld, LDAP_OPT_MATCHED_DN, &matched_msg);
350 			if ( matched_msg != NULL ) {
351 				if ( *matched_msg != '\0' ) {
352 					fprintf( rejfp, _(", matched DN: %s"), matched_msg );
353 				}
354 				ldap_memfree( matched_msg );
355 			}
356 
357 			error_msg = NULL;
358 			ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, &error_msg);
359 			if ( error_msg != NULL ) {
360 				if ( *error_msg != '\0' ) {
361 					fprintf( rejfp, _(", additional info: %s"), error_msg );
362 				}
363 				ldap_memfree( error_msg );
364 			}
365 			fprintf( rejfp, "\n%s\n", rejbuf );
366 		}
367 
368 		if (rejfp) ber_memfree( rejbuf );
369 	}
370 	ber_memfree( rbuf );
371 
372 #ifdef LDAP_X_TXN
373 	if( retval == 0 && txn ) {
374 		rc = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, NULL );
375 		if ( rc != LDAP_OPT_SUCCESS ) {
376 			fprintf( stderr, "Could not unset controls for ldap_txn_end\n");
377 		}
378 
379 		/* create transaction */
380 		rc = ldap_txn_end_s( ld, !txnabort, txn_id, NULL, NULL, NULL );
381 		if( rc != LDAP_SUCCESS ) {
382 			tool_perror( "ldap_txn_end_s", rc, NULL, NULL, NULL, NULL );
383 			retval = rc;
384 		}
385 	}
386 #endif
387 
388 	if ( !dont ) {
389 		tool_unbind( ld );
390 	}
391 
392 	if ( rejfp != NULL ) {
393 		fclose( rejfp );
394 	}
395 
396 	tool_destroy();
397 	return( retval );
398 }
399 
400 
401 static int
402 process_ldif_rec( char *rbuf, int linenum )
403 {
404 	char	*line, *dn, *newrdn, *newsup;
405 	int		rc, modop;
406 	int		expect_modop, expect_sep;
407 	int		deleteoldrdn;
408 	int		new_entry, delete_entry, got_all;
409 	LDAPMod	**pmods, *lm = NULL;
410 	int version;
411 	LDAPControl **pctrls;
412 	int i, j, k, lines, idn, nmods;
413 	struct berval *btype, *vals, **bvl, bv;
414 	char *freeval;
415 	unsigned char *mops = NULL;
416 
417 	new_entry = ldapadd;
418 
419 	rc = got_all = delete_entry = modop = expect_modop = 0;
420 	expect_sep = 0;
421 	version = 0;
422 	deleteoldrdn = 1;
423 	pmods = NULL;
424 	pctrls = NULL;
425 	dn = newrdn = newsup = NULL;
426 
427 	lines = ldif_countlines( rbuf );
428 	btype = ber_memcalloc( 1, (lines+1)*2*sizeof(struct berval)+lines );
429 	if ( !btype )
430 		return LDAP_NO_MEMORY;
431 
432 	vals = btype+lines+1;
433 	freeval = (char *)(vals+lines+1);
434 	i = -1;
435 
436 	while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
437 		int freev;
438 
439 		if ( *line == '\n' || *line == '\0' ) {
440 			break;
441 		}
442 
443 		++i;
444 
445 		if ( line[0] == '-' && !line[1] ) {
446 			BER_BVZERO( btype+i );
447 			freeval[i] = 0;
448 			continue;
449 		}
450 
451 		if ( ( rc = ldif_parse_line2( line, btype+i, vals+i, &freev ) ) < 0 ) {
452 			fprintf( stderr, _("%s: invalid format (line %d) entry: \"%s\"\n"),
453 				prog, linenum+i, dn == NULL ? "" : dn );
454 			rc = LDAP_PARAM_ERROR;
455 			break;
456 		}
457 		freeval[i] = freev;
458 
459 		if ( dn == NULL ) {
460 			if ( linenum+i == 1 && !BVICMP( btype+i, &BV_VERSION )) {
461 				int	v;
462 				if( vals[i].bv_len == 0 || lutil_atoi( &v, vals[i].bv_val) != 0 || v != 1 ) {
463 					fprintf( stderr,
464 						_("%s: invalid version %s, line %d (ignored)\n"),
465 						prog, vals[i].bv_val, linenum );
466 				}
467 				version++;
468 
469 			} else if ( !BVICMP( btype+i, &BV_DN )) {
470 				dn = vals[i].bv_val;
471 				idn = i;
472 			}
473 			/* skip all lines until we see "dn:" */
474 		}
475 	}
476 
477 	/* check to make sure there was a dn: line */
478 	if ( !dn ) {
479 		rc = 0;
480 		goto leave;
481 	}
482 
483 	lines = i+1;
484 
485 	if( lines == 0 ) {
486 		rc = 0;
487 		goto leave;
488 	}
489 
490 	if( version && lines == 1 ) {
491 		rc = 0;
492 		goto leave;
493 	}
494 
495 	i = idn+1;
496 	/* Check for "control" tag after dn and before changetype. */
497 	if (!BVICMP( btype+i, &BV_CONTROL)) {
498 		/* Parse and add it to the list of controls */
499 		rc = parse_ldif_control( vals+i, &pctrls );
500 		if (rc != 0) {
501 			fprintf( stderr,
502 				_("%s: Error processing %s line, line %d: %s\n"),
503 				prog, BV_CONTROL.bv_val, linenum+i, ldap_err2string(rc) );
504 		}
505 		i++;
506 		if ( i>= lines ) {
507 short_input:
508 			fprintf( stderr,
509 				_("%s: Expecting more input after %s line, line %d\n"),
510 				prog, btype[i-1].bv_val, linenum+i );
511 
512 			rc = LDAP_PARAM_ERROR;
513 			goto leave;
514 		}
515 	}
516 
517 	/* Check for changetype */
518 	if ( !BVICMP( btype+i, &BV_CHANGETYPE )) {
519 #ifdef LIBERAL_CHANGETYPE_MODOP
520 		/* trim trailing spaces (and log warning ...) */
521 		int icnt;
522 		for ( icnt = vals[i].bv_len; --icnt > 0; ) {
523 			if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) {
524 				break;
525 			}
526 		}
527 
528 		if ( ++icnt != vals[i].bv_len ) {
529 			fprintf( stderr, _("%s: illegal trailing space after"
530 				" \"%s: %s\" trimmed (line %d, entry \"%s\")\n"),
531 				prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn );
532 			vals[i].bv_val[icnt] = '\0';
533 		}
534 #endif /* LIBERAL_CHANGETYPE_MODOP */
535 
536 		if ( BVICMP( vals+i, &BV_MODIFYCT ) == 0 ) {
537 			new_entry = 0;
538 			expect_modop = 1;
539 		} else if ( BVICMP( vals+i, &BV_ADDCT ) == 0 ) {
540 			new_entry = 1;
541 			modop = LDAP_MOD_ADD;
542 		} else if ( BVICMP( vals+i, &BV_MODRDNCT ) == 0
543 			|| BVICMP( vals+i, &BV_MODDNCT ) == 0
544 			|| BVICMP( vals+i, &BV_RENAMECT ) == 0)
545 		{
546 			i++;
547 			if ( i >= lines )
548 				goto short_input;
549 			if ( BVICMP( btype+i, &BV_NEWRDN )) {
550 				fprintf( stderr, _("%s: expecting \"%s:\" but saw"
551 					" \"%s:\" (line %d, entry \"%s\")\n"),
552 					prog, BV_NEWRDN.bv_val, btype[i].bv_val, linenum+i, dn );
553 				rc = LDAP_PARAM_ERROR;
554 				goto leave;
555 			}
556 			newrdn = vals[i].bv_val;
557 			i++;
558 			if ( i >= lines )
559 				goto short_input;
560 			if ( BVICMP( btype+i, &BV_DELETEOLDRDN )) {
561 				fprintf( stderr, _("%s: expecting \"%s:\" but saw"
562 					" \"%s:\" (line %d, entry \"%s\")\n"),
563 					prog, BV_DELETEOLDRDN.bv_val, btype[i].bv_val, linenum+i, dn );
564 				rc = LDAP_PARAM_ERROR;
565 				goto leave;
566 			}
567 			deleteoldrdn = ( vals[i].bv_val[0] == '0' ) ? 0 : 1;
568 			i++;
569 			if ( i < lines ) {
570 				if ( BVICMP( btype+i, &BV_NEWSUP )) {
571 					fprintf( stderr, _("%s: expecting \"%s:\" but saw"
572 						" \"%s:\" (line %d, entry \"%s\")\n"),
573 						prog, BV_NEWSUP.bv_val, btype[i].bv_val, linenum+i, dn );
574 					rc = LDAP_PARAM_ERROR;
575 					goto leave;
576 				}
577 				newsup = vals[i].bv_val;
578 				i++;
579 			}
580 			got_all = 1;
581 		} else if ( BVICMP( vals+i, &BV_DELETECT ) == 0 ) {
582 			got_all = delete_entry = 1;
583 		} else {
584 			fprintf( stderr,
585 				_("%s:  unknown %s \"%s\" (line %d, entry \"%s\")\n"),
586 				prog, BV_CHANGETYPE.bv_val, vals[i].bv_val, linenum+i, dn );
587 			rc = LDAP_PARAM_ERROR;
588 			goto leave;
589 		}
590 		i++;
591 	} else if ( ldapadd ) {		/*  missing changetype => add */
592 		new_entry = 1;
593 		modop = LDAP_MOD_ADD;
594 	} else {
595 		expect_modop = 1;	/* missing changetype => modify */
596 	}
597 
598 	if ( got_all ) {
599 		if ( i < lines ) {
600 			fprintf( stderr,
601 				_("%s: extra lines at end (line %d, entry \"%s\")\n"),
602 				prog, linenum+i, dn );
603 			rc = LDAP_PARAM_ERROR;
604 			goto leave;
605 		}
606 		goto doit;
607 	}
608 
609 	nmods = lines - i;
610 	idn = i;
611 
612 	if ( new_entry ) {
613 		int fv;
614 
615 		/* Make sure all attributes with multiple values are contiguous */
616 		for (; i<lines; i++) {
617 			for (j=i+1; j<lines; j++) {
618 				if ( !BVICMP( btype+i, btype+j )) {
619 					nmods--;
620 					/* out of order, move intervening attributes down */
621 					if ( j != i+1 ) {
622 						bv = vals[j];
623 						fv = freeval[j];
624 						for (k=j; k>i; k--) {
625 							btype[k] = btype[k-1];
626 							vals[k] = vals[k-1];
627 							freeval[k] = freeval[k-1];
628 						}
629 						k++;
630 						btype[k] = btype[i];
631 						vals[k] = bv;
632 						freeval[k] = fv;
633 					}
634 					i++;
635 				}
636 			}
637 		}
638 		/* Allocate space for array of mods, array of pointers to mods,
639 		 * and array of pointers to values, allowing for NULL terminators
640 		 * for the pointer arrays...
641 		 */
642 		lm = ber_memalloc( nmods * sizeof(LDAPMod) +
643 			(nmods+1) * sizeof(LDAPMod*) +
644 			(lines + nmods - idn) * sizeof(struct berval *));
645 		pmods = (LDAPMod **)(lm+nmods);
646 		bvl = (struct berval **)(pmods+nmods+1);
647 
648 		j = 0;
649 		k = -1;
650 		BER_BVZERO(&bv);
651 		for (i=idn; i<lines; i++) {
652 			if ( !BVICMP( btype+i, &BV_DN )) {
653 				fprintf( stderr, _("%s: attributeDescription \"%s\":"
654 					" (possible missing newline"
655 						" after line %d, entry \"%s\"?)\n"),
656 					prog, btype[i].bv_val, linenum+i - 1, dn );
657 			}
658 			if ( BVICMP(btype+i,&bv)) {
659 				bvl[k++] = NULL;
660 				bv = btype[i];
661 				lm[j].mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
662 				lm[j].mod_type = bv.bv_val;
663 				lm[j].mod_bvalues = bvl+k;
664 				pmods[j] = lm+j;
665 				j++;
666 			}
667 			bvl[k++] = vals+i;
668 		}
669 		bvl[k] = NULL;
670 		pmods[j] = NULL;
671 		goto doit;
672 	}
673 
674 	mops = ber_memalloc( lines+1 );
675 	mops[lines] = M_SEP;
676 	mops[i-1] = M_SEP;
677 
678 	for ( ; i<lines; i++ ) {
679 		if ( expect_modop ) {
680 #ifdef LIBERAL_CHANGETYPE_MODOP
681 			/* trim trailing spaces (and log warning ...) */
682 		    int icnt;
683 		    for ( icnt = vals[i].bv_len; --icnt > 0; ) {
684 				if ( !isspace( (unsigned char) vals[i].bv_val[icnt] ) ) break;
685 			}
686 
687 			if ( ++icnt != vals[i].bv_len ) {
688 				fprintf( stderr, _("%s: illegal trailing space after"
689 					" \"%s: %s\" trimmed (line %d, entry \"%s\")\n"),
690 					prog, type, vals[i].bv_val, linenum+i, dn );
691 				vals[i].bv_val[icnt] = '\0';
692 			}
693 #endif /* LIBERAL_CHANGETYPE_MODOP */
694 
695 			expect_modop = 0;
696 			expect_sep = 1;
697 			if ( BVICMP( btype+i, &BV_MODOPADD ) == 0 ) {
698 				modop = LDAP_MOD_ADD;
699 				mops[i] = M_SEP;
700 				nmods--;
701 			} else if ( BVICMP( btype+i, &BV_MODOPREPLACE ) == 0 ) {
702 			/* defer handling these since they might have no values.
703 			 * Use the BVALUES flag to signal that these were
704 			 * deferred. If values are provided later, this
705 			 * flag will be switched off.
706 			 */
707 				modop = LDAP_MOD_REPLACE;
708 				mops[i] = modop | LDAP_MOD_BVALUES;
709 				btype[i] = vals[i];
710 			} else if ( BVICMP( btype+i, &BV_MODOPDELETE ) == 0 ) {
711 				modop = LDAP_MOD_DELETE;
712 				mops[i] = modop | LDAP_MOD_BVALUES;
713 				btype[i] = vals[i];
714 			} else if ( BVICMP( btype+i, &BV_MODOPINCREMENT ) == 0 ) {
715 				modop = LDAP_MOD_INCREMENT;
716 				mops[i] = M_SEP;
717 				nmods--;
718 			} else {	/* no modify op: invalid LDIF */
719 				fprintf( stderr, _("%s: modify operation type is missing at"
720 					" line %d, entry \"%s\"\n"),
721 					prog, linenum+i, dn );
722 				rc = LDAP_PARAM_ERROR;
723 				goto leave;
724 			}
725 			bv = vals[i];
726 		} else if ( expect_sep && BER_BVISEMPTY( btype+i )) {
727 			mops[i] = M_SEP;
728 			expect_sep = 0;
729 			expect_modop = 1;
730 			nmods--;
731 		} else {
732 			if ( BVICMP( btype+i, &bv )) {
733 				fprintf( stderr, _("%s: wrong attributeType at"
734 					" line %d, entry \"%s\"\n"),
735 					prog, linenum+i, dn );
736 				rc = LDAP_PARAM_ERROR;
737 				goto leave;
738 			}
739 			mops[i] = modop;
740 			/* If prev op was deferred and matches this type,
741 			 * clear the flag
742 			 */
743 			if ( (mops[i-1]&LDAP_MOD_BVALUES) && !BVICMP(btype+i,
744 				btype+i-1)) {
745 				mops[i-1] = M_SEP;
746 				nmods--;
747 			}
748 		}
749 	}
750 
751 #if 0	/* we should faithfully encode the LDIF, not combine */
752 	/* Make sure all modops with multiple values are contiguous */
753 	for (i=idn; i<lines; i++) {
754 		if ( mops[i] == M_SEP )
755 			continue;
756 		for (j=i+1; j<lines; j++) {
757 			if ( mops[j] == M_SEP || mops[i] != mops[j] )
758 				continue;
759 			if ( !BVICMP( btype+i, btype+j )) {
760 				nmods--;
761 				/* out of order, move intervening attributes down */
762 				if ( j != i+1 ) {
763 					int c;
764 					struct berval bv;
765 					char fv;
766 
767 					c = mops[j];
768 					bv = vals[j];
769 					fv = freeval[j];
770 					for (k=j; k>i; k--) {
771 						btype[k] = btype[k-1];
772 						vals[k] = vals[k-1];
773 						freeval[k] = freeval[k-1];
774 						mops[k] = mops[k-1];
775 					}
776 					k++;
777 					btype[k] = btype[i];
778 					vals[k] = bv;
779 					freeval[k] = fv;
780 					mops[k] = c;
781 				}
782 				i++;
783 			}
784 		}
785 	}
786 #endif
787 
788 	/* Allocate space for array of mods, array of pointers to mods,
789 	 * and array of pointers to values, allowing for NULL terminators
790 	 * for the pointer arrays...
791 	 */
792 	lm = ber_memalloc( nmods * sizeof(LDAPMod) +
793 		(nmods+1) * sizeof(LDAPMod*) +
794 		(lines + nmods - idn) * sizeof(struct berval *));
795 	pmods = (LDAPMod **)(lm+nmods);
796 	bvl = (struct berval **)(pmods+nmods+1);
797 
798 	j = 0;
799 	k = -1;
800 	BER_BVZERO(&bv);
801 	mops[idn-1] = M_SEP;
802 	for (i=idn; i<lines; i++) {
803 		if ( mops[i] == M_SEP )
804 			continue;
805 		if ( mops[i] != mops[i-1] || BVICMP(btype+i,&bv)) {
806 			bvl[k++] = NULL;
807 			bv = btype[i];
808 			lm[j].mod_op = mops[i] | LDAP_MOD_BVALUES;
809 			lm[j].mod_type = bv.bv_val;
810 			if ( mops[i] & LDAP_MOD_BVALUES ) {
811 				lm[j].mod_bvalues = NULL;
812 			} else {
813 				lm[j].mod_bvalues = bvl+k;
814 			}
815 			pmods[j] = lm+j;
816 			j++;
817 		}
818 		bvl[k++] = vals+i;
819 	}
820 	bvl[k] = NULL;
821 	pmods[j] = NULL;
822 
823 doit:
824 	/* If default controls are set (as with -M option) and controls are
825 	   specified in the LDIF file, we must add the default controls to
826 	   the list of controls sent with the ldap operation.
827 	*/
828 	if ( rc == 0 ) {
829 		if (pctrls) {
830 			LDAPControl **defctrls = NULL;   /* Default server controls */
831 			LDAPControl **newctrls = NULL;
832 			ldap_get_option(ld, LDAP_OPT_SERVER_CONTROLS, &defctrls);
833 			if (defctrls) {
834 				int npc=0;                       /* Num of LDIF controls */
835 				int ndefc=0;                     /* Num of default controls */
836 				while (pctrls[npc]) npc++;       /* Count LDIF controls */
837 				while (defctrls[ndefc]) ndefc++; /* Count default controls */
838 				newctrls = ber_memrealloc(pctrls,
839 					(npc+ndefc+1)*sizeof(LDAPControl*));
840 
841 				if (newctrls == NULL) {
842 					rc = LDAP_NO_MEMORY;
843 				} else {
844 					int i;
845 					pctrls = newctrls;
846 					for (i=npc; i<npc+ndefc; i++) {
847 						pctrls[i] = ldap_control_dup(defctrls[i-npc]);
848 						if (pctrls[i] == NULL) {
849 							rc = LDAP_NO_MEMORY;
850 							break;
851 						}
852 					}
853 					pctrls[npc+ndefc] = NULL;
854 				}
855 				ldap_controls_free(defctrls);  /* Must be freed by library */
856 			}
857 		}
858 	}
859 
860 	if ( rc == 0 ) {
861 		if ( delete_entry ) {
862 			rc = dodelete( dn, pctrls );
863 		} else if ( newrdn != NULL ) {
864 			rc = dorename( dn, newrdn, newsup, deleteoldrdn, pctrls );
865 		} else {
866 			rc = domodify( dn, pmods, pctrls, new_entry );
867 		}
868 
869 		if ( rc == LDAP_SUCCESS ) {
870 			rc = 0;
871 		}
872 	}
873 
874 leave:
875     if (pctrls != NULL) {
876     	ldap_controls_free( pctrls );
877 	}
878 	if ( lm != NULL ) {
879 		ber_memfree( lm );
880 	}
881 	if ( mops != NULL ) {
882 		ber_memfree( mops );
883 	}
884 	for (i=lines-1; i>=0; i--)
885 		if ( freeval[i] ) ber_memfree( vals[i].bv_val );
886 	ber_memfree( btype );
887 
888 	return( rc );
889 }
890 
891 /* Parse an LDIF control line of the form
892       control:  oid  [true/false]  [: value]              or
893       control:  oid  [true/false]  [:: base64-value]      or
894       control:  oid  [true/false]  [:< url]
895    The control is added to the list of controls in *ppctrls.
896 */
897 static int
898 parse_ldif_control(
899 	struct berval *bval,
900 	LDAPControl ***ppctrls )
901 {
902 	char *oid = NULL;
903 	int criticality = 0;   /* Default is false if not present */
904 	int i, rc=0;
905 	char *s, *oidStart;
906 	LDAPControl *newctrl = NULL;
907 	LDAPControl **pctrls = NULL;
908 	struct berval type, bv;
909 	int freeval;
910 
911 	if (ppctrls) pctrls = *ppctrls;
912 	/* OID should come first. Validate and extract it. */
913 	s = bval->bv_val;
914 	if (*s == 0) return ( LDAP_PARAM_ERROR );
915 	oidStart = s;
916 	while (isdigit((unsigned char)*s) || *s == '.') {
917 		s++;                           /* OID should be digits or . */
918 	}
919 	if (s == oidStart) {
920 		return ( LDAP_PARAM_ERROR );   /* OID was not present */
921 	}
922 	if (*s) {                          /* End of OID should be space or NULL */
923 		if (!isspace((unsigned char)*s)) {
924 			return ( LDAP_PARAM_ERROR ); /* else OID contained invalid chars */
925 		}
926 		*s++ = 0;                    /* Replace space with null to terminate */
927 	}
928 
929 	oid = ber_strdup(oidStart);
930 	if (oid == NULL) return ( LDAP_NO_MEMORY );
931 
932 	/* Optional Criticality field is next. */
933 	while (*s && isspace((unsigned char)*s)) {
934 		s++;                         /* Skip white space before criticality */
935 	}
936 	if (strncasecmp(s, "true", 4) == 0) {
937 		criticality = 1;
938 		s += 4;
939 	}
940 	else if (strncasecmp(s, "false", 5) == 0) {
941 		criticality = 0;
942 		s += 5;
943 	}
944 
945 	/* Optional value field is next */
946 	while (*s && isspace((unsigned char)*s)) {
947 		s++;                         /* Skip white space before value */
948 	}
949 	if (*s) {
950 		if (*s != ':') {           /* If value is present, must start with : */
951 			rc = LDAP_PARAM_ERROR;
952 			goto cleanup;
953 		}
954 
955 		/* Back up so value is in the form
956 		     a: value
957 		     a:: base64-value
958 		     a:< url
959 		   Then we can use ldif_parse_line2 to extract and decode the value
960 		*/
961 		s--;
962 		*s = 'a';
963 
964 		rc = ldif_parse_line2(s, &type, &bv, &freeval);
965 		if (rc < 0) {
966 			rc = LDAP_PARAM_ERROR;
967 			goto cleanup;
968 		}
969     }
970 
971 	/* Create a new LDAPControl structure. */
972 	newctrl = (LDAPControl *)ber_memalloc(sizeof(LDAPControl));
973 	if ( newctrl == NULL ) {
974 		rc = LDAP_NO_MEMORY;
975 		goto cleanup;
976 	}
977 	newctrl->ldctl_oid = oid;
978 	oid = NULL;
979 	newctrl->ldctl_iscritical = criticality;
980 	if ( freeval )
981 		newctrl->ldctl_value = bv;
982 	else
983 		ber_dupbv( &newctrl->ldctl_value, &bv );
984 
985 	/* Add the new control to the passed-in list of controls. */
986 	i = 0;
987 	if (pctrls) {
988 		while ( pctrls[i] ) {    /* Count the # of controls passed in */
989 			i++;
990 		}
991 	}
992 	/* Allocate 1 more slot for the new control and 1 for the NULL. */
993 	pctrls = (LDAPControl **) ber_memrealloc(pctrls,
994 		(i+2)*(sizeof(LDAPControl *)));
995 	if (pctrls == NULL) {
996 		rc = LDAP_NO_MEMORY;
997 		goto cleanup;
998 	}
999 	pctrls[i] = newctrl;
1000 	newctrl = NULL;
1001 	pctrls[i+1] = NULL;
1002 	*ppctrls = pctrls;
1003 
1004 cleanup:
1005 	if (newctrl) {
1006 		if (newctrl->ldctl_oid) ber_memfree(newctrl->ldctl_oid);
1007 		if (newctrl->ldctl_value.bv_val) {
1008 			ber_memfree(newctrl->ldctl_value.bv_val);
1009 		}
1010 		ber_memfree(newctrl);
1011 	}
1012 	if (oid) ber_memfree(oid);
1013 
1014 	return( rc );
1015 }
1016 
1017 
1018 static int
1019 domodify(
1020 	const char *dn,
1021 	LDAPMod **pmods,
1022 	LDAPControl **pctrls,
1023 	int newentry )
1024 {
1025 	int			rc, i, j, k, notascii, op;
1026 	struct berval	*bvp;
1027 
1028 	if ( dn == NULL ) {
1029 		fprintf( stderr, _("%s: no DN specified\n"), prog );
1030 		return( LDAP_PARAM_ERROR );
1031 	}
1032 
1033 	if ( pmods == NULL ) {
1034 		/* implement "touch" (empty sequence)
1035 		 * modify operation (note that there
1036 		 * is no symmetry with the UNIX command,
1037 		 * since \"touch\" on a non-existent entry
1038 		 * will fail)*/
1039 		printf( "warning: no attributes to %sadd (entry=\"%s\")\n",
1040 			newentry ? "" : "change or ", dn );
1041 
1042 	} else {
1043 		for ( i = 0; pmods[ i ] != NULL; ++i ) {
1044 			op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1045 			if( op == LDAP_MOD_ADD && ( pmods[i]->mod_bvalues == NULL )) {
1046 				fprintf( stderr,
1047 					_("%s: attribute \"%s\" has no values (entry=\"%s\")\n"),
1048 					prog, pmods[i]->mod_type, dn );
1049 				return LDAP_PARAM_ERROR;
1050 			}
1051 		}
1052 
1053 		if ( verbose ) {
1054 			for ( i = 0; pmods[ i ] != NULL; ++i ) {
1055 				op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
1056 				printf( "%s %s:\n",
1057 					op == LDAP_MOD_REPLACE ? _("replace") :
1058 						op == LDAP_MOD_ADD ?  _("add") :
1059 							op == LDAP_MOD_INCREMENT ?  _("increment") :
1060 								op == LDAP_MOD_DELETE ?  _("delete") :
1061 									_("unknown"),
1062 					pmods[ i ]->mod_type );
1063 
1064 				if ( pmods[ i ]->mod_bvalues != NULL ) {
1065 					for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
1066 						bvp = pmods[ i ]->mod_bvalues[ j ];
1067 						notascii = 0;
1068 						for ( k = 0; (unsigned long) k < bvp->bv_len; ++k ) {
1069 							if ( !isascii( bvp->bv_val[ k ] )) {
1070 								notascii = 1;
1071 								break;
1072 							}
1073 						}
1074 						if ( notascii ) {
1075 							printf( _("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len );
1076 						} else {
1077 							printf( "\t%s\n", bvp->bv_val );
1078 						}
1079 					}
1080 				}
1081 			}
1082 		}
1083 	}
1084 
1085 	if ( newentry ) {
1086 		printf( "%sadding new entry \"%s\"\n", dont ? "!" : "", dn );
1087 	} else {
1088 		printf( "%smodifying entry \"%s\"\n", dont ? "!" : "", dn );
1089 	}
1090 
1091 	if ( !dont ) {
1092 		int	msgid;
1093 		if ( newentry ) {
1094 			rc = ldap_add_ext( ld, dn, pmods, pctrls, NULL, &msgid );
1095 		} else {
1096 			rc = ldap_modify_ext( ld, dn, pmods, pctrls, NULL, &msgid );
1097 		}
1098 
1099 		if ( rc != LDAP_SUCCESS ) {
1100 			/* print error message about failed update including DN */
1101 			fprintf( stderr, _("%s: update failed: %s\n"), prog, dn );
1102 			tool_perror( newentry ? "ldap_add" : "ldap_modify",
1103 				rc, NULL, NULL, NULL, NULL );
1104 			goto done;
1105 		}
1106 		rc = process_response( ld, msgid,
1107 			newentry ? LDAP_RES_ADD : LDAP_RES_MODIFY, dn );
1108 
1109 		if ( verbose && rc == LDAP_SUCCESS ) {
1110 			printf( _("modify complete\n") );
1111 		}
1112 
1113 	} else {
1114 		rc = LDAP_SUCCESS;
1115 	}
1116 
1117 done:
1118 	putchar( '\n' );
1119 	return rc;
1120 }
1121 
1122 
1123 static int
1124 dodelete(
1125 	const char *dn,
1126 	LDAPControl **pctrls )
1127 {
1128 	int	rc;
1129 	int msgid;
1130 
1131 	printf( _("%sdeleting entry \"%s\"\n"), dont ? "!" : "", dn );
1132 	if ( !dont ) {
1133 		rc = ldap_delete_ext( ld, dn, pctrls, NULL, &msgid );
1134 		if ( rc != LDAP_SUCCESS ) {
1135 			fprintf( stderr, _("%s: delete failed: %s\n"), prog, dn );
1136 			tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
1137 			goto done;
1138 		}
1139 		rc = process_response( ld, msgid, LDAP_RES_DELETE, dn );
1140 
1141 		if ( verbose && rc == LDAP_SUCCESS ) {
1142 			printf( _("delete complete\n") );
1143 		}
1144 	} else {
1145 		rc = LDAP_SUCCESS;
1146 	}
1147 
1148 done:
1149 	putchar( '\n' );
1150 	return( rc );
1151 }
1152 
1153 
1154 static int
1155 dorename(
1156 	const char *dn,
1157 	const char *newrdn,
1158 	const char* newsup,
1159 	int deleteoldrdn,
1160 	LDAPControl **pctrls )
1161 {
1162 	int	rc;
1163 	int msgid;
1164 
1165 	printf( _("%smodifying rdn of entry \"%s\"\n"), dont ? "!" : "", dn );
1166 	if ( verbose ) {
1167 		printf( _("\tnew RDN: \"%s\" (%skeep existing values)\n"),
1168 			newrdn, deleteoldrdn ? _("do not ") : "" );
1169 	}
1170 	if ( !dont ) {
1171 		rc = ldap_rename( ld, dn, newrdn, newsup, deleteoldrdn,
1172 			pctrls, NULL, &msgid );
1173 		if ( rc != LDAP_SUCCESS ) {
1174 			fprintf( stderr, _("%s: rename failed: %s\n"), prog, dn );
1175 			tool_perror( "ldap_rename", rc, NULL, NULL, NULL, NULL );
1176 			goto done;
1177 		}
1178 		rc = process_response( ld, msgid, LDAP_RES_RENAME, dn );
1179 
1180 		if ( verbose && rc == LDAP_SUCCESS ) {
1181 			printf( _("rename complete\n") );
1182 		}
1183 	} else {
1184 		rc = LDAP_SUCCESS;
1185 	}
1186 
1187 done:
1188 	putchar( '\n' );
1189 	return( rc );
1190 }
1191 
1192 static const char *
1193 res2str( int res ) {
1194 	switch ( res ) {
1195 	case LDAP_RES_ADD:
1196 		return "ldap_add";
1197 	case LDAP_RES_DELETE:
1198 		return "ldap_delete";
1199 	case LDAP_RES_MODIFY:
1200 		return "ldap_modify";
1201 	case LDAP_RES_MODRDN:
1202 		return "ldap_rename";
1203 	default:
1204 		assert( 0 );
1205 	}
1206 
1207 	return "ldap_unknown";
1208 }
1209 
1210 static int process_response(
1211 	LDAP *ld,
1212 	int msgid,
1213 	int op,
1214 	const char *dn )
1215 {
1216 	LDAPMessage	*res;
1217 	int		rc = LDAP_OTHER, msgtype;
1218 	struct timeval	tv = { 0, 0 };
1219 	int		err;
1220 	char		*text = NULL, *matched = NULL, **refs = NULL;
1221 	LDAPControl	**ctrls = NULL;
1222 
1223 	for ( ; ; ) {
1224 		tv.tv_sec = 0;
1225 		tv.tv_usec = 100000;
1226 
1227 		rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
1228 		if ( tool_check_abandon( ld, msgid ) ) {
1229 			return LDAP_CANCELLED;
1230 		}
1231 
1232 		if ( rc == -1 ) {
1233 			ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
1234 			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
1235 			return rc;
1236 		}
1237 
1238 		if ( rc != 0 ) {
1239 			break;
1240 		}
1241 	}
1242 
1243 	msgtype = ldap_msgtype( res );
1244 
1245 	rc = ldap_parse_result( ld, res, &err, &matched, &text, &refs, &ctrls, 1 );
1246 	if ( rc == LDAP_SUCCESS ) rc = err;
1247 
1248 #ifdef LDAP_X_TXN
1249 	if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) {
1250 		rc = LDAP_SUCCESS;
1251 	} else
1252 #endif
1253 	if ( rc != LDAP_SUCCESS ) {
1254 		tool_perror( res2str( op ), rc, NULL, matched, text, refs );
1255 	} else if ( msgtype != op ) {
1256 		fprintf( stderr, "%s: msgtype: expected %d got %d\n",
1257 			res2str( op ), op, msgtype );
1258 		rc = LDAP_OTHER;
1259 	}
1260 
1261 	if ( text ) ldap_memfree( text );
1262 	if ( matched ) ldap_memfree( matched );
1263 	if ( text ) ber_memvfree( (void **)refs );
1264 
1265 	if ( ctrls ) {
1266 		tool_print_ctrls( ld, ctrls );
1267 		ldap_controls_free( ctrls );
1268 	}
1269 
1270 	return rc;
1271 }
1272