xref: /illumos-gate/usr/src/cmd/ldap/common/common.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * The contents of this file are subject to the Netscape Public
8  * License Version 1.1 (the "License"); you may not use this file
9  * except in compliance with the License. You may obtain a copy of
10  * the License at http://www.mozilla.org/NPL/
11  *
12  * Software distributed under the License is distributed on an "AS
13  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14  * implied. See the License for the specific language governing
15  * rights and limitations under the License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is Netscape
21  * Communications Corporation. Portions created by Netscape are
22  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
23  * Rights Reserved.
24  *
25  * Contributor(s):
26  */
27 
28 /*
29  * code that is shared by two or more of the LDAP command line tools
30  */
31 
32 #include "ldaptool.h"
33 #include "fileurl.h"
34 #ifdef SOLARIS_LDAP_CMD
35 #include "solaris-int.h"
36 #include <ldap.h>
37 #include <locale.h>
38 #include <libgen.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <limits.h>
42 #endif	/* SOLARIS_LDAP_CMD */
43 
44 #ifdef LDAP_TOOL_ARGPIN
45 #include "argpin.h"
46 #include "ntuserpin.h"
47 #endif /* LDAP_TOOL_ARGPIN */
48 
49 #ifndef SOLARIS_LDAP_CMD
50 #include <nspr.h> /* for PR_Cleanup() */
51 #endif	/* SOLARIS_LDAP_CMD */
52 #include <stdlib.h>
53 #include <time.h>	/* for time() and ctime() */
54 #ifdef HAVE_SASL_OPTIONS
55 #ifdef SOLARIS_LDAP_CMD
56 #include <sasl/sasl.h>
57 #else
58 #include <sasl.h>
59 #endif	/* SOLARIS_LDAP_CMD */
60 #include "ldaptool-sasl.h"
61 #endif	/* HAVE_SASL_OPTIONS */
62 
63 #ifndef SOLARIS_LDAP_CMD
64 #define gettext(s) s
65 #endif
66 
67 #ifdef SOLARIS_LDAP_CMD
68 #define	PATH_BUF_SIZE	(PATH_MAX + 1)
69 #endif
70 
71 static LDAP_REBINDPROC_CALLBACK get_rebind_credentials;
72 static void print_library_info( const LDAPAPIInfo *aip, FILE *fp );
73 static int wait4result( LDAP *ld, int msgid, struct berval **servercredp,
74 	char *msg );
75 static int parse_result( LDAP *ld, LDAPMessage *res,
76 	struct berval **servercredp, char *msg, int freeit );
77 
78 #ifdef LDAPTOOL_DEBUG_MEMORY
79 static void *ldaptool_debug_malloc( size_t size );
80 static void *ldaptool_debug_calloc( size_t nelem, size_t elsize );
81 static void *ldaptool_debug_realloc( void *ptr, size_t size );
82 static void ldaptool_debug_free( void *ptr );
83 #endif /* LDAPTOOL_DEBUG_MEMORY */
84 
85 #if defined(NET_SSL)
86 static char *certpath2keypath( char *certdbpath );
87 static int ldaptool_setcallbacks( struct ldapssl_pkcs_fns *pfns);
88 static char * buildTokenCertName( const char *tokenName, const char *certName);
89 #ifdef FORTEZZA
90 static int ldaptool_fortezza_init( int exit_on_error );
91 static int ldaptool_fortezza_alert( void *arg, PRBool onOpen,
92 	char *string, int value1, void *value2 );
93 static void * ldaptool_fortezza_getpin( char **passwordp );
94 static char * ldaptool_fortezza_err2string( int err );
95 #endif /* FORTEZZA */
96 #endif
97 #ifdef HAVE_SASL_OPTIONS
98 static int saslSetParam(char *saslarg);
99 #endif	/* HAVE_SASL_OPTIONS */
100 
101 /*
102  * display usage for common options with one exception: -f is not included
103  * since the description tends to be tool-specific.
104  *
105  * As of 1-Jul-1998, of the characters in the set [A-Za-z] the following are
106  * not currently used by any of the tools: EJgjqr
107  */
108 void
109 ldaptool_common_usage( int two_hosts )
110 {
111     fprintf( stderr, gettext("    -n\t\tshow what would be done but don't actually do it\n") );
112     fprintf( stderr, gettext("    -v\t\trun in verbose mode (diagnostics to standard output)\n") );
113     if ( two_hosts ) {
114 	fprintf( stderr, gettext("    -h host\tLDAP server1 name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST );
115 	fprintf( stderr, gettext("    -p port\tLDAP server1 TCP port number (default: %d)\n"), LDAP_PORT );
116 	fprintf( stderr, gettext("    -h host\tLDAP server2 name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST );
117 	fprintf( stderr, gettext("    -p port\tLDAP server2 TCP port number (default: %d)\n"), LDAP_PORT );
118     } else {
119 	fprintf( stderr, gettext("    -h host\tLDAP server name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST );
120 	fprintf( stderr, gettext("    -p port\tLDAP server TCP port number (default: %d)\n"), LDAP_PORT );
121     }
122     fprintf( stderr,
123 	    gettext("    -V n\tLDAP protocol version number (%d or %d; default: %d)\n"),
124 	    LDAP_VERSION2, LDAP_VERSION3, LDAP_VERSION3 );
125 #if defined(NET_SSL)
126     fprintf( stderr, gettext("    -Z\t\tmake an SSL-encrypted connection\n") );
127     fprintf( stderr, gettext("    -P pathname\tpath to SSL certificate database (default: current directory)\n") );
128     fprintf( stderr, gettext("    -N\t\tname of certificate to use for SSL client authentication\n") );
129 #ifndef SOLARIS_LDAP_CMD
130     fprintf( stderr, gettext("    -K pathname\tpath to key database to use for SSL client authentication\n") );
131     fprintf( stderr, gettext("    \t\t(default: path to certificate database provided with -P option)\n") );
132 #endif	/* SOLARIS_LDAP_CMD */
133 #ifdef LDAP_TOOL_PKCS11
134     fprintf( stderr, gettext("    -m pathname\tpath to security module database\n"));
135 #endif /* LDAP_TOOL_PKCS11 */
136     fprintf( stderr, gettext("    -W\t\tSSL key password\n") );
137 #ifndef SOLARIS_LDAP_CMD
138     fprintf( stderr, gettext("    -3\t\tcheck hostnames in SSL certificates\n") );
139 #endif	/* SOLARIS_LDAP_CMD */
140 
141 #ifdef LDAP_TOOL_PKCS11
142     fprintf( stderr, gettext("    -Q [token][:certificate name]\tPKCS 11\n") );
143     /*    fprintf( stderr, "    -X pathname\tFORTEZZA compromised key list (CKL)\n" ); */
144     fprintf( stderr, gettext("    -I pin\tcard password file\n") );
145 #endif /* LDAP_TOOL_PKCS11 */
146 
147 #endif /* NET_SSL */
148     fprintf( stderr, gettext("    -D binddn\tbind dn\n") );
149     fprintf( stderr, gettext("    -w passwd\tbind passwd (for simple authentication)\n") );
150     fprintf( stderr, gettext("    -w - \tprompt for bind passwd (for simple authentication)\n") );
151     fprintf( stderr, gettext("    -j file\tread bind passwd (for simple authentication)\n") );
152     fprintf( stderr, gettext("      \t\tor SSL key password from 'file'\n") );
153     fprintf( stderr, gettext("    -E\t\task server to expose (report) bind identity\n") );
154 #ifdef LDAP_DEBUG
155     fprintf( stderr, gettext("    -d level\tset LDAP debugging level to `level'\n") );
156 #endif
157     fprintf( stderr, gettext("    -R\t\tdo not automatically follow referrals\n") );
158     fprintf( stderr, gettext("    -O limit\tmaximum number of referral hops to traverse (default: %d)\n"), LDAPTOOL_DEFREFHOPLIMIT );
159     fprintf( stderr, gettext("    -M\t\tmanage references (treat them as regular entries)\n") );
160 #ifndef SOLARIS_LDAP_CMD
161     fprintf( stderr, gettext("    -0\t\tignore LDAP library version mismatches\n") );
162 #endif	/* SOLARIS_LDAP_CMD */
163 
164 #ifndef NO_LIBLCACHE
165     fprintf( stderr, gettext("    -C cfgfile\tuse local database described by cfgfile\n") );
166 #endif
167     fprintf( stderr, gettext("    -i charset\tcharacter set for command line input (default taken from locale)\n") );
168     fprintf( stderr, gettext("    -k dir\tconversion routine directory (default: current directory)\n") );
169 #if 0
170 /*
171  * Suppress usage for -y (old proxied authorization control) even though
172  * we still support it.  We want to encourage people to use -Y instead (the
173  * new proxied authorization control).
174  */
175     fprintf( stderr, gettext("    -y proxydn\tDN used for proxy authorization\n") );
176 #endif
177     fprintf( stderr, gettext("    -Y proxyid\tproxied authorization id,\n") );
178     fprintf( stderr, gettext("              \te.g, dn:uid=bjensen,dc=example,dc=com\n") );
179     fprintf( stderr, gettext("    -H\t\tdisplay usage information\n") );
180 #ifdef SOLARIS_LDAP_CMD
181     fprintf( stderr, gettext("    -?\t\tdisplay usage information\n") );
182 #endif	/* SOLARIS_LDAP_CMD */
183     fprintf( stderr, gettext("    -J controloid[:criticality[:value|::b64value|:<fileurl]]\n") );
184     fprintf( stderr, gettext("\t\tcriticality is a boolean value (default is false)\n") );
185 #ifdef HAVE_SASL_OPTIONS
186     fprintf( stderr, gettext("    -o attrName=attrVal\tSASL options which are described in the man page\n"));
187 #endif	/* HAVE_SASL_OPTIONS */
188 }
189 
190 /* globals */
191 char			*ldaptool_charset = "";
192 char			*ldaptool_host = LDAPTOOL_DEFHOST;
193 char			*ldaptool_host2 = LDAPTOOL_DEFHOST;
194 int			ldaptool_port = LDAP_PORT;
195 int			ldaptool_port2 = LDAP_PORT;
196 int			ldaptool_verbose = 0;
197 int			ldaptool_not = 0;
198 #ifdef SOLARIS_LDAP_CMD
199 int			ldaptool_require_binddn = 1;
200 #endif	/* SOLARIS_LDAP_CMD */
201 FILE			*ldaptool_fp = NULL;
202 FILE			*password_fp = NULL;
203 char			*ldaptool_progname = "";
204 char			*ldaptool_nls_lang = NULL;
205 char                    *proxyauth_id = NULL;
206 int			proxyauth_version = 2;	/* use newer proxy control */
207 LDAPControl		*ldaptool_request_ctrls[CONTROL_REQUESTS] = {0};
208 #ifdef LDAP_DEBUG
209 int			ldaptool_dbg_lvl = 0;
210 #endif /* LDAP_DEBUG */
211 
212 /* statics */
213 static char		*binddn = NULL;
214 static char		*passwd = NULL;
215 static int		send_auth_response_ctrl = 0;
216 static int		user_specified_port = 0;
217 static int		user_specified_port2 = 0;
218 static int		chase_referrals = 1;
219 static int		lib_version_mismatch_is_fatal = 1;
220 static int		ldversion = -1;	/* use default */
221 static int		refhoplim = LDAPTOOL_DEFREFHOPLIMIT;
222 static int		send_manage_dsait_ctrl = 0;
223 static int		prompt_password = 0;
224 #ifdef HAVE_SASL_OPTIONS
225 static unsigned		sasl_flags = LDAP_SASL_INTERACTIVE;
226 static char		*sasl_mech = NULL;
227 static char		*sasl_authid = NULL;
228 static char		*sasl_mode = NULL;
229 static char		*sasl_realm = NULL;
230 static char		*sasl_username = NULL;
231 static char		*sasl_secprops = NULL;
232 static int		ldapauth = -1;
233 #endif	/* HAVE_SASL_OPTIONS */
234 
235 #ifndef NO_LIBLCACHE
236 static char		*cache_config_file = NULL;
237 #endif /* !NO_LIBLCACHE */
238 #if defined(NET_SSL)
239 static int		secure = 0;
240 static int		isZ = 0;
241 static int		isN = 0;
242 static int		isW = 0;
243 static int		isw = 0;
244 static int		isD = 0;
245 static int		isj = 0;
246 static int		ssl_strength = LDAPTOOL_DEFSSLSTRENGTH;
247 #ifdef SOLARIS_LDAP_CMD
248 static char		pathname[PATH_BUF_SIZE];
249 #endif
250 static char		*ssl_certdbpath = NULL;
251 static char		*ssl_keydbpath = NULL;
252 static char		*ssl_keyname = NULL;
253 static char		*ssl_certname = NULL;
254 static char		*ssl_passwd = NULL;
255 
256 #ifdef LDAP_TOOL_PKCS11
257 static char     	*ssl_secmodpath = NULL;
258 
259 static char             *pkcs_token = NULL;
260 
261 static char             *ssl_donglefile = NULL;
262 
263 #if 0
264 static char             *pkcs_pin = NULL;
265 #endif
266 static struct ldapssl_pkcs_fns local_pkcs_fns =
267     {0,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL };
268 
269 #ifdef FORTEZZA
270 static uint32		fortezza_cardmask = 0;
271 static char		*fortezza_personality = NULL;
272 static char		*fortezza_krlfile = NULL;
273 static char		*fortezza_pin = NULL;
274 #endif /* FORTEZZA */
275 #endif /* LDAP_TOOL_PKCS11 */
276 #endif /* NET_SSL */
277 
278 /*
279  * Handle general initialization and options that are common to all of
280  * the LDAP tools.
281  * Handle options that are common to all of the LDAP tools.
282  * Note the the H option is included here but handled via the
283  * extra_opt_callback function (along with any "extra_opts" ).
284  *
285  * Return: final value for optind or -1 if usage should be displayed (for
286  * some fatal errors, we call exit here).
287  */
288 int
289 ldaptool_process_args( int argc, char **argv, char *extra_opts,
290 	int two_hosts, void (*extra_opt_callback)( int option, char *optarg ))
291 {
292     int		rc, i, hostnum;
293     char	*optstring, *common_opts;
294     extern char	*optarg;
295     extern int	optind;
296     LDAPAPIInfo	ldai;
297     char *ctrl_arg, *ctrl_oid=NULL, *ctrl_value=NULL;
298     int ctrl_criticality=0, vlen;
299     LDAPControl *ldctrl;
300 #ifdef SOLARIS_LDAP_CMD
301 	struct stat st;
302 #endif
303 
304 
305     /*
306      * Set program name global based on argv[0].
307      */
308     if (( ldaptool_progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
309         ldaptool_progname = argv[ 0 ];
310     } else {
311         ++ldaptool_progname;
312     }
313 
314 #ifdef LDAPTOOL_DEBUG_MEMORY
315     {
316 	struct ldap_memalloc_fns mafns = {
317 		ldaptool_debug_malloc,
318 		ldaptool_debug_calloc,
319 		ldaptool_debug_realloc,
320 		ldaptool_debug_free
321 	};
322 
323 	ldap_set_option( NULL, LDAP_OPT_MEMALLOC_FN_PTRS, &mafns );
324     }
325 #endif	/* LDAPTOOL_DEBUG_MEMORY */
326 
327 #ifdef LDAP_DEBUG
328     i = LDAP_DEBUG_ANY;
329     ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, (void *) &i);
330 #endif
331 
332     /*
333      * Perform a sanity check on the revision of the LDAP API library to
334      * make sure it is at least as new as the one we were compiled against.
335      * If the API implementation is from the same vendor as we were compiled
336      * against, we also check to make sure the vendor version is at least
337      * as new as the library we were compiled against.
338      *
339      * Version differences are fatal unless the -0 option is passed on the
340      * tool command line (that's a zero, not an oh).  We check for the
341      * presence of -0 in a crude way to it must appear by itself in argv.
342      */
343     for ( i = 1; i < argc; ++i ) {
344 	if ( strcmp( argv[i], "-0" ) == 0 ) {
345 	    lib_version_mismatch_is_fatal = 0;
346 	    break;
347 	}
348     }
349 
350     memset( &ldai, 0, sizeof(ldai));
351     ldai.ldapai_info_version = LDAP_API_INFO_VERSION;
352     if (( rc = ldap_get_option( NULL, LDAP_OPT_API_INFO, &ldai )) != 0 ) {
353 	fprintf( stderr, gettext("%s: unable to retrieve LDAP library version"
354 		" information;\n\tthis program requires an LDAP library that"
355 		" implements revision\n\t%d or greater of the LDAP API.\n"),
356 		ldaptool_progname, LDAP_API_VERSION );
357 	if ( lib_version_mismatch_is_fatal ) {
358 	    exit( LDAP_LOCAL_ERROR );
359 	}
360     } else if ( ldai.ldapai_api_version < LDAP_API_VERSION ) {
361 	fprintf( stderr, gettext("%s: this program requires an LDAP library that"
362 		" implements revision\n\t%d or greater of the LDAP API;"
363 		" running with revision %d.\n"),
364 		ldaptool_progname, LDAP_API_VERSION, ldai.ldapai_api_version );
365 	if ( lib_version_mismatch_is_fatal ) {
366 	    exit( LDAP_LOCAL_ERROR );
367 	}
368     } else if ( strcmp( ldai.ldapai_vendor_name, LDAP_VENDOR_NAME ) != 0) {
369 	fprintf( stderr, gettext("%s: this program requires %s's LDAP\n"
370 		"\tlibrary version %2.2f or greater; running with\n"
371 		"\t%s's version %2.2f.\n"),
372 		ldaptool_progname, LDAP_VENDOR_NAME,
373 		(float)LDAP_VENDOR_VERSION / 100,
374 		ldai.ldapai_vendor_name,
375 		(float)ldai.ldapai_vendor_version / 100 );
376 	if ( lib_version_mismatch_is_fatal ) {
377 	    exit( LDAP_LOCAL_ERROR );
378 	}
379     } else if (ldai.ldapai_vendor_version < LDAP_VENDOR_VERSION ) {
380 	fprintf( stderr, gettext("%s: this program requires %s's LDAP\n"
381 		"\tlibrary version %2.2f or greater; running with"
382 		" version %2.2f.\n"),
383 		ldaptool_progname, LDAP_VENDOR_NAME,
384 		(float)LDAP_VENDOR_VERSION / 100,
385 		(float)ldai.ldapai_vendor_version / 100 );
386 	if ( lib_version_mismatch_is_fatal ) {
387 	    exit( LDAP_LOCAL_ERROR );
388 	}
389     }
390 
391     /*
392      * Process command line options.
393      */
394     if ( extra_opts == NULL ) {
395 	extra_opts = "";
396     }
397 
398 #ifdef HAVE_SASL_OPTIONS
399 #ifdef SOLARIS_LDAP_CMD
400     common_opts = "nvEMRH?Zd:D:f:h:j:N:O:o:P:p:W:w:V:i:k:y:Y:J:";
401 #else
402     common_opts = "nvEMRHZ03d:D:f:h:j:I:K:N:O:o:P:p:Q:W:w:V:X:m:i:k:y:Y:J:";
403 #endif	/* SOLARIS_LDAP_CMD */
404 #else
405     common_opts = "nvEMRHZ03d:D:f:h:j:I:K:N:O:P:p:Q:W:w:V:X:m:i:k:y:Y:J:";
406 #endif	/* HAVE_SASL_OPTIONS */
407 
408     /* note: optstring must include room for liblcache "C:" option */
409     if (( optstring = (char *) malloc( strlen( extra_opts ) + strlen( common_opts )
410 	    + 3 )) == NULL ) {
411 	perror( "malloc" );
412 	exit( LDAP_NO_MEMORY );
413     }
414 
415 #ifdef NO_LIBLCACHE
416     sprintf( optstring, "%s%s", common_opts, extra_opts );
417 #else
418     sprintf( optstring, "%s%sC:", common_opts, extra_opts );
419 #endif
420 
421     hostnum = 0;
422     while ( (i = getopt( argc, argv, optstring )) != EOF ) {
423 	switch( i ) {
424 	case 'n':	/* do Not do any LDAP operations */
425 	    ++ldaptool_not;
426 	    break;
427 	case 'v':	/* verbose mode */
428 	    ++ldaptool_verbose;
429 	    break;
430 	case 'd':
431 #ifdef LDAP_DEBUG
432 	    ldaptool_dbg_lvl = atoi( optarg );	/* */
433 #ifdef SOLARIS_LDAP_CMD
434 	    ldap_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
435 		    (void *)&ldaptool_dbg_lvl);
436 #else
437 	    ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
438 		    (void *)&ldaptool_dbg_lvl);
439 #endif	/* SOLARIS_LDAP_CMD */
440 	    ldaptool_dbg_lvl |= LDAP_DEBUG_ANY;
441 	    ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL,
442 		    (void *)&ldaptool_dbg_lvl);
443 #else /* LDAP_DEBUG */
444 	    fprintf( stderr, gettext("compile with -DLDAP_DEBUG for debugging\n") );
445 #endif /* LDAP_DEBUG */
446 	    break;
447 	case 'R':	/* don't automatically chase referrals */
448 	    chase_referrals = 0;
449 	    break;
450 #ifndef NO_LIBLCACHE
451 	case 'C':	/* search local database */
452 	    cache_config_file = strdup( optarg );
453 	    break;
454 #endif
455 	case 'f':	/* input file */
456 	    if ( optarg[0] == '-' && optarg[1] == '\0' ) {
457 		ldaptool_fp = stdin;
458 	    } else if (( ldaptool_fp = ldaptool_open_file( optarg, "r" )) == NULL ) {
459 		perror( optarg );
460 		exit( LDAP_PARAM_ERROR );
461 	    }
462 	    break;
463 	case 'h':	/* ldap host */
464 	    if ( hostnum == 0 ) {
465 		ldaptool_host = strdup( optarg );
466 	    } else {
467 		ldaptool_host2 = strdup( optarg );
468 	    }
469 	    ++hostnum;
470 	    break;
471 	case 'D':	/* bind DN */
472 	    isD = 1;
473 	    binddn = strdup( optarg );
474 	    break;
475 	case 'E':	/* expose bind identity via auth. response control */
476 	    ++send_auth_response_ctrl;
477 	    break;
478 
479 	case 'p':	/* ldap port */
480 	    if ( !user_specified_port ) {
481 		++user_specified_port;
482 		ldaptool_port = atoi( optarg );
483 	    } else {
484 		++user_specified_port2;
485 		ldaptool_port2 = atoi( optarg );
486 	    }
487 	    break;
488 #if defined(NET_SSL)
489 	case 'P':	/* path to security database */
490 	    secure = 1; /* do SSL encryption */
491 #ifndef SOLARIS_LDAP_CMD
492 	    ssl_certdbpath = strdup(optarg);
493 	    if (NULL == ssl_certdbpath) {
494 		perror("malloc");
495 		exit( LDAP_NO_MEMORY );
496 	    }
497 #else
498 		/*
499 		 * Verify whether it's a base directory or a cert db file.
500 		 * If it is not a directory, truncate the file name as
501 		 * the revised NSS_Init() doesn't take file name any longer.
502 		 */
503 		if (strlcpy(pathname, optarg, PATH_BUF_SIZE) >= PATH_BUF_SIZE) {
504 			fprintf(stderr, gettext("\"-P\": Path name is too "
505 				"long\n"));
506 			exit(LDAP_PARAM_ERROR);
507 		}
508 
509 		if (stat(pathname, &st) != 0) {
510 			perror("stat");
511 			fprintf(stderr, gettext("\"-P\": Path name is "
512 				"invalid\n"));
513 			exit(LDAP_PARAM_ERROR);
514 		} else {
515 			if (S_ISREG(st.st_mode)) {
516 				/* redir to a regular file's dir name */
517 				ssl_certdbpath = dirname(pathname);
518 			} else
519 				ssl_certdbpath = pathname;
520 		}
521 #endif /* SOLARIS_LDAP_CMD */
522 	    break;
523 	case 'Z':	/* do SSL encryption */
524 	    secure = 1;
525 	    isZ = 1;
526 	    break;
527 	case 'N':	/* nickname of cert. to use for client auth. */
528 	    ssl_certname = strdup( optarg );
529 	    if (NULL == ssl_certname)
530 	    {
531 		perror("malloc");
532 		exit( LDAP_NO_MEMORY );
533 	    }
534 	    isN = 1;
535 	    break;
536 #ifndef SOLARIS_LDAP_CMD
537 	case 'K':	/* location of key database */
538 	    ssl_keydbpath = strdup( optarg );
539 	    if (NULL == ssl_keydbpath)
540 	    {
541 		perror("malloc");
542 		exit( LDAP_NO_MEMORY );
543 	    }
544 	    break;
545 #endif	/* SOLARIS_LDAP_CMD */
546 
547 	case 'W':	/* SSL key password */
548 	    ssl_passwd = strdup( optarg );
549 	    if (NULL == ssl_passwd)
550 	    {
551 		perror("malloc");
552 		exit( LDAP_NO_MEMORY );
553 	    }
554 	    isW = 1;
555 	    break;
556 
557 #ifndef SOLARIS_LDAP_CMD
558 	case '3': /* check hostnames in SSL certificates ("no third") */
559 	    ssl_strength = LDAPSSL_AUTH_CNCHECK;
560 	    break;
561 #endif	/* SOLARIS_LDAP_CMD */
562 
563 #ifdef LDAP_TOOL_PKCS11
564 	case 'm':	/* SSL secmod path */
565 	    ssl_secmodpath = strdup( optarg);
566 	    if (NULL == ssl_secmodpath)
567 	    {
568 		perror("malloc");
569 		exit( LDAP_NO_MEMORY );
570 	    }
571 	    break;
572 
573 	case 'Q': 	/* FORTEZZA [card][:personality] */
574 	    pkcs_token = strdup(optarg);
575 	    if (NULL == pkcs_token)
576 	    {
577 		perror("malloc");
578 		exit( LDAP_NO_MEMORY );
579 	    }
580 
581 	    break;
582 	    /* This option removed to prevent interference
583 	       with the getEffectiveRights option, also -X
584 	       case 'X':	* path to FORTEZZA CKL file *
585 
586 	       fortezza_krlfile = strdup( optarg );
587 
588 
589 	       break;
590 	    */
591 	case 'I':	/* FORTEZZA PIN (password file) */
592 	    ssl_donglefile = strdup( optarg );
593 
594 	    break;
595 #endif /* LDAP_TOOL_PKCS11 */
596 
597 #endif /* NET_SSL */
598 	case 'w':	/* bind password */
599 	    isw = 1;
600 	    if ( optarg[0] == '-' && optarg[1] == '\0' )
601 		prompt_password = 1;
602 	    else
603 		passwd = strdup( optarg );
604 	    break;
605 	    case 'j':       /* bind password or SSL key password from file */
606 	    isj = 1;
607 	    if ((password_fp = fopen( optarg, "r" )) == NULL ) {
608 		fprintf(stderr, gettext("%s: Unable to open '%s' file\n"),
609 			ldaptool_progname, optarg);
610 		exit( LDAP_PARAM_ERROR );
611 	    }
612             break;
613 	case 'O':	/* referral hop limit */
614 	    refhoplim = atoi( optarg );
615 	    break;
616 	case 'V':	/* protocol version */
617 	    ldversion = atoi (optarg);
618 	    if ( ldversion != LDAP_VERSION2 && ldversion != LDAP_VERSION3 ) {
619 		fprintf( stderr, gettext("%s: LDAP protocol version %d is not "
620 			"supported (use -V%d or -V%d)\n"),
621 			ldaptool_progname, ldversion, LDAP_VERSION2,
622 			LDAP_VERSION3 );
623 		exit( LDAP_PARAM_ERROR );
624 	    }
625 	    break;
626 	case 'M':	/* send a manageDsaIT control */
627 	    send_manage_dsait_ctrl = 1;
628 	    break;
629 
630 	case 'i':   /* character set specified */
631 	    ldaptool_charset = strdup( optarg );
632 	    if (NULL == ldaptool_charset)
633 	    {
634 		perror( "malloc" );
635 		exit( LDAP_NO_MEMORY );
636 	    }
637 
638 	    break;
639 	case 'k':   /* conversion directory */
640 	    ldaptool_convdir = strdup( optarg );
641 	    if (NULL == ldaptool_convdir)
642 	    {
643 		perror( "malloc" );
644 		exit( LDAP_NO_MEMORY );
645 	    }
646 	    break;
647 	case 'y':   /* old (version 1) proxied authorization control */
648 		proxyauth_version = 1;
649 	case 'Y':   /* new (version 2 ) proxied authorization control */
650 		/*FALLTHRU*/
651 	    proxyauth_id = strdup(optarg);
652 	    if (NULL == proxyauth_id)
653 	    {
654 		perror( "malloc" );
655 		exit( LDAP_NO_MEMORY );
656 	    }
657 
658 	    break;
659 
660 #ifndef SOLARIS_LDAP_CMD
661  	case '0':	/* zero -- override LDAP library version check */
662 	    break;	/* already handled above */
663 #endif	/* SOLARIS_LDAP_CMD */
664 	case 'J':	 /* send an arbitrary control */
665 	    if ( (ctrl_arg = strdup( optarg)) == NULL ) {
666 		perror ("strdup");
667 		exit (LDAP_NO_MEMORY);
668 	    }
669 	    if (ldaptool_parse_ctrl_arg(ctrl_arg, ':', &ctrl_oid,
670 		    &ctrl_criticality, &ctrl_value, &vlen)) {
671 		return (-1);
672 	    }
673 	    ldctrl = calloc(1,sizeof(LDAPControl));
674 	    if (ctrl_value) {
675 		rc = ldaptool_berval_from_ldif_value( ctrl_value,
676 			vlen, &(ldctrl->ldctl_value),
677 			1 /* recognize file URLs */,
678 			0 /* always try file */,
679 			1 /* report errors */ );
680 		if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) {
681 		    fprintf( stderr, gettext("Unable to parse %s\n"), ctrl_value);
682 		    return (-1);
683 		}
684 	    }
685 	    ldctrl->ldctl_oid = ctrl_oid;
686 	    ldctrl->ldctl_iscritical = ctrl_criticality;
687 	    ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
688 	    break;
689 #ifdef HAVE_SASL_OPTIONS
690 	case 'o':	/* attribute assignment */
691 	      if ((rc = saslSetParam(optarg)) == -1) {
692 	      	  return (-1);
693 	      }
694 	      ldapauth = LDAP_AUTH_SASL;
695 	      ldversion = LDAP_VERSION3;
696 	      break;
697 #endif	/* HAVE_SASL_OPTIONS */
698 	default:
699 	    (*extra_opt_callback)( i, optarg );
700 	}
701     }
702 
703 
704     /* If '-Z' is specified, check if '-P' is specified too. */
705     if ( isN || isW ) {
706 	if ( !isZ ) {
707 		fprintf( stderr, gettext("%s: with -N, -W options, please specify -Z\n\n"), ldaptool_progname );
708 		return (-1);
709 	}
710     }
711 
712     /* if '-N' is specified, -W is needed too */
713     if ( isN && NULL == ssl_passwd ) {
714         fprintf( stderr, gettext("%s: with the -N option, please specify -W also\n\n"),
715 		ldaptool_progname );
716         return (-1);
717     }
718 
719 #ifdef SOLARIS_LDAP_CMD
720     if ( isj && ( isw || isW )) {
721 	fprintf(stderr, gettext("%s: -j and -w or -W options cannot be specified simultaneously\n\n"), ldaptool_progname );
722 #else
723     if ( isj && isw ) {
724 	fprintf(stderr, gettext("%s: -j and -w options cannot be specified simultaneously\n\n"), ldaptool_progname );
725 #endif	/* SOLARIS_LDAP_CMD */
726 	return (-1);
727     }
728 
729     /* complain if -j or -w does not also have -D, unless using SASL */
730 #ifdef HAVE_SASL_OPTIONS
731     if ( (isj || isw) && !isD && (  ldapauth != LDAP_AUTH_SASL ) ) {
732 #else
733     if ( (isj || isw) && !isD ) {
734 #endif
735 	fprintf(stderr, gettext("%s: with -j, -w options, please specify -D\n\n"), ldaptool_progname );
736 	return (-1);
737     }
738 
739     /* use default key and cert DB paths if not set on the command line */
740     if ( NULL == ssl_keydbpath ) {
741         if ( NULL == ssl_certdbpath ) {
742             ssl_keydbpath = LDAPTOOL_DEFKEYDBPATH;
743         } else {
744             ssl_keydbpath = certpath2keypath( ssl_certdbpath );
745         }
746     }
747     if ( NULL == ssl_certdbpath ) {
748         ssl_certdbpath = LDAPTOOL_DEFCERTDBPATH;
749     }
750 
751     if (prompt_password != 0) {
752 	char *password_string = "Enter bind password: ";
753 
754 #if defined(_WIN32)
755 	char pbuf[257];
756 	fputs(password_string,stdout);
757 	fflush(stdout);
758 	if (fgets(pbuf,256,stdin) == NULL) {
759 	    passwd = NULL;
760 	} else {
761 	    char *tmp;
762 
763 	    tmp = strchr(pbuf,'\n');
764 	    if (tmp) *tmp = '\0';
765 	    tmp = strchr(pbuf,'\r');
766 	    if (tmp) *tmp = '\0';
767 	    passwd = strdup(pbuf);
768 	}
769 #else
770 #if defined(SOLARIS)
771 	/* 256 characters on Solaris */
772 	passwd = getpassphrase(password_string);
773 #else
774 	/* limited to 16 chars on Tru64, 32 on AIX */
775 	passwd = getpass(password_string);
776 #endif
777 #endif
778 
779     } else if (password_fp != NULL) {
780 	char *linep = NULL;
781 	int   increment = 0;
782 	int   c, index;
783 
784 	/* allocate initial block of memory */
785 	if ((linep = (char *)malloc(BUFSIZ)) == NULL) {
786 	    fprintf( stderr, gettext("%s: not enough memory to read password from file\n"), ldaptool_progname );
787 	    exit( LDAP_NO_MEMORY );
788 	}
789 	increment++;
790 	index = 0;
791 	while ((c = fgetc( password_fp )) != '\n' && c != EOF) {
792 
793 	    /* check if we will overflow the buffer */
794 	    if ((c != EOF) && (index == ((increment * BUFSIZ) -1))) {
795 
796 		/* if we did, add another BUFSIZ worth of bytes */
797 		if ((linep = (char *)
798 		    realloc(linep, (increment + 1) * BUFSIZ)) == NULL) {
799 			fprintf( stderr, gettext("%s: not enough memory to read password from file\n"), ldaptool_progname );
800 			exit( LDAP_NO_MEMORY );
801 		}
802 	 	increment++;
803 	    }
804 	    linep[index++] = c;
805 	}
806 	linep[index] = '\0';
807 	passwd = linep;
808     }
809 
810 #ifdef SOLARIS_LDAP_CMD
811     if (binddn != NULL && passwd == NULL) {
812 	char *password_string = gettext("Enter bind password: ");
813 	passwd = getpassphrase(password_string);
814     }
815 
816 #ifdef HAVE_SASL_OPTIONS
817     if (ldapauth == LDAP_AUTH_SASL) {
818 	/* BindDN not required for SASL */
819 	ldaptool_require_binddn = 0;
820     }
821 #endif	/* HAVE_SASL_OPTIONS */
822 
823 #ifdef NET_SSL
824     if (secure == 1) {
825 	/* BindDN not required for SSL */
826 	ldaptool_require_binddn = 0;
827     }
828 #endif	/* NET_SSL */
829 
830     if (ldaptool_require_binddn && binddn == NULL && passwd == NULL) {
831 		fprintf(stderr,
832 			gettext("%s: DN and Bind Password are required.\n"),
833 			ldaptool_progname );
834 		exit(1);
835     }
836 #endif	/* SOLARIS_LDAP_CMD */
837 
838     /*
839      * If verbose (-v) flag was passed in, display program name and start time.
840      * If the verbose flag was passed at least twice (-vv), also display
841      * information about the API library we are running with.
842      */
843     if ( ldaptool_verbose ) {
844 	time_t	curtime;
845 
846 	curtime = time( NULL );
847 	printf( gettext("%s: started %s\n"), ldaptool_progname, ctime( &curtime ));
848 	if ( ldaptool_verbose > 1 ) {
849 	    print_library_info( &ldai, stdout );
850 	}
851     }
852 
853 #ifdef LDAP_TOOL_PKCS11
854     if ((NULL != pkcs_token) && (NULL != ssl_certname)) {
855 	char *result;
856 
857 	if ( (result = buildTokenCertName( pkcs_token, ssl_certname)) != NULL){
858 	    free( ssl_certname );
859 	    ssl_certname = result;
860 	}
861     }
862 #endif /* LDAP_TOOL_PKCS11 */
863 
864     free( optstring );
865 
866     /*
867      * Clean up and return index of first non-option argument.
868      */
869     if ( ldai.ldapai_extensions != NULL ) {
870 	ldap_value_free( ldai.ldapai_extensions );
871     }
872     if ( ldai.ldapai_vendor_name != NULL ) {
873 	ldap_memfree( ldai.ldapai_vendor_name );
874     }
875 
876 #ifdef HAVE_SASL_OPTIONS
877     if (ldversion == LDAP_VERSION2 && ldapauth == LDAP_AUTH_SASL) {
878        fprintf( stderr, gettext("Incompatible with version %d\n"), ldversion);
879        return (-1);
880     }
881 #endif	/* HAVE_SASL_OPTIONS */
882     return( optind );
883 }
884 
885 
886 /*
887  * Write detailed information about the API library we are running with to fp.
888  */
889 static void
890 print_library_info( const LDAPAPIInfo *aip, FILE *fp )
891 {
892     int                 i;
893     LDAPAPIFeatureInfo  fi;
894 
895     fprintf( fp, gettext("LDAP Library Information -\n"
896 	    "    Highest supported protocol version: %d\n"
897 	    "    LDAP API revision:                  %d\n"
898 	    "    API vendor name:                    %s\n"
899 	    "    Vendor-specific version:            %.2f\n"),
900 	    aip->ldapai_protocol_version, aip->ldapai_api_version,
901 	    aip->ldapai_vendor_name,
902 	    (float)aip->ldapai_vendor_version / 100.0 );
903 
904     if ( aip->ldapai_extensions != NULL ) {
905 	fputs( gettext("    LDAP API Extensions:\n"), fp );
906 
907 	for ( i = 0; aip->ldapai_extensions[i] != NULL; i++ )  {
908 	    fprintf( fp, gettext("        %s"), aip->ldapai_extensions[i] );
909 	    fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
910 	    fi.ldapaif_name = aip->ldapai_extensions[i];
911 	    fi.ldapaif_version = 0;
912 
913 	    if ( ldap_get_option( NULL, LDAP_OPT_API_FEATURE_INFO, &fi )
914 		    != 0 ) {
915 		fprintf( fp, gettext(" %s: ldap_get_option( NULL,"
916 			" LDAP_OPT_API_FEATURE_INFO, ... ) for %s failed"
917 			" (Feature Info version: %d)\n"), ldaptool_progname,
918 			fi.ldapaif_name, fi.ldapaif_info_version );
919 	    } else {
920 		fprintf( fp, gettext(" (revision %d)\n"), fi.ldapaif_version);
921 	    }
922 	}
923     }
924    fputc( '\n', fp );
925 }
926 
927 
928 
929 #ifdef LDAP_TOOL_ARGPIN
930 static int PinArgRegistration( void )
931 {
932 
933     /* pkcs_init was successful  register the pin args */
934 
935     SVRCOREArgPinObj *ArgPinObj;
936     char *tokenName;
937 #ifndef _WIN32
938     SVRCOREStdPinObj *StdPinObj;
939 #else
940     SVRCOREFilePinObj *FilePinObj;
941     SVRCOREAltPinObj *AltPinObj;
942     SVRCORENTUserPinObj *NTUserPinObj;
943     int err;
944 #endif
945     char *pin;
946     char *filename;
947     /* Create and register the pin object for PKCS 11 */
948     local_pkcs_fns.pkcs_getdonglefilename(NULL, &filename);
949     local_pkcs_fns.pkcs_getpin(NULL, "", &pin);
950 #ifndef _WIN32
951     if ( SVRCORE_CreateStdPinObj(&StdPinObj, filename, PR_TRUE) !=
952 	 SVRCORE_Success) {
953 	fprintf(stderr, gettext("Security Initialization: Unable to create PinObj "
954 	       "(%d)"), PR_GetError());
955 	return -1;
956     }
957     if (pin != NULL)
958     {
959 	local_pkcs_fns.pkcs_gettokenname(NULL, &tokenName);
960 	SVRCORE_CreateArgPinObj(&ArgPinObj, tokenName, pin, (SVRCOREPinObj *)StdPinObj);
961 	SVRCORE_RegisterPinObj((SVRCOREPinObj *)ArgPinObj);
962     }
963     else
964     {
965 	SVRCORE_RegisterPinObj((SVRCOREPinObj *)StdPinObj);
966     }
967 #else
968     if (NULL != pin)
969     {
970 	local_pkcs_fns.pkcs_gettokenname(NULL, &tokenName);
971 	if ((err = SVRCORE_CreateNTUserPinObj(&NTUserPinObj)) != SVRCORE_Success){
972 	    fprintf(stderr, gettext("Security Initialization: Unable to create NTUserPinObj "
973 		   "(%d)"), PR_GetError());
974 	    exit( LDAP_LOCAL_ERROR );
975 	}
976 	if ((err = SVRCORE_CreateArgPinObj(&ArgPinObj, tokenName, pin,
977 					   (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success)
978 	{
979 	    fprintf(stderr, gettext("Security Initialization: Unable to create ArgPinObj "
980 		   "(%d)"), PR_GetError());
981 	    return -1;
982 
983 	}
984 	SVRCORE_RegisterPinObj((SVRCOREPinObj *)ArgPinObj);
985 
986     }
987     else
988     {
989 	if ((err = SVRCORE_CreateNTUserPinObj(&NTUserPinObj)) != SVRCORE_Success){
990 	    fprintf(stderr, gettext("Security Initialization: Unable to create NTUserPinObj "
991 		   "(%d)"), PR_GetError());
992 		return -1;
993 	}
994 	if (filename && *filename)
995 	{
996 	    if ((err = SVRCORE_CreateFilePinObj(&FilePinObj, filename)) !=
997 		SVRCORE_Success) {
998 		fprintf(stderr, gettext("Security Initialization: Unable to create FilePinObj "
999 		       "(%d)"), PR_GetError());
1000 		return -1;
1001 
1002 	    }
1003 	    if ((err = SVRCORE_CreateAltPinObj(&AltPinObj, (SVRCOREPinObj *)FilePinObj,
1004 					       (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success) {
1005 		fprintf(stderr, gettext("Security Initialization: Unable to create AltPinObj "
1006 		       "(%d)"), PR_GetError());
1007 		return -1;
1008 	    }
1009 	    SVRCORE_RegisterPinObj((SVRCOREPinObj *)AltPinObj);
1010 	}
1011 	else
1012 	{
1013 	    SVRCORE_RegisterPinObj((SVRCOREPinObj *)NTUserPinObj);
1014 	}
1015     }
1016 #endif
1017     return LDAP_SUCCESS;
1018 
1019 }
1020 #endif /* LDAP_TOOL_ARGPIN */
1021 
1022 
1023 /*
1024  * initialize and return an LDAP session handle.
1025  * if errors occur, we exit here.
1026  */
1027 LDAP *
1028 ldaptool_ldap_init( int second_host )
1029 {
1030     LDAP	*ld = NULL;
1031     char	*host;
1032     int		port, rc, user_port;
1033 
1034     if ( ldaptool_not ) {
1035 	return( NULL );
1036     }
1037 
1038     if ( second_host ) {
1039 	host = ldaptool_host2;
1040 	port = ldaptool_port2;
1041 	user_port = user_specified_port2;
1042     } else {
1043 	host = ldaptool_host;
1044 	port = ldaptool_port;
1045 	user_port = user_specified_port;
1046     }
1047 
1048 
1049     if ( ldaptool_verbose ) {
1050 	printf( gettext("ldap_init( %s, %d )\n"), host, port );
1051     }
1052 
1053 #if defined(NET_SSL)
1054     /*
1055      * Initialize security libraries and databases and LDAP session.  If
1056      * ssl_certname is not NULL, then we will attempt to use client auth.
1057      * if the server supports it.
1058      */
1059 #ifdef LDAP_TOOL_PKCS11
1060     ldaptool_setcallbacks( &local_pkcs_fns );
1061 
1062     if ( !second_host 	&& secure
1063 	 &&(rc = ldapssl_pkcs_init( &local_pkcs_fns))  < 0) {
1064 	    /* secure connection requested -- fail if no SSL */
1065 #ifndef SOLARIS_LDAP_CMD
1066 	    rc = PORT_GetError();
1067 #endif	/* SOLARIS_LDAP_CMD */
1068 	    fprintf( stderr, gettext("SSL initialization failed: error %d (%s)\n"),
1069 		    rc, ldapssl_err2string( rc ));
1070 	    exit( LDAP_LOCAL_ERROR );
1071     }
1072 
1073 #ifdef LDAP_TOOL_ARGPIN
1074     if (secure) {
1075 	if (PinArgRegistration( )) {
1076 	    exit( LDAP_LOCAL_ERROR);
1077 	}
1078     }
1079 #endif /* LDAP_TOOL_ARGPIN */
1080 
1081 #else /* LDAP_TOOL_PKCS11 */
1082     if ( !second_host 	&& secure
1083 	 &&(rc = ldapssl_client_init( ssl_certdbpath, NULL )) < 0) {
1084 	    /* secure connection requested -- fail if no SSL */
1085 #ifndef SOLARIS_LDAP_CMD
1086 	    rc = PORT_GetError();
1087 #endif	/* SOLARIS_LDAP_CMD */
1088 	    fprintf( stderr, gettext("SSL initialization failed: error %d (%s)\n"),
1089 		    rc, ldapssl_err2string( rc ));
1090 	    exit( LDAP_LOCAL_ERROR );
1091     }
1092 #endif /* LDAP_TOOL_PKCS11 */
1093 
1094     /* set the default SSL strength (used for all future ld's we create) */
1095     if ( ldapssl_set_strength( NULL, ssl_strength ) < 0 ) {
1096         perror( "ldapssl_set_strength" );
1097         exit( LDAP_LOCAL_ERROR );
1098     }
1099 
1100 
1101     if (secure) {
1102 	if ( !user_port ) {
1103 	    port = LDAPS_PORT;
1104 	}
1105 
1106 	if (( ld = ldapssl_init( host, port,
1107 		secure )) != NULL && ssl_certname != NULL )
1108 	    if (ldapssl_enable_clientauth( ld, ssl_keydbpath, ssl_passwd,
1109 		ssl_certname ) != 0 ) {
1110 		exit ( ldaptool_print_lderror( ld, "ldapssl_enable_clientauth",
1111 		    LDAPTOOL_CHECK4SSL_ALWAYS ));
1112 	    }
1113     } else {
1114 	/* In order to support IPv6, we use NSPR I/O */
1115 #ifdef SOLARIS_LDAP_CMD
1116 	ld = ldap_init( host, port );
1117 #else
1118 	ld = prldap_init( host, port, 0 /* not shared across threads */ );
1119 #endif /* SOLARIS_LDAP_CMD */
1120     }
1121 
1122 #else /* NET_SSL */
1123     /* In order to support IPv6, we use NSPR I/O */
1124 #ifdef SOLARIS_LDAP_CMD
1125     ld = ldap_init( host, port );
1126 #else
1127     ld = prldap_init( host, port, 0 /* not shared across threads */ );
1128 #endif /* SOLARIS_LDAP_CMD */
1129 #endif /* NET_SSL */
1130 
1131     if ( ld == NULL ) {
1132 	perror( "ldap_init" );
1133 	exit( LDAP_LOCAL_ERROR );
1134     }
1135 
1136 #ifndef NO_LIBLCACHE
1137     if ( cache_config_file != NULL ) {
1138 	int	opt;
1139 
1140 	if ( lcache_init( ld, cache_config_file ) != 0 ) {
1141 		exit( ldaptool_print_lderror( ld, cache_config_file,
1142 			LDAPTOOL_CHECK4SSL_NEVER ));
1143 	}
1144 	opt = 1;
1145 	(void) ldap_set_option( ld, LDAP_OPT_CACHE_ENABLE, &opt );
1146 	opt = LDAP_CACHE_LOCALDB;
1147 	(void) ldap_set_option( ld, LDAP_OPT_CACHE_STRATEGY, &opt );
1148 	if ( ldversion == -1 ) {	/* not set with -V */
1149 	    ldversion = LDAP_VERSION2;	/* local db only supports v2 */
1150 	}
1151     }
1152 #endif
1153 
1154 
1155     ldap_set_option( ld, LDAP_OPT_REFERRALS, chase_referrals ? LDAP_OPT_ON:
1156 	LDAP_OPT_OFF );
1157     if ( chase_referrals ) {
1158 	ldap_set_rebind_proc( ld, get_rebind_credentials, NULL );
1159 	ldap_set_option( ld, LDAP_OPT_REFERRAL_HOP_LIMIT, &refhoplim );
1160     }
1161 
1162     if ( ldversion == -1 ) {	/* not set with -V and not using local db */
1163 	ldversion = LDAP_VERSION3;
1164     }
1165     ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion );
1166 
1167     return( ld );
1168 }
1169 
1170 
1171 /*
1172  * perform a bind to the LDAP server if needed.
1173  * if an error occurs, we exit here.
1174  */
1175 void
1176 ldaptool_bind( LDAP *ld )
1177 {
1178     int		rc;
1179     char	*conv;
1180     LDAPControl	auth_resp_ctrl, *ctrl_array[ 2 ], **bindctrls;
1181 #ifdef HAVE_SASL_OPTIONS
1182     void *defaults;
1183 #endif
1184 
1185     if ( ldaptool_not ) {
1186 	return;
1187     }
1188 
1189     if ( send_auth_response_ctrl ) {
1190 	auth_resp_ctrl.ldctl_oid = LDAP_CONTROL_AUTH_REQUEST;
1191 	auth_resp_ctrl.ldctl_value.bv_val = NULL;
1192 	auth_resp_ctrl.ldctl_value.bv_len = 0;
1193 	auth_resp_ctrl.ldctl_iscritical = 0;
1194 
1195 	ctrl_array[0] = &auth_resp_ctrl;
1196 	ctrl_array[1] = NULL;
1197 	bindctrls = ctrl_array;
1198     } else {
1199 	bindctrls = NULL;
1200     }
1201 
1202     /*
1203      * if using LDAPv3 and not using client auth., omit NULL bind for
1204      * efficiency.
1205      */
1206     if ( ldversion > LDAP_VERSION2 && binddn == NULL && passwd == NULL
1207 	    && ssl_certname == NULL ) {
1208 #ifdef HAVE_SASL_OPTIONS
1209 	if ( ldapauth != LDAP_AUTH_SASL ) {
1210 	   return;
1211 	}
1212 #else
1213 	return;
1214 #endif
1215     }
1216 
1217     /*
1218      * do the bind, backing off one LDAP version if necessary
1219      */
1220     conv = ldaptool_local2UTF8( binddn );
1221 
1222 #ifdef HAVE_SASL_OPTIONS
1223     if ( ldapauth == LDAP_AUTH_SASL) {
1224 	if ( sasl_mech == NULL) {
1225 	   fprintf( stderr, gettext("Please specify the SASL mechanism name when "
1226 				"using SASL options\n"));
1227 	   return;
1228 	}
1229 
1230         if ( sasl_secprops != NULL) {
1231            rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS,
1232                                 (void *) sasl_secprops );
1233 
1234            if ( rc != LDAP_SUCCESS ) {
1235               fprintf( stderr, gettext("Unable to set LDAP_OPT_X_SASL_SECPROPS: %s\n"),
1236 				sasl_secprops );
1237               return;
1238            }
1239         }
1240 
1241         defaults = ldaptool_set_sasl_defaults( ld, sasl_mech, sasl_authid, sasl_username, passwd, sasl_realm );
1242         if (defaults == NULL) {
1243 	   perror ("malloc");
1244 	   exit (LDAP_NO_MEMORY);
1245 	}
1246 
1247         rc = ldap_sasl_interactive_bind_s( ld, binddn, sasl_mech, NULL, NULL,
1248                         sasl_flags, ldaptool_sasl_interact, defaults );
1249 
1250         if (rc != LDAP_SUCCESS ) {
1251            ldap_perror( ld, "ldap_sasl_interactive_bind_s" );
1252         }
1253     } else
1254 #endif	/* HAVE_SASL_OPTIONS */
1255         /*
1256          * if using LDAPv3 and client auth., try a SASL EXTERNAL bind
1257          */
1258          if ( ldversion > LDAP_VERSION2 && binddn == NULL && passwd == NULL
1259 	    	&& ssl_certname != NULL ) {
1260 	     rc = ldaptool_sasl_bind_s( ld, NULL, LDAP_SASL_EXTERNAL, NULL,
1261 			bindctrls, NULL, NULL, "ldap_sasl_bind" );
1262     	 }
1263          else {
1264 	     rc = ldaptool_simple_bind_s( ld, conv, passwd, bindctrls, NULL,
1265 		    "ldap_simple_bind" );
1266 	  }
1267 
1268     if ( rc == LDAP_SUCCESS ) {
1269         if ( conv != NULL ) {
1270            free( conv );
1271 	}
1272 	return;			/* success */
1273     }
1274 
1275 #ifdef HAVE_SASL_OPTIONS
1276   if (ldapauth != LDAP_AUTH_SASL) {
1277 #endif	/* HAVE_SASL_OPTIONS */
1278     if ( rc == LDAP_PROTOCOL_ERROR && ldversion > LDAP_VERSION2 ) {
1279 	/*
1280 	 * try again, backing off one LDAP version
1281 	 * this is okay even for client auth. because the way to achieve
1282 	 * client auth. with LDAPv2 is to perform a NULL simple bind.
1283 	 */
1284 	--ldversion;
1285 	fprintf( stderr, gettext("%s: the server doesn't understand LDAPv%d;"
1286 		" trying LDAPv%d instead...\n"), ldaptool_progname,
1287 		ldversion + 1, ldversion );
1288 	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion );
1289 	if (( rc = ldaptool_simple_bind_s( ld, conv, passwd,
1290 		bindctrls, NULL, "ldap_simple_bind" )) == LDAP_SUCCESS ) {
1291             if( conv != NULL )
1292                 free( conv );
1293 	    return;		/* a qualified success */
1294 	}
1295     }
1296 #ifdef HAVE_SASL_OPTIONS
1297   }
1298 #endif	/* HAVE_SASL_OPTIONS */
1299 
1300     if ( conv != NULL ) {
1301         free( conv );
1302     }
1303 
1304     /*
1305      * bind(s) failed -- fatal error
1306      */
1307     ldap_unbind( ld );
1308     exit( rc );
1309 }
1310 
1311 
1312 /*
1313  * close open files, unbind, etc.
1314  */
1315 void
1316 ldaptool_cleanup( LDAP *ld )
1317 {
1318     if ( ld != NULL ) {
1319 	ldap_unbind( ld );
1320     }
1321 
1322     if ( ldaptool_fp != NULL && ldaptool_fp != stdin ) {
1323 	fclose( ldaptool_fp );
1324 	ldaptool_fp = NULL;
1325     }
1326 }
1327 
1328 
1329 /*
1330  * Retrieve and print an LDAP error message.  Returns the LDAP error code.
1331  */
1332 int
1333 ldaptool_print_lderror( LDAP *ld, char *msg, int check4ssl )
1334 {
1335     int		lderr = ldap_get_lderrno( ld, NULL, NULL );
1336 
1337     ldap_perror( ld, msg );
1338 #ifndef SOLARIS_LDAP_CMD
1339     if ( secure && check4ssl != LDAPTOOL_CHECK4SSL_NEVER ) {
1340 	if ( check4ssl == LDAPTOOL_CHECK4SSL_ALWAYS
1341 		|| ( lderr == LDAP_SERVER_DOWN )) {
1342 	    int		sslerr = PORT_GetError();
1343 
1344 	    fprintf( stderr, gettext("\tSSL error %d (%s)\n"), sslerr,
1345 		    ldapssl_err2string( sslerr ));
1346 	}
1347     }
1348 #endif	/* SOLARIS_LDAP_CMD */
1349 
1350     return( lderr );
1351 }
1352 
1353 
1354 /*
1355  * print referrals to stderr
1356  */
1357 void
1358 ldaptool_print_referrals( char **refs )
1359 {
1360     int		i;
1361 
1362     if ( refs != NULL ) {
1363 	for ( i = 0; refs[ i ] != NULL; ++i ) {
1364 	    fprintf( stderr, gettext("Referral: %s\n"), refs[ i ] );
1365 	}
1366     }
1367 }
1368 
1369 
1370 /*
1371  * print contents of an extended response to stderr
1372  * this is mainly to support unsolicited notifications
1373  * Returns an LDAP error code (from the extended result).
1374  */
1375 int
1376 ldaptool_print_extended_response( LDAP *ld, LDAPMessage *res, char *msg )
1377 {
1378     char		*oid;
1379     struct berval	*data;
1380 
1381     if ( ldap_parse_extended_result( ld, res, &oid, &data, 0 )
1382 	    != LDAP_SUCCESS ) {
1383 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1384     } else {
1385 	if ( oid != NULL ) {
1386 	    if ( strcmp ( oid, LDAP_NOTICE_OF_DISCONNECTION ) == 0 ) {
1387 		fprintf( stderr, gettext("%s: Notice of Disconnection\n"), msg );
1388 	    } else {
1389 		fprintf( stderr, gettext("%s: OID %s\n"), msg, oid );
1390 	    }
1391 	    ldap_memfree( oid );
1392 	} else {
1393 	    fprintf( stderr, gettext("%s: missing OID\n"), msg );
1394 	}
1395 
1396 	if ( data != NULL ) {
1397 	    fprintf( stderr, gettext("%s: Data (length %ld):\n"), msg, data->bv_len );
1398 #if 0
1399 /* XXXmcs: maybe we should display the actual data? */
1400 	    lber_bprint( data->bv_val, data->bv_len );
1401 #endif
1402 	    ber_bvfree( data );
1403 	}
1404     }
1405 
1406     return parse_result( ld, res, NULL, msg, 1 );
1407 }
1408 
1409 
1410 /*
1411  * Like ldap_sasl_bind_s() but calls wait4result() to display
1412  * any referrals returned and report errors in a consistent way.
1413  */
1414 int
1415 ldaptool_sasl_bind_s( LDAP *ld, const char *dn, const char *mechanism,
1416 	const struct berval *cred, LDAPControl **serverctrls,
1417 	LDAPControl **clientctrls, struct berval **servercredp, char *msg )
1418 {
1419     int		rc, msgid;
1420 
1421     if ( servercredp != NULL ) {
1422 	    *servercredp = NULL;
1423     }
1424 
1425     if (( rc = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls,
1426 	    clientctrls, &msgid )) != LDAP_SUCCESS ) {
1427 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1428     } else {
1429 	rc = wait4result( ld, msgid, servercredp, msg );
1430     }
1431 
1432     return( rc );
1433 }
1434 
1435 
1436 /*
1437  * Like ldap_simple_bind_s() but calls wait4result() to display
1438  * any referrals returned and report errors in a consistent way.
1439  */
1440 int
1441 ldaptool_simple_bind_s( LDAP *ld, const char *dn, const char *passwd,
1442 	LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg )
1443 {
1444     struct berval	bv;
1445 
1446     bv.bv_val = (char *)passwd;		/* XXXmcs: had to cast away const */
1447     bv.bv_len = ( passwd == NULL ? 0 : strlen( passwd ));
1448     return( ldaptool_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, &bv, serverctrls,
1449 	    clientctrls, NULL, msg ));
1450 }
1451 
1452 
1453 /*
1454  * Like ldap_add_ext_s() but calls wait4result() to display
1455  * any referrals returned and report errors in a consistent way.
1456  */
1457 int
1458 ldaptool_add_ext_s( LDAP *ld, const char *dn, LDAPMod **attrs,
1459 	LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg )
1460 {
1461     int		rc, msgid;
1462 
1463     if (( rc = ldap_add_ext( ld, dn, attrs, serverctrls, clientctrls, &msgid ))
1464 	    != LDAP_SUCCESS ) {
1465 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1466     } else {
1467 	/*
1468 	 * 25-April-2000 Note: the next line used to read:
1469 	 *	rc = wait4result( ld, msgid, NULL, msg );
1470 	 * 'msgid' it was changed to 'LDAP_RES_ANY' in order to receive
1471 	 * unsolicited notifications.
1472 	 */
1473 	rc = wait4result( ld, LDAP_RES_ANY, NULL, msg );
1474     }
1475 
1476     return( rc );
1477 }
1478 
1479 
1480 /*
1481  * Like ldap_modify_ext_s() but calls wait4result() to display
1482  * any referrals returned and report errors in a consistent way.
1483  */
1484 int
1485 ldaptool_modify_ext_s( LDAP *ld, const char *dn, LDAPMod **mods,
1486 	LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg )
1487 {
1488     int		rc, msgid;
1489 
1490     if (( rc = ldap_modify_ext( ld, dn, mods, serverctrls, clientctrls,
1491 	    &msgid )) != LDAP_SUCCESS ) {
1492 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1493     } else {
1494 	rc = wait4result( ld, msgid, NULL, msg );
1495     }
1496 
1497     return( rc );
1498 }
1499 
1500 
1501 /*
1502  * Like ldap_delete_ext_s() but calls wait4result() to display
1503  * any referrals returned and report errors in a consistent way.
1504  */
1505 int
1506 ldaptool_delete_ext_s( LDAP *ld, const char *dn, LDAPControl **serverctrls,
1507 	LDAPControl **clientctrls, char *msg )
1508 {
1509     int		rc, msgid;
1510 
1511     if (( rc = ldap_delete_ext( ld, dn, serverctrls, clientctrls, &msgid ))
1512 	    != LDAP_SUCCESS ) {
1513 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1514     } else {
1515 	rc = wait4result( ld, msgid, NULL, msg );
1516     }
1517 
1518     return( rc );
1519 }
1520 
1521 
1522 /*
1523  * Like ldap_compare_ext_s() but calls wait4result() to display
1524  * any referrals returned and report errors in a consistent way.
1525  */
1526 int ldaptool_compare_ext_s( LDAP *ld, const char *dn, const char *attrtype,
1527 	    const struct berval *bvalue, LDAPControl **serverctrls,
1528 	    LDAPControl **clientctrls, char *msg )
1529 {
1530     int		rc, msgid;
1531 
1532     if (( rc = ldap_compare_ext( ld, dn, attrtype, bvalue, serverctrls,
1533 	    clientctrls, &msgid )) != LDAP_SUCCESS ) {
1534 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1535     } else {
1536 	rc = wait4result( ld, msgid, NULL, msg );
1537     }
1538 
1539     return( rc );
1540 }
1541 
1542 
1543 /*
1544  * Like ldap_rename_s() but calls wait4result() to display
1545  * any referrals returned and report errors in a consistent way.
1546  */
1547 int
1548 ldaptool_rename_s(  LDAP *ld, const char *dn, const char *newrdn,
1549 	const char *newparent, int deleteoldrdn, LDAPControl **serverctrls,
1550 	LDAPControl **clientctrls, char *msg )
1551 {
1552     int		rc, msgid;
1553 
1554     if (( rc = ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn,
1555 	    serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) {
1556 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1557     } else {
1558 	rc = wait4result( ld, msgid, NULL, msg );
1559     }
1560 
1561     return( rc );
1562 }
1563 
1564 
1565 /*
1566  * Wait for a result, check for and display errors and referrals.
1567  * Also recognize and display "Unsolicited notification" messages.
1568  * Returns an LDAP error code.
1569  */
1570 static int
1571 wait4result( LDAP *ld, int msgid, struct berval **servercredp, char *msg )
1572 {
1573     LDAPMessage	*res;
1574     int		rc, received_only_unsolicited = 1;
1575 
1576     while ( received_only_unsolicited ) {
1577 	res = NULL;
1578 	if (( rc = ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res ))
1579 		    == -1 ) {
1580 	    ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1581 	    return( ldap_get_lderrno( ld, NULL, NULL ));
1582 	}
1583 
1584 	/*
1585 	 * Special handling for unsolicited notifications:
1586 	 *    1. Parse and display contents.
1587 	 *    2. go back and wait for another (real) result.
1588 	 */
1589 	if ( rc == LDAP_RES_EXTENDED
1590 		    && ldap_msgid( res ) == LDAP_RES_UNSOLICITED ) {
1591 	    rc = ldaptool_print_extended_response( ld, res,
1592 		    "Unsolicited response" );
1593 	} else {
1594 	    rc = parse_result( ld, res, servercredp, msg, 1 );
1595 	    received_only_unsolicited = 0;	/* we're done */
1596 	}
1597     }
1598 
1599     return( rc );
1600 }
1601 
1602 
1603 static int
1604 parse_result( LDAP *ld, LDAPMessage *res, struct berval **servercredp,
1605 	char *msg, int freeit )
1606 {
1607     int		rc, lderr, errno;
1608     int		pw_days=0, pw_hrs=0, pw_mins=0, pw_secs=0; /* for pwpolicy */
1609     char	**refs = NULL;
1610     LDAPControl	**ctrls;
1611 
1612     if (( rc = ldap_parse_result( ld, res, &lderr, NULL, NULL, &refs,
1613 	    &ctrls, 0 )) != LDAP_SUCCESS ) {
1614 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1615 	ldap_msgfree( res );
1616 	return( rc );
1617     }
1618 
1619     /* check for authentication response control & PWPOLICY control*/
1620     if ( NULL != ctrls ) {
1621 	int		i;
1622 	char		*s;
1623 
1624 	for ( i = 0; NULL != ctrls[i]; ++i ) {
1625 	    if ( 0 == strcmp( ctrls[i]->ldctl_oid,
1626 			LDAP_CONTROL_AUTH_RESPONSE )) {
1627 		    s = ctrls[i]->ldctl_value.bv_val;
1628 		    if ( NULL == s ) {
1629 			s = "Null";
1630 		    } else if ( *s == '\0' ) {
1631 			s = "Anonymous";
1632 		    }
1633 		fprintf( stderr, gettext("%s: bound as %s\n"), ldaptool_progname, s );
1634 	    }
1635 
1636 	    if ( 0 == strcmp( ctrls[i]->ldctl_oid,
1637 			LDAP_CONTROL_PWEXPIRING )) {
1638 
1639 		    /* Warn the user his passwd is to expire */
1640 		    errno = 0;
1641 		    pw_secs = atoi(ctrls[i]->ldctl_value.bv_val);
1642 		    if ( pw_secs > 0  && errno != ERANGE ) {
1643 			if ( pw_secs > 86400 ) {
1644 				pw_days = ( pw_secs / 86400 );
1645 				pw_secs = ( pw_secs % 86400 );
1646 			}
1647 			if ( pw_secs > 3600 ) {
1648 				pw_hrs = ( pw_secs / 3600 );
1649 				pw_secs = ( pw_secs % 3600 );
1650 			}
1651 			if ( pw_secs > 60 ) {
1652 				pw_mins = ( pw_secs / 60 );
1653 				pw_secs = ( pw_secs % 60 );
1654 			}
1655 
1656 			printf(gettext("%s: Warning ! Your password will expire after "), ldaptool_progname);
1657 			if ( pw_days ) {
1658 				printf (gettext("%d days, "), pw_days);
1659 			}
1660 			if ( pw_hrs ) {
1661 				printf (gettext("%d hrs, "), pw_hrs);
1662 			}
1663 			if ( pw_mins ) {
1664 				printf (gettext("%d mins, "), pw_mins);
1665 			}
1666 			printf(gettext("%d seconds.\n"), pw_secs);
1667 
1668 		   }
1669 		}
1670 	}
1671 	ldap_controls_free( ctrls );
1672     }
1673 
1674     if ( servercredp != NULL && ( rc = ldap_parse_sasl_bind_result( ld, res,
1675 	    servercredp, 0 )) != LDAP_SUCCESS ) {
1676 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1677 	ldap_msgfree( res );
1678 	return( rc );
1679     }
1680 
1681     if ( freeit ) {
1682 	ldap_msgfree( res );
1683     }
1684 
1685     if ( LDAPTOOL_RESULT_IS_AN_ERROR( lderr )) {
1686 	ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP );
1687     }
1688 
1689     if ( refs != NULL ) {
1690 	ldaptool_print_referrals( refs );
1691 	ldap_value_free( refs );
1692     }
1693 
1694     return( lderr );
1695 }
1696 
1697 
1698 /*
1699  * if -M was passed on the command line, create and return a "Manage DSA IT"
1700  * LDAPv3 control.  If not, return NULL.
1701  */
1702 LDAPControl *
1703 ldaptool_create_manage_dsait_control( void )
1704 {
1705     LDAPControl	*ctl;
1706 
1707     if ( !send_manage_dsait_ctrl ) {
1708 	return( NULL );
1709     }
1710 
1711     if (( ctl = (LDAPControl *)calloc( 1, sizeof( LDAPControl ))) == NULL ||
1712 	    ( ctl->ldctl_oid = strdup( LDAP_CONTROL_MANAGEDSAIT )) == NULL ) {
1713 	perror( "calloc" );
1714 	exit( LDAP_NO_MEMORY );
1715     }
1716 
1717     ctl->ldctl_iscritical = 1;
1718 
1719     return( ctl );
1720 }
1721 
1722 /*
1723  * if -y "dn" was supplied on the command line, create the control
1724  */
1725 LDAPControl *
1726 ldaptool_create_proxyauth_control( LDAP *ld )
1727 {
1728     LDAPControl	*ctl = NULL;
1729     int rc;
1730 
1731 
1732     if ( !proxyauth_id)
1733 	return( NULL );
1734 
1735     if ( 2 == proxyauth_version ) {
1736 	rc = ldap_create_proxiedauth_control( ld, proxyauth_id, &ctl);
1737     } else {
1738 	rc = ldap_create_proxyauth_control( ld, proxyauth_id, 1, &ctl);
1739     }
1740     if ( rc != LDAP_SUCCESS)
1741     {
1742 	if (ctl)
1743 	    ldap_control_free( ctl);
1744 	return NULL;
1745     }
1746     return( ctl );
1747 }
1748 
1749 #ifndef SOLARIS_LDAP_CMD
1750 LDAPControl *
1751 ldaptool_create_geteffectiveRights_control ( LDAP *ld, const char *authzid,
1752 											const char **attrlist)
1753 {
1754     LDAPControl	*ctl = NULL;
1755     int rc;
1756 
1757 	rc = ldap_create_geteffectiveRights_control( ld, authzid, attrlist, 1,
1758 							&ctl);
1759 
1760     if ( rc != LDAP_SUCCESS)
1761     {
1762 		if (ctl)
1763 	    	ldap_control_free( ctl);
1764 		return NULL;
1765     }
1766     return( ctl );
1767 }
1768 #endif	/* SOLARIS_LDAP_CMD */
1769 
1770 
1771 void
1772 ldaptool_add_control_to_array( LDAPControl *ctrl, LDAPControl **array)
1773 {
1774 
1775     int i;
1776     for (i=0; i< CONTROL_REQUESTS; i++)
1777     {
1778 	if (*(array + i) == NULL)
1779 	{
1780 	    *(array + i +1) = NULL;
1781 	    *(array + i) = ctrl;
1782 	    return ;
1783 	}
1784     }
1785     fprintf(stderr, gettext("%s: failed to store request control!!!!!!\n"),
1786 	    ldaptool_progname);
1787 }
1788 
1789 /*
1790  * Dispose of all controls in array and prepare array for reuse.
1791  */
1792 void
1793 ldaptool_reset_control_array( LDAPControl **array )
1794 {
1795     int		i;
1796 
1797     for ( i = 0; i < CONTROL_REQUESTS; i++ ) {
1798 	if ( array[i] != NULL ) {
1799 	    ldap_control_free( array[i] );
1800 	    array[i] = NULL;
1801 	}
1802     }
1803 }
1804 
1805 /*
1806  * This function calculates control value and its length. *value can
1807  * be pointing to plain value, ":b64encoded value" or "<fileurl".
1808  */
1809 static int
1810 calculate_ctrl_value( const char *value,
1811 	char **ctrl_value, int *vlen)
1812 {
1813     int b64;
1814     if (*value == ':') {
1815 	value++;
1816 	b64 = 1;
1817     } else {
1818 	b64 = 0;
1819     }
1820     *ctrl_value = (char *)value;
1821 
1822     if ( b64 ) {
1823 	if (( *vlen = ldif_base64_decode( (char *)value,
1824 		(unsigned char *)value )) < 0 ) {
1825 	    fprintf( stderr,
1826 		gettext("Unable to decode base64 control value \"%s\"\n"), value);
1827 	    return( -1 );
1828 	}
1829     } else {
1830 	*vlen = (int)strlen(*ctrl_value);
1831     }
1832     return( 0 );
1833 }
1834 
1835 /*
1836  * Parse the optarg from -J option of ldapsearch
1837  * and within LDIFfile for ldapmodify. Take ctrl_arg
1838  * (the whole string) and divide it into oid, criticality
1839  * and value. This function breaks down original ctrl_arg
1840  * with '\0' in places. Also, calculate length of valuestring.
1841  */
1842 int
1843 ldaptool_parse_ctrl_arg(char *ctrl_arg, char sep,
1844 		char **ctrl_oid, int *ctrl_criticality,
1845 		char **ctrl_value, int *vlen)
1846 {
1847     char *s, *p;
1848     int strict;
1849 
1850     /* Initialize passed variables with default values */
1851     *ctrl_oid = *ctrl_value = NULL;
1852     *ctrl_criticality = 0;
1853     *vlen = 0;
1854 
1855     strict = (sep == ' ' ? 1 : 0);
1856     if(!(s=strchr(ctrl_arg, sep))) {
1857 	/* Possible values of ctrl_arg are
1858 	 * oid[:value|::b64value|:<fileurl] within LDIF, i.e. sep=' '
1859 	 * oid from command line option, i.e. sep=':'
1860 	 */
1861 	if (sep == ' ') {
1862 	    if (!(s=strchr(ctrl_arg, ':'))) {
1863 		*ctrl_oid = ctrl_arg;
1864 	    }
1865 	    else {
1866 		/* ctrl_arg is of oid:[value|:b64value|<fileurl]
1867 		 * form in the LDIF record. So, grab the oid and then
1868 		 * jump to continue the parsing of ctrl_arg.
1869 		 * 's' is pointing just after oid ends.
1870 		 */
1871 		*s++ = '\0';
1872 		*ctrl_oid = ctrl_arg;
1873 		return (calculate_ctrl_value( s, ctrl_value, vlen ));
1874 	    }
1875 	} else {
1876 		/* oid - from command line option, i.e. sep=':' */
1877 		*ctrl_oid = ctrl_arg;
1878 	}
1879     }
1880     else {
1881 	/* Possible values of ctrl_arg are
1882 	 * oid:criticality[:value|::b64value|:<fileurl] - command line
1883 	 * oid criticality[:value|::b64value|:<fileurl] - LDIF
1884 	 * And 's' is pointing just after oid ends.
1885 	 */
1886 
1887 	if (*(s+1) == '\0') {
1888 	    fprintf( stderr, gettext("missing value\n") );
1889 	    return( -1 );
1890 	}
1891 	*s = '\0';
1892 	*ctrl_oid = ctrl_arg;
1893 	p = ++s;
1894 	if(!(s=strchr(p, ':'))) {
1895 	    if ( (*ctrl_criticality = ldaptool_boolean_str2value(p, strict))
1896 			== -1 ) {
1897 		fprintf( stderr, gettext("Invalid criticality value\n") );
1898 		return( -1 );
1899 	    }
1900 	}
1901 	else {
1902 	    if (*(s+1) == '\0') {
1903 	        fprintf( stderr, gettext("missing value\n") );
1904 	        return ( -1 );
1905 	    }
1906 	    *s++ = '\0';
1907             if ( (*ctrl_criticality = ldaptool_boolean_str2value(p, strict))
1908 			== -1 ) {
1909 		fprintf( stderr, gettext("Invalid criticality value\n") );
1910 		return ( -1 );
1911 	    }
1912 	    return (calculate_ctrl_value( s, ctrl_value, vlen ));
1913 	}
1914     }
1915 
1916     return( 0 );
1917 }
1918 
1919 
1920 /*
1921  * callback function for LDAP bind credentials
1922  */
1923 static int
1924 LDAP_CALL
1925 LDAP_CALLBACK
1926 get_rebind_credentials( LDAP *ld, char **whop, char **credp,
1927         int *methodp, int freeit, void* arg )
1928 {
1929     if ( !freeit ) {
1930 	*whop = binddn;
1931 	*credp = passwd;
1932 	*methodp = LDAP_AUTH_SIMPLE;
1933     }
1934 
1935     return( LDAP_SUCCESS );
1936 }
1937 
1938 
1939 /*
1940  * return pointer to pathname to temporary directory.
1941  * First we see if the environment variable "TEMP" is set and use it.
1942  * Then we see if the environment variable "TMP" is set and use it.
1943  * If this fails, we use "/tmp" on UNIX and fail on Windows.
1944  */
1945 char *
1946 ldaptool_get_tmp_dir( void )
1947 {
1948     char	*p;
1949     int		offset;
1950 
1951     if (( p = getenv( "TEMP" )) == NULL && ( p = getenv( "TMP" )) == NULL ) {
1952 #ifdef _WINDOWS
1953 	fprintf( stderr, gettext("%s: please set the TEMP environment variable.\n"),
1954 		ldaptool_progname );
1955 	exit( LDAP_LOCAL_ERROR );
1956 #else
1957 	return( "/tmp" );	/* last resort on UNIX */
1958 #endif
1959     }
1960 
1961     /*
1962      * remove trailing slash if present
1963      */
1964     offset = strlen( p ) - 1;
1965     if ( p[offset] == '/'
1966 #ifdef _WINDOWS
1967 	    || p[offset] == '\\'
1968 #endif
1969 	    ) {
1970 	if (( p = strdup( p )) == NULL ) {
1971 	    perror( "strdup" );
1972 	    exit( LDAP_NO_MEMORY );
1973 	}
1974 
1975 	p[offset] = '\0';
1976     }
1977 
1978     return( p );
1979 }
1980 
1981 
1982 int
1983 ldaptool_berval_is_ascii( const struct berval *bvp )
1984 {
1985     unsigned long	j;
1986     int			is_ascii = 1;	 /* optimistic */
1987 
1988     for ( j = 0; j < bvp->bv_len; ++j ) {
1989 	if ( !isascii( bvp->bv_val[ j ] )) {
1990 	    is_ascii = 0;
1991 	    break;
1992 	}
1993     }
1994 
1995     return( is_ascii );
1996 }
1997 
1998 
1999 #ifdef LDAP_DEBUG_MEMORY
2000 #define LDAPTOOL_ALLOC_FREED	0xF001
2001 #define LDAPTOOL_ALLOC_INUSE	0xF002
2002 
2003 static void *
2004 ldaptool_debug_alloc( void *ptr, size_t size )
2005 {
2006     int		*statusp;
2007     void	*systemptr;
2008 
2009     if ( ptr == NULL ) {
2010 	systemptr = NULL;
2011     } else {
2012 	systemptr = (void *)((char *)ptr - sizeof(int));
2013     }
2014 
2015     if (( statusp = (int *)realloc( systemptr, size + sizeof(int))) == NULL ) {
2016 	fprintf( stderr, gettext("%s: realloc( 0x%x, %d) failed\n"),
2017 		ldaptool_progname, systemptr, size );
2018 	return( NULL );
2019     }
2020 
2021     *statusp = LDAPTOOL_ALLOC_INUSE;
2022 
2023     return( (char *)statusp + sizeof(int));
2024 }
2025 
2026 
2027 static void *
2028 ldaptool_debug_realloc( void *ptr, size_t size )
2029 {
2030     void	*p;
2031 
2032     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2033 	fprintf( stderr, gettext("%s: => realloc( 0x%x, %d )\n"),
2034 		ldaptool_progname, ptr, size );
2035     }
2036 
2037     p = ldaptool_debug_alloc( ptr, size );
2038 
2039     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2040 	fprintf( stderr, gettext("%s: 0x%x <= realloc()\n"), ldaptool_progname, p );
2041     }
2042 
2043     return( p );
2044 }
2045 
2046 
2047 static void *
2048 ldaptool_debug_malloc( size_t size )
2049 {
2050     void	*p;
2051 
2052     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2053 	fprintf( stderr, gettext("%s: => malloc( %d)\n"), ldaptool_progname, size );
2054     }
2055 
2056     p = ldaptool_debug_alloc( NULL, size );
2057 
2058     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2059 	fprintf( stderr, gettext("%s: 0x%x <= malloc()\n"), ldaptool_progname, p );
2060     }
2061 
2062     return( p );
2063 }
2064 
2065 
2066 static void *
2067 ldaptool_debug_calloc( size_t nelem, size_t elsize )
2068 {
2069     void	*p;
2070 
2071     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2072 	fprintf( stderr, gettext("%s: => calloc( %d, %d )\n"),
2073 		ldaptool_progname, nelem, elsize );
2074     }
2075 
2076     if (( p = ldaptool_debug_alloc( NULL, nelem * elsize )) != NULL ) {
2077 	memset( p, 0, nelem * elsize );
2078     }
2079 
2080     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2081 	fprintf( stderr, gettext("%s: 0x%x <= calloc()\n"), ldaptool_progname, p );
2082     }
2083 
2084     return( p );
2085 }
2086 
2087 
2088 static void
2089 ldaptool_debug_free( void *ptr )
2090 {
2091     int		*statusp = (int *)((char *)ptr - sizeof(int));
2092 
2093     if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) {
2094 	fprintf( stderr, gettext("%s: => free( 0x%x )\n"), ldaptool_progname, ptr );
2095     }
2096 
2097     if ( ptr == NULL ) {
2098 	fprintf( stderr, gettext("%s: bad free( 0x0 ) attempted (NULL pointer)\n"),
2099 		ldaptool_progname );
2100     } else if ( *statusp != LDAPTOOL_ALLOC_INUSE ) {
2101 	fprintf( stderr, gettext("%s: bad free( 0x%x ) attempted"
2102 		" (block not in use; status is %d)\n"),
2103 		ldaptool_progname, ptr, *statusp );
2104     } else {
2105 	*statusp = LDAPTOOL_ALLOC_FREED;
2106 	free( statusp );
2107     }
2108 }
2109 #endif /* LDAP_DEBUG_MEMORY */
2110 
2111 
2112 #if defined(NET_SSL)
2113 /*
2114  * Derive key database path from certificate database path and return a
2115  * malloc'd string.
2116  *
2117  * We just return an exact copy of "certdbpath" unless it ends in "cert.db",
2118  * "cert5.db", or "cert7.db".  In those cases we strip off everything from
2119  * "cert" on and append "key.db", "key5.db", or "key3.db" as appropriate.
2120  * Strangely enough cert7.db and key3.db go together.
2121  */
2122 static char *
2123 certpath2keypath( char *certdbpath )
2124 {
2125     char	*keydbpath, *appendstr;
2126     int		len, striplen;
2127 
2128     if ( certdbpath == NULL ) {
2129 	return( NULL );
2130     }
2131 
2132     if (( keydbpath = strdup( certdbpath )) == NULL ) {
2133 	perror( "strdup" );
2134 	exit( LDAP_NO_MEMORY );
2135     }
2136 
2137     len = strlen( keydbpath );
2138     if ( len > 7 &&
2139 	    strcasecmp( "cert.db", keydbpath + len - 7 ) == 0 ) {
2140 	striplen = 7;
2141 	appendstr = "key.db";
2142 
2143     } else if ( len > 8 &&
2144 	    strcasecmp( "cert5.db", keydbpath + len - 8 ) == 0 ) {
2145 	striplen = 8;
2146 	appendstr = "key5.db";
2147     } else if ( len > 8 &&
2148 	    strcasecmp( "cert7.db", keydbpath + len - 8 ) == 0 ) {
2149 	striplen = 8;
2150 	appendstr = "key3.db";
2151     } else {
2152 	striplen = 0;
2153     }
2154 
2155     if ( striplen > 0 ) {
2156 	/*
2157 	 * The following code assumes that strlen( appendstr ) < striplen!
2158 	 */
2159 	strcpy( keydbpath + len - striplen, appendstr );
2160     }
2161 
2162     return( keydbpath );
2163 }
2164 
2165 #ifdef LDAP_TOOL_PKCS11
2166 static
2167 char *
2168 buildTokenCertName( const char *tokenName, const char *certName)
2169 {
2170 
2171     int tokenlen = strlen(tokenName);
2172     int len = tokenlen + strlen(certName) +2;
2173     char *result;
2174 
2175     if (( result = malloc( len )) != NULL) {
2176 	strcpy(result, tokenName);
2177 	*(result+tokenlen) = ':';
2178 	++tokenlen;
2179 	strcpy(result+tokenlen, certName);
2180     } else {
2181 	perror("malloc");
2182 	exit( LDAP_NO_MEMORY );
2183     }
2184     return result;
2185 }
2186 
2187 
2188 
2189 static
2190 int
2191 ldaptool_getcertpath( void *context, char **certlocp )
2192 {
2193 
2194     *certlocp = ssl_certdbpath;
2195     if ( ldaptool_verbose ) {
2196 	if (ssl_certdbpath)
2197 	{
2198 	    printf(gettext("ldaptool_getcertpath -- %s\n"), ssl_certdbpath );
2199 	}
2200 	else
2201 	{
2202 	    printf(gettext("ldaptool_getcertpath -- (null)\n"));
2203 	}
2204 
2205     }
2206     return LDAP_SUCCESS;
2207 }
2208 
2209 int
2210 ldaptool_getcertname( void *context, char **certnamep )
2211 {
2212 
2213    *certnamep = ssl_certname;
2214     if ( ldaptool_verbose ) {
2215 	if (ssl_certname)
2216 	{
2217 	    printf(gettext("ldaptool_getcertname -- %s\n"), *certnamep);
2218 	}
2219 	else
2220 	{
2221 	    printf(gettext("ldaptool_getcertname -- (null)\n"));
2222 	}
2223     }
2224     return LDAP_SUCCESS;
2225 }
2226 
2227 int
2228 ldaptool_getkeypath(void *context, char **keylocp )
2229 {
2230     *keylocp = ssl_keydbpath;
2231     if ( ldaptool_verbose ) {
2232 	if (ssl_keydbpath)
2233 	{
2234 	    printf(gettext("ldaptool_getkeypath -- %s\n"),*keylocp);
2235 	}
2236 	else
2237 	{
2238 	    printf(gettext("ldaptool_getkeypath -- (null)\n"));
2239 	}
2240     }
2241 
2242     return LDAP_SUCCESS;
2243 }
2244 
2245 int
2246 ldaptool_gettokenname( void *context, char **tokennamep )
2247 {
2248 
2249     *tokennamep = pkcs_token;
2250     if ( ldaptool_verbose ) {
2251 	if (pkcs_token)
2252 	{
2253 	    printf(gettext("ldaptool_gettokenname -- %s\n"),*tokennamep);
2254 	}
2255 	else
2256 	{
2257 	    printf(gettext("ldaptool_gettokenname -- (null)\n"));
2258 	}
2259     }
2260 
2261     return LDAP_SUCCESS;
2262 }
2263 int
2264 ldaptool_gettokenpin( void *context, const char *tokennamep, char **tokenpinp)
2265 {
2266 
2267 #if 0
2268   char *localtoken;
2269 #endif
2270 
2271 /* XXXceb this stuff is removed for the time being.
2272  * This function should return the pin from ssl_password
2273  */
2274 
2275 
2276   *tokenpinp = ssl_passwd;
2277   return LDAP_SUCCESS;
2278 
2279 #if 0
2280 
2281   ldaptool_gettokenname( NULL, &localtoken);
2282 
2283   if (strcmp( localtoken, tokennamep))
2284 
2285       *tokenpinp = pkcs_pin;
2286    else
2287       *tokenpinp = NULL;
2288 
2289     if ( ldaptool_verbose ) {
2290 	if (pkcs_pin)
2291 	{
2292 	    printf(gettext("ldaptool_getokenpin --%s\n"), tokenpinp);
2293 	}
2294 	else
2295 	{
2296 	    printf(gettext("ldaptool_getokenpin -- (null)\n"));
2297 	}
2298     }
2299     return LDAP_SUCCESS;
2300 #endif
2301 }
2302 
2303 int
2304 ldaptool_getmodpath( void *context, char **modulep )
2305 {
2306     *modulep = ssl_secmodpath;
2307     if ( ldaptool_verbose ) {
2308 	if (ssl_secmodpath)
2309 	{
2310 	    printf(gettext("ldaptool_getmodpath -- %s\n"), *modulep);
2311 	}
2312 	else
2313 	{
2314 	    printf(gettext("ldaptool_getmodpath -- (null)\n"));
2315 	}
2316     }
2317 
2318     return LDAP_SUCCESS;
2319 }
2320 
2321 int
2322 ldaptool_getdonglefilename( void *context, char **filename )
2323 {
2324     *filename = ssl_donglefile;
2325     if ( ldaptool_verbose ) {
2326 	if (ssl_donglefile)
2327 	{
2328 	    printf(gettext("ldaptool_getdonglefilename -- %s\n"), *filename);
2329 	}
2330 	else
2331 	{
2332 	    printf(gettext("ldaptool_getdonglefilename -- (null)\n"));
2333 	}
2334 
2335     }
2336 
2337     return LDAP_SUCCESS;
2338 }
2339 
2340 static int
2341 ldaptool_setcallbacks( struct ldapssl_pkcs_fns *pfns)
2342 {
2343   pfns->pkcs_getcertpath = (int (*)(void *, char **))ldaptool_getcertpath;
2344   pfns->pkcs_getcertname =  (int (*)(void *, char **))ldaptool_getcertname;
2345   pfns->pkcs_getkeypath =  (int (*)(void *, char **)) ldaptool_getkeypath;
2346   pfns->pkcs_getmodpath =  (int (*)(void *, char **)) ldaptool_getmodpath;
2347   pfns->pkcs_getpin =  (int (*)(void *, const char*, char **)) ldaptool_gettokenpin;
2348   pfns->pkcs_gettokenname =  (int (*)(void *, char **)) ldaptool_gettokenname;
2349   pfns->pkcs_getdonglefilename =  (int (*)(void *, char **)) ldaptool_getdonglefilename;
2350   pfns->local_structure_id=PKCS_STRUCTURE_ID;
2351   return LDAP_SUCCESS;
2352 }
2353 
2354 
2355 
2356 #ifdef FORTEZZA
2357 static int
2358 ldaptool_fortezza_init( int exit_on_error )
2359 {
2360     int		rc, errcode;
2361 
2362     if ( fortezza_personality == NULL && fortezza_cardmask == 0 ) { /* no FORTEZZA desired */
2363 	SSL_EnableGroup( SSL_GroupFortezza, DSFalse );	/* disable FORTEZZA */
2364 	return( 0 );
2365     }
2366 
2367     if (( rc = FortezzaConfigureServer( ldaptool_fortezza_getpin, fortezza_cardmask,
2368 	    fortezza_personality, ldaptool_fortezza_alert, NULL, &errcode,
2369 	    fortezza_krlfile )) < 0 ) {
2370 	fprintf( stderr,
2371 		"%s: FORTEZZA initialization failed (error %d - %s)\n",
2372 		ldaptool_progname, errcode,
2373 		ldaptool_fortezza_err2string( errcode ));
2374 	if ( exit_on_error ) {
2375 	    exit( LDAP_LOCAL_ERROR );
2376 	}
2377 
2378 	SSL_EnableGroup( SSL_GroupFortezza, DSFalse );	/* disable FORTEZZA */
2379 	return( -1 );
2380     }
2381 
2382     SSL_EnableGroup( SSL_GroupFortezza, DSTrue );	/* enable FORTEZZA */
2383     return( 0 );
2384 }
2385 
2386 
2387 static int
2388 ldaptool_fortezza_alert( void *arg, PRBool onOpen, char *string,
2389 	int value1, void *value2 )
2390 {
2391     fprintf( stderr, "%s: FORTEZZA alert: ", ldaptool_progname );
2392     fprintf( stderr, string, value1, value2 );
2393     fprintf( stderr, "\n" );
2394     return( 1 );
2395 }
2396 
2397 
2398 static void *
2399 ldaptool_fortezza_getpin( char **passwordp )
2400 {
2401     *passwordp = fortezza_pin;
2402     return( *passwordp );
2403 }
2404 
2405 
2406 /*
2407  * convert a Fortezza error code (as returned by FortezzaConfigureServer()
2408  * into a human-readable string.
2409  *
2410  * Error strings are intentionally similar to those found in
2411  * ns/netsite/lib/libadmin/httpcon.c
2412  */
2413 static char *
2414 ldaptool_fortezza_err2string( int err )
2415 {
2416     char	*s;
2417 
2418     switch( err ) {
2419     case FORTEZZA_BADPASSWD:
2420 	s = "invalid pin number";
2421 	break;
2422     case FORTEZZA_BADCARD:
2423 	s = "bad or missing card";
2424 	break;
2425     case FORTEZZA_MISSING_KRL:
2426 	s = "bad or missing compromised key list";
2427 	break;
2428     case FORTEZZA_CERT_INIT_ERROR:
2429 	s = "unable to initialize certificate cache.  either a cert on "
2430 		"the card is bad, or an old FORTEZZA certificate is in a"
2431 		 "readonly database";
2432 	break;
2433     case FORTEZZA_EXPIRED_CERT:
2434 	s = "unable to verify certificate";
2435 	break;
2436     default:
2437 	s = "unknown error";
2438     }
2439 
2440     return( s );
2441 }
2442 
2443 #endif /* FORTEZZA */
2444 #endif /* LDAP_TOOL_PKCS11 */
2445 #endif /* NET_SSL */
2446 
2447 int
2448 ldaptool_boolean_str2value ( const char *ptr, int strict )
2449 {
2450     if (strict) {
2451 	if ( !(strcasecmp(ptr, "true"))) {
2452 	    return 1;
2453 	}
2454 	else if ( !(strcasecmp(ptr, "false"))) {
2455 	    return 0;
2456 	}
2457 	else {
2458 	    return (-1);
2459 	}
2460     }
2461     else {
2462 	if ( !(strcasecmp(ptr, "true")) ||
2463 	     !(strcasecmp(ptr, "t")) ||
2464 	     !(strcmp(ptr, "1")) ) {
2465 		return (1);
2466 	}
2467 	else if ( !(strcasecmp(ptr, "false")) ||
2468 	     !(strcasecmp(ptr, "f")) ||
2469 	     !(strcmp(ptr, "0")) ) {
2470 	    	return (0);
2471 	}
2472 	else {
2473 	    return (-1);
2474 	}
2475     }
2476 }
2477 
2478 FILE *
2479 ldaptool_open_file(const char *filename, const char *mode)
2480 {
2481 #ifdef _LARGEFILE64_SOURCE
2482 	return fopen64(filename, mode);
2483 #else
2484 	return fopen(filename, mode);
2485 #endif
2486 }
2487 
2488 #ifdef later
2489 /* Functions for list in ldapdelete.c */
2490 
2491 void L_Init(Head *list)
2492 {
2493     if(list)
2494     {
2495         list->first = NULL;
2496         list->last = NULL;
2497         list->count = 0;
2498     }
2499 }
2500 
2501 void L_Insert(Element *Node, Head *HeadNode)
2502 {
2503     if (!Node || !HeadNode)
2504         return;
2505 
2506     Node->right = NULL;
2507 
2508     if (HeadNode->first == NULL)
2509     {
2510         Node->left= NULL;
2511         HeadNode->last = HeadNode->first = Node;
2512     }
2513     else
2514     {
2515         Node->left = HeadNode->last;
2516         HeadNode->last = Node->left->right = Node;
2517     }
2518     HeadNode->count++;
2519 }
2520 
2521 void L_Remove(Element *Node, Head *HeadNode)
2522 {
2523     Element *traverse = NULL;
2524     Element *prevnode = NULL;
2525 
2526     if(!Node || !HeadNode)
2527         return;
2528 
2529     for(traverse = HeadNode->first; traverse; traverse = traverse->right)
2530     {
2531         if(traverse == Node)
2532         {
2533             if(HeadNode->first == traverse)
2534             {
2535                 HeadNode->first = traverse->right;
2536             }
2537             if(HeadNode->last == traverse)
2538             {
2539                 HeadNode->last = prevnode;
2540             }
2541             traverse = traverse->right;
2542             if(prevnode != NULL)
2543             {
2544                 prevnode->right = traverse;
2545             }
2546             if(traverse != NULL)
2547             {
2548                 traverse->left = prevnode;
2549             }
2550             HeadNode->count--;
2551             return;
2552         }
2553         else /* traverse != node */
2554         {
2555             prevnode = traverse;
2556         }
2557     }
2558 }
2559 #endif
2560 
2561 #ifdef HAVE_SASL_OPTIONS
2562 /*
2563  * Function checks for valid args, returns an error if not found
2564  * and sets SASL params from command line
2565  */
2566 
2567 static int
2568 saslSetParam(char *saslarg)
2569 {
2570 	char *attr = NULL;
2571 
2572 	attr = strchr(saslarg, '=');
2573 	if (attr == NULL) {
2574            fprintf( stderr, gettext("Didn't find \"=\" character in %s\n"), saslarg);
2575            return (-1);
2576 	}
2577 	*attr = '\0';
2578 	attr++;
2579 
2580 	if (!strcasecmp(saslarg, "secProp")) {
2581 	     if ( sasl_secprops != NULL ) {
2582                 fprintf( stderr, gettext("secProp previously specified\n"));
2583                 return (-1);
2584              }
2585              if (( sasl_secprops = strdup(attr)) == NULL ) {
2586 		perror ("malloc");
2587                 exit (LDAP_NO_MEMORY);
2588              }
2589 	} else if (!strcasecmp(saslarg, "realm")) {
2590 	     if ( sasl_realm != NULL ) {
2591                 fprintf( stderr, gettext("Realm previously specified\n"));
2592                 return (-1);
2593              }
2594              if (( sasl_realm = strdup(attr)) == NULL ) {
2595 		perror ("malloc");
2596                 exit (LDAP_NO_MEMORY);
2597              }
2598 	} else if (!strcasecmp(saslarg, "authzid")) {
2599              if (sasl_username != NULL) {
2600                 fprintf( stderr, gettext("Authorization name previously specified\n"));
2601                 return (-1);
2602              }
2603              if (( sasl_username = strdup(attr)) == NULL ) {
2604 		perror ("malloc");
2605                 exit (LDAP_NO_MEMORY);
2606              }
2607 	} else if (!strcasecmp(saslarg, "authid")) {
2608              if ( sasl_authid != NULL ) {
2609                 fprintf( stderr, gettext("Authentication name previously specified\n"));
2610                 return (-1);
2611              }
2612              if (( sasl_authid = strdup(attr)) == NULL) {
2613 		perror ("malloc");
2614                 exit (LDAP_NO_MEMORY);
2615              }
2616 	} else if (!strcasecmp(saslarg, "mech")) {
2617 	     if ( sasl_mech != NULL ) {
2618                 fprintf( stderr, gettext("Mech previously specified\n"));
2619                 return (-1);
2620              }
2621 	     if (( sasl_mech = strdup(attr)) == NULL) {
2622 		perror ("malloc");
2623 		exit (LDAP_NO_MEMORY);
2624 	     }
2625 	} else {
2626 	     fprintf (stderr, gettext("Invalid attribute name %s\n"), saslarg);
2627 	     return (-1);
2628 	}
2629 	return 0;
2630 }
2631 #endif	/* HAVE_SASL_OPTIONS */
2632 
2633 /*
2634  * check for and report input or output error on named stream
2635  * return ldap_err or ferror() (ldap_err takes precedence)
2636  * assume that fflush() already has been called if needed.
2637  * don't want to fflush() an input stream.
2638  */
2639 int
2640 ldaptool_check_ferror(FILE * stream, const int ldap_err, const char *msg)
2641 {
2642 	int err = 0;
2643 	if ((err = ferror(stream)) != 0 ) {
2644 		fprintf(stderr, gettext("%s: ERROR: "), ldaptool_progname);
2645 		perror(msg);
2646 		err = LDAP_LOCAL_ERROR;
2647 	}
2648 
2649 	/*
2650 	 * reporting LDAP error code is more important than
2651 	 * reporting errors from ferror()
2652 	 */
2653 	if (ldap_err == LDAP_SUCCESS) {
2654 		return(err);
2655 	} else {
2656 		return(ldap_err);
2657 	}
2658 }
2659