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