xref: /onnv-gate/usr/src/cmd/ldap/common/ldapmodify.c (revision 8097:4d57974af082)
10Sstevel@tonic-gate /*
2*8097SSreedhar.Chalamalasetti@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public
80Sstevel@tonic-gate  * License Version 1.1 (the "License"); you may not use this file
90Sstevel@tonic-gate  * except in compliance with the License. You may obtain a copy of
100Sstevel@tonic-gate  * the License at http://www.mozilla.org/NPL/
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * Software distributed under the License is distributed on an "AS
130Sstevel@tonic-gate  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
140Sstevel@tonic-gate  * implied. See the License for the specific language governing
150Sstevel@tonic-gate  * rights and limitations under the License.
160Sstevel@tonic-gate  *
170Sstevel@tonic-gate  * The Original Code is Mozilla Communicator client code, released
180Sstevel@tonic-gate  * March 31, 1998.
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * The Initial Developer of the Original Code is Netscape
210Sstevel@tonic-gate  * Communications Corporation. Portions created by Netscape are
220Sstevel@tonic-gate  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
230Sstevel@tonic-gate  * Rights Reserved.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * Contributor(s):
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /* ldapmodify.c - generic program to modify or add entries using LDAP */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include "ldaptool.h"
310Sstevel@tonic-gate #include "fileurl.h"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
340Sstevel@tonic-gate #include <locale.h>
350Sstevel@tonic-gate #include "ldif.h"
360Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD
390Sstevel@tonic-gate #define gettext(s) s
400Sstevel@tonic-gate #endif
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static int		newval, contoper, force, valsfromfiles, display_binary_values;
430Sstevel@tonic-gate static int		ldif_version = -1;	/* -1 => unknown version */
440Sstevel@tonic-gate static char		*rejfile = NULL;
450Sstevel@tonic-gate static char		*bulkimport_suffix = NULL;
460Sstevel@tonic-gate static int		ldapmodify_quiet = 0;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
490Sstevel@tonic-gate static int		error = 0, replace, nbthreads = 1;
500Sstevel@tonic-gate static int		thr_create_errors = 0;
510Sstevel@tonic-gate static pthread_mutex_t	read_mutex = {0};
520Sstevel@tonic-gate static pthread_mutex_t	wait_mutex = {0};
530Sstevel@tonic-gate static pthread_cond_t	wait_cond  = {0};
540Sstevel@tonic-gate #else
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * For Solaris, ld is defined local to process() because
570Sstevel@tonic-gate  * multiple threads restricts Solaris from using a global
580Sstevel@tonic-gate  * ld variable.
590Sstevel@tonic-gate  * Solaris uses multiple threads to create multiple
600Sstevel@tonic-gate  * ldap connections if nbthreads > 1 (i.e -l option).
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate static LDAP		*ld;
630Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #define LDAPMOD_MAXLINE		4096
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /* strings found in replog/LDIF entries (mostly lifted from slurpd/slurp.h) */
680Sstevel@tonic-gate #define T_REPLICA_STR		"replica"
690Sstevel@tonic-gate #define T_DN_STR		"dn"
700Sstevel@tonic-gate #define T_VERSION_STR		"version"
710Sstevel@tonic-gate #define T_CHANGETYPESTR         "changetype"
720Sstevel@tonic-gate #define T_ADDCTSTR		"add"
730Sstevel@tonic-gate #define T_MODIFYCTSTR		"modify"
740Sstevel@tonic-gate #define T_DELETECTSTR		"delete"
750Sstevel@tonic-gate #define T_RENAMECTSTR		"rename"	/* non-standard */
760Sstevel@tonic-gate #define T_MODDNCTSTR		"moddn"
770Sstevel@tonic-gate #define T_MODRDNCTSTR		"modrdn"
780Sstevel@tonic-gate #define T_MODOPADDSTR		"add"
790Sstevel@tonic-gate #define T_MODOPREPLACESTR	"replace"
800Sstevel@tonic-gate #define T_MODOPDELETESTR	"delete"
810Sstevel@tonic-gate #define T_MODSEPSTR		"-"
820Sstevel@tonic-gate #define T_NEWRDNSTR		"newrdn"
830Sstevel@tonic-gate #define	T_NEWSUPERIORSTR	"newsuperior"
840Sstevel@tonic-gate #define	T_NEWPARENTSTR		"newparent"
850Sstevel@tonic-gate #define T_DELETEOLDRDNSTR	"deleteoldrdn"
860Sstevel@tonic-gate #define T_NEWSUPERIORSTR        "newsuperior"
870Sstevel@tonic-gate #define T_NEWPARENTSTR          "newparent"	/* non-standard */
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /* bulk import */
900Sstevel@tonic-gate #define	BULKIMPORT_START_OID	"2.16.840.1.113730.3.5.7"
910Sstevel@tonic-gate #define	BULKIMPORT_STOP_OID	"2.16.840.1.113730.3.5.8"
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static int process( void *arg );
940Sstevel@tonic-gate static void options_callback( int option, char *optarg );
950Sstevel@tonic-gate static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr,
960Sstevel@tonic-gate 	char *value, int vlen );
970Sstevel@tonic-gate static void freepmods( LDAPMod **pmods );
980Sstevel@tonic-gate static char *read_one_record( FILE *fp );
990Sstevel@tonic-gate static char *strdup_and_trim( char *s );
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1020Sstevel@tonic-gate static int process_ldapmod_rec( LDAP *ld, char *rbuf );
1030Sstevel@tonic-gate static int process_ldif_rec( LDAP *ld, char *rbuf );
1040Sstevel@tonic-gate static int domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry );
1050Sstevel@tonic-gate static int dodelete( LDAP *ld, char *dn );
1060Sstevel@tonic-gate static int dorename( LDAP *ld, char *dn, char *newrdn, char *newparent,
1070Sstevel@tonic-gate 	int deleteoldrdn );
1080Sstevel@tonic-gate #else
1090Sstevel@tonic-gate static int process_ldapmod_rec( char *rbuf );
1100Sstevel@tonic-gate static int process_ldif_rec( char *rbuf );
1110Sstevel@tonic-gate static int domodify( char *dn, LDAPMod **pmods, int newentry );
1120Sstevel@tonic-gate static int dodelete( char *dn );
1130Sstevel@tonic-gate static int dorename( char *dn, char *newrdn, char *newparent,
1140Sstevel@tonic-gate 	int deleteoldrdn );
1150Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static void
usage(void)1180Sstevel@tonic-gate usage( void )
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate     fprintf( stderr, gettext("usage: %s [options]\n"), ldaptool_progname );
1210Sstevel@tonic-gate     fprintf( stderr, gettext("options:\n") );
1220Sstevel@tonic-gate     ldaptool_common_usage( 0 );
1230Sstevel@tonic-gate     fprintf( stderr, gettext("    -c\t\tcontinuous mode (do not stop on errors)\n") );
1240Sstevel@tonic-gate     fprintf( stderr, gettext("    -A\t\tdisplay non-ASCII values in conjunction with -v\n") );
1250Sstevel@tonic-gate     fprintf( stderr, gettext("    -f file\tread modifications from file (default: standard input)\n") );
1260Sstevel@tonic-gate     if ( strcmp( ldaptool_progname, "ldapmodify" ) == 0 ){
1270Sstevel@tonic-gate 	fprintf( stderr, gettext("    -a\t\tadd entries\n") );
1280Sstevel@tonic-gate     }
1290Sstevel@tonic-gate     fprintf( stderr, gettext("    -b\t\tread values that start with / from files (for bin attrs)\n") );
1300Sstevel@tonic-gate     fprintf( stderr, gettext("    -F\t\tforce application of all changes, regardless of\n") );
1310Sstevel@tonic-gate     fprintf( stderr, gettext("      \t\treplica lines\n") );
1320Sstevel@tonic-gate     fprintf( stderr, gettext("    -e rejfile\tsave rejected entries in \"rejfile\"\n") );
1330Sstevel@tonic-gate     fprintf( stderr, gettext("    -B suffix\tbulk import to \"suffix\"\n"));
1340Sstevel@tonic-gate     fprintf( stderr, gettext("    -q\t\tbe quiet when adding/modifying entries\n") );
1350Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1360Sstevel@tonic-gate     fprintf( stderr, gettext("    -r\t\treplace values\n"));
1370Sstevel@tonic-gate     fprintf( stderr, gettext("    -l nb-connections\tnumber of LDAP connections\n"));
1380Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1390Sstevel@tonic-gate     exit( LDAP_PARAM_ERROR );
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
main(int argc,char ** argv)1440Sstevel@tonic-gate main( int argc, char **argv )
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate     int		optind, i;
147*8097SSreedhar.Chalamalasetti@Sun.COM     int		rc;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1500Sstevel@tonic-gate     char *locale = setlocale(LC_ALL, "");
1510Sstevel@tonic-gate     textdomain(TEXT_DOMAIN);
1520Sstevel@tonic-gate #endif
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate #ifdef notdef
1550Sstevel@tonic-gate #ifdef HPUX11
1560Sstevel@tonic-gate #ifndef __LP64__
1570Sstevel@tonic-gate 	_main( argc, argv);
1580Sstevel@tonic-gate #endif /* __LP64_ */
1590Sstevel@tonic-gate #endif /* HPUX11 */
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate     valsfromfiles = display_binary_values = 0;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1650Sstevel@tonic-gate     optind = ldaptool_process_args( argc, argv, "aAbcFe:B:qrl:", 0,
1660Sstevel@tonic-gate 	    options_callback );
1670Sstevel@tonic-gate #else
1680Sstevel@tonic-gate     optind = ldaptool_process_args( argc, argv, "aAbcFe:B:q", 0,
1690Sstevel@tonic-gate 	    options_callback );
1700Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate     if ( optind == -1 ) {
1740Sstevel@tonic-gate 	usage();
1750Sstevel@tonic-gate     }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate     if ( !newval && strcmp( ldaptool_progname, "ldapadd" ) == 0 ) {
1780Sstevel@tonic-gate 	newval = 1;
1790Sstevel@tonic-gate     }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate     if ( ldaptool_fp == NULL ) {
1820Sstevel@tonic-gate 	ldaptool_fp = stdin;
1830Sstevel@tonic-gate     }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate     if ( argc - optind != 0 ) {
1860Sstevel@tonic-gate 	usage();
1870Sstevel@tonic-gate     }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
1900Sstevel@tonic-gate     /* trivial case */
191*8097SSreedhar.Chalamalasetti@Sun.COM     if ( nbthreads == 1 ) {
192*8097SSreedhar.Chalamalasetti@Sun.COM 	rc = process(NULL);
193*8097SSreedhar.Chalamalasetti@Sun.COM 	/* check for and report output error */
194*8097SSreedhar.Chalamalasetti@Sun.COM 	fflush( stdout );
195*8097SSreedhar.Chalamalasetti@Sun.COM 	rc = ldaptool_check_ferror( stdout, rc,
196*8097SSreedhar.Chalamalasetti@Sun.COM 		gettext("output error (output might be incomplete)") );
197*8097SSreedhar.Chalamalasetti@Sun.COM 	return( rc );
198*8097SSreedhar.Chalamalasetti@Sun.COM     }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate     for ( i=0; i<nbthreads; ++i ) {
2010Sstevel@tonic-gate  	if ( thr_create(NULL, 0, process, NULL, NULL, NULL) != 0 )
2020Sstevel@tonic-gate 		++thr_create_errors;
2030Sstevel@tonic-gate     }
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate     if ( thr_create_errors < nbthreads )
2060Sstevel@tonic-gate     	while ( thr_join(0, NULL, NULL) == 0 );
2070Sstevel@tonic-gate     else
2080Sstevel@tonic-gate 	error = -1;
209*8097SSreedhar.Chalamalasetti@Sun.COM     rc = error;
210*8097SSreedhar.Chalamalasetti@Sun.COM     /* check for and report output error */
211*8097SSreedhar.Chalamalasetti@Sun.COM     fflush( stdout );
212*8097SSreedhar.Chalamalasetti@Sun.COM     rc = ldaptool_check_ferror( stdout, rc,
213*8097SSreedhar.Chalamalasetti@Sun.COM 		gettext("output error (output might be incomplete)") );
214*8097SSreedhar.Chalamalasetti@Sun.COM     return( rc );
2150Sstevel@tonic-gate #else
216*8097SSreedhar.Chalamalasetti@Sun.COM     rc = process(NULL);
217*8097SSreedhar.Chalamalasetti@Sun.COM     /* check for and report output error */
218*8097SSreedhar.Chalamalasetti@Sun.COM     fflush( stdout );
219*8097SSreedhar.Chalamalasetti@Sun.COM     rc = ldaptool_check_ferror( stdout, rc,
220*8097SSreedhar.Chalamalasetti@Sun.COM 		gettext("output error (output might be incomplete)") );
221*8097SSreedhar.Chalamalasetti@Sun.COM     return( rc );
2220Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
2260Sstevel@tonic-gate #define	exit(a)	\
2270Sstevel@tonic-gate 	if (nbthreads > 1) { \
2280Sstevel@tonic-gate     		mutex_lock(&read_mutex); \
2290Sstevel@tonic-gate 		error |= a; \
2300Sstevel@tonic-gate     		mutex_unlock(&read_mutex); \
2310Sstevel@tonic-gate 		thr_exit(&error); \
2320Sstevel@tonic-gate 	} else { \
2330Sstevel@tonic-gate 		exit(a); \
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static int
process(void * arg)2380Sstevel@tonic-gate process( void *arg )
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate     char	*rbuf, *saved_rbuf, *start, *p, *q;
2410Sstevel@tonic-gate     FILE	*rfp = NULL;
2420Sstevel@tonic-gate     int		rc, use_ldif, deref;
2430Sstevel@tonic-gate     LDAPControl	*ldctrl;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
2460Sstevel@tonic-gate     LDAP	*ld;
2470Sstevel@tonic-gate #endif  /* SOLARIS_LDAP_CMD */
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate     ld = ldaptool_ldap_init( 0 );
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate     if ( !ldaptool_not ) {
2520Sstevel@tonic-gate 	deref = LDAP_DEREF_NEVER;	/* this seems prudent */
2530Sstevel@tonic-gate 	ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
2540Sstevel@tonic-gate     }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate     ldaptool_bind( ld );
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate     if (( ldctrl = ldaptool_create_manage_dsait_control()) != NULL ) {
2590Sstevel@tonic-gate 	ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls);
2600Sstevel@tonic-gate     }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate     if ((ldctrl = ldaptool_create_proxyauth_control(ld)) !=NULL) {
2630Sstevel@tonic-gate 	ldaptool_add_control_to_array( ldctrl, ldaptool_request_ctrls);
2640Sstevel@tonic-gate     }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate     rc = 0;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate     /* turn on bulk import?*/
2690Sstevel@tonic-gate     if (bulkimport_suffix) {
2700Sstevel@tonic-gate 	struct berval	bv, *retdata;
2710Sstevel@tonic-gate 	char		*retoid;
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	bv.bv_val = bulkimport_suffix;
2740Sstevel@tonic-gate 	bv.bv_len = strlen(bulkimport_suffix);
2750Sstevel@tonic-gate 	if ((rc = ldap_extended_operation_s(ld,
2760Sstevel@tonic-gate 	    BULKIMPORT_START_OID, &bv, NULL,
2770Sstevel@tonic-gate 	    NULL, &retoid, &retdata)) != 0) {
2780Sstevel@tonic-gate 		fprintf(stderr, gettext("Error: unable to service "
2790Sstevel@tonic-gate 		    "extended operation request\n\t'%s' for "
2800Sstevel@tonic-gate 		    "bulk import\n\t(error:%d:'%s')\n"),
2810Sstevel@tonic-gate 		    BULKIMPORT_START_OID, rc, ldap_err2string(rc));
2820Sstevel@tonic-gate 		return (rc);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 	if (retoid)
2850Sstevel@tonic-gate 		ldap_memfree(retoid);
2860Sstevel@tonic-gate 	if (retdata)
2870Sstevel@tonic-gate 		ber_bvfree(retdata);
2880Sstevel@tonic-gate     }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate     while (( rc == 0 || contoper ) &&
2910Sstevel@tonic-gate 		( rbuf = read_one_record( ldaptool_fp )) != NULL ) {
2920Sstevel@tonic-gate 	/*
2930Sstevel@tonic-gate 	 * we assume record is ldif/slapd.replog if the first line
2940Sstevel@tonic-gate 	 * has a colon that appears to the left of any equal signs, OR
2950Sstevel@tonic-gate 	 * if the first line consists entirely of digits (an entry id)
2960Sstevel@tonic-gate 	 */
2970Sstevel@tonic-gate 	use_ldif = ( p = strchr( rbuf, ':' )) != NULL &&
2980Sstevel@tonic-gate 		( q = strchr( rbuf, '\n' )) != NULL && p < q &&
2990Sstevel@tonic-gate 		(( q = strchr( rbuf, '=' )) == NULL || p < q );
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	start = rbuf;
3020Sstevel@tonic-gate 	saved_rbuf = strdup( rbuf );
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ( !use_ldif && ( q = strchr( rbuf, '\n' )) != NULL ) {
3050Sstevel@tonic-gate 	    for ( p = rbuf; p < q; ++p ) {
3060Sstevel@tonic-gate 		if ( !isdigit( *p )) {
3070Sstevel@tonic-gate 		    break;
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 	    }
3100Sstevel@tonic-gate 	    if ( p >= q ) {
3110Sstevel@tonic-gate 		use_ldif = 1;
3120Sstevel@tonic-gate 		start = q + 1;
3130Sstevel@tonic-gate 	    }
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
3170Sstevel@tonic-gate 	if ( use_ldif ) {
3180Sstevel@tonic-gate 	    rc = process_ldif_rec( ld, start );
3190Sstevel@tonic-gate 	} else {
3200Sstevel@tonic-gate 	    rc = process_ldapmod_rec( ld, start );
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate #else
3230Sstevel@tonic-gate 	if ( use_ldif ) {
3240Sstevel@tonic-gate 	    rc = process_ldif_rec( start );
3250Sstevel@tonic-gate 	} else {
3260Sstevel@tonic-gate 	    rc = process_ldapmod_rec( start );
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if ( rc != LDAP_SUCCESS && rejfile != NULL ) {
3310Sstevel@tonic-gate 	    /* Write this record to the reject file */
3320Sstevel@tonic-gate 	    int newfile = 0;
3330Sstevel@tonic-gate 	    struct stat stbuf;
3340Sstevel@tonic-gate 	    if ( stat( rejfile, &stbuf ) < 0 ) {
3350Sstevel@tonic-gate 		if ( errno == ENOENT ) {
3360Sstevel@tonic-gate 		    newfile = 1;
3370Sstevel@tonic-gate 		}
3380Sstevel@tonic-gate 	    }
3390Sstevel@tonic-gate 	    if (( rfp = ldaptool_open_file( rejfile, "a" )) == NULL ) {
3400Sstevel@tonic-gate 		fprintf( stderr, gettext("Cannot open error file \"%s\" - "
3410Sstevel@tonic-gate 			"erroneous entries will not be saved\n"), rejfile );
3420Sstevel@tonic-gate 		rejfile = NULL;
3430Sstevel@tonic-gate 	    } else {
3440Sstevel@tonic-gate 		if ( newfile == 0 ) {
3450Sstevel@tonic-gate 		    fputs( "\n", rfp );
3460Sstevel@tonic-gate 		}
3470Sstevel@tonic-gate 		fprintf( rfp, gettext("# Error: %s\n"), ldap_err2string( rc ));
3480Sstevel@tonic-gate 		fputs( saved_rbuf, rfp );
3490Sstevel@tonic-gate 		fclose( rfp );
3500Sstevel@tonic-gate 		rfp = NULL;
3510Sstevel@tonic-gate 	    }
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	free( rbuf );
3550Sstevel@tonic-gate 	free( saved_rbuf );
3560Sstevel@tonic-gate     }
3570Sstevel@tonic-gate     ldaptool_reset_control_array( ldaptool_request_ctrls );
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate     /* turn off bulk import?*/
3600Sstevel@tonic-gate     if (bulkimport_suffix) {
3610Sstevel@tonic-gate 	struct berval	bv, *retdata;
3620Sstevel@tonic-gate 	char		*retoid;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	bv.bv_val = "";
3650Sstevel@tonic-gate 	bv.bv_len = 0;
3660Sstevel@tonic-gate 	if ((rc = ldap_extended_operation_s(ld,
3670Sstevel@tonic-gate 	    BULKIMPORT_STOP_OID, &bv, NULL,
3680Sstevel@tonic-gate 	    NULL, &retoid, &retdata)) != 0) {
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		fprintf(stderr, gettext("Error: unable to service "
3710Sstevel@tonic-gate 		    "extended operation request\n\t '%s' for "
3720Sstevel@tonic-gate 		    "bulk import\n\t(rc:%d:'%s')\n"),
3730Sstevel@tonic-gate 		    BULKIMPORT_STOP_OID, rc, ldap_err2string(rc));
3740Sstevel@tonic-gate 		return (rc);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 	if (retoid)
3770Sstevel@tonic-gate 		ldap_memfree(retoid);
3780Sstevel@tonic-gate 	if (retdata)
3790Sstevel@tonic-gate 		ber_bvfree(retdata);
3800Sstevel@tonic-gate     }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
3830Sstevel@tonic-gate     mutex_lock(&read_mutex);
3840Sstevel@tonic-gate #endif
3850Sstevel@tonic-gate     ldaptool_cleanup( ld );
3860Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
3870Sstevel@tonic-gate     mutex_unlock(&read_mutex);
3880Sstevel@tonic-gate #endif
3890Sstevel@tonic-gate     return( rc );
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate static void
options_callback(int option,char * optarg)3940Sstevel@tonic-gate options_callback( int option, char *optarg )
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate     switch( option ) {
3970Sstevel@tonic-gate     case 'a':	/* add */
3980Sstevel@tonic-gate 	newval = 1;
3990Sstevel@tonic-gate 	break;
4000Sstevel@tonic-gate     case 'b':	/* read values from files (for binary attributes) */
4010Sstevel@tonic-gate 	valsfromfiles = 1;
4020Sstevel@tonic-gate 	break;
4030Sstevel@tonic-gate     case 'A':	/* display non-ASCII values when -v is used */
4040Sstevel@tonic-gate 	display_binary_values = 1;
4050Sstevel@tonic-gate 	break;
4060Sstevel@tonic-gate     case 'c':	/* continuous operation */
4070Sstevel@tonic-gate 	contoper = 1;
4080Sstevel@tonic-gate 	break;
4090Sstevel@tonic-gate     case 'F':	/* force all changes records to be used */
4100Sstevel@tonic-gate 	force = 1;
4110Sstevel@tonic-gate 	break;
4120Sstevel@tonic-gate     case 'e':
4130Sstevel@tonic-gate 	rejfile = strdup( optarg );
4140Sstevel@tonic-gate 	break;
4150Sstevel@tonic-gate     case 'B':	/* bulk import option */
4160Sstevel@tonic-gate 	bulkimport_suffix = strdup( optarg );
4170Sstevel@tonic-gate 	break;
4180Sstevel@tonic-gate     case 'q':	/* quiet mode on add/modify operations */
4190Sstevel@tonic-gate 	ldapmodify_quiet = 1;
4200Sstevel@tonic-gate 	break;
4210Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
4220Sstevel@tonic-gate     case 'r':	/* default is to replace rather than add values */
4230Sstevel@tonic-gate 	replace = 1;
4240Sstevel@tonic-gate 	break;
4250Sstevel@tonic-gate     case 'l':
4260Sstevel@tonic-gate 	nbthreads = atoi(optarg);
4270Sstevel@tonic-gate 	break;
4280Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
4290Sstevel@tonic-gate     default:
4300Sstevel@tonic-gate 	usage();
4310Sstevel@tonic-gate     }
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate static int
4370Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
process_ldif_rec(LDAP * ld,char * rbuf)4380Sstevel@tonic-gate process_ldif_rec( LDAP *ld, char *rbuf )
4390Sstevel@tonic-gate #else
4400Sstevel@tonic-gate process_ldif_rec( char *rbuf )
4410Sstevel@tonic-gate #endif
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate     char	*line, *dn, *type, *value, *newrdn, *newparent, *p;
4440Sstevel@tonic-gate     char	*ctrl_oid=NULL, *ctrl_value=NULL;
4450Sstevel@tonic-gate     int 	ctrl_criticality=1;
4460Sstevel@tonic-gate     LDAPControl *ldctrl;
4470Sstevel@tonic-gate     int		rc, linenum, vlen, modop, replicaport;
4480Sstevel@tonic-gate     int		expect_modop, expect_sep, expect_chgtype_or_control, expect_newrdn;
4490Sstevel@tonic-gate     int		expect_deleteoldrdn, expect_newparent, rename, moddn;
4500Sstevel@tonic-gate     int		deleteoldrdn, saw_replica, use_record, new_entry, delete_entry;
4510Sstevel@tonic-gate     int         got_all, got_value;
4520Sstevel@tonic-gate     LDAPMod	**pmods;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate     new_entry = newval;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate     rc = got_all = saw_replica = delete_entry = expect_modop = 0;
4570Sstevel@tonic-gate     expect_deleteoldrdn = expect_newrdn = expect_newparent = expect_sep = 0;
4580Sstevel@tonic-gate     expect_chgtype_or_control = linenum = got_value = rename = moddn = 0;
4590Sstevel@tonic-gate     deleteoldrdn = 1;
4600Sstevel@tonic-gate     use_record = force;
4610Sstevel@tonic-gate     pmods = NULL;
4620Sstevel@tonic-gate     dn = newrdn = newparent = NULL;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
4650Sstevel@tonic-gate     while ( rc == 0 && ( line = str_getline( &rbuf )) != NULL ) {
4660Sstevel@tonic-gate #else
4670Sstevel@tonic-gate     while ( rc == 0 && ( line = ldif_getline( &rbuf )) != NULL ) {
4680Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
4690Sstevel@tonic-gate 	++linenum;
4700Sstevel@tonic-gate 	if ( expect_sep && strcasecmp( line, T_MODSEPSTR ) == 0 ) {
4710Sstevel@tonic-gate 	    expect_sep = 0;
4720Sstevel@tonic-gate 	    expect_modop = 1;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	    /*If we see a separator in the input stream,
4750Sstevel@tonic-gate 	     but we didn't get a value from the last modify
4760Sstevel@tonic-gate 	     then we have to fill pmods with an empty value*/
4770Sstevel@tonic-gate 	    if (modop == LDAP_MOD_REPLACE && !got_value){
4780Sstevel@tonic-gate 	      addmodifyop( &pmods, modop, value, NULL, 0);
4790Sstevel@tonic-gate 	    }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	    got_value = 0;
4820Sstevel@tonic-gate 	    continue;
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
4860Sstevel@tonic-gate 	if ( str_parse_line( line, &type, &value, &vlen ) < 0 ) {
4870Sstevel@tonic-gate #else
4880Sstevel@tonic-gate 	if ( ldif_parse_line( line, &type, &value, &vlen ) < 0 ) {
4890Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
4900Sstevel@tonic-gate 	    fprintf( stderr, gettext("%s: invalid format (line %d of entry: %s)\n"),
4910Sstevel@tonic-gate 		    ldaptool_progname, linenum, dn == NULL ? "" : dn );
4920Sstevel@tonic-gate 	    fprintf( stderr, gettext("%s: line contents: (%s)\n"),
4930Sstevel@tonic-gate 		    ldaptool_progname, line );
4940Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
4950Sstevel@tonic-gate 	    break;
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate evaluate_line:
4990Sstevel@tonic-gate 	if ( dn == NULL ) {
5000Sstevel@tonic-gate 	    if ( !use_record && strcasecmp( type, T_REPLICA_STR ) == 0 ) {
5010Sstevel@tonic-gate 		++saw_replica;
5020Sstevel@tonic-gate 		if (( p = strchr( value, ':' )) == NULL ) {
5030Sstevel@tonic-gate 		    replicaport = LDAP_PORT;
5040Sstevel@tonic-gate 		} else {
5050Sstevel@tonic-gate 		    *p++ = '\0';
5060Sstevel@tonic-gate 		    replicaport = atoi( p );
5070Sstevel@tonic-gate 		}
5080Sstevel@tonic-gate 		if ( strcasecmp( value, ldaptool_host ) == 0 &&
5090Sstevel@tonic-gate 			replicaport == ldaptool_port ) {
5100Sstevel@tonic-gate 		    use_record = 1;
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_DN_STR ) == 0 ) {
5140Sstevel@tonic-gate 		if (( dn = strdup( value )) == NULL ) {
5150Sstevel@tonic-gate 		    perror( "strdup" );
5160Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
5170Sstevel@tonic-gate 		}
5180Sstevel@tonic-gate 		expect_chgtype_or_control = 1;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_VERSION_STR ) == 0 ) {
5210Sstevel@tonic-gate 		ldif_version = atoi( value );
5220Sstevel@tonic-gate 		if ( ldif_version != LDIF_VERSION_ONE ) {
5230Sstevel@tonic-gate 		    fprintf( stderr, gettext("%s:  LDIF version %d is not supported;"
5240Sstevel@tonic-gate 			" use version: %d\n"), ldaptool_progname, ldif_version,
5250Sstevel@tonic-gate 			LDIF_VERSION_ONE );
5260Sstevel@tonic-gate 		    exit( LDAP_PARAM_ERROR );
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 		if ( ldaptool_verbose ) {
5290Sstevel@tonic-gate 		    printf( gettext("Processing a version %d LDIF file...\n"),
5300Sstevel@tonic-gate 			    ldif_version );
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		/* Now check if there's something left to process   */
5340Sstevel@tonic-gate 		/* and if not, go get the new record, else continue */
5350Sstevel@tonic-gate 		if ( *rbuf == '\0' ) {
5360Sstevel@tonic-gate 			return( 0 );
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	    } else if ( !saw_replica ) {
5400Sstevel@tonic-gate 		printf( gettext("%s: skipping change record: no dn: line\n"),
5410Sstevel@tonic-gate 			ldaptool_progname );
5420Sstevel@tonic-gate 		return( 0 );
5430Sstevel@tonic-gate 	    }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	    continue; /* skip all lines until we see "dn:" */
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if ( expect_chgtype_or_control ) {
5490Sstevel@tonic-gate 	    expect_chgtype_or_control = 0;
5500Sstevel@tonic-gate 	    if ( !use_record && saw_replica ) {
5510Sstevel@tonic-gate 		printf( gettext("%s: skipping change record for entry: %s\n\t(LDAP host/port does not match replica: lines)\n"),
5520Sstevel@tonic-gate 			ldaptool_progname, dn );
5530Sstevel@tonic-gate 		free( dn );
5540Sstevel@tonic-gate 		return( 0 );
5550Sstevel@tonic-gate 	    }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate #ifndef SOLARIS_LDAP_CMD
5580Sstevel@tonic-gate 	    if ( strcasecmp( type, "control" ) == 0 ) {
5590Sstevel@tonic-gate 		value = strdup_and_trim( value );
5600Sstevel@tonic-gate 		if (ldaptool_parse_ctrl_arg(value, ' ', &ctrl_oid,
5610Sstevel@tonic-gate 			&ctrl_criticality, &ctrl_value, &vlen)) {
5620Sstevel@tonic-gate 			    usage();
5630Sstevel@tonic-gate 		}
5640Sstevel@tonic-gate         	ldctrl = calloc(1,sizeof(LDAPControl));
5650Sstevel@tonic-gate         	if (ctrl_value) {
5660Sstevel@tonic-gate         	    rc = ldaptool_berval_from_ldif_value( ctrl_value, vlen,
5670Sstevel@tonic-gate 			 &(ldctrl->ldctl_value),
5680Sstevel@tonic-gate 			 1 /* recognize file URLs */, 0 /* always try file */,
5690Sstevel@tonic-gate             		 1 /* report errors */ );
5700Sstevel@tonic-gate         	    if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) {
5710Sstevel@tonic-gate             		fprintf( stderr, gettext("Unable to parse %s\n"), ctrl_value);
5720Sstevel@tonic-gate             		usage();
5730Sstevel@tonic-gate         	    }
5740Sstevel@tonic-gate         	}
5750Sstevel@tonic-gate         	ldctrl->ldctl_oid = ctrl_oid;
5760Sstevel@tonic-gate         	ldctrl->ldctl_iscritical = ctrl_criticality;
5770Sstevel@tonic-gate         	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
5780Sstevel@tonic-gate 		expect_chgtype_or_control = 1;
5790Sstevel@tonic-gate 		continue;
5800Sstevel@tonic-gate 	    }
5810Sstevel@tonic-gate #endif /* SOLARIS_LDAP_CMD */
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	    if ( strcasecmp( type, T_CHANGETYPESTR ) == 0 ) {
5840Sstevel@tonic-gate 		value = strdup_and_trim( value );
5850Sstevel@tonic-gate 		if ( strcasecmp( value, T_MODIFYCTSTR ) == 0 ) {
5860Sstevel@tonic-gate 		    new_entry = 0;
5870Sstevel@tonic-gate 		    expect_modop = 1;
5880Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_ADDCTSTR ) == 0 ) {
5890Sstevel@tonic-gate 		    new_entry = 1;
5900Sstevel@tonic-gate 		    modop = LDAP_MOD_ADD;
5910Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_MODRDNCTSTR ) == 0 ) {
5920Sstevel@tonic-gate 		    expect_newrdn = 1;
5930Sstevel@tonic-gate 		    moddn = 1;
5940Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_MODDNCTSTR ) == 0 ) {
5950Sstevel@tonic-gate 		    expect_newrdn = 1;
5960Sstevel@tonic-gate 		    moddn = 1;
5970Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_RENAMECTSTR ) == 0 ) {
5980Sstevel@tonic-gate 		    expect_newrdn = 1;
5990Sstevel@tonic-gate 		    rename = 1;
6000Sstevel@tonic-gate 		} else if ( strcasecmp( value, T_DELETECTSTR ) == 0 ) {
6010Sstevel@tonic-gate 		    got_all = delete_entry = 1;
6020Sstevel@tonic-gate 		} else {
6030Sstevel@tonic-gate 		    fprintf( stderr,
6040Sstevel@tonic-gate 			    gettext("%s:  unknown %s \"%s\" (line %d of entry: %s)\n"),
6050Sstevel@tonic-gate 			    ldaptool_progname, T_CHANGETYPESTR, value,
6060Sstevel@tonic-gate 			    linenum, dn );
6070Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
6080Sstevel@tonic-gate 		}
6090Sstevel@tonic-gate 		free( value );
6100Sstevel@tonic-gate 		continue;
6110Sstevel@tonic-gate 	    } else if ( newval ) {		/*  missing changetype => add */
6120Sstevel@tonic-gate 		new_entry = 1;
6130Sstevel@tonic-gate 		modop = LDAP_MOD_ADD;
6140Sstevel@tonic-gate 	    } else {
6150Sstevel@tonic-gate 	      /*The user MUST put in changetype: blah
6160Sstevel@tonic-gate 	       unless adding a new entry with either -a or ldapadd*/
6170Sstevel@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"),
6180Sstevel@tonic-gate 		ldaptool_progname, type, linenum, dn);
6190Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
6200Sstevel@tonic-gate 		/*expect_modop = 1;	 missing changetype => modify */
6210Sstevel@tonic-gate 	    }
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	if ( expect_modop ) {
6250Sstevel@tonic-gate 	    expect_modop = 0;
6260Sstevel@tonic-gate 	    expect_sep = 1;
6270Sstevel@tonic-gate 	    if ( strcasecmp( type, T_MODOPADDSTR ) == 0 ) {
6280Sstevel@tonic-gate 		modop = LDAP_MOD_ADD;
6290Sstevel@tonic-gate 		continue;
6300Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_MODOPREPLACESTR ) == 0 ) {
6310Sstevel@tonic-gate 		modop = LDAP_MOD_REPLACE;
6320Sstevel@tonic-gate 		continue;
6330Sstevel@tonic-gate 	    } else if ( strcasecmp( type, T_MODOPDELETESTR ) == 0 ) {
6340Sstevel@tonic-gate 		modop = LDAP_MOD_DELETE;
6350Sstevel@tonic-gate 		addmodifyop( &pmods, modop, value, NULL, 0 );
6360Sstevel@tonic-gate 		continue;
6370Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
6380Sstevel@tonic-gate 	    }  else { /* no modify op: use default */
6390Sstevel@tonic-gate 		modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
6400Sstevel@tonic-gate 	    }
6410Sstevel@tonic-gate #else
6420Sstevel@tonic-gate 	    }  else { /*Bug 27479. Remove default add operation*/
6430Sstevel@tonic-gate 	      fprintf(stderr, gettext("%s: Invalid parameter \"%s\" specified for changetype modify (line %d of entry %s)\n"),
6440Sstevel@tonic-gate 		      ldaptool_progname, type, linenum, dn);
6450Sstevel@tonic-gate 	      rc = LDAP_PARAM_ERROR;
6460Sstevel@tonic-gate 	    }
6470Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	  }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	if ( expect_newrdn ) {
6520Sstevel@tonic-gate 	    if ( strcasecmp( type, T_NEWRDNSTR ) == 0 ) {
6530Sstevel@tonic-gate 		if ( *value == '\0' ) {
6540Sstevel@tonic-gate 		    fprintf( stderr,
6550Sstevel@tonic-gate 			    gettext("%s: newrdn value missing (line %d of entry: %s)\n"),
6560Sstevel@tonic-gate 			    ldaptool_progname, linenum, dn == NULL ? "" : dn );
6570Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
6580Sstevel@tonic-gate 		} else if (( newrdn = strdup( value )) == NULL ) {
6590Sstevel@tonic-gate 		    perror( "strdup" );
6600Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
6610Sstevel@tonic-gate 		} else {
6620Sstevel@tonic-gate 		    expect_newrdn = 0;
6630Sstevel@tonic-gate 		    if ( rename ) {
6640Sstevel@tonic-gate 			expect_newparent = 1;
6650Sstevel@tonic-gate 		    } else {
6660Sstevel@tonic-gate 			expect_deleteoldrdn = 1;
6670Sstevel@tonic-gate 		    }
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 	    } else {
6700Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
6710Sstevel@tonic-gate 			ldaptool_progname, T_NEWRDNSTR, type, linenum, dn );
6720Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
6730Sstevel@tonic-gate 	    }
6740Sstevel@tonic-gate 	} else if ( expect_newparent ) {
6750Sstevel@tonic-gate 	    expect_newparent = 0;
6760Sstevel@tonic-gate 	    if ( rename ) {
6770Sstevel@tonic-gate 		expect_deleteoldrdn = 1;
6780Sstevel@tonic-gate 	    }
6790Sstevel@tonic-gate 	    if ( strcasecmp( type, T_NEWPARENTSTR ) == 0
6800Sstevel@tonic-gate 		    || strcasecmp( type, T_NEWSUPERIORSTR ) == 0 ) {
6810Sstevel@tonic-gate 		if (( newparent = strdup( value )) == NULL ) {
6820Sstevel@tonic-gate 		    perror( "strdup" );
6830Sstevel@tonic-gate 		    exit( LDAP_NO_MEMORY );
6840Sstevel@tonic-gate 		}
6850Sstevel@tonic-gate 	    } else {
6860Sstevel@tonic-gate 		/* Since this is an optional argument for rename/moddn, cause
6870Sstevel@tonic-gate 		 * the current line to be re-evaluated if newparent doesn't
6880Sstevel@tonic-gate 		 * follow deleteoldrdn.
6890Sstevel@tonic-gate 		 */
6900Sstevel@tonic-gate 		newparent = NULL;
6910Sstevel@tonic-gate 		goto evaluate_line;
6920Sstevel@tonic-gate 	    }
6930Sstevel@tonic-gate 	} else if ( expect_deleteoldrdn ) {
6940Sstevel@tonic-gate 	    if ( strcasecmp( type, T_DELETEOLDRDNSTR ) == 0 ) {
6950Sstevel@tonic-gate 		if ( *value == '\0' ) {
6960Sstevel@tonic-gate 		    fprintf( stderr,
6970Sstevel@tonic-gate 			    gettext("%s: missing 0 or 1 (line %d of entry: %s)\n"),
6980Sstevel@tonic-gate 			    ldaptool_progname, linenum, dn == NULL ? "" : dn );
6990Sstevel@tonic-gate 		    rc = LDAP_PARAM_ERROR;
7000Sstevel@tonic-gate 		} else {
7010Sstevel@tonic-gate 		    deleteoldrdn = ( *value == '0' ) ? 0 : 1;
7020Sstevel@tonic-gate 		    expect_deleteoldrdn = 0;
7030Sstevel@tonic-gate 		    if ( moddn ) {
7040Sstevel@tonic-gate 			expect_newparent = 1;
7050Sstevel@tonic-gate 		    }
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 	    } else {
7080Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: expecting \"%s:\" but saw \"%s:\" (line %d of entry %s)\n"),
7090Sstevel@tonic-gate 			ldaptool_progname, T_DELETEOLDRDNSTR, type, linenum,
7100Sstevel@tonic-gate 			dn );
7110Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
7120Sstevel@tonic-gate 	    }
7130Sstevel@tonic-gate 	    got_all = 1;
7140Sstevel@tonic-gate 	} else if ( got_all ) {
7150Sstevel@tonic-gate 	    fprintf( stderr,
7160Sstevel@tonic-gate 		    gettext("%s: extra lines at end (line %d of entry %s)\n"),
7170Sstevel@tonic-gate 		    ldaptool_progname, linenum, dn );
7180Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
7190Sstevel@tonic-gate 	    got_all = 1;
7200Sstevel@tonic-gate 	} else {
7210Sstevel@tonic-gate 	    addmodifyop( &pmods, modop, type, value, vlen );
7220Sstevel@tonic-gate 	    /*There was a value to replace*/
7230Sstevel@tonic-gate 	    got_value = 1;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate     }
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate     if ( rc == 0 ) {
7290Sstevel@tonic-gate 	if ( delete_entry ) {
7300Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
7310Sstevel@tonic-gate 	    rc = dodelete( ld, dn );
7320Sstevel@tonic-gate #else
7330Sstevel@tonic-gate 	    rc = dodelete( dn );
7340Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
7350Sstevel@tonic-gate 	} else if ( newrdn != NULL ) {
7360Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
7370Sstevel@tonic-gate 	    rc = dorename( ld, dn, newrdn, newparent, deleteoldrdn );
7380Sstevel@tonic-gate #else
7390Sstevel@tonic-gate 	    rc = dorename( dn, newrdn, newparent, deleteoldrdn );
7400Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
7410Sstevel@tonic-gate 	    rename = 0;
7420Sstevel@tonic-gate 	} else {
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	  /*Patch to fix Bug 22183
7450Sstevel@tonic-gate 	    If pmods is null, then there is no
7460Sstevel@tonic-gate 	    attribute to replace, so we alloc
7470Sstevel@tonic-gate 	    an empty pmods*/
7480Sstevel@tonic-gate 	  if (modop == LDAP_MOD_REPLACE && !got_value && expect_sep){
7490Sstevel@tonic-gate 	    addmodifyop( &pmods, modop, value, NULL, 0);
7500Sstevel@tonic-gate 	  }/*End Patch*/
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
7540Sstevel@tonic-gate 	  rc = domodify( ld, dn, pmods, new_entry );
7550Sstevel@tonic-gate #else
7560Sstevel@tonic-gate 	  rc = domodify( dn, pmods, new_entry );
7570Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if ( rc == LDAP_SUCCESS ) {
7610Sstevel@tonic-gate 	    rc = 0;
7620Sstevel@tonic-gate 	}
7630Sstevel@tonic-gate     }
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate     if ( dn != NULL ) {
7660Sstevel@tonic-gate 	free( dn );
7670Sstevel@tonic-gate     }
7680Sstevel@tonic-gate     if ( newrdn != NULL ) {
7690Sstevel@tonic-gate 	free( newrdn );
7700Sstevel@tonic-gate     }
7710Sstevel@tonic-gate     if ( newparent != NULL ) {
7720Sstevel@tonic-gate 	free( newparent );
7730Sstevel@tonic-gate     }
7740Sstevel@tonic-gate     if ( pmods != NULL ) {
7750Sstevel@tonic-gate 	freepmods( pmods );
7760Sstevel@tonic-gate     }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate     return( rc );
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate static int
7830Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
7840Sstevel@tonic-gate process_ldapmod_rec( LDAP *ld, char *rbuf )
7850Sstevel@tonic-gate #else
7860Sstevel@tonic-gate process_ldapmod_rec( char *rbuf )
7870Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate     char	*line, *dn, *p, *q, *attr, *value;
7900Sstevel@tonic-gate     int		rc, linenum, modop;
7910Sstevel@tonic-gate     LDAPMod	**pmods;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate     pmods = NULL;
7940Sstevel@tonic-gate     dn = NULL;
7950Sstevel@tonic-gate     linenum = 0;
7960Sstevel@tonic-gate     line = rbuf;
7970Sstevel@tonic-gate     rc = 0;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate     while ( rc == 0 && rbuf != NULL && *rbuf != '\0' ) {
8000Sstevel@tonic-gate 	++linenum;
8010Sstevel@tonic-gate 	if (( p = strchr( rbuf, '\n' )) == NULL ) {
8020Sstevel@tonic-gate 	    rbuf = NULL;
8030Sstevel@tonic-gate 	} else {
8040Sstevel@tonic-gate 	    if ( *(p-1) == '\\' ) {	/* lines ending in '\' are continued */
8050Sstevel@tonic-gate 		strcpy( p - 1, p );
8060Sstevel@tonic-gate 		rbuf = p;
8070Sstevel@tonic-gate 		continue;
8080Sstevel@tonic-gate 	    }
8090Sstevel@tonic-gate 	    *p++ = '\0';
8100Sstevel@tonic-gate 	    rbuf = p;
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	if ( dn == NULL ) {	/* first line contains DN */
8140Sstevel@tonic-gate 	    if (( dn = strdup( line )) == NULL ) {
8150Sstevel@tonic-gate 		perror( "strdup" );
8160Sstevel@tonic-gate 		exit( LDAP_NO_MEMORY );
8170Sstevel@tonic-gate 	    }
8180Sstevel@tonic-gate 	} else {
8190Sstevel@tonic-gate 	    if (( p = strchr( line, '=' )) == NULL ) {
8200Sstevel@tonic-gate 		value = NULL;
8210Sstevel@tonic-gate 		p = line + strlen( line );
8220Sstevel@tonic-gate 	    } else {
8230Sstevel@tonic-gate 		*p++ = '\0';
8240Sstevel@tonic-gate 		value = p;
8250Sstevel@tonic-gate 	    }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	    for ( attr = line; *attr != '\0' && isspace( *attr ); ++attr ) {
8280Sstevel@tonic-gate 		;	/* skip attribute leading white space */
8290Sstevel@tonic-gate 	    }
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	    for ( q = p - 1; q > attr && isspace( *q ); --q ) {
8320Sstevel@tonic-gate 		*q = '\0';	/* remove attribute trailing white space */
8330Sstevel@tonic-gate 	    }
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	    if ( value != NULL ) {
8360Sstevel@tonic-gate 		while ( isspace( *value )) {
8370Sstevel@tonic-gate 		    ++value;		/* skip value leading white space */
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 		for ( q = value + strlen( value ) - 1; q > value &&
8400Sstevel@tonic-gate 			isspace( *q ); --q ) {
8410Sstevel@tonic-gate 		    *q = '\0';	/* remove value trailing white space */
8420Sstevel@tonic-gate 		}
8430Sstevel@tonic-gate 		if ( *value == '\0' ) {
8440Sstevel@tonic-gate 		    value = NULL;
8450Sstevel@tonic-gate 		}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	    }
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	    if ( value == NULL && newval ) {
8500Sstevel@tonic-gate 		fprintf( stderr, gettext("%s: missing value on line %d (attr is %s)\n"),
8510Sstevel@tonic-gate 			ldaptool_progname, linenum, attr );
8520Sstevel@tonic-gate 		rc = LDAP_PARAM_ERROR;
8530Sstevel@tonic-gate 	    } else {
8540Sstevel@tonic-gate 		 switch ( *attr ) {
8550Sstevel@tonic-gate 		case '-':
8560Sstevel@tonic-gate 		    modop = LDAP_MOD_DELETE;
8570Sstevel@tonic-gate 		    ++attr;
8580Sstevel@tonic-gate 		    break;
8590Sstevel@tonic-gate 		case '+':
8600Sstevel@tonic-gate 		    modop = LDAP_MOD_ADD;
8610Sstevel@tonic-gate 		    ++attr;
8620Sstevel@tonic-gate 		    break;
8630Sstevel@tonic-gate 		default:
8640Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
8650Sstevel@tonic-gate 		    modop = replace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
8660Sstevel@tonic-gate #else
8670Sstevel@tonic-gate 		    /*Bug 27479. Remove the add default*/
8680Sstevel@tonic-gate 		      fprintf(stderr, gettext("%s: Invalid parameter specified for changetype modify (line %d of entry %s)\n"),
8690Sstevel@tonic-gate 		      ldaptool_progname, linenum, dn);
8700Sstevel@tonic-gate 		      rc = LDAP_PARAM_ERROR;
8710Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		addmodifyop( &pmods, modop, attr, value,
8750Sstevel@tonic-gate 			( value == NULL ) ? 0 : strlen( value ));
8760Sstevel@tonic-gate 	    }
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	line = rbuf;
8800Sstevel@tonic-gate     }
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate     if ( rc == 0 ) {
8830Sstevel@tonic-gate 	if ( dn == NULL ) {
8840Sstevel@tonic-gate 	    rc = LDAP_PARAM_ERROR;
8850Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
8860Sstevel@tonic-gate 	} else if (( rc = domodify( ld, dn, pmods, newval )) == LDAP_SUCCESS ){
8870Sstevel@tonic-gate #else
8880Sstevel@tonic-gate 	} else if (( rc = domodify( dn, pmods, newval )) == LDAP_SUCCESS ){
8890Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
8900Sstevel@tonic-gate 	  rc = 0;
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate       }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate     if ( pmods != NULL ) {
8950Sstevel@tonic-gate 	freepmods( pmods );
8960Sstevel@tonic-gate     }
8970Sstevel@tonic-gate     if ( dn != NULL ) {
8980Sstevel@tonic-gate 	free( dn );
8990Sstevel@tonic-gate     }
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate     return( rc );
9020Sstevel@tonic-gate }
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate static void
9060Sstevel@tonic-gate addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
9070Sstevel@tonic-gate {
9080Sstevel@tonic-gate     LDAPMod		**pmods;
9090Sstevel@tonic-gate     int			i, j, rc;
9100Sstevel@tonic-gate     struct berval	*bvp;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate     pmods = *pmodsp;
9130Sstevel@tonic-gate     modop |= LDAP_MOD_BVALUES;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate     i = 0;
9160Sstevel@tonic-gate     if ( pmods != NULL ) {
9170Sstevel@tonic-gate 	for ( ; pmods[ i ] != NULL; ++i ) {
9180Sstevel@tonic-gate 	    if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
9190Sstevel@tonic-gate 		    pmods[ i ]->mod_op == modop ) {
9200Sstevel@tonic-gate 		break;
9210Sstevel@tonic-gate 	    }
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate     }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate     if ( pmods == NULL || pmods[ i ] == NULL ) {
9260Sstevel@tonic-gate 	if (( pmods = (LDAPMod **)LDAPTOOL_SAFEREALLOC( pmods, (i + 2) *
9270Sstevel@tonic-gate 		sizeof( LDAPMod * ))) == NULL ) {
9280Sstevel@tonic-gate 	    perror( "realloc" );
9290Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 	*pmodsp = pmods;
9320Sstevel@tonic-gate 	pmods[ i + 1 ] = NULL;
9330Sstevel@tonic-gate 	if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod )))
9340Sstevel@tonic-gate 		== NULL ) {
9350Sstevel@tonic-gate 	    perror( "calloc" );
9360Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 	pmods[ i ]->mod_op = modop;
9390Sstevel@tonic-gate 	if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) {
9400Sstevel@tonic-gate 	    perror( "strdup" );
9410Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
9420Sstevel@tonic-gate 	}
9430Sstevel@tonic-gate     }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate     if ( value != NULL ) {
9460Sstevel@tonic-gate 	j = 0;
9470Sstevel@tonic-gate 	if ( pmods[ i ]->mod_bvalues != NULL ) {
9480Sstevel@tonic-gate 	    for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
9490Sstevel@tonic-gate 		;
9500Sstevel@tonic-gate 	    }
9510Sstevel@tonic-gate 	}
9520Sstevel@tonic-gate 	if (( pmods[ i ]->mod_bvalues = (struct berval **)
9530Sstevel@tonic-gate 		LDAPTOOL_SAFEREALLOC( pmods[ i ]->mod_bvalues,
9540Sstevel@tonic-gate 		(j + 2) * sizeof( struct berval * ))) == NULL ) {
9550Sstevel@tonic-gate 	    perror( "realloc" );
9560Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 	pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
9590Sstevel@tonic-gate 	if (( bvp = (struct berval *)malloc( sizeof( struct berval )))
9600Sstevel@tonic-gate 		== NULL ) {
9610Sstevel@tonic-gate 	    perror( "malloc" );
9620Sstevel@tonic-gate 	    exit( LDAP_NO_MEMORY );
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 	pmods[ i ]->mod_bvalues[ j ] = bvp;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate #ifdef notdef
9670Sstevel@tonic-gate 	if (ldaptool_verbose) {
9680Sstevel@tonic-gate 		printf(gettext("%s: value: %s vlen: %d\n"), "ldapmodify", value, vlen);
9690Sstevel@tonic-gate 	}
9700Sstevel@tonic-gate #endif
9710Sstevel@tonic-gate 	rc = ldaptool_berval_from_ldif_value( value, vlen, bvp,
9720Sstevel@tonic-gate 		    ( ldif_version >= LDIF_VERSION_ONE ), valsfromfiles,
9730Sstevel@tonic-gate 			1 /* report errors */ );
9740Sstevel@tonic-gate 	if ( rc != LDAPTOOL_FILEURL_SUCCESS ) {
9750Sstevel@tonic-gate 	    exit( ldaptool_fileurlerr2ldaperr( rc ));
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate     }
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate static int
9820Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
9830Sstevel@tonic-gate domodify( LDAP *ld, char *dn, LDAPMod **pmods, int newentry )
9840Sstevel@tonic-gate #else
9850Sstevel@tonic-gate domodify( char *dn, LDAPMod **pmods, int newentry )
9860Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
9870Sstevel@tonic-gate {
9880Sstevel@tonic-gate     int			i, j, notascii, op;
9890Sstevel@tonic-gate     struct berval	*bvp;
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate     if ( pmods == NULL ) {
9920Sstevel@tonic-gate 	fprintf( stderr, gettext("%s: no attributes to change or add (entry %s)\n"),
9930Sstevel@tonic-gate 		ldaptool_progname, dn );
9940Sstevel@tonic-gate 	return( LDAP_PARAM_ERROR );
9950Sstevel@tonic-gate     }
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate     if ( ldaptool_verbose ) {
9980Sstevel@tonic-gate 	for ( i = 0; pmods[ i ] != NULL; ++i ) {
9990Sstevel@tonic-gate 	    op = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
10000Sstevel@tonic-gate 	    printf( gettext("%s %s:\n"), op == LDAP_MOD_REPLACE ?
10010Sstevel@tonic-gate 		    gettext("replace") : op == LDAP_MOD_ADD ?
10020Sstevel@tonic-gate 		    gettext("add") : gettext("delete"), pmods[ i ]->mod_type );
10030Sstevel@tonic-gate 	    if ( pmods[ i ]->mod_bvalues != NULL ) {
10040Sstevel@tonic-gate 		for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
10050Sstevel@tonic-gate 		    bvp = pmods[ i ]->mod_bvalues[ j ];
10060Sstevel@tonic-gate 		    notascii = 0;
10070Sstevel@tonic-gate 		    if ( !display_binary_values ) {
10080Sstevel@tonic-gate 			notascii = !ldaptool_berval_is_ascii( bvp );
10090Sstevel@tonic-gate 		    }
10100Sstevel@tonic-gate 		    if ( notascii ) {
10110Sstevel@tonic-gate 			printf( gettext("\tNOT ASCII (%ld bytes)\n"), bvp->bv_len );
10120Sstevel@tonic-gate 		    } else {
10130Sstevel@tonic-gate 			printf( "\t%s\n", bvp->bv_val );
10140Sstevel@tonic-gate 		    }
10150Sstevel@tonic-gate 		}
10160Sstevel@tonic-gate 	    }
10170Sstevel@tonic-gate 	}
10180Sstevel@tonic-gate     }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate     if ( !ldapmodify_quiet) {
10210Sstevel@tonic-gate 	if ( newentry ) {
10220Sstevel@tonic-gate 	    printf( gettext("%sadding new entry %s\n"),
10230Sstevel@tonic-gate 		ldaptool_not ? "!" : "", dn );
10240Sstevel@tonic-gate 	} else {
10250Sstevel@tonic-gate 	    printf( gettext("%smodifying entry %s\n"),
10260Sstevel@tonic-gate 		ldaptool_not ? "!" : "", dn );
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate     }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate     if ( !ldaptool_not ) {
10310Sstevel@tonic-gate 	if ( newentry ) {
10320Sstevel@tonic-gate 	unsigned int	sleep_interval = 2; /* seconds */
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
10350Sstevel@tonic-gate 	    /* Backward compatibility with old Solaris command */
10360Sstevel@tonic-gate 	    unsigned int nb = 0;
10370Sstevel@tonic-gate 	    timestruc_t to;
10380Sstevel@tonic-gate 	    while ((i = ldaptool_add_ext_s( ld, dn, pmods,
10390Sstevel@tonic-gate 			ldaptool_request_ctrls, NULL, "ldap_add" ))
10400Sstevel@tonic-gate 			!= LDAP_SUCCESS) {
10410Sstevel@tonic-gate 		if (i == LDAP_BUSY) {
10420Sstevel@tonic-gate 			if ( sleep_interval > 3600 ) {
10430Sstevel@tonic-gate 				printf(gettext("ldap_add: Unable to complete "
10440Sstevel@tonic-gate 						"request.  Server is too "
10450Sstevel@tonic-gate 						"busy servicing other "
10460Sstevel@tonic-gate 						"requests\n"));
10470Sstevel@tonic-gate 				break;
10480Sstevel@tonic-gate 			}
10490Sstevel@tonic-gate 			if ( !ldapmodify_quiet ) {
10500Sstevel@tonic-gate 				printf(gettext("ldap_add: LDAP_BUSY returned "
10510Sstevel@tonic-gate 						"by server.  Will retry "
10520Sstevel@tonic-gate 						"operation in %d seconds\n"),
10530Sstevel@tonic-gate 						sleep_interval);
10540Sstevel@tonic-gate 			}
10550Sstevel@tonic-gate 			sleep( sleep_interval );
10560Sstevel@tonic-gate 			sleep_interval *= 2;
10570Sstevel@tonic-gate 		} else if (i == LDAP_NO_SUCH_OBJECT) {
10580Sstevel@tonic-gate 			/*
10590Sstevel@tonic-gate 			 * Wait for the parent entry to be created by
10600Sstevel@tonic-gate 			 * another thread. Do not retry more than the
10610Sstevel@tonic-gate 			 * number of threads.
10620Sstevel@tonic-gate 			 */
10630Sstevel@tonic-gate 			++nb;
10640Sstevel@tonic-gate 			if (nb >= nbthreads)
10650Sstevel@tonic-gate 				break;
10660Sstevel@tonic-gate 			mutex_lock(&wait_mutex);
10670Sstevel@tonic-gate 			to.tv_sec = 5;
10680Sstevel@tonic-gate 			to.tv_nsec = 0;
10690Sstevel@tonic-gate 			if (cond_reltimedwait(&wait_cond, &wait_mutex, &to)
10700Sstevel@tonic-gate 				== ETIME) {
10710Sstevel@tonic-gate 					nb = nbthreads; /* last chance */
10720Sstevel@tonic-gate 			}
10730Sstevel@tonic-gate 			mutex_unlock(&wait_mutex);
10740Sstevel@tonic-gate 		} else {
10750Sstevel@tonic-gate 			break;
10760Sstevel@tonic-gate 		}
10770Sstevel@tonic-gate 	    }
10780Sstevel@tonic-gate 	    cond_broadcast(&wait_cond);
10790Sstevel@tonic-gate #else
10800Sstevel@tonic-gate 	    while ((i = ldaptool_add_ext_s( ld, dn, pmods,
10810Sstevel@tonic-gate 			ldaptool_request_ctrls, NULL, "ldap_add" ))
10820Sstevel@tonic-gate 			== LDAP_BUSY) {
10830Sstevel@tonic-gate 		if ( sleep_interval > 3600 ) {
10840Sstevel@tonic-gate 			printf("ldap_add: Unable to complete request. ");
10850Sstevel@tonic-gate 			printf("Server is too ");
10860Sstevel@tonic-gate 			printf("busy servicing other requests\n");
10870Sstevel@tonic-gate 			break;
10880Sstevel@tonic-gate 		}
10890Sstevel@tonic-gate 		if ( !ldapmodify_quiet ) {
10900Sstevel@tonic-gate 			printf("ldap_add: LDAP_BUSY returned by server. ");
10910Sstevel@tonic-gate 			printf("Will retry operation ");
10920Sstevel@tonic-gate 			printf("in %d seconds\n", sleep_interval);
10930Sstevel@tonic-gate 		}
10940Sstevel@tonic-gate 		sleep( sleep_interval );
10950Sstevel@tonic-gate 		sleep_interval *= 2;
10960Sstevel@tonic-gate 	    }
10970Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
10980Sstevel@tonic-gate 	} else {
10990Sstevel@tonic-gate 	    i = ldaptool_modify_ext_s( ld, dn, pmods, ldaptool_request_ctrls,
11000Sstevel@tonic-gate 		    NULL, "ldap_modify" );
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 	if ( i == LDAP_SUCCESS && ldaptool_verbose ) {
11030Sstevel@tonic-gate 	    printf( gettext("modify complete\n") );
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate     } else {
11060Sstevel@tonic-gate 	i = LDAP_SUCCESS;
11070Sstevel@tonic-gate     }
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate     if ( !ldapmodify_quiet) {
11100Sstevel@tonic-gate 	putchar( '\n' );
11110Sstevel@tonic-gate     }
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate     return( i );
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate static int
11180Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
11190Sstevel@tonic-gate dodelete( LDAP *ld, char *dn )
11200Sstevel@tonic-gate #else
11210Sstevel@tonic-gate dodelete( char *dn )
11220Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate     int	rc;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate     printf( gettext("%sdeleting entry %s\n"), ldaptool_not ? "!" : "", dn );
11270Sstevel@tonic-gate     if ( !ldaptool_not ) {
11280Sstevel@tonic-gate 	if (( rc = ldaptool_delete_ext_s( ld, dn, ldaptool_request_ctrls,
11290Sstevel@tonic-gate 		NULL, "ldap_delete" )) == LDAP_SUCCESS && ldaptool_verbose ) {
11300Sstevel@tonic-gate 	    printf( gettext("delete complete") );
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate     } else {
11330Sstevel@tonic-gate 	rc = LDAP_SUCCESS;
11340Sstevel@tonic-gate     }
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate     putchar( '\n' );
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate     return( rc );
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate static int
11430Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
11440Sstevel@tonic-gate dorename( LDAP *ld, char *dn, char *newrdn, char *newparent, int deleteoldrdn )
11450Sstevel@tonic-gate #else
11460Sstevel@tonic-gate dorename( char *dn, char *newrdn, char *newparent, int deleteoldrdn )
11470Sstevel@tonic-gate #endif	/* SOLARIS_LDAP_CMD */
11480Sstevel@tonic-gate {
11490Sstevel@tonic-gate     int	rc;
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate     if ( ldaptool_verbose ) {
11520Sstevel@tonic-gate 	if ( newparent == NULL ) {
11530Sstevel@tonic-gate 	    printf(deleteoldrdn ?
11540Sstevel@tonic-gate 		  gettext("new RDN: %s (do not keep existing values)\n"):
11550Sstevel@tonic-gate 		  gettext("new RDN: %s (keep existing values)\n"));
11560Sstevel@tonic-gate 	} else {
11570Sstevel@tonic-gate 	    printf(deleteoldrdn ?
11580Sstevel@tonic-gate 		  gettext("new RDN: %s, new parent %s ( do not keep existing values)\n"):
11590Sstevel@tonic-gate 		  gettext("new RDN: %s, new parent %s ( keep existing values)\n"));
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate     }
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate     printf( gettext("%smodifying RDN of entry %s%s\n"),
11640Sstevel@tonic-gate 	    ldaptool_not ? "!" : "", dn, ( newparent == NULL ) ? "" :
11650Sstevel@tonic-gate 	    gettext(" and/or moving it beneath a new parent\n") );
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate     if ( !ldaptool_not ) {
11680Sstevel@tonic-gate 	if (( rc = ldaptool_rename_s( ld, dn, newrdn, newparent, deleteoldrdn,
11690Sstevel@tonic-gate 		ldaptool_request_ctrls, NULL, "ldap_rename" )) == LDAP_SUCCESS
11700Sstevel@tonic-gate 		&& ldaptool_verbose ) {
11710Sstevel@tonic-gate 	    printf( gettext("rename completed\n") );
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate     } else {
11740Sstevel@tonic-gate 	rc = LDAP_SUCCESS;
11750Sstevel@tonic-gate     }
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate     putchar( '\n' );
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate     return( rc );
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate static void
11840Sstevel@tonic-gate freepmods( LDAPMod **pmods )
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate     int	i;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate     for ( i = 0; pmods[ i ] != NULL; ++i ) {
11890Sstevel@tonic-gate 	if ( pmods[ i ]->mod_bvalues != NULL ) {
11900Sstevel@tonic-gate 	    ber_bvecfree( pmods[ i ]->mod_bvalues );
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 	if ( pmods[ i ]->mod_type != NULL ) {
11930Sstevel@tonic-gate 	    free( pmods[ i ]->mod_type );
11940Sstevel@tonic-gate 	}
11950Sstevel@tonic-gate 	free( pmods[ i ] );
11960Sstevel@tonic-gate     }
11970Sstevel@tonic-gate     free( pmods );
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate static char *
12020Sstevel@tonic-gate read_one_record( FILE *fp )
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate     int         len, gotnothing;
12050Sstevel@tonic-gate     char        *buf, line[ LDAPMOD_MAXLINE ];
12060Sstevel@tonic-gate     int		lcur, lmax;
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate     lcur = lmax = 0;
12090Sstevel@tonic-gate     buf = NULL;
12100Sstevel@tonic-gate     gotnothing = 1;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
12130Sstevel@tonic-gate     mutex_lock(&read_mutex);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate     if (fp == NULL) {
12160Sstevel@tonic-gate     	mutex_unlock(&read_mutex);
12170Sstevel@tonic-gate 	return(NULL);
12180Sstevel@tonic-gate     }
12190Sstevel@tonic-gate #endif
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate     while ( fgets( line, sizeof(line), fp ) != NULL ) {
12220Sstevel@tonic-gate 	if ( (len = strlen( line )) < 2 ) {
12230Sstevel@tonic-gate 	    if ( gotnothing ) {
12240Sstevel@tonic-gate 		continue;
12250Sstevel@tonic-gate 	    } else {
12260Sstevel@tonic-gate 		break;
12270Sstevel@tonic-gate 	    }
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	/* Check if the blank line starts with '\r' (CR) */
12310Sstevel@tonic-gate 	if ( ((len = strlen( line )) == 2) && (line[0] == '\r') ) {
12320Sstevel@tonic-gate 	    if ( gotnothing ) {
12330Sstevel@tonic-gate 		continue;
12340Sstevel@tonic-gate 	    } else {
12350Sstevel@tonic-gate 		break;
12360Sstevel@tonic-gate 	      }
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	if ( *line == '#' ) {
12400Sstevel@tonic-gate 	    continue;			/* skip comment lines */
12410Sstevel@tonic-gate 	}
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	gotnothing = 0;
12440Sstevel@tonic-gate         if ( lcur + len + 1 > lmax ) {
12450Sstevel@tonic-gate             lmax = LDAPMOD_MAXLINE
12460Sstevel@tonic-gate 		    * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
12470Sstevel@tonic-gate 	    if (( buf = (char *)LDAPTOOL_SAFEREALLOC( buf, lmax )) == NULL ) {
12480Sstevel@tonic-gate 		perror( "realloc" );
12490Sstevel@tonic-gate 		#ifdef SOLARIS_LDAP_CMD
12500Sstevel@tonic-gate     			mutex_unlock(&read_mutex);
12510Sstevel@tonic-gate 		#endif
12520Sstevel@tonic-gate 		exit( LDAP_NO_MEMORY );
12530Sstevel@tonic-gate 	    }
12540Sstevel@tonic-gate         }
12550Sstevel@tonic-gate         strcpy( buf + lcur, line );
12560Sstevel@tonic-gate         lcur += len;
12570Sstevel@tonic-gate     }
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate #ifdef SOLARIS_LDAP_CMD
12600Sstevel@tonic-gate     mutex_unlock(&read_mutex);
12610Sstevel@tonic-gate #endif
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate     return( buf );
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate  * strdup and trim trailing blanks
12690Sstevel@tonic-gate  */
12700Sstevel@tonic-gate static char *
12710Sstevel@tonic-gate strdup_and_trim( char *s )
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate     char	*p;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate     if (( s = strdup( s )) == NULL ) {
12760Sstevel@tonic-gate 	perror( "strdup" );
12770Sstevel@tonic-gate 	exit( LDAP_NO_MEMORY );
12780Sstevel@tonic-gate     }
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate     p = s + strlen( s ) - 1;
12810Sstevel@tonic-gate     while ( p >= s && isspace( *p )) {
12820Sstevel@tonic-gate 	--p;
12830Sstevel@tonic-gate     }
12840Sstevel@tonic-gate     *++p = '\0';
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate     return( s );
12870Sstevel@tonic-gate }
1288