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