xref: /illumos-gate/usr/src/cmd/ldap/common/ldapmodify.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
10*7c478bd9Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
11*7c478bd9Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
12*7c478bd9Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
15*7c478bd9Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
16*7c478bd9Sstevel@tonic-gate  * implied. See the License for the specific language governing
17*7c478bd9Sstevel@tonic-gate  * rights and limitations under the License.
18*7c478bd9Sstevel@tonic-gate  *
19*7c478bd9Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
20*7c478bd9Sstevel@tonic-gate  * March 31, 1998.
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
23*7c478bd9Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
24*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
25*7c478bd9Sstevel@tonic-gate  * Rights Reserved.
26*7c478bd9Sstevel@tonic-gate  *
27*7c478bd9Sstevel@tonic-gate  * Contributor(s):
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /* ldapmodify.c - generic program to modify or add entries using LDAP */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include "ldaptool.h"
33*7c478bd9Sstevel@tonic-gate #include "fileurl.h"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
36*7c478bd9Sstevel@tonic-gate #include <locale.h>
37*7c478bd9Sstevel@tonic-gate #include "ldif.h"
38*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD
41*7c478bd9Sstevel@tonic-gate #define gettext(s) s
42*7c478bd9Sstevel@tonic-gate #endif
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate static int		newval, contoper, force, valsfromfiles, display_binary_values;
45*7c478bd9Sstevel@tonic-gate static int		ldif_version = -1;	/* -1 => unknown version */
46*7c478bd9Sstevel@tonic-gate static char		*rejfile = NULL;
47*7c478bd9Sstevel@tonic-gate static char		*bulkimport_suffix = NULL;
48*7c478bd9Sstevel@tonic-gate static int		ldapmodify_quiet = 0;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
51*7c478bd9Sstevel@tonic-gate static int		error = 0, replace, nbthreads = 1;
52*7c478bd9Sstevel@tonic-gate static int		thr_create_errors = 0;
53*7c478bd9Sstevel@tonic-gate static pthread_mutex_t	read_mutex = {0};
54*7c478bd9Sstevel@tonic-gate static pthread_mutex_t	wait_mutex = {0};
55*7c478bd9Sstevel@tonic-gate static pthread_cond_t	wait_cond  = {0};
56*7c478bd9Sstevel@tonic-gate #else
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * For Solaris, ld is defined local to process() because
59*7c478bd9Sstevel@tonic-gate  * multiple threads restricts Solaris from using a global
60*7c478bd9Sstevel@tonic-gate  * ld variable.
61*7c478bd9Sstevel@tonic-gate  * Solaris uses multiple threads to create multiple
62*7c478bd9Sstevel@tonic-gate  * ldap connections if nbthreads > 1 (i.e -l option).
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate static LDAP		*ld;
65*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #define LDAPMOD_MAXLINE		4096
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
70*7c478bd9Sstevel@tonic-gate #define T_REPLICA_STR		"replica"
71*7c478bd9Sstevel@tonic-gate #define T_DN_STR		"dn"
72*7c478bd9Sstevel@tonic-gate #define T_VERSION_STR		"version"
73*7c478bd9Sstevel@tonic-gate #define T_CHANGETYPESTR         "changetype"
74*7c478bd9Sstevel@tonic-gate #define T_ADDCTSTR		"add"
75*7c478bd9Sstevel@tonic-gate #define T_MODIFYCTSTR		"modify"
76*7c478bd9Sstevel@tonic-gate #define T_DELETECTSTR		"delete"
77*7c478bd9Sstevel@tonic-gate #define T_RENAMECTSTR		"rename"	/* non-standard */
78*7c478bd9Sstevel@tonic-gate #define T_MODDNCTSTR		"moddn"
79*7c478bd9Sstevel@tonic-gate #define T_MODRDNCTSTR		"modrdn"
80*7c478bd9Sstevel@tonic-gate #define T_MODOPADDSTR		"add"
81*7c478bd9Sstevel@tonic-gate #define T_MODOPREPLACESTR	"replace"
82*7c478bd9Sstevel@tonic-gate #define T_MODOPDELETESTR	"delete"
83*7c478bd9Sstevel@tonic-gate #define T_MODSEPSTR		"-"
84*7c478bd9Sstevel@tonic-gate #define T_NEWRDNSTR		"newrdn"
85*7c478bd9Sstevel@tonic-gate #define	T_NEWSUPERIORSTR	"newsuperior"
86*7c478bd9Sstevel@tonic-gate #define	T_NEWPARENTSTR		"newparent"
87*7c478bd9Sstevel@tonic-gate #define T_DELETEOLDRDNSTR	"deleteoldrdn"
88*7c478bd9Sstevel@tonic-gate #define T_NEWSUPERIORSTR        "newsuperior"
89*7c478bd9Sstevel@tonic-gate #define T_NEWPARENTSTR          "newparent"	/* non-standard */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate /* bulk import */
92*7c478bd9Sstevel@tonic-gate #define	BULKIMPORT_START_OID	"2.16.840.1.113730.3.5.7"
93*7c478bd9Sstevel@tonic-gate #define	BULKIMPORT_STOP_OID	"2.16.840.1.113730.3.5.8"
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static int process( void *arg );
96*7c478bd9Sstevel@tonic-gate static void options_callback( int option, char *optarg );
97*7c478bd9Sstevel@tonic-gate static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr,
98*7c478bd9Sstevel@tonic-gate 	char *value, int vlen );
99*7c478bd9Sstevel@tonic-gate static void freepmods( LDAPMod **pmods );
100*7c478bd9Sstevel@tonic-gate static char *read_one_record( FILE *fp );
101*7c478bd9Sstevel@tonic-gate static char *strdup_and_trim( char *s );
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
104*7c478bd9Sstevel@tonic-gate static int process_ldapmod_rec( LDAP *ld, char *rbuf );
105*7c478bd9Sstevel@tonic-gate static int process_ldif_rec( LDAP *ld, char *rbuf );
106*7c478bd9Sstevel@tonic-gate static int domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry );
107*7c478bd9Sstevel@tonic-gate static int dodelete( LDAP *ld, char *dn );
108*7c478bd9Sstevel@tonic-gate static int dorename( LDAP *ld, char *dn, char *newrdn, char *newparent,
109*7c478bd9Sstevel@tonic-gate 	int deleteoldrdn );
110*7c478bd9Sstevel@tonic-gate #else
111*7c478bd9Sstevel@tonic-gate static int process_ldapmod_rec( char *rbuf );
112*7c478bd9Sstevel@tonic-gate static int process_ldif_rec( char *rbuf );
113*7c478bd9Sstevel@tonic-gate static int domodify( char *dn, LDAPMod **pmods, int newentry );
114*7c478bd9Sstevel@tonic-gate static int dodelete( char *dn );
115*7c478bd9Sstevel@tonic-gate static int dorename( char *dn, char *newrdn, char *newparent,
116*7c478bd9Sstevel@tonic-gate 	int deleteoldrdn );
117*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate static void
120*7c478bd9Sstevel@tonic-gate usage( void )
121*7c478bd9Sstevel@tonic-gate {
122*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("usage: %s [options]\n"), ldaptool_progname );
123*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("options:\n") );
124*7c478bd9Sstevel@tonic-gate     ldaptool_common_usage( 0 );
125*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -c\t\tcontinuous mode (do not stop on errors)\n") );
126*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -A\t\tdisplay non-ASCII values in conjunction with -v\n") );
127*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -f file\tread modifications from file (default: standard input)\n") );
128*7c478bd9Sstevel@tonic-gate     if ( strcmp( ldaptool_progname, "ldapmodify" ) == 0 ){
129*7c478bd9Sstevel@tonic-gate 	fprintf( stderr, gettext("    -a\t\tadd entries\n") );
130*7c478bd9Sstevel@tonic-gate     }
131*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -b\t\tread values that start with / from files (for bin attrs)\n") );
132*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -F\t\tforce application of all changes, regardless of\n") );
133*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("      \t\treplica lines\n") );
134*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -e rejfile\tsave rejected entries in \"rejfile\"\n") );
135*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -B suffix\tbulk import to \"suffix\"\n"));
136*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -q\t\tbe quiet when adding/modifying entries\n") );
137*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
138*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -r\t\treplace values\n"));
139*7c478bd9Sstevel@tonic-gate     fprintf( stderr, gettext("    -l nb-connections\tnumber of LDAP connections\n"));
140*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
141*7c478bd9Sstevel@tonic-gate     exit( LDAP_PARAM_ERROR );
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate int
146*7c478bd9Sstevel@tonic-gate main( int argc, char **argv )
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate     int		optind, i;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
151*7c478bd9Sstevel@tonic-gate     char *locale = setlocale(LC_ALL, "");
152*7c478bd9Sstevel@tonic-gate     textdomain(TEXT_DOMAIN);
153*7c478bd9Sstevel@tonic-gate #endif
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate #ifdef notdef
156*7c478bd9Sstevel@tonic-gate #ifdef HPUX11
157*7c478bd9Sstevel@tonic-gate #ifndef __LP64__
158*7c478bd9Sstevel@tonic-gate 	_main( argc, argv);
159*7c478bd9Sstevel@tonic-gate #endif /* __LP64_ */
160*7c478bd9Sstevel@tonic-gate #endif /* HPUX11 */
161*7c478bd9Sstevel@tonic-gate #endif
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate     valsfromfiles = display_binary_values = 0;
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
166*7c478bd9Sstevel@tonic-gate     optind = ldaptool_process_args( argc, argv, "aAbcFe:B:qrl:", 0,
167*7c478bd9Sstevel@tonic-gate 	    options_callback );
168*7c478bd9Sstevel@tonic-gate #else
169*7c478bd9Sstevel@tonic-gate     optind = ldaptool_process_args( argc, argv, "aAbcFe:B:q", 0,
170*7c478bd9Sstevel@tonic-gate 	    options_callback );
171*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate     if ( optind == -1 ) {
175*7c478bd9Sstevel@tonic-gate 	usage();
176*7c478bd9Sstevel@tonic-gate     }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate     if ( !newval && strcmp( ldaptool_progname, "ldapadd" ) == 0 ) {
179*7c478bd9Sstevel@tonic-gate 	newval = 1;
180*7c478bd9Sstevel@tonic-gate     }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate     if ( ldaptool_fp == NULL ) {
183*7c478bd9Sstevel@tonic-gate 	ldaptool_fp = stdin;
184*7c478bd9Sstevel@tonic-gate     }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate     if ( argc - optind != 0 ) {
187*7c478bd9Sstevel@tonic-gate 	usage();
188*7c478bd9Sstevel@tonic-gate     }
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
191*7c478bd9Sstevel@tonic-gate     /* trivial case */
192*7c478bd9Sstevel@tonic-gate     if ( nbthreads == 1 )
193*7c478bd9Sstevel@tonic-gate 	return ( process(NULL) );
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate     for ( i=0; i<nbthreads; ++i ) {
196*7c478bd9Sstevel@tonic-gate  	if ( thr_create(NULL, 0, process, NULL, NULL, NULL) != 0 )
197*7c478bd9Sstevel@tonic-gate 		++thr_create_errors;
198*7c478bd9Sstevel@tonic-gate     }
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate     if ( thr_create_errors < nbthreads )
201*7c478bd9Sstevel@tonic-gate     	while ( thr_join(0, NULL, NULL) == 0 );
202*7c478bd9Sstevel@tonic-gate     else
203*7c478bd9Sstevel@tonic-gate 	error = -1;
204*7c478bd9Sstevel@tonic-gate     return ( error );
205*7c478bd9Sstevel@tonic-gate #else
206*7c478bd9Sstevel@tonic-gate     return ( process(NULL) );
207*7c478bd9Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
211*7c478bd9Sstevel@tonic-gate #define	exit(a)	\
212*7c478bd9Sstevel@tonic-gate 	if (nbthreads > 1) { \
213*7c478bd9Sstevel@tonic-gate     		mutex_lock(&read_mutex); \
214*7c478bd9Sstevel@tonic-gate 		error |= a; \
215*7c478bd9Sstevel@tonic-gate     		mutex_unlock(&read_mutex); \
216*7c478bd9Sstevel@tonic-gate 		thr_exit(&error); \
217*7c478bd9Sstevel@tonic-gate 	} else { \
218*7c478bd9Sstevel@tonic-gate 		exit(a); \
219*7c478bd9Sstevel@tonic-gate 	}
220*7c478bd9Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate static int
223*7c478bd9Sstevel@tonic-gate process( void *arg )
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate     char	*rbuf, *saved_rbuf, *start, *p, *q;
226*7c478bd9Sstevel@tonic-gate     FILE	*rfp = NULL;
227*7c478bd9Sstevel@tonic-gate     int		rc, use_ldif, deref;
228*7c478bd9Sstevel@tonic-gate     LDAPControl	*ldctrl;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
231*7c478bd9Sstevel@tonic-gate     LDAP	*ld;
232*7c478bd9Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate     ld = ldaptool_ldap_init( 0 );
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate     if ( !ldaptool_not ) {
237*7c478bd9Sstevel@tonic-gate 	deref = LDAP_DEREF_NEVER;	/* this seems prudent */
238*7c478bd9Sstevel@tonic-gate 	ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
239*7c478bd9Sstevel@tonic-gate     }
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate     ldaptool_bind( ld );
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate     if (( ldctrl = ldaptool_create_manage_dsait_control()) != NULL ) {
244*7c478bd9Sstevel@tonic-gate 	ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls);
245*7c478bd9Sstevel@tonic-gate     }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate     if ((ldctrl = ldaptool_create_proxyauth_control(ld)) !=NULL) {
248*7c478bd9Sstevel@tonic-gate 	ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls);
249*7c478bd9Sstevel@tonic-gate     }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate     rc = 0;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate     /* turn on bulk import?*/
254*7c478bd9Sstevel@tonic-gate     if (bulkimport_suffix) {
255*7c478bd9Sstevel@tonic-gate 	struct berval	bv, *retdata;
256*7c478bd9Sstevel@tonic-gate 	char		*retoid;
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	bv.bv_val = bulkimport_suffix;
259*7c478bd9Sstevel@tonic-gate 	bv.bv_len = strlen(bulkimport_suffix);
260*7c478bd9Sstevel@tonic-gate 	if ((rc = ldap_extended_operation_s(ld,
261*7c478bd9Sstevel@tonic-gate 	    BULKIMPORT_START_OID, &bv, NULL,
262*7c478bd9Sstevel@tonic-gate 	    NULL, &retoid, &retdata)) != 0) {
263*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Error: unable to service "
264*7c478bd9Sstevel@tonic-gate 		    "extended operation request\n\t'%s' for "
265*7c478bd9Sstevel@tonic-gate 		    "bulk import\n\t(error:%d:'%s')\n"),
266*7c478bd9Sstevel@tonic-gate 		    BULKIMPORT_START_OID, rc, ldap_err2string(rc));
267*7c478bd9Sstevel@tonic-gate 		return (rc);
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 	if (retoid)
270*7c478bd9Sstevel@tonic-gate 		ldap_memfree(retoid);
271*7c478bd9Sstevel@tonic-gate 	if (retdata)
272*7c478bd9Sstevel@tonic-gate 		ber_bvfree(retdata);
273*7c478bd9Sstevel@tonic-gate     }
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate     while (( rc == 0 || contoper ) &&
276*7c478bd9Sstevel@tonic-gate 		( rbuf = read_one_record( ldaptool_fp )) != NULL ) {
277*7c478bd9Sstevel@tonic-gate 	/*
278*7c478bd9Sstevel@tonic-gate 	 * we assume record is ldif/slapd.replog if the first line
279*7c478bd9Sstevel@tonic-gate 	 * has a colon that appears to the left of any equal signs, OR
280*7c478bd9Sstevel@tonic-gate 	 * if the first line consists entirely of digits (an entry id)
281*7c478bd9Sstevel@tonic-gate 	 */
282*7c478bd9Sstevel@tonic-gate 	use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
283*7c478bd9Sstevel@tonic-gate 		( q = strchr( rbuf, '\n' )) != NULL && p < q &&
284*7c478bd9Sstevel@tonic-gate 		(( q = strchr( rbuf, '=' )) == NULL || p < q );
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	start = rbuf;
287*7c478bd9Sstevel@tonic-gate 	saved_rbuf = strdup( rbuf );
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
290*7c478bd9Sstevel@tonic-gate 	    for ( p = rbuf; p < q; ++p ) {
291*7c478bd9Sstevel@tonic-gate 		if ( !isdigit( *p )) {
292*7c478bd9Sstevel@tonic-gate 		    break;
293*7c478bd9Sstevel@tonic-gate 		}
294*7c478bd9Sstevel@tonic-gate 	    }
295*7c478bd9Sstevel@tonic-gate 	    if ( p >= q ) {
296*7c478bd9Sstevel@tonic-gate 		use_ldif = 1;
297*7c478bd9Sstevel@tonic-gate 		start = q + 1;
298*7c478bd9Sstevel@tonic-gate 	    }
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
302*7c478bd9Sstevel@tonic-gate 	if ( use_ldif ) {
303*7c478bd9Sstevel@tonic-gate 	    rc = process_ldif_rec( ld, start );
304*7c478bd9Sstevel@tonic-gate 	} else {
305*7c478bd9Sstevel@tonic-gate 	    rc = process_ldapmod_rec( ld, start );
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate #else
308*7c478bd9Sstevel@tonic-gate 	if ( use_ldif ) {
309*7c478bd9Sstevel@tonic-gate 	    rc = process_ldif_rec( start );
310*7c478bd9Sstevel@tonic-gate 	} else {
311*7c478bd9Sstevel@tonic-gate 	    rc = process_ldapmod_rec( start );
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS && rejfile != NULL ) {
316*7c478bd9Sstevel@tonic-gate 	    /* Write this record to the reject file */
317*7c478bd9Sstevel@tonic-gate 	    int newfile = 0;
318*7c478bd9Sstevel@tonic-gate 	    struct stat stbuf;
319*7c478bd9Sstevel@tonic-gate 	    if ( stat( rejfile, &stbuf ) < 0 ) {
320*7c478bd9Sstevel@tonic-gate 		if ( errno == ENOENT ) {
321*7c478bd9Sstevel@tonic-gate 		    newfile = 1;
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate 	    }
324*7c478bd9Sstevel@tonic-gate 	    if (( rfp = ldaptool_open_file( rejfile, "a" )) == NULL ) {
325*7c478bd9Sstevel@tonic-gate 		fprintf( stderr, gettext("Cannot open error file \"%s\" - "
326*7c478bd9Sstevel@tonic-gate 			"erroneous entries will not be saved\n"), rejfile );
327*7c478bd9Sstevel@tonic-gate 		rejfile = NULL;
328*7c478bd9Sstevel@tonic-gate 	    } else {
329*7c478bd9Sstevel@tonic-gate 		if ( newfile == 0 ) {
330*7c478bd9Sstevel@tonic-gate 		    fputs( "\n", rfp );
331*7c478bd9Sstevel@tonic-gate 		}
332*7c478bd9Sstevel@tonic-gate 		fprintf( rfp, gettext("# Error: %s\n"), ldap_err2string( rc ));
333*7c478bd9Sstevel@tonic-gate 		fputs( saved_rbuf, rfp );
334*7c478bd9Sstevel@tonic-gate 		fclose( rfp );
335*7c478bd9Sstevel@tonic-gate 		rfp = NULL;
336*7c478bd9Sstevel@tonic-gate 	    }
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	free( rbuf );
340*7c478bd9Sstevel@tonic-gate 	free( saved_rbuf );
341*7c478bd9Sstevel@tonic-gate     }
342*7c478bd9Sstevel@tonic-gate     ldaptool_reset_control_array( ldaptool_request_ctrls );
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate     /* turn off bulk import?*/
345*7c478bd9Sstevel@tonic-gate     if (bulkimport_suffix) {
346*7c478bd9Sstevel@tonic-gate 	struct berval	bv, *retdata;
347*7c478bd9Sstevel@tonic-gate 	char		*retoid;
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	bv.bv_val = "";
350*7c478bd9Sstevel@tonic-gate 	bv.bv_len = 0;
351*7c478bd9Sstevel@tonic-gate 	if ((rc = ldap_extended_operation_s(ld,
352*7c478bd9Sstevel@tonic-gate 	    BULKIMPORT_STOP_OID, &bv, NULL,
353*7c478bd9Sstevel@tonic-gate 	    NULL, &retoid, &retdata)) != 0) {
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Error: unable to service "
356*7c478bd9Sstevel@tonic-gate 		    "extended operation request\n\t '%s' for "
357*7c478bd9Sstevel@tonic-gate 		    "bulk import\n\t(rc:%d:'%s')\n"),
358*7c478bd9Sstevel@tonic-gate 		    BULKIMPORT_STOP_OID, rc, ldap_err2string(rc));
359*7c478bd9Sstevel@tonic-gate 		return (rc);
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 	if (retoid)
362*7c478bd9Sstevel@tonic-gate 		ldap_memfree(retoid);
363*7c478bd9Sstevel@tonic-gate 	if (retdata)
364*7c478bd9Sstevel@tonic-gate 		ber_bvfree(retdata);
365*7c478bd9Sstevel@tonic-gate     }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
368*7c478bd9Sstevel@tonic-gate     mutex_lock(&read_mutex);
369*7c478bd9Sstevel@tonic-gate #endif
370*7c478bd9Sstevel@tonic-gate     ldaptool_cleanup( ld );
371*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
372*7c478bd9Sstevel@tonic-gate     mutex_unlock(&read_mutex);
373*7c478bd9Sstevel@tonic-gate #endif
374*7c478bd9Sstevel@tonic-gate     return( rc );
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate static void
379*7c478bd9Sstevel@tonic-gate options_callback( int option, char *optarg )
380*7c478bd9Sstevel@tonic-gate {
381*7c478bd9Sstevel@tonic-gate     switch( option ) {
382*7c478bd9Sstevel@tonic-gate     case 'a':	/* add */
383*7c478bd9Sstevel@tonic-gate 	newval = 1;
384*7c478bd9Sstevel@tonic-gate 	break;
385*7c478bd9Sstevel@tonic-gate     case 'b':	/* read values from files (for binary attributes) */
386*7c478bd9Sstevel@tonic-gate 	valsfromfiles = 1;
387*7c478bd9Sstevel@tonic-gate 	break;
388*7c478bd9Sstevel@tonic-gate     case 'A':	/* display non-ASCII values when -v is used */
389*7c478bd9Sstevel@tonic-gate 	display_binary_values = 1;
390*7c478bd9Sstevel@tonic-gate 	break;
391*7c478bd9Sstevel@tonic-gate     case 'c':	/* continuous operation */
392*7c478bd9Sstevel@tonic-gate 	contoper = 1;
393*7c478bd9Sstevel@tonic-gate 	break;
394*7c478bd9Sstevel@tonic-gate     case 'F':	/* force all changes records to be used */
395*7c478bd9Sstevel@tonic-gate 	force = 1;
396*7c478bd9Sstevel@tonic-gate 	break;
397*7c478bd9Sstevel@tonic-gate     case 'e':
398*7c478bd9Sstevel@tonic-gate 	rejfile = strdup( optarg );
399*7c478bd9Sstevel@tonic-gate 	break;
400*7c478bd9Sstevel@tonic-gate     case 'B':	/* bulk import option */
401*7c478bd9Sstevel@tonic-gate 	bulkimport_suffix = strdup( optarg );
402*7c478bd9Sstevel@tonic-gate 	break;
403*7c478bd9Sstevel@tonic-gate     case 'q':	/* quiet mode on add/modify operations */
404*7c478bd9Sstevel@tonic-gate 	ldapmodify_quiet = 1;
405*7c478bd9Sstevel@tonic-gate 	break;
406*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
407*7c478bd9Sstevel@tonic-gate     case 'r':	/* default is to replace rather than add values */
408*7c478bd9Sstevel@tonic-gate 	replace = 1;
409*7c478bd9Sstevel@tonic-gate 	break;
410*7c478bd9Sstevel@tonic-gate     case 'l':
411*7c478bd9Sstevel@tonic-gate 	nbthreads = atoi(optarg);
412*7c478bd9Sstevel@tonic-gate 	break;
413*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
414*7c478bd9Sstevel@tonic-gate     default:
415*7c478bd9Sstevel@tonic-gate 	usage();
416*7c478bd9Sstevel@tonic-gate     }
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate static int
422*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
423*7c478bd9Sstevel@tonic-gate process_ldif_rec( LDAP *ld, char *rbuf )
424*7c478bd9Sstevel@tonic-gate #else
425*7c478bd9Sstevel@tonic-gate process_ldif_rec( char *rbuf )
426*7c478bd9Sstevel@tonic-gate #endif
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate     char	*line, *dn, *type, *value, *newrdn, *newparent, *p;
429*7c478bd9Sstevel@tonic-gate     char	*ctrl_oid=NULL, *ctrl_value=NULL;
430*7c478bd9Sstevel@tonic-gate     int 	ctrl_criticality=1;
431*7c478bd9Sstevel@tonic-gate     LDAPControl *ldctrl;
432*7c478bd9Sstevel@tonic-gate     int		rc, linenum, vlen, modop, replicaport;
433*7c478bd9Sstevel@tonic-gate     int		expect_modop, expect_sep, expect_chgtype_or_control, expect_newrdn;
434*7c478bd9Sstevel@tonic-gate     int		expect_deleteoldrdn, expect_newparent, rename, moddn;
435*7c478bd9Sstevel@tonic-gate     int		deleteoldrdn, saw_replica, use_record, new_entry, delete_entry;
436*7c478bd9Sstevel@tonic-gate     int         got_all, got_value;
437*7c478bd9Sstevel@tonic-gate     LDAPMod	**pmods;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate     new_entry = newval;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate     rc = got_all = saw_replica = delete_entry = expect_modop = 0;
442*7c478bd9Sstevel@tonic-gate     expect_deleteoldrdn = expect_newrdn = expect_newparent = expect_sep = 0;
443*7c478bd9Sstevel@tonic-gate     expect_chgtype_or_control = linenum = got_value = rename = moddn = 0;
444*7c478bd9Sstevel@tonic-gate     deleteoldrdn = 1;
445*7c478bd9Sstevel@tonic-gate     use_record = force;
446*7c478bd9Sstevel@tonic-gate     pmods = NULL;
447*7c478bd9Sstevel@tonic-gate     dn = newrdn = newparent = NULL;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
450*7c478bd9Sstevel@tonic-gate     while ( rc == 0 && ( line = str_getline( &rbuf )) != NULL ) {
451*7c478bd9Sstevel@tonic-gate #else
452*7c478bd9Sstevel@tonic-gate     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
453*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
454*7c478bd9Sstevel@tonic-gate 	++linenum;
455*7c478bd9Sstevel@tonic-gate 	if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
456*7c478bd9Sstevel@tonic-gate 	    expect_sep = 0;
457*7c478bd9Sstevel@tonic-gate 	    expect_modop = 1;
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	    /*If we see a separator in the input stream,
460*7c478bd9Sstevel@tonic-gate 	     but we didn't get a value from the last modify
461*7c478bd9Sstevel@tonic-gate 	     then we have to fill pmods with an empty value*/
462*7c478bd9Sstevel@tonic-gate 	    if (modop == LDAP_MOD_REPLACE && !got_value){
463*7c478bd9Sstevel@tonic-gate 	      addmodifyop( &pmods, modop, value, NULL, 0);
464*7c478bd9Sstevel@tonic-gate 	    }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	    got_value = 0;
467*7c478bd9Sstevel@tonic-gate 	    continue;
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
471*7c478bd9Sstevel@tonic-gate 	if ( str_parse_line( line, &type, &value, &vlen ) < 0 ) {
472*7c478bd9Sstevel@tonic-gate #else
473*7c478bd9Sstevel@tonic-gate 	if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) {
474*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
475*7c478bd9Sstevel@tonic-gate 	    fprintf( stderr, gettext("%s: invalid format (line %d of entry: %s)\n"),
476*7c478bd9Sstevel@tonic-gate 		    ldaptool_progname, linenum, dn == NULL ? "" : dn );
477*7c478bd9Sstevel@tonic-gate 	    fprintf( stderr, gettext("%s: line contents: (%s)\n"),
478*7c478bd9Sstevel@tonic-gate 		    ldaptool_progname, line );
479*7c478bd9Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
480*7c478bd9Sstevel@tonic-gate 	    break;
481*7c478bd9Sstevel@tonic-gate 	}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate evaluate_line:
484*7c478bd9Sstevel@tonic-gate 	if ( dn == NULL ) {
485*7c478bd9Sstevel@tonic-gate 	    if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
486*7c478bd9Sstevel@tonic-gate 		++saw_replica;
487*7c478bd9Sstevel@tonic-gate 		if (( p = strchr( value, ':' )) == NULL ) {
488*7c478bd9Sstevel@tonic-gate 		    replicaport = LDAP_PORT;
489*7c478bd9Sstevel@tonic-gate 		} else {
490*7c478bd9Sstevel@tonic-gate 		    *p++ = '\0';
491*7c478bd9Sstevel@tonic-gate 		    replicaport = atoi( p );
492*7c478bd9Sstevel@tonic-gate 		}
493*7c478bd9Sstevel@tonic-gate 		if ( strcasecmp( value, ldaptool_host ) == 0 &&
494*7c478bd9Sstevel@tonic-gate 			replicaport == ldaptool_port ) {
495*7c478bd9Sstevel@tonic-gate 		    use_record = 1;
496*7c478bd9Sstevel@tonic-gate 		}
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
499*7c478bd9Sstevel@tonic-gate 		if (( dn = strdup( value )) == NULL ) {
500*7c478bd9Sstevel@tonic-gate 		    perror( "strdup" );
501*7c478bd9Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
502*7c478bd9Sstevel@tonic-gate 		}
503*7c478bd9Sstevel@tonic-gate 		expect_chgtype_or_control = 1;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_VERSION_STR ) == 0 ) {
506*7c478bd9Sstevel@tonic-gate 		ldif_version = atoi( value );
507*7c478bd9Sstevel@tonic-gate 		if ( ldif_version != LDIF_VERSION_ONE ) {
508*7c478bd9Sstevel@tonic-gate 		    fprintf( stderr, gettext("%s:  LDIF version %d is not supported;"
509*7c478bd9Sstevel@tonic-gate 			" use version: %d\n"), ldaptool_progname, ldif_version,
510*7c478bd9Sstevel@tonic-gate 			LDIF_VERSION_ONE );
511*7c478bd9Sstevel@tonic-gate 		    exit( LDAP_PARAM_ERROR );
512*7c478bd9Sstevel@tonic-gate 		}
513*7c478bd9Sstevel@tonic-gate 		if ( ldaptool_verbose ) {
514*7c478bd9Sstevel@tonic-gate 		    printf( gettext("Processing a version %d LDIF file...\n"),
515*7c478bd9Sstevel@tonic-gate 			    ldif_version );
516*7c478bd9Sstevel@tonic-gate 		}
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 		/* Now check if there's something left to process   */
519*7c478bd9Sstevel@tonic-gate 		/* and if not, go get the new record, else continue */
520*7c478bd9Sstevel@tonic-gate 		if ( *rbuf == '\0' ) {
521*7c478bd9Sstevel@tonic-gate 			return( 0 );
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	    } else if ( !saw_replica ) {
525*7c478bd9Sstevel@tonic-gate 		printf( gettext("%s: skipping change record: no dn: line\n"),
526*7c478bd9Sstevel@tonic-gate 			ldaptool_progname );
527*7c478bd9Sstevel@tonic-gate 		return( 0 );
528*7c478bd9Sstevel@tonic-gate 	    }
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	    continue; /* skip all lines until we see "dn:" */
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	if ( expect_chgtype_or_control ) {
534*7c478bd9Sstevel@tonic-gate 	    expect_chgtype_or_control = 0;
535*7c478bd9Sstevel@tonic-gate 	    if ( !use_record && saw_replica ) {
536*7c478bd9Sstevel@tonic-gate 		printf( gettext("%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n"),
537*7c478bd9Sstevel@tonic-gate 			ldaptool_progname, dn );
538*7c478bd9Sstevel@tonic-gate 		free( dn );
539*7c478bd9Sstevel@tonic-gate 		return( 0 );
540*7c478bd9Sstevel@tonic-gate 	    }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD
543*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, "control" ) == 0 ) {
544*7c478bd9Sstevel@tonic-gate 		value = strdup_and_trim( value );
545*7c478bd9Sstevel@tonic-gate 		if (ldaptool_parse_ctrl_arg(value, ' ', &ctrl_oid,
546*7c478bd9Sstevel@tonic-gate 			&ctrl_criticality, &ctrl_value, &vlen)) {
547*7c478bd9Sstevel@tonic-gate 			    usage();
548*7c478bd9Sstevel@tonic-gate 		}
549*7c478bd9Sstevel@tonic-gate         	ldctrl = calloc(1,sizeof(LDAPControl));
550*7c478bd9Sstevel@tonic-gate         	if (ctrl_value) {
551*7c478bd9Sstevel@tonic-gate         	    rc = ldaptool_berval_from_ldif_value( ctrl_value, vlen,
552*7c478bd9Sstevel@tonic-gate 			 &(ldctrl->ldctl_value),
553*7c478bd9Sstevel@tonic-gate 			 1 /* recognize file URLs */, 0 /* always try file */,
554*7c478bd9Sstevel@tonic-gate             		 1 /* report errors */ );
555*7c478bd9Sstevel@tonic-gate         	    if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) {
556*7c478bd9Sstevel@tonic-gate             		fprintf( stderr, gettext("Unable to parse %s\n"), ctrl_value);
557*7c478bd9Sstevel@tonic-gate             		usage();
558*7c478bd9Sstevel@tonic-gate         	    }
559*7c478bd9Sstevel@tonic-gate         	}
560*7c478bd9Sstevel@tonic-gate         	ldctrl->ldctl_oid = ctrl_oid;
561*7c478bd9Sstevel@tonic-gate         	ldctrl->ldctl_iscritical = ctrl_criticality;
562*7c478bd9Sstevel@tonic-gate         	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
563*7c478bd9Sstevel@tonic-gate 		expect_chgtype_or_control = 1;
564*7c478bd9Sstevel@tonic-gate 		continue;
565*7c478bd9Sstevel@tonic-gate 	    }
566*7c478bd9Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
569*7c478bd9Sstevel@tonic-gate 		value = strdup_and_trim( value );
570*7c478bd9Sstevel@tonic-gate 		if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
571*7c478bd9Sstevel@tonic-gate 		    new_entry = 0;
572*7c478bd9Sstevel@tonic-gate 		    expect_modop = 1;
573*7c478bd9Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
574*7c478bd9Sstevel@tonic-gate 		    new_entry = 1;
575*7c478bd9Sstevel@tonic-gate 		    modop = LDAP_MOD_ADD;
576*7c478bd9Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) {
577*7c478bd9Sstevel@tonic-gate 		    expect_newrdn = 1;
578*7c478bd9Sstevel@tonic-gate 		    moddn = 1;
579*7c478bd9Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_MODDNCTSTR ) == 0 ) {
580*7c478bd9Sstevel@tonic-gate 		    expect_newrdn = 1;
581*7c478bd9Sstevel@tonic-gate 		    moddn = 1;
582*7c478bd9Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_RENAMECTSTR ) == 0 ) {
583*7c478bd9Sstevel@tonic-gate 		    expect_newrdn = 1;
584*7c478bd9Sstevel@tonic-gate 		    rename = 1;
585*7c478bd9Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
586*7c478bd9Sstevel@tonic-gate 		    got_all = delete_entry = 1;
587*7c478bd9Sstevel@tonic-gate 		} else {
588*7c478bd9Sstevel@tonic-gate 		    fprintf( stderr,
589*7c478bd9Sstevel@tonic-gate 			    gettext("%s:  unknown %s \"%s\" (line %d of entry: %s)\n"),
590*7c478bd9Sstevel@tonic-gate 			    ldaptool_progname, T_CHANGETYPESTR, value,
591*7c478bd9Sstevel@tonic-gate 			    linenum, dn );
592*7c478bd9Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 		free( value );
595*7c478bd9Sstevel@tonic-gate 		continue;
596*7c478bd9Sstevel@tonic-gate 	    } else if ( newval ) {		/*  missing changetype => add */
597*7c478bd9Sstevel@tonic-gate 		new_entry = 1;
598*7c478bd9Sstevel@tonic-gate 		modop = LDAP_MOD_ADD;
599*7c478bd9Sstevel@tonic-gate 	    } else {
600*7c478bd9Sstevel@tonic-gate 	      /*The user MUST put in changetype: blah
601*7c478bd9Sstevel@tonic-gate 	       unless adding a new entry with either -a or ldapadd*/
602*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Missing changetype operation specification.\n\tThe dn line must be followed by \"changetype: operation\"\n\t(unless ldapmodify is called with -a option)\n\twhere operation is add|delete|modify|modrdn|moddn|rename\n\t\"%s\" is not a valid changetype operation specification\n\t(line %d of entry %s)\n"),
603*7c478bd9Sstevel@tonic-gate 		ldaptool_progname, type, linenum, dn);
604*7c478bd9Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
605*7c478bd9Sstevel@tonic-gate 		/*expect_modop = 1;	 missing changetype => modify */
606*7c478bd9Sstevel@tonic-gate 	    }
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	if ( expect_modop ) {
610*7c478bd9Sstevel@tonic-gate 	    expect_modop = 0;
611*7c478bd9Sstevel@tonic-gate 	    expect_sep = 1;
612*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
613*7c478bd9Sstevel@tonic-gate 		modop = LDAP_MOD_ADD;
614*7c478bd9Sstevel@tonic-gate 		continue;
615*7c478bd9Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
616*7c478bd9Sstevel@tonic-gate 		modop = LDAP_MOD_REPLACE;
617*7c478bd9Sstevel@tonic-gate 		continue;
618*7c478bd9Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
619*7c478bd9Sstevel@tonic-gate 		modop = LDAP_MOD_DELETE;
620*7c478bd9Sstevel@tonic-gate 		addmodifyop( &pmods, modop, value, NULL, 0 );
621*7c478bd9Sstevel@tonic-gate 		continue;
622*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
623*7c478bd9Sstevel@tonic-gate 	    }  else { /* no modify op: use default */
624*7c478bd9Sstevel@tonic-gate 		modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
625*7c478bd9Sstevel@tonic-gate 	    }
626*7c478bd9Sstevel@tonic-gate #else
627*7c478bd9Sstevel@tonic-gate 	    }  else { /*Bug 27479. Remove default add operation*/
628*7c478bd9Sstevel@tonic-gate 	      fprintf(stderr, gettext("%s: Invalid parameter \"%s\" specified for changetype modify (line %d of entry %s)\n"),
629*7c478bd9Sstevel@tonic-gate 		      ldaptool_progname, type, linenum, dn);
630*7c478bd9Sstevel@tonic-gate 	      rc = LDAP_PARAM_ERROR;
631*7c478bd9Sstevel@tonic-gate 	    }
632*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	  }
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	if ( expect_newrdn ) {
637*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
638*7c478bd9Sstevel@tonic-gate 		if ( *value == '\0' ) {
639*7c478bd9Sstevel@tonic-gate 		    fprintf( stderr,
640*7c478bd9Sstevel@tonic-gate 			    gettext("%s: newrdn value missing (line %d of entry: %s)\n"),
641*7c478bd9Sstevel@tonic-gate 			    ldaptool_progname, linenum, dn == NULL ? "" : dn );
642*7c478bd9Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
643*7c478bd9Sstevel@tonic-gate 		} else if (( newrdn = strdup( value )) == NULL ) {
644*7c478bd9Sstevel@tonic-gate 		    perror( "strdup" );
645*7c478bd9Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
646*7c478bd9Sstevel@tonic-gate 		} else {
647*7c478bd9Sstevel@tonic-gate 		    expect_newrdn = 0;
648*7c478bd9Sstevel@tonic-gate 		    if ( rename ) {
649*7c478bd9Sstevel@tonic-gate 			expect_newparent = 1;
650*7c478bd9Sstevel@tonic-gate 		    } else {
651*7c478bd9Sstevel@tonic-gate 			expect_deleteoldrdn = 1;
652*7c478bd9Sstevel@tonic-gate 		    }
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 	    } else {
655*7c478bd9Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
656*7c478bd9Sstevel@tonic-gate 			ldaptool_progname, T_NEWRDNSTR, type, linenum, dn );
657*7c478bd9Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
658*7c478bd9Sstevel@tonic-gate 	    }
659*7c478bd9Sstevel@tonic-gate 	} else if ( expect_newparent ) {
660*7c478bd9Sstevel@tonic-gate 	    expect_newparent = 0;
661*7c478bd9Sstevel@tonic-gate 	    if ( rename ) {
662*7c478bd9Sstevel@tonic-gate 		expect_deleteoldrdn = 1;
663*7c478bd9Sstevel@tonic-gate 	    }
664*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, T_NEWPARENTSTR ) == 0
665*7c478bd9Sstevel@tonic-gate 		    || strcasecmp( type, T_NEWSUPERIORSTR ) == 0 ) {
666*7c478bd9Sstevel@tonic-gate 		if (( newparent = strdup( value )) == NULL ) {
667*7c478bd9Sstevel@tonic-gate 		    perror( "strdup" );
668*7c478bd9Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
669*7c478bd9Sstevel@tonic-gate 		}
670*7c478bd9Sstevel@tonic-gate 	    } else {
671*7c478bd9Sstevel@tonic-gate 		/* Since this is an optional argument for rename/moddn, cause
672*7c478bd9Sstevel@tonic-gate 		 * the current line to be re-evaluated if newparent doesn't
673*7c478bd9Sstevel@tonic-gate 		 * follow deleteoldrdn.
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		newparent = NULL;
676*7c478bd9Sstevel@tonic-gate 		goto evaluate_line;
677*7c478bd9Sstevel@tonic-gate 	    }
678*7c478bd9Sstevel@tonic-gate 	} else if ( expect_deleteoldrdn ) {
679*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
680*7c478bd9Sstevel@tonic-gate 		if ( *value == '\0' ) {
681*7c478bd9Sstevel@tonic-gate 		    fprintf( stderr,
682*7c478bd9Sstevel@tonic-gate 			    gettext("%s: missing 0 or 1 (line %d of entry: %s)\n"),
683*7c478bd9Sstevel@tonic-gate 			    ldaptool_progname, linenum, dn == NULL ? "" : dn );
684*7c478bd9Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
685*7c478bd9Sstevel@tonic-gate 		} else {
686*7c478bd9Sstevel@tonic-gate 		    deleteoldrdn = ( *value == '0' ) ? 0 : 1;
687*7c478bd9Sstevel@tonic-gate 		    expect_deleteoldrdn = 0;
688*7c478bd9Sstevel@tonic-gate 		    if ( moddn ) {
689*7c478bd9Sstevel@tonic-gate 			expect_newparent = 1;
690*7c478bd9Sstevel@tonic-gate 		    }
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 	    } else {
693*7c478bd9Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
694*7c478bd9Sstevel@tonic-gate 			ldaptool_progname, T_DELETEOLDRDNSTR, type, linenum,
695*7c478bd9Sstevel@tonic-gate 			dn );
696*7c478bd9Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
697*7c478bd9Sstevel@tonic-gate 	    }
698*7c478bd9Sstevel@tonic-gate 	    got_all = 1;
699*7c478bd9Sstevel@tonic-gate 	} else if ( got_all ) {
700*7c478bd9Sstevel@tonic-gate 	    fprintf( stderr,
701*7c478bd9Sstevel@tonic-gate 		    gettext("%s: extra lines at end (line %d of entry %s)\n"),
702*7c478bd9Sstevel@tonic-gate 		    ldaptool_progname, linenum, dn );
703*7c478bd9Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
704*7c478bd9Sstevel@tonic-gate 	    got_all = 1;
705*7c478bd9Sstevel@tonic-gate 	} else {
706*7c478bd9Sstevel@tonic-gate 	    addmodifyop( &pmods, modop, type, value, vlen );
707*7c478bd9Sstevel@tonic-gate 	    /*There was a value to replace*/
708*7c478bd9Sstevel@tonic-gate 	    got_value = 1;
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	}
711*7c478bd9Sstevel@tonic-gate     }
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate     if ( rc == 0 ) {
714*7c478bd9Sstevel@tonic-gate 	if ( delete_entry ) {
715*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
716*7c478bd9Sstevel@tonic-gate 	    rc = dodelete( ld, dn );
717*7c478bd9Sstevel@tonic-gate #else
718*7c478bd9Sstevel@tonic-gate 	    rc = dodelete( dn );
719*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
720*7c478bd9Sstevel@tonic-gate 	} else if ( newrdn != NULL ) {
721*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
722*7c478bd9Sstevel@tonic-gate 	    rc = dorename( ld, dn, newrdn, newparent, deleteoldrdn );
723*7c478bd9Sstevel@tonic-gate #else
724*7c478bd9Sstevel@tonic-gate 	    rc = dorename( dn, newrdn, newparent, deleteoldrdn );
725*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
726*7c478bd9Sstevel@tonic-gate 	    rename = 0;
727*7c478bd9Sstevel@tonic-gate 	} else {
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	  /*Patch to fix Bug 22183
730*7c478bd9Sstevel@tonic-gate 	    If pmods is null, then there is no
731*7c478bd9Sstevel@tonic-gate 	    attribute to replace, so we alloc
732*7c478bd9Sstevel@tonic-gate 	    an empty pmods*/
733*7c478bd9Sstevel@tonic-gate 	  if (modop == LDAP_MOD_REPLACE && !got_value && expect_sep){
734*7c478bd9Sstevel@tonic-gate 	    addmodifyop( &pmods, modop, value, NULL, 0);
735*7c478bd9Sstevel@tonic-gate 	  }/*End Patch*/
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
739*7c478bd9Sstevel@tonic-gate 	  rc = domodify( ld, dn, pmods, new_entry );
740*7c478bd9Sstevel@tonic-gate #else
741*7c478bd9Sstevel@tonic-gate 	  rc = domodify( dn, pmods, new_entry );
742*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if ( rc == LDAP_SUCCESS ) {
746*7c478bd9Sstevel@tonic-gate 	    rc = 0;
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate     }
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate     if ( dn != NULL ) {
751*7c478bd9Sstevel@tonic-gate 	free( dn );
752*7c478bd9Sstevel@tonic-gate     }
753*7c478bd9Sstevel@tonic-gate     if ( newrdn != NULL ) {
754*7c478bd9Sstevel@tonic-gate 	free( newrdn );
755*7c478bd9Sstevel@tonic-gate     }
756*7c478bd9Sstevel@tonic-gate     if ( newparent != NULL ) {
757*7c478bd9Sstevel@tonic-gate 	free( newparent );
758*7c478bd9Sstevel@tonic-gate     }
759*7c478bd9Sstevel@tonic-gate     if ( pmods != NULL ) {
760*7c478bd9Sstevel@tonic-gate 	freepmods( pmods );
761*7c478bd9Sstevel@tonic-gate     }
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate     return( rc );
764*7c478bd9Sstevel@tonic-gate }
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate static int
768*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
769*7c478bd9Sstevel@tonic-gate process_ldapmod_rec( LDAP *ld, char *rbuf )
770*7c478bd9Sstevel@tonic-gate #else
771*7c478bd9Sstevel@tonic-gate process_ldapmod_rec( char *rbuf )
772*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
773*7c478bd9Sstevel@tonic-gate {
774*7c478bd9Sstevel@tonic-gate     char	*line, *dn, *p, *q, *attr, *value;
775*7c478bd9Sstevel@tonic-gate     int		rc, linenum, modop;
776*7c478bd9Sstevel@tonic-gate     LDAPMod	**pmods;
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate     pmods = NULL;
779*7c478bd9Sstevel@tonic-gate     dn = NULL;
780*7c478bd9Sstevel@tonic-gate     linenum = 0;
781*7c478bd9Sstevel@tonic-gate     line = rbuf;
782*7c478bd9Sstevel@tonic-gate     rc = 0;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate     while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
785*7c478bd9Sstevel@tonic-gate 	++linenum;
786*7c478bd9Sstevel@tonic-gate 	if (( p = strchr( rbuf, '\n' )) == NULL ) {
787*7c478bd9Sstevel@tonic-gate 	    rbuf = NULL;
788*7c478bd9Sstevel@tonic-gate 	} else {
789*7c478bd9Sstevel@tonic-gate 	    if ( *(p-1) == '\\' ) {	/* lines ending in '\' are continued */
790*7c478bd9Sstevel@tonic-gate 		strcpy( p - 1, p );
791*7c478bd9Sstevel@tonic-gate 		rbuf = p;
792*7c478bd9Sstevel@tonic-gate 		continue;
793*7c478bd9Sstevel@tonic-gate 	    }
794*7c478bd9Sstevel@tonic-gate 	    *p++ = '\0';
795*7c478bd9Sstevel@tonic-gate 	    rbuf = p;
796*7c478bd9Sstevel@tonic-gate 	}
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	if ( dn == NULL ) {	/* first line contains DN */
799*7c478bd9Sstevel@tonic-gate 	    if (( dn = strdup( line )) == NULL ) {
800*7c478bd9Sstevel@tonic-gate 		perror( "strdup" );
801*7c478bd9Sstevel@tonic-gate 		exit( LDAP_NO_MEMORY );
802*7c478bd9Sstevel@tonic-gate 	    }
803*7c478bd9Sstevel@tonic-gate 	} else {
804*7c478bd9Sstevel@tonic-gate 	    if (( p = strchr( line, '=' )) == NULL ) {
805*7c478bd9Sstevel@tonic-gate 		value = NULL;
806*7c478bd9Sstevel@tonic-gate 		p = line + strlen( line );
807*7c478bd9Sstevel@tonic-gate 	    } else {
808*7c478bd9Sstevel@tonic-gate 		*p++ = '\0';
809*7c478bd9Sstevel@tonic-gate 		value = p;
810*7c478bd9Sstevel@tonic-gate 	    }
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	    for ( attr = line; *attr != '\0' && isspace( *attr ); ++attr ) {
813*7c478bd9Sstevel@tonic-gate 		;	/* skip attribute leading white space */
814*7c478bd9Sstevel@tonic-gate 	    }
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	    for ( q = p - 1; q > attr && isspace( *q ); --q ) {
817*7c478bd9Sstevel@tonic-gate 		*q = '\0';	/* remove attribute trailing white space */
818*7c478bd9Sstevel@tonic-gate 	    }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	    if ( value != NULL ) {
821*7c478bd9Sstevel@tonic-gate 		while ( isspace( *value )) {
822*7c478bd9Sstevel@tonic-gate 		    ++value;		/* skip value leading white space */
823*7c478bd9Sstevel@tonic-gate 		}
824*7c478bd9Sstevel@tonic-gate 		for ( q = value + strlen( value ) - 1; q > value &&
825*7c478bd9Sstevel@tonic-gate 			isspace( *q ); --q ) {
826*7c478bd9Sstevel@tonic-gate 		    *q = '\0';	/* remove value trailing white space */
827*7c478bd9Sstevel@tonic-gate 		}
828*7c478bd9Sstevel@tonic-gate 		if ( *value == '\0' ) {
829*7c478bd9Sstevel@tonic-gate 		    value = NULL;
830*7c478bd9Sstevel@tonic-gate 		}
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	    }
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	    if ( value == NULL && newval ) {
835*7c478bd9Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: missing value on line %d (attr is %s)\n"),
836*7c478bd9Sstevel@tonic-gate 			ldaptool_progname, linenum, attr );
837*7c478bd9Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
838*7c478bd9Sstevel@tonic-gate 	    } else {
839*7c478bd9Sstevel@tonic-gate 		 switch ( *attr ) {
840*7c478bd9Sstevel@tonic-gate 		case '-':
841*7c478bd9Sstevel@tonic-gate 		    modop = LDAP_MOD_DELETE;
842*7c478bd9Sstevel@tonic-gate 		    ++attr;
843*7c478bd9Sstevel@tonic-gate 		    break;
844*7c478bd9Sstevel@tonic-gate 		case '+':
845*7c478bd9Sstevel@tonic-gate 		    modop = LDAP_MOD_ADD;
846*7c478bd9Sstevel@tonic-gate 		    ++attr;
847*7c478bd9Sstevel@tonic-gate 		    break;
848*7c478bd9Sstevel@tonic-gate 		default:
849*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
850*7c478bd9Sstevel@tonic-gate 		    modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
851*7c478bd9Sstevel@tonic-gate #else
852*7c478bd9Sstevel@tonic-gate 		    /*Bug 27479. Remove the add default*/
853*7c478bd9Sstevel@tonic-gate 		      fprintf(stderr, gettext("%s: Invalid parameter specified for changetype modify (line %d of entry %s)\n"),
854*7c478bd9Sstevel@tonic-gate 		      ldaptool_progname, linenum, dn);
855*7c478bd9Sstevel@tonic-gate 		      rc = LDAP_PARAM_ERROR;
856*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
857*7c478bd9Sstevel@tonic-gate 		}
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 		addmodifyop( &pmods, modop, attr, value,
860*7c478bd9Sstevel@tonic-gate 			( value == NULL ) ? 0 : strlen( value ));
861*7c478bd9Sstevel@tonic-gate 	    }
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	line = rbuf;
865*7c478bd9Sstevel@tonic-gate     }
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate     if ( rc == 0 ) {
868*7c478bd9Sstevel@tonic-gate 	if ( dn == NULL ) {
869*7c478bd9Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
870*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
871*7c478bd9Sstevel@tonic-gate 	} else if (( rc = domodify( ld, dn, pmods, newval )) == LDAP_SUCCESS ){
872*7c478bd9Sstevel@tonic-gate #else
873*7c478bd9Sstevel@tonic-gate 	} else if (( rc = domodify( dn, pmods, newval )) == LDAP_SUCCESS ){
874*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
875*7c478bd9Sstevel@tonic-gate 	  rc = 0;
876*7c478bd9Sstevel@tonic-gate 	}
877*7c478bd9Sstevel@tonic-gate       }
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate     if ( pmods != NULL ) {
880*7c478bd9Sstevel@tonic-gate 	freepmods( pmods );
881*7c478bd9Sstevel@tonic-gate     }
882*7c478bd9Sstevel@tonic-gate     if ( dn != NULL ) {
883*7c478bd9Sstevel@tonic-gate 	free( dn );
884*7c478bd9Sstevel@tonic-gate     }
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate     return( rc );
887*7c478bd9Sstevel@tonic-gate }
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate static void
891*7c478bd9Sstevel@tonic-gate addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
892*7c478bd9Sstevel@tonic-gate {
893*7c478bd9Sstevel@tonic-gate     LDAPMod		**pmods;
894*7c478bd9Sstevel@tonic-gate     int			i, j, rc;
895*7c478bd9Sstevel@tonic-gate     struct berval	*bvp;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate     pmods = *pmodsp;
898*7c478bd9Sstevel@tonic-gate     modop |= LDAP_MOD_BVALUES;
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate     i = 0;
901*7c478bd9Sstevel@tonic-gate     if ( pmods != NULL ) {
902*7c478bd9Sstevel@tonic-gate 	for ( ; pmods[ i ] != NULL; ++i ) {
903*7c478bd9Sstevel@tonic-gate 	    if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
904*7c478bd9Sstevel@tonic-gate 		    pmods[ i ]->mod_op == modop ) {
905*7c478bd9Sstevel@tonic-gate 		break;
906*7c478bd9Sstevel@tonic-gate 	    }
907*7c478bd9Sstevel@tonic-gate 	}
908*7c478bd9Sstevel@tonic-gate     }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate     if ( pmods == NULL || pmods[ i ] == NULL ) {
911*7c478bd9Sstevel@tonic-gate 	if (( pmods = (LDAPMod **)LDAPTOOL_SAFEREALLOC( pmods, (i + 2) *
912*7c478bd9Sstevel@tonic-gate 		sizeof( LDAPMod * ))) == NULL ) {
913*7c478bd9Sstevel@tonic-gate 	    perror( "realloc" );
914*7c478bd9Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
915*7c478bd9Sstevel@tonic-gate 	}
916*7c478bd9Sstevel@tonic-gate 	*pmodsp = pmods;
917*7c478bd9Sstevel@tonic-gate 	pmods[ i + 1 ] = NULL;
918*7c478bd9Sstevel@tonic-gate 	if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
919*7c478bd9Sstevel@tonic-gate 		== NULL ) {
920*7c478bd9Sstevel@tonic-gate 	    perror( "calloc" );
921*7c478bd9Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 	pmods[ i ]->mod_op = modop;
924*7c478bd9Sstevel@tonic-gate 	if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
925*7c478bd9Sstevel@tonic-gate 	    perror( "strdup" );
926*7c478bd9Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
927*7c478bd9Sstevel@tonic-gate 	}
928*7c478bd9Sstevel@tonic-gate     }
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate     if ( value != NULL ) {
931*7c478bd9Sstevel@tonic-gate 	j = 0;
932*7c478bd9Sstevel@tonic-gate 	if ( pmods[ i ]->mod_bvalues != NULL ) {
933*7c478bd9Sstevel@tonic-gate 	    for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
934*7c478bd9Sstevel@tonic-gate 		;
935*7c478bd9Sstevel@tonic-gate 	    }
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 	if (( pmods[ i ]->mod_bvalues = (struct berval **)
938*7c478bd9Sstevel@tonic-gate 		LDAPTOOL_SAFEREALLOC( pmods[ i ]->mod_bvalues,
939*7c478bd9Sstevel@tonic-gate 		(j + 2) * sizeof( struct berval * ))) == NULL ) {
940*7c478bd9Sstevel@tonic-gate 	    perror( "realloc" );
941*7c478bd9Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
942*7c478bd9Sstevel@tonic-gate 	}
943*7c478bd9Sstevel@tonic-gate 	pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
944*7c478bd9Sstevel@tonic-gate 	if (( bvp = (struct berval *)malloc( sizeof( struct berval )))
945*7c478bd9Sstevel@tonic-gate 		== NULL ) {
946*7c478bd9Sstevel@tonic-gate 	    perror( "malloc" );
947*7c478bd9Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
948*7c478bd9Sstevel@tonic-gate 	}
949*7c478bd9Sstevel@tonic-gate 	pmods[ i ]->mod_bvalues[ j ] = bvp;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate #ifdef notdef
952*7c478bd9Sstevel@tonic-gate 	if (ldaptool_verbose) {
953*7c478bd9Sstevel@tonic-gate 		printf(gettext("%s: value: %s vlen: %d\n"), "ldapmodify", value, vlen);
954*7c478bd9Sstevel@tonic-gate 	}
955*7c478bd9Sstevel@tonic-gate #endif
956*7c478bd9Sstevel@tonic-gate 	rc = ldaptool_berval_from_ldif_value( value, vlen, bvp,
957*7c478bd9Sstevel@tonic-gate 		    ( ldif_version >= LDIF_VERSION_ONE ), valsfromfiles,
958*7c478bd9Sstevel@tonic-gate 			1 /* report errors */ );
959*7c478bd9Sstevel@tonic-gate 	if ( rc != LDAPTOOL_FILEURL_SUCCESS ) {
960*7c478bd9Sstevel@tonic-gate 	    exit( ldaptool_fileurlerr2ldaperr( rc ));
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate     }
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate static int
967*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
968*7c478bd9Sstevel@tonic-gate domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry )
969*7c478bd9Sstevel@tonic-gate #else
970*7c478bd9Sstevel@tonic-gate domodify( char *dn, LDAPMod **pmods, int newentry )
971*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
972*7c478bd9Sstevel@tonic-gate {
973*7c478bd9Sstevel@tonic-gate     int			i, j, notascii, op;
974*7c478bd9Sstevel@tonic-gate     struct berval	*bvp;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate     if ( pmods == NULL ) {
977*7c478bd9Sstevel@tonic-gate 	fprintf( stderr, gettext("%s: no attributes to change or add (entry %s)\n"),
978*7c478bd9Sstevel@tonic-gate 		ldaptool_progname, dn );
979*7c478bd9Sstevel@tonic-gate 	return( LDAP_PARAM_ERROR );
980*7c478bd9Sstevel@tonic-gate     }
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate     if ( ldaptool_verbose ) {
983*7c478bd9Sstevel@tonic-gate 	for ( i = 0; pmods[ i ] != NULL; ++i ) {
984*7c478bd9Sstevel@tonic-gate 	    op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
985*7c478bd9Sstevel@tonic-gate 	    printf( gettext("%s %s:\n"), op == LDAP_MOD_REPLACE ?
986*7c478bd9Sstevel@tonic-gate 		    gettext("replace") : op == LDAP_MOD_ADD ?
987*7c478bd9Sstevel@tonic-gate 		    gettext("add") : gettext("delete"), pmods[ i ]->mod_type );
988*7c478bd9Sstevel@tonic-gate 	    if ( pmods[ i ]->mod_bvalues != NULL ) {
989*7c478bd9Sstevel@tonic-gate 		for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
990*7c478bd9Sstevel@tonic-gate 		    bvp = pmods[ i ]->mod_bvalues[ j ];
991*7c478bd9Sstevel@tonic-gate 		    notascii = 0;
992*7c478bd9Sstevel@tonic-gate 		    if ( !display_binary_values ) {
993*7c478bd9Sstevel@tonic-gate 			notascii = !ldaptool_berval_is_ascii( bvp );
994*7c478bd9Sstevel@tonic-gate 		    }
995*7c478bd9Sstevel@tonic-gate 		    if ( notascii ) {
996*7c478bd9Sstevel@tonic-gate 			printf( gettext("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len );
997*7c478bd9Sstevel@tonic-gate 		    } else {
998*7c478bd9Sstevel@tonic-gate 			printf( "\t%s\n", bvp->bv_val );
999*7c478bd9Sstevel@tonic-gate 		    }
1000*7c478bd9Sstevel@tonic-gate 		}
1001*7c478bd9Sstevel@tonic-gate 	    }
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate     }
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate     if ( !ldapmodify_quiet) {
1006*7c478bd9Sstevel@tonic-gate 	if ( newentry ) {
1007*7c478bd9Sstevel@tonic-gate 	    printf( gettext("%sadding new entry %s\n"),
1008*7c478bd9Sstevel@tonic-gate 		ldaptool_not ? "!" : "", dn );
1009*7c478bd9Sstevel@tonic-gate 	} else {
1010*7c478bd9Sstevel@tonic-gate 	    printf( gettext("%smodifying entry %s\n"),
1011*7c478bd9Sstevel@tonic-gate 		ldaptool_not ? "!" : "", dn );
1012*7c478bd9Sstevel@tonic-gate 	}
1013*7c478bd9Sstevel@tonic-gate     }
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate     if ( !ldaptool_not ) {
1016*7c478bd9Sstevel@tonic-gate 	if ( newentry ) {
1017*7c478bd9Sstevel@tonic-gate 	unsigned int	sleep_interval = 2; /* seconds */
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1020*7c478bd9Sstevel@tonic-gate 	    /* Backward compatibility with old Solaris command */
1021*7c478bd9Sstevel@tonic-gate 	    unsigned int nb = 0;
1022*7c478bd9Sstevel@tonic-gate 	    timestruc_t to;
1023*7c478bd9Sstevel@tonic-gate 	    while ((i = ldaptool_add_ext_s( ld, dn, pmods,
1024*7c478bd9Sstevel@tonic-gate 			ldaptool_request_ctrls, NULL, "ldap_add" ))
1025*7c478bd9Sstevel@tonic-gate 			!= LDAP_SUCCESS) {
1026*7c478bd9Sstevel@tonic-gate 		if (i == LDAP_BUSY) {
1027*7c478bd9Sstevel@tonic-gate 			if ( sleep_interval > 3600 ) {
1028*7c478bd9Sstevel@tonic-gate 				printf(gettext("ldap_add: Unable to complete "
1029*7c478bd9Sstevel@tonic-gate 						"request.  Server is too "
1030*7c478bd9Sstevel@tonic-gate 						"busy servicing other "
1031*7c478bd9Sstevel@tonic-gate 						"requests\n"));
1032*7c478bd9Sstevel@tonic-gate 				break;
1033*7c478bd9Sstevel@tonic-gate 			}
1034*7c478bd9Sstevel@tonic-gate 			if ( !ldapmodify_quiet ) {
1035*7c478bd9Sstevel@tonic-gate 				printf(gettext("ldap_add: LDAP_BUSY returned "
1036*7c478bd9Sstevel@tonic-gate 						"by server.  Will retry "
1037*7c478bd9Sstevel@tonic-gate 						"operation in %d seconds\n"),
1038*7c478bd9Sstevel@tonic-gate 						sleep_interval);
1039*7c478bd9Sstevel@tonic-gate 			}
1040*7c478bd9Sstevel@tonic-gate 			sleep( sleep_interval );
1041*7c478bd9Sstevel@tonic-gate 			sleep_interval *= 2;
1042*7c478bd9Sstevel@tonic-gate 		} else if (i == LDAP_NO_SUCH_OBJECT) {
1043*7c478bd9Sstevel@tonic-gate 			/*
1044*7c478bd9Sstevel@tonic-gate 			 * Wait for the parent entry to be created by
1045*7c478bd9Sstevel@tonic-gate 			 * another thread. Do not retry more than the
1046*7c478bd9Sstevel@tonic-gate 			 * number of threads.
1047*7c478bd9Sstevel@tonic-gate 			 */
1048*7c478bd9Sstevel@tonic-gate 			++nb;
1049*7c478bd9Sstevel@tonic-gate 			if (nb >= nbthreads)
1050*7c478bd9Sstevel@tonic-gate 				break;
1051*7c478bd9Sstevel@tonic-gate 			mutex_lock(&wait_mutex);
1052*7c478bd9Sstevel@tonic-gate 			to.tv_sec = 5;
1053*7c478bd9Sstevel@tonic-gate 			to.tv_nsec = 0;
1054*7c478bd9Sstevel@tonic-gate 			if (cond_reltimedwait(&wait_cond, &wait_mutex, &to)
1055*7c478bd9Sstevel@tonic-gate 				== ETIME) {
1056*7c478bd9Sstevel@tonic-gate 					nb = nbthreads; /* last chance */
1057*7c478bd9Sstevel@tonic-gate 			}
1058*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&wait_mutex);
1059*7c478bd9Sstevel@tonic-gate 		} else {
1060*7c478bd9Sstevel@tonic-gate 			break;
1061*7c478bd9Sstevel@tonic-gate 		}
1062*7c478bd9Sstevel@tonic-gate 	    }
1063*7c478bd9Sstevel@tonic-gate 	    cond_broadcast(&wait_cond);
1064*7c478bd9Sstevel@tonic-gate #else
1065*7c478bd9Sstevel@tonic-gate 	    while ((i = ldaptool_add_ext_s( ld, dn, pmods,
1066*7c478bd9Sstevel@tonic-gate 			ldaptool_request_ctrls, NULL, "ldap_add" ))
1067*7c478bd9Sstevel@tonic-gate 			== LDAP_BUSY) {
1068*7c478bd9Sstevel@tonic-gate 		if ( sleep_interval > 3600 ) {
1069*7c478bd9Sstevel@tonic-gate 			printf("ldap_add: Unable to complete request. ");
1070*7c478bd9Sstevel@tonic-gate 			printf("Server is too ");
1071*7c478bd9Sstevel@tonic-gate 			printf("busy servicing other requests\n");
1072*7c478bd9Sstevel@tonic-gate 			break;
1073*7c478bd9Sstevel@tonic-gate 		}
1074*7c478bd9Sstevel@tonic-gate 		if ( !ldapmodify_quiet ) {
1075*7c478bd9Sstevel@tonic-gate 			printf("ldap_add: LDAP_BUSY returned by server. ");
1076*7c478bd9Sstevel@tonic-gate 			printf("Will retry operation ");
1077*7c478bd9Sstevel@tonic-gate 			printf("in %d seconds\n", sleep_interval);
1078*7c478bd9Sstevel@tonic-gate 		}
1079*7c478bd9Sstevel@tonic-gate 		sleep( sleep_interval );
1080*7c478bd9Sstevel@tonic-gate 		sleep_interval *= 2;
1081*7c478bd9Sstevel@tonic-gate 	    }
1082*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1083*7c478bd9Sstevel@tonic-gate 	} else {
1084*7c478bd9Sstevel@tonic-gate 	    i = ldaptool_modify_ext_s( ld, dn, pmods, ldaptool_request_ctrls,
1085*7c478bd9Sstevel@tonic-gate 		    NULL, "ldap_modify" );
1086*7c478bd9Sstevel@tonic-gate 	}
1087*7c478bd9Sstevel@tonic-gate 	if ( i == LDAP_SUCCESS && ldaptool_verbose ) {
1088*7c478bd9Sstevel@tonic-gate 	    printf( gettext("modify complete\n") );
1089*7c478bd9Sstevel@tonic-gate 	}
1090*7c478bd9Sstevel@tonic-gate     } else {
1091*7c478bd9Sstevel@tonic-gate 	i = LDAP_SUCCESS;
1092*7c478bd9Sstevel@tonic-gate     }
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate     if ( !ldapmodify_quiet) {
1095*7c478bd9Sstevel@tonic-gate 	putchar( '\n' );
1096*7c478bd9Sstevel@tonic-gate     }
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate     return( i );
1099*7c478bd9Sstevel@tonic-gate }
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate static int
1103*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1104*7c478bd9Sstevel@tonic-gate dodelete( LDAP *ld, char *dn )
1105*7c478bd9Sstevel@tonic-gate #else
1106*7c478bd9Sstevel@tonic-gate dodelete( char *dn )
1107*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1108*7c478bd9Sstevel@tonic-gate {
1109*7c478bd9Sstevel@tonic-gate     int	rc;
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate     printf( gettext("%sdeleting entry %s\n"), ldaptool_not ? "!" : "", dn );
1112*7c478bd9Sstevel@tonic-gate     if ( !ldaptool_not ) {
1113*7c478bd9Sstevel@tonic-gate 	if (( rc = ldaptool_delete_ext_s( ld, dn, ldaptool_request_ctrls,
1114*7c478bd9Sstevel@tonic-gate 		NULL, "ldap_delete" )) == LDAP_SUCCESS && ldaptool_verbose ) {
1115*7c478bd9Sstevel@tonic-gate 	    printf( gettext("delete complete") );
1116*7c478bd9Sstevel@tonic-gate 	}
1117*7c478bd9Sstevel@tonic-gate     } else {
1118*7c478bd9Sstevel@tonic-gate 	rc = LDAP_SUCCESS;
1119*7c478bd9Sstevel@tonic-gate     }
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate     putchar( '\n' );
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate     return( rc );
1124*7c478bd9Sstevel@tonic-gate }
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate static int
1128*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1129*7c478bd9Sstevel@tonic-gate dorename( LDAP *ld, char *dn, char *newrdn, char *newparent, int deleteoldrdn )
1130*7c478bd9Sstevel@tonic-gate #else
1131*7c478bd9Sstevel@tonic-gate dorename( char *dn, char *newrdn, char *newparent, int deleteoldrdn )
1132*7c478bd9Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1133*7c478bd9Sstevel@tonic-gate {
1134*7c478bd9Sstevel@tonic-gate     int	rc;
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate     if ( ldaptool_verbose ) {
1137*7c478bd9Sstevel@tonic-gate 	if ( newparent == NULL ) {
1138*7c478bd9Sstevel@tonic-gate 	    printf(deleteoldrdn ?
1139*7c478bd9Sstevel@tonic-gate 		  gettext("new RDN: %s (do not keep existing values)\n"):
1140*7c478bd9Sstevel@tonic-gate 		  gettext("new RDN: %s (keep existing values)\n"));
1141*7c478bd9Sstevel@tonic-gate 	} else {
1142*7c478bd9Sstevel@tonic-gate 	    printf(deleteoldrdn ?
1143*7c478bd9Sstevel@tonic-gate 		  gettext("new RDN: %s, new parent %s ( do not keep existing values)\n"):
1144*7c478bd9Sstevel@tonic-gate 		  gettext("new RDN: %s, new parent %s ( keep existing values)\n"));
1145*7c478bd9Sstevel@tonic-gate 	}
1146*7c478bd9Sstevel@tonic-gate     }
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate     printf( gettext("%smodifying RDN of entry %s%s\n"),
1149*7c478bd9Sstevel@tonic-gate 	    ldaptool_not ? "!" : "", dn, ( newparent == NULL ) ? "" :
1150*7c478bd9Sstevel@tonic-gate 	    gettext(" and/or moving it beneath a new parent\n") );
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate     if ( !ldaptool_not ) {
1153*7c478bd9Sstevel@tonic-gate 	if (( rc = ldaptool_rename_s( ld, dn, newrdn, newparent, deleteoldrdn,
1154*7c478bd9Sstevel@tonic-gate 		ldaptool_request_ctrls, NULL, "ldap_rename" )) == LDAP_SUCCESS
1155*7c478bd9Sstevel@tonic-gate 		&& ldaptool_verbose ) {
1156*7c478bd9Sstevel@tonic-gate 	    printf( gettext("rename completed\n") );
1157*7c478bd9Sstevel@tonic-gate 	}
1158*7c478bd9Sstevel@tonic-gate     } else {
1159*7c478bd9Sstevel@tonic-gate 	rc = LDAP_SUCCESS;
1160*7c478bd9Sstevel@tonic-gate     }
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate     putchar( '\n' );
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate     return( rc );
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate static void
1169*7c478bd9Sstevel@tonic-gate freepmods( LDAPMod **pmods )
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate     int	i;
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate     for ( i = 0; pmods[ i ] != NULL; ++i ) {
1174*7c478bd9Sstevel@tonic-gate 	if ( pmods[ i ]->mod_bvalues != NULL ) {
1175*7c478bd9Sstevel@tonic-gate 	    ber_bvecfree( pmods[ i ]->mod_bvalues );
1176*7c478bd9Sstevel@tonic-gate 	}
1177*7c478bd9Sstevel@tonic-gate 	if ( pmods[ i ]->mod_type != NULL ) {
1178*7c478bd9Sstevel@tonic-gate 	    free( pmods[ i ]->mod_type );
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate 	free( pmods[ i ] );
1181*7c478bd9Sstevel@tonic-gate     }
1182*7c478bd9Sstevel@tonic-gate     free( pmods );
1183*7c478bd9Sstevel@tonic-gate }
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate static char *
1187*7c478bd9Sstevel@tonic-gate read_one_record( FILE *fp )
1188*7c478bd9Sstevel@tonic-gate {
1189*7c478bd9Sstevel@tonic-gate     int         len, gotnothing;
1190*7c478bd9Sstevel@tonic-gate     char        *buf, line[ LDAPMOD_MAXLINE ];
1191*7c478bd9Sstevel@tonic-gate     int		lcur, lmax;
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate     lcur = lmax = 0;
1194*7c478bd9Sstevel@tonic-gate     buf = NULL;
1195*7c478bd9Sstevel@tonic-gate     gotnothing = 1;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1198*7c478bd9Sstevel@tonic-gate     mutex_lock(&read_mutex);
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate     if (fp == NULL) {
1201*7c478bd9Sstevel@tonic-gate     	mutex_unlock(&read_mutex);
1202*7c478bd9Sstevel@tonic-gate 	return(NULL);
1203*7c478bd9Sstevel@tonic-gate     }
1204*7c478bd9Sstevel@tonic-gate #endif
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate     while ( fgets( line, sizeof(line), fp ) != NULL ) {
1207*7c478bd9Sstevel@tonic-gate 	if ( (len = strlen( line )) < 2 ) {
1208*7c478bd9Sstevel@tonic-gate 	    if ( gotnothing ) {
1209*7c478bd9Sstevel@tonic-gate 		continue;
1210*7c478bd9Sstevel@tonic-gate 	    } else {
1211*7c478bd9Sstevel@tonic-gate 		break;
1212*7c478bd9Sstevel@tonic-gate 	    }
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	/* Check if the blank line starts with '\r' (CR) */
1216*7c478bd9Sstevel@tonic-gate 	if ( ((len = strlen( line )) == 2) && (line[0] == '\r') ) {
1217*7c478bd9Sstevel@tonic-gate 	    if ( gotnothing ) {
1218*7c478bd9Sstevel@tonic-gate 		continue;
1219*7c478bd9Sstevel@tonic-gate 	    } else {
1220*7c478bd9Sstevel@tonic-gate 		break;
1221*7c478bd9Sstevel@tonic-gate 	      }
1222*7c478bd9Sstevel@tonic-gate 	}
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	if ( *line == '#' ) {
1225*7c478bd9Sstevel@tonic-gate 	    continue;			/* skip comment lines */
1226*7c478bd9Sstevel@tonic-gate 	}
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	gotnothing = 0;
1229*7c478bd9Sstevel@tonic-gate         if ( lcur + len + 1 > lmax ) {
1230*7c478bd9Sstevel@tonic-gate             lmax = LDAPMOD_MAXLINE
1231*7c478bd9Sstevel@tonic-gate 		    * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
1232*7c478bd9Sstevel@tonic-gate 	    if (( buf = (char *)LDAPTOOL_SAFEREALLOC( buf, lmax )) == NULL ) {
1233*7c478bd9Sstevel@tonic-gate 		perror( "realloc" );
1234*7c478bd9Sstevel@tonic-gate 		#ifdef SOLARIS_LDAP_CMD
1235*7c478bd9Sstevel@tonic-gate     			mutex_unlock(&read_mutex);
1236*7c478bd9Sstevel@tonic-gate 		#endif
1237*7c478bd9Sstevel@tonic-gate 		exit( LDAP_NO_MEMORY );
1238*7c478bd9Sstevel@tonic-gate 	    }
1239*7c478bd9Sstevel@tonic-gate         }
1240*7c478bd9Sstevel@tonic-gate         strcpy( buf + lcur, line );
1241*7c478bd9Sstevel@tonic-gate         lcur += len;
1242*7c478bd9Sstevel@tonic-gate     }
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1245*7c478bd9Sstevel@tonic-gate     mutex_unlock(&read_mutex);
1246*7c478bd9Sstevel@tonic-gate #endif
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate     return( buf );
1249*7c478bd9Sstevel@tonic-gate }
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate /*
1253*7c478bd9Sstevel@tonic-gate  * strdup and trim trailing blanks
1254*7c478bd9Sstevel@tonic-gate  */
1255*7c478bd9Sstevel@tonic-gate static char *
1256*7c478bd9Sstevel@tonic-gate strdup_and_trim( char *s )
1257*7c478bd9Sstevel@tonic-gate {
1258*7c478bd9Sstevel@tonic-gate     char	*p;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate     if (( s = strdup( s )) == NULL ) {
1261*7c478bd9Sstevel@tonic-gate 	perror( "strdup" );
1262*7c478bd9Sstevel@tonic-gate 	exit( LDAP_NO_MEMORY );
1263*7c478bd9Sstevel@tonic-gate     }
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate     p = s + strlen( s ) - 1;
1266*7c478bd9Sstevel@tonic-gate     while ( p >= s && isspace( *p )) {
1267*7c478bd9Sstevel@tonic-gate 	--p;
1268*7c478bd9Sstevel@tonic-gate     }
1269*7c478bd9Sstevel@tonic-gate     *++p = '\0';
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate     return( s );
1272*7c478bd9Sstevel@tonic-gate }
1273