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