/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * code that is shared by two or more of the LDAP command line tools */ #include "ldaptool.h" #include "fileurl.h" #ifdef SOLARIS_LDAP_CMD #include "solaris-int.h" #include #include #include #include #include #include #endif /* SOLARIS_LDAP_CMD */ #ifdef LDAP_TOOL_ARGPIN #include "argpin.h" #include "ntuserpin.h" #endif /* LDAP_TOOL_ARGPIN */ #ifndef SOLARIS_LDAP_CMD #include /* for PR_Cleanup() */ #endif /* SOLARIS_LDAP_CMD */ #include #include /* for time() and ctime() */ #ifdef HAVE_SASL_OPTIONS #ifdef SOLARIS_LDAP_CMD #include #else #include #endif /* SOLARIS_LDAP_CMD */ #include "ldaptool-sasl.h" #endif /* HAVE_SASL_OPTIONS */ #ifndef SOLARIS_LDAP_CMD #define gettext(s) s #endif #ifdef SOLARIS_LDAP_CMD #define PATH_BUF_SIZE (PATH_MAX + 1) #endif static LDAP_REBINDPROC_CALLBACK get_rebind_credentials; static void print_library_info( const LDAPAPIInfo *aip, FILE *fp ); static int wait4result( LDAP *ld, int msgid, struct berval **servercredp, char *msg ); static int parse_result( LDAP *ld, LDAPMessage *res, struct berval **servercredp, char *msg, int freeit ); #ifdef LDAPTOOL_DEBUG_MEMORY static void *ldaptool_debug_malloc( size_t size ); static void *ldaptool_debug_calloc( size_t nelem, size_t elsize ); static void *ldaptool_debug_realloc( void *ptr, size_t size ); static void ldaptool_debug_free( void *ptr ); #endif /* LDAPTOOL_DEBUG_MEMORY */ #if defined(NET_SSL) static char *certpath2keypath( char *certdbpath ); static int ldaptool_setcallbacks( struct ldapssl_pkcs_fns *pfns); static char * buildTokenCertName( const char *tokenName, const char *certName); #ifdef FORTEZZA static int ldaptool_fortezza_init( int exit_on_error ); static int ldaptool_fortezza_alert( void *arg, PRBool onOpen, char *string, int value1, void *value2 ); static void * ldaptool_fortezza_getpin( char **passwordp ); static char * ldaptool_fortezza_err2string( int err ); #endif /* FORTEZZA */ #endif #ifdef HAVE_SASL_OPTIONS static int saslSetParam(char *saslarg); #endif /* HAVE_SASL_OPTIONS */ /* * display usage for common options with one exception: -f is not included * since the description tends to be tool-specific. * * As of 1-Jul-1998, of the characters in the set [A-Za-z] the following are * not currently used by any of the tools: EJgjqr */ void ldaptool_common_usage( int two_hosts ) { fprintf( stderr, gettext(" -n\t\tshow what would be done but don't actually do it\n") ); fprintf( stderr, gettext(" -v\t\trun in verbose mode (diagnostics to standard output)\n") ); if ( two_hosts ) { fprintf( stderr, gettext(" -h host\tLDAP server1 name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST ); fprintf( stderr, gettext(" -p port\tLDAP server1 TCP port number (default: %d)\n"), LDAP_PORT ); fprintf( stderr, gettext(" -h host\tLDAP server2 name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST ); fprintf( stderr, gettext(" -p port\tLDAP server2 TCP port number (default: %d)\n"), LDAP_PORT ); } else { fprintf( stderr, gettext(" -h host\tLDAP server name or IP address (default: %s)\n"), LDAPTOOL_DEFHOST ); fprintf( stderr, gettext(" -p port\tLDAP server TCP port number (default: %d)\n"), LDAP_PORT ); } fprintf( stderr, gettext(" -V n\tLDAP protocol version number (%d or %d; default: %d)\n"), LDAP_VERSION2, LDAP_VERSION3, LDAP_VERSION3 ); #if defined(NET_SSL) fprintf( stderr, gettext(" -Z\t\tmake an SSL-encrypted connection\n") ); fprintf( stderr, gettext(" -P pathname\tpath to SSL certificate database (default: current directory)\n") ); fprintf( stderr, gettext(" -N\t\tname of certificate to use for SSL client authentication\n") ); #ifndef SOLARIS_LDAP_CMD fprintf( stderr, gettext(" -K pathname\tpath to key database to use for SSL client authentication\n") ); fprintf( stderr, gettext(" \t\t(default: path to certificate database provided with -P option)\n") ); #endif /* SOLARIS_LDAP_CMD */ #ifdef LDAP_TOOL_PKCS11 fprintf( stderr, gettext(" -m pathname\tpath to security module database\n")); #endif /* LDAP_TOOL_PKCS11 */ fprintf( stderr, gettext(" -W\t\tSSL key password\n") ); #ifndef SOLARIS_LDAP_CMD fprintf( stderr, gettext(" -3\t\tcheck hostnames in SSL certificates\n") ); #endif /* SOLARIS_LDAP_CMD */ #ifdef LDAP_TOOL_PKCS11 fprintf( stderr, gettext(" -Q [token][:certificate name]\tPKCS 11\n") ); /* fprintf( stderr, " -X pathname\tFORTEZZA compromised key list (CKL)\n" ); */ fprintf( stderr, gettext(" -I pin\tcard password file\n") ); #endif /* LDAP_TOOL_PKCS11 */ #endif /* NET_SSL */ fprintf( stderr, gettext(" -D binddn\tbind dn\n") ); fprintf( stderr, gettext(" -w passwd\tbind passwd (for simple authentication)\n") ); fprintf( stderr, gettext(" -w - \tprompt for bind passwd (for simple authentication)\n") ); fprintf( stderr, gettext(" -j file\tread bind passwd (for simple authentication)\n") ); fprintf( stderr, gettext(" \t\tor SSL key password from 'file'\n") ); fprintf( stderr, gettext(" -E\t\task server to expose (report) bind identity\n") ); #ifdef LDAP_DEBUG fprintf( stderr, gettext(" -d level\tset LDAP debugging level to `level'\n") ); #endif fprintf( stderr, gettext(" -R\t\tdo not automatically follow referrals\n") ); fprintf( stderr, gettext(" -O limit\tmaximum number of referral hops to traverse (default: %d)\n"), LDAPTOOL_DEFREFHOPLIMIT ); fprintf( stderr, gettext(" -M\t\tmanage references (treat them as regular entries)\n") ); #ifndef SOLARIS_LDAP_CMD fprintf( stderr, gettext(" -0\t\tignore LDAP library version mismatches\n") ); #endif /* SOLARIS_LDAP_CMD */ #ifndef NO_LIBLCACHE fprintf( stderr, gettext(" -C cfgfile\tuse local database described by cfgfile\n") ); #endif fprintf( stderr, gettext(" -i charset\tcharacter set for command line input (default taken from locale)\n") ); fprintf( stderr, gettext(" -k dir\tconversion routine directory (default: current directory)\n") ); #if 0 /* * Suppress usage for -y (old proxied authorization control) even though * we still support it. We want to encourage people to use -Y instead (the * new proxied authorization control). */ fprintf( stderr, gettext(" -y proxydn\tDN used for proxy authorization\n") ); #endif fprintf( stderr, gettext(" -Y proxyid\tproxied authorization id,\n") ); fprintf( stderr, gettext(" \te.g, dn:uid=bjensen,dc=example,dc=com\n") ); fprintf( stderr, gettext(" -H\t\tdisplay usage information\n") ); #ifdef SOLARIS_LDAP_CMD fprintf( stderr, gettext(" -?\t\tdisplay usage information\n") ); #endif /* SOLARIS_LDAP_CMD */ fprintf( stderr, gettext(" -J controloid[:criticality[:value|::b64value|:= PATH_BUF_SIZE) { fprintf(stderr, gettext("\"-P\": Path name is too " "long\n")); exit(LDAP_PARAM_ERROR); } if (stat(pathname, &st) != 0) { perror("stat"); fprintf(stderr, gettext("\"-P\": Path name is " "invalid\n")); exit(LDAP_PARAM_ERROR); } else { if (S_ISREG(st.st_mode)) { /* redir to a regular file's dir name */ ssl_certdbpath = dirname(pathname); } else ssl_certdbpath = pathname; } #endif /* SOLARIS_LDAP_CMD */ break; case 'Z': /* do SSL encryption */ secure = 1; isZ = 1; break; case 'N': /* nickname of cert. to use for client auth. */ ssl_certname = strdup( optarg ); if (NULL == ssl_certname) { perror("malloc"); exit( LDAP_NO_MEMORY ); } isN = 1; break; #ifndef SOLARIS_LDAP_CMD case 'K': /* location of key database */ ssl_keydbpath = strdup( optarg ); if (NULL == ssl_keydbpath) { perror("malloc"); exit( LDAP_NO_MEMORY ); } break; #endif /* SOLARIS_LDAP_CMD */ case 'W': /* SSL key password */ ssl_passwd = strdup( optarg ); if (NULL == ssl_passwd) { perror("malloc"); exit( LDAP_NO_MEMORY ); } isW = 1; break; #ifndef SOLARIS_LDAP_CMD case '3': /* check hostnames in SSL certificates ("no third") */ ssl_strength = LDAPSSL_AUTH_CNCHECK; break; #endif /* SOLARIS_LDAP_CMD */ #ifdef LDAP_TOOL_PKCS11 case 'm': /* SSL secmod path */ ssl_secmodpath = strdup( optarg); if (NULL == ssl_secmodpath) { perror("malloc"); exit( LDAP_NO_MEMORY ); } break; case 'Q': /* FORTEZZA [card][:personality] */ pkcs_token = strdup(optarg); if (NULL == pkcs_token) { perror("malloc"); exit( LDAP_NO_MEMORY ); } break; /* This option removed to prevent interference with the getEffectiveRights option, also -X case 'X': * path to FORTEZZA CKL file * fortezza_krlfile = strdup( optarg ); break; */ case 'I': /* FORTEZZA PIN (password file) */ ssl_donglefile = strdup( optarg ); break; #endif /* LDAP_TOOL_PKCS11 */ #endif /* NET_SSL */ case 'w': /* bind password */ isw = 1; if ( optarg[0] == '-' && optarg[1] == '\0' ) prompt_password = 1; else passwd = strdup( optarg ); break; case 'j': /* bind password or SSL key password from file */ isj = 1; if ((password_fp = fopen( optarg, "r" )) == NULL ) { fprintf(stderr, gettext("%s: Unable to open '%s' file\n"), ldaptool_progname, optarg); exit( LDAP_PARAM_ERROR ); } break; case 'O': /* referral hop limit */ refhoplim = atoi( optarg ); break; case 'V': /* protocol version */ ldversion = atoi (optarg); if ( ldversion != LDAP_VERSION2 && ldversion != LDAP_VERSION3 ) { fprintf( stderr, gettext("%s: LDAP protocol version %d is not " "supported (use -V%d or -V%d)\n"), ldaptool_progname, ldversion, LDAP_VERSION2, LDAP_VERSION3 ); exit( LDAP_PARAM_ERROR ); } break; case 'M': /* send a manageDsaIT control */ send_manage_dsait_ctrl = 1; break; case 'i': /* character set specified */ ldaptool_charset = strdup( optarg ); if (NULL == ldaptool_charset) { perror( "malloc" ); exit( LDAP_NO_MEMORY ); } break; case 'k': /* conversion directory */ ldaptool_convdir = strdup( optarg ); if (NULL == ldaptool_convdir) { perror( "malloc" ); exit( LDAP_NO_MEMORY ); } break; case 'y': /* old (version 1) proxied authorization control */ proxyauth_version = 1; /* FALLTHROUGH */ case 'Y': /* new (version 2 ) proxied authorization control */ proxyauth_id = strdup(optarg); if (NULL == proxyauth_id) { perror( "malloc" ); exit( LDAP_NO_MEMORY ); } break; #ifndef SOLARIS_LDAP_CMD case '0': /* zero -- override LDAP library version check */ break; /* already handled above */ #endif /* SOLARIS_LDAP_CMD */ case 'J': /* send an arbitrary control */ if ( (ctrl_arg = strdup( optarg)) == NULL ) { perror ("strdup"); exit (LDAP_NO_MEMORY); } if (ldaptool_parse_ctrl_arg(ctrl_arg, ':', &ctrl_oid, &ctrl_criticality, &ctrl_value, &vlen)) { return (-1); } ldctrl = calloc(1,sizeof(LDAPControl)); if (ctrl_value) { rc = ldaptool_berval_from_ldif_value( ctrl_value, vlen, &(ldctrl->ldctl_value), 1 /* recognize file URLs */, 0 /* always try file */, 1 /* report errors */ ); if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) { fprintf( stderr, gettext("Unable to parse %s\n"), ctrl_value); return (-1); } } ldctrl->ldctl_oid = ctrl_oid; ldctrl->ldctl_iscritical = ctrl_criticality; ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls); break; #ifdef HAVE_SASL_OPTIONS case 'o': /* attribute assignment */ if ((rc = saslSetParam(optarg)) == -1) { return (-1); } ldapauth = LDAP_AUTH_SASL; ldversion = LDAP_VERSION3; break; #endif /* HAVE_SASL_OPTIONS */ default: (*extra_opt_callback)( i, optarg ); } } /* If '-Z' is specified, check if '-P' is specified too. */ if ( isN || isW ) { if ( !isZ ) { fprintf( stderr, gettext("%s: with -N, -W options, please specify -Z\n\n"), ldaptool_progname ); return (-1); } } /* if '-N' is specified, -W is needed too */ if ( isN && NULL == ssl_passwd ) { fprintf( stderr, gettext("%s: with the -N option, please specify -W also\n\n"), ldaptool_progname ); return (-1); } #ifdef SOLARIS_LDAP_CMD if ( isj && ( isw || isW )) { fprintf(stderr, gettext("%s: -j and -w or -W options cannot be specified simultaneously\n\n"), ldaptool_progname ); #else if ( isj && isw ) { fprintf(stderr, gettext("%s: -j and -w options cannot be specified simultaneously\n\n"), ldaptool_progname ); #endif /* SOLARIS_LDAP_CMD */ return (-1); } /* complain if -j or -w does not also have -D, unless using SASL */ #ifdef HAVE_SASL_OPTIONS if ( (isj || isw) && !isD && ( ldapauth != LDAP_AUTH_SASL ) ) { #else if ( (isj || isw) && !isD ) { #endif fprintf(stderr, gettext("%s: with -j, -w options, please specify -D\n\n"), ldaptool_progname ); return (-1); } /* use default key and cert DB paths if not set on the command line */ if ( NULL == ssl_keydbpath ) { if ( NULL == ssl_certdbpath ) { ssl_keydbpath = LDAPTOOL_DEFKEYDBPATH; } else { ssl_keydbpath = certpath2keypath( ssl_certdbpath ); } } if ( NULL == ssl_certdbpath ) { ssl_certdbpath = LDAPTOOL_DEFCERTDBPATH; } if (prompt_password != 0) { char *password_string = "Enter bind password: "; #if defined(_WIN32) char pbuf[257]; fputs(password_string,stdout); fflush(stdout); if (fgets(pbuf,256,stdin) == NULL) { passwd = NULL; } else { char *tmp; tmp = strchr(pbuf,'\n'); if (tmp) *tmp = '\0'; tmp = strchr(pbuf,'\r'); if (tmp) *tmp = '\0'; passwd = strdup(pbuf); } #else #if defined(SOLARIS) /* 256 characters on Solaris */ passwd = getpassphrase(password_string); #else /* limited to 16 chars on Tru64, 32 on AIX */ passwd = getpass(password_string); #endif #endif } else if (password_fp != NULL) { char *linep = NULL; int increment = 0; int c, index; /* allocate initial block of memory */ if ((linep = (char *)malloc(BUFSIZ)) == NULL) { fprintf( stderr, gettext("%s: not enough memory to read password from file\n"), ldaptool_progname ); exit( LDAP_NO_MEMORY ); } increment++; index = 0; while ((c = fgetc( password_fp )) != '\n' && c != EOF) { /* check if we will overflow the buffer */ if ((c != EOF) && (index == ((increment * BUFSIZ) -1))) { /* if we did, add another BUFSIZ worth of bytes */ if ((linep = (char *) realloc(linep, (increment + 1) * BUFSIZ)) == NULL) { fprintf( stderr, gettext("%s: not enough memory to read password from file\n"), ldaptool_progname ); exit( LDAP_NO_MEMORY ); } increment++; } linep[index++] = c; } linep[index] = '\0'; passwd = linep; } #ifdef SOLARIS_LDAP_CMD if (binddn != NULL && passwd == NULL) { char *password_string = gettext("Enter bind password: "); passwd = getpassphrase(password_string); } #ifdef HAVE_SASL_OPTIONS if (ldapauth == LDAP_AUTH_SASL) { /* BindDN not required for SASL */ ldaptool_require_binddn = 0; } #endif /* HAVE_SASL_OPTIONS */ #ifdef NET_SSL if (secure == 1) { /* BindDN not required for SSL */ ldaptool_require_binddn = 0; } #endif /* NET_SSL */ if (ldaptool_require_binddn && binddn == NULL && passwd == NULL) { fprintf(stderr, gettext("%s: DN and Bind Password are required.\n"), ldaptool_progname ); exit(1); } #endif /* SOLARIS_LDAP_CMD */ /* * If verbose (-v) flag was passed in, display program name and start time. * If the verbose flag was passed at least twice (-vv), also display * information about the API library we are running with. */ if ( ldaptool_verbose ) { time_t curtime; curtime = time( NULL ); printf( gettext("%s: started %s\n"), ldaptool_progname, ctime( &curtime )); if ( ldaptool_verbose > 1 ) { print_library_info( &ldai, stdout ); } } #ifdef LDAP_TOOL_PKCS11 if ((NULL != pkcs_token) && (NULL != ssl_certname)) { char *result; if ( (result = buildTokenCertName( pkcs_token, ssl_certname)) != NULL){ free( ssl_certname ); ssl_certname = result; } } #endif /* LDAP_TOOL_PKCS11 */ free( optstring ); /* * Clean up and return index of first non-option argument. */ if ( ldai.ldapai_extensions != NULL ) { ldap_value_free( ldai.ldapai_extensions ); } if ( ldai.ldapai_vendor_name != NULL ) { ldap_memfree( ldai.ldapai_vendor_name ); } #ifdef HAVE_SASL_OPTIONS if (ldversion == LDAP_VERSION2 && ldapauth == LDAP_AUTH_SASL) { fprintf( stderr, gettext("Incompatible with version %d\n"), ldversion); return (-1); } #endif /* HAVE_SASL_OPTIONS */ return( optind ); } /* * Write detailed information about the API library we are running with to fp. */ static void print_library_info( const LDAPAPIInfo *aip, FILE *fp ) { int i; LDAPAPIFeatureInfo fi; fprintf( fp, gettext("LDAP Library Information -\n" " Highest supported protocol version: %d\n" " LDAP API revision: %d\n" " API vendor name: %s\n" " Vendor-specific version: %.2f\n"), aip->ldapai_protocol_version, aip->ldapai_api_version, aip->ldapai_vendor_name, (float)aip->ldapai_vendor_version / 100.0 ); if ( aip->ldapai_extensions != NULL ) { fputs( gettext(" LDAP API Extensions:\n"), fp ); for ( i = 0; aip->ldapai_extensions[i] != NULL; i++ ) { fprintf( fp, gettext(" %s"), aip->ldapai_extensions[i] ); fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION; fi.ldapaif_name = aip->ldapai_extensions[i]; fi.ldapaif_version = 0; if ( ldap_get_option( NULL, LDAP_OPT_API_FEATURE_INFO, &fi ) != 0 ) { fprintf( fp, gettext(" %s: ldap_get_option( NULL," " LDAP_OPT_API_FEATURE_INFO, ... ) for %s failed" " (Feature Info version: %d)\n"), ldaptool_progname, fi.ldapaif_name, fi.ldapaif_info_version ); } else { fprintf( fp, gettext(" (revision %d)\n"), fi.ldapaif_version); } } } fputc( '\n', fp ); } #ifdef LDAP_TOOL_ARGPIN static int PinArgRegistration( void ) { /* pkcs_init was successful register the pin args */ SVRCOREArgPinObj *ArgPinObj; char *tokenName; #ifndef _WIN32 SVRCOREStdPinObj *StdPinObj; #else SVRCOREFilePinObj *FilePinObj; SVRCOREAltPinObj *AltPinObj; SVRCORENTUserPinObj *NTUserPinObj; int err; #endif char *pin; char *filename; /* Create and register the pin object for PKCS 11 */ local_pkcs_fns.pkcs_getdonglefilename(NULL, &filename); local_pkcs_fns.pkcs_getpin(NULL, "", &pin); #ifndef _WIN32 if ( SVRCORE_CreateStdPinObj(&StdPinObj, filename, PR_TRUE) != SVRCORE_Success) { fprintf(stderr, gettext("Security Initialization: Unable to create PinObj " "(%d)"), PR_GetError()); return -1; } if (pin != NULL) { local_pkcs_fns.pkcs_gettokenname(NULL, &tokenName); SVRCORE_CreateArgPinObj(&ArgPinObj, tokenName, pin, (SVRCOREPinObj *)StdPinObj); SVRCORE_RegisterPinObj((SVRCOREPinObj *)ArgPinObj); } else { SVRCORE_RegisterPinObj((SVRCOREPinObj *)StdPinObj); } #else if (NULL != pin) { local_pkcs_fns.pkcs_gettokenname(NULL, &tokenName); if ((err = SVRCORE_CreateNTUserPinObj(&NTUserPinObj)) != SVRCORE_Success){ fprintf(stderr, gettext("Security Initialization: Unable to create NTUserPinObj " "(%d)"), PR_GetError()); exit( LDAP_LOCAL_ERROR ); } if ((err = SVRCORE_CreateArgPinObj(&ArgPinObj, tokenName, pin, (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success) { fprintf(stderr, gettext("Security Initialization: Unable to create ArgPinObj " "(%d)"), PR_GetError()); return -1; } SVRCORE_RegisterPinObj((SVRCOREPinObj *)ArgPinObj); } else { if ((err = SVRCORE_CreateNTUserPinObj(&NTUserPinObj)) != SVRCORE_Success){ fprintf(stderr, gettext("Security Initialization: Unable to create NTUserPinObj " "(%d)"), PR_GetError()); return -1; } if (filename && *filename) { if ((err = SVRCORE_CreateFilePinObj(&FilePinObj, filename)) != SVRCORE_Success) { fprintf(stderr, gettext("Security Initialization: Unable to create FilePinObj " "(%d)"), PR_GetError()); return -1; } if ((err = SVRCORE_CreateAltPinObj(&AltPinObj, (SVRCOREPinObj *)FilePinObj, (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success) { fprintf(stderr, gettext("Security Initialization: Unable to create AltPinObj " "(%d)"), PR_GetError()); return -1; } SVRCORE_RegisterPinObj((SVRCOREPinObj *)AltPinObj); } else { SVRCORE_RegisterPinObj((SVRCOREPinObj *)NTUserPinObj); } } #endif return LDAP_SUCCESS; } #endif /* LDAP_TOOL_ARGPIN */ /* * initialize and return an LDAP session handle. * if errors occur, we exit here. */ LDAP * ldaptool_ldap_init( int second_host ) { LDAP *ld = NULL; char *host; int port, rc, user_port; if ( ldaptool_not ) { return( NULL ); } if ( second_host ) { host = ldaptool_host2; port = ldaptool_port2; user_port = user_specified_port2; } else { host = ldaptool_host; port = ldaptool_port; user_port = user_specified_port; } if ( ldaptool_verbose ) { printf( gettext("ldap_init( %s, %d )\n"), host, port ); } #if defined(NET_SSL) /* * Initialize security libraries and databases and LDAP session. If * ssl_certname is not NULL, then we will attempt to use client auth. * if the server supports it. */ #ifdef LDAP_TOOL_PKCS11 ldaptool_setcallbacks( &local_pkcs_fns ); if ( !second_host && secure &&(rc = ldapssl_pkcs_init( &local_pkcs_fns)) < 0) { /* secure connection requested -- fail if no SSL */ #ifndef SOLARIS_LDAP_CMD rc = PORT_GetError(); #endif /* SOLARIS_LDAP_CMD */ fprintf( stderr, gettext("SSL initialization failed: error %d (%s)\n"), rc, ldapssl_err2string( rc )); exit( LDAP_LOCAL_ERROR ); } #ifdef LDAP_TOOL_ARGPIN if (secure) { if (PinArgRegistration( )) { exit( LDAP_LOCAL_ERROR); } } #endif /* LDAP_TOOL_ARGPIN */ #else /* LDAP_TOOL_PKCS11 */ if ( !second_host && secure &&(rc = ldapssl_client_init( ssl_certdbpath, NULL )) < 0) { /* secure connection requested -- fail if no SSL */ #ifndef SOLARIS_LDAP_CMD rc = PORT_GetError(); #endif /* SOLARIS_LDAP_CMD */ fprintf( stderr, gettext("SSL initialization failed: error %d (%s)\n"), rc, ldapssl_err2string( rc )); exit( LDAP_LOCAL_ERROR ); } #endif /* LDAP_TOOL_PKCS11 */ /* set the default SSL strength (used for all future ld's we create) */ if ( ldapssl_set_strength( NULL, ssl_strength ) < 0 ) { perror( "ldapssl_set_strength" ); exit( LDAP_LOCAL_ERROR ); } if (secure) { if ( !user_port ) { port = LDAPS_PORT; } if (( ld = ldapssl_init( host, port, secure )) != NULL && ssl_certname != NULL ) if (ldapssl_enable_clientauth( ld, ssl_keydbpath, ssl_passwd, ssl_certname ) != 0 ) { exit ( ldaptool_print_lderror( ld, "ldapssl_enable_clientauth", LDAPTOOL_CHECK4SSL_ALWAYS )); } } else { /* In order to support IPv6, we use NSPR I/O */ #ifdef SOLARIS_LDAP_CMD ld = ldap_init( host, port ); #else ld = prldap_init( host, port, 0 /* not shared across threads */ ); #endif /* SOLARIS_LDAP_CMD */ } #else /* NET_SSL */ /* In order to support IPv6, we use NSPR I/O */ #ifdef SOLARIS_LDAP_CMD ld = ldap_init( host, port ); #else ld = prldap_init( host, port, 0 /* not shared across threads */ ); #endif /* SOLARIS_LDAP_CMD */ #endif /* NET_SSL */ if ( ld == NULL ) { perror( "ldap_init" ); exit( LDAP_LOCAL_ERROR ); } #ifndef NO_LIBLCACHE if ( cache_config_file != NULL ) { int opt; if ( lcache_init( ld, cache_config_file ) != 0 ) { exit( ldaptool_print_lderror( ld, cache_config_file, LDAPTOOL_CHECK4SSL_NEVER )); } opt = 1; (void) ldap_set_option( ld, LDAP_OPT_CACHE_ENABLE, &opt ); opt = LDAP_CACHE_LOCALDB; (void) ldap_set_option( ld, LDAP_OPT_CACHE_STRATEGY, &opt ); if ( ldversion == -1 ) { /* not set with -V */ ldversion = LDAP_VERSION2; /* local db only supports v2 */ } } #endif ldap_set_option( ld, LDAP_OPT_REFERRALS, chase_referrals ? LDAP_OPT_ON: LDAP_OPT_OFF ); if ( chase_referrals ) { ldap_set_rebind_proc( ld, get_rebind_credentials, NULL ); ldap_set_option( ld, LDAP_OPT_REFERRAL_HOP_LIMIT, &refhoplim ); } if ( ldversion == -1 ) { /* not set with -V and not using local db */ ldversion = LDAP_VERSION3; } ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion ); return( ld ); } /* * perform a bind to the LDAP server if needed. * if an error occurs, we exit here. */ void ldaptool_bind( LDAP *ld ) { int rc; char *conv; LDAPControl auth_resp_ctrl, *ctrl_array[ 2 ], **bindctrls; #ifdef HAVE_SASL_OPTIONS void *defaults; #endif if ( ldaptool_not ) { return; } if ( send_auth_response_ctrl ) { auth_resp_ctrl.ldctl_oid = LDAP_CONTROL_AUTH_REQUEST; auth_resp_ctrl.ldctl_value.bv_val = NULL; auth_resp_ctrl.ldctl_value.bv_len = 0; auth_resp_ctrl.ldctl_iscritical = 0; ctrl_array[0] = &auth_resp_ctrl; ctrl_array[1] = NULL; bindctrls = ctrl_array; } else { bindctrls = NULL; } /* * if using LDAPv3 and not using client auth., omit NULL bind for * efficiency. */ if ( ldversion > LDAP_VERSION2 && binddn == NULL && passwd == NULL && ssl_certname == NULL ) { #ifdef HAVE_SASL_OPTIONS if ( ldapauth != LDAP_AUTH_SASL ) { return; } #else return; #endif } /* * do the bind, backing off one LDAP version if necessary */ conv = ldaptool_local2UTF8( binddn ); #ifdef HAVE_SASL_OPTIONS if ( ldapauth == LDAP_AUTH_SASL) { if ( sasl_mech == NULL) { fprintf( stderr, gettext("Please specify the SASL mechanism name when " "using SASL options\n")); return; } if ( sasl_secprops != NULL) { rc = ldap_set_option( ld, LDAP_OPT_X_SASL_SECPROPS, (void *) sasl_secprops ); if ( rc != LDAP_SUCCESS ) { fprintf( stderr, gettext("Unable to set LDAP_OPT_X_SASL_SECPROPS: %s\n"), sasl_secprops ); return; } } defaults = ldaptool_set_sasl_defaults( ld, sasl_mech, sasl_authid, sasl_username, passwd, sasl_realm ); if (defaults == NULL) { perror ("malloc"); exit (LDAP_NO_MEMORY); } rc = ldap_sasl_interactive_bind_s( ld, binddn, sasl_mech, NULL, NULL, sasl_flags, ldaptool_sasl_interact, defaults ); if (rc != LDAP_SUCCESS ) { ldap_perror( ld, "ldap_sasl_interactive_bind_s" ); } } else #endif /* HAVE_SASL_OPTIONS */ /* * if using LDAPv3 and client auth., try a SASL EXTERNAL bind */ if ( ldversion > LDAP_VERSION2 && binddn == NULL && passwd == NULL && ssl_certname != NULL ) { rc = ldaptool_sasl_bind_s( ld, NULL, LDAP_SASL_EXTERNAL, NULL, bindctrls, NULL, NULL, "ldap_sasl_bind" ); } else { rc = ldaptool_simple_bind_s( ld, conv, passwd, bindctrls, NULL, "ldap_simple_bind" ); } if ( rc == LDAP_SUCCESS ) { if ( conv != NULL ) { free( conv ); } return; /* success */ } #ifdef HAVE_SASL_OPTIONS if (ldapauth != LDAP_AUTH_SASL) { #endif /* HAVE_SASL_OPTIONS */ if ( rc == LDAP_PROTOCOL_ERROR && ldversion > LDAP_VERSION2 ) { /* * try again, backing off one LDAP version * this is okay even for client auth. because the way to achieve * client auth. with LDAPv2 is to perform a NULL simple bind. */ --ldversion; fprintf( stderr, gettext("%s: the server doesn't understand LDAPv%d;" " trying LDAPv%d instead...\n"), ldaptool_progname, ldversion + 1, ldversion ); ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion ); if (( rc = ldaptool_simple_bind_s( ld, conv, passwd, bindctrls, NULL, "ldap_simple_bind" )) == LDAP_SUCCESS ) { if( conv != NULL ) free( conv ); return; /* a qualified success */ } } #ifdef HAVE_SASL_OPTIONS } #endif /* HAVE_SASL_OPTIONS */ if ( conv != NULL ) { free( conv ); } /* * bind(s) failed -- fatal error */ ldap_unbind( ld ); exit( rc ); } /* * close open files, unbind, etc. */ void ldaptool_cleanup( LDAP *ld ) { if ( ld != NULL ) { ldap_unbind( ld ); } if ( ldaptool_fp != NULL && ldaptool_fp != stdin ) { fclose( ldaptool_fp ); ldaptool_fp = NULL; } } /* * Retrieve and print an LDAP error message. Returns the LDAP error code. */ int ldaptool_print_lderror( LDAP *ld, char *msg, int check4ssl ) { int lderr = ldap_get_lderrno( ld, NULL, NULL ); ldap_perror( ld, msg ); #ifndef SOLARIS_LDAP_CMD if ( secure && check4ssl != LDAPTOOL_CHECK4SSL_NEVER ) { if ( check4ssl == LDAPTOOL_CHECK4SSL_ALWAYS || ( lderr == LDAP_SERVER_DOWN )) { int sslerr = PORT_GetError(); fprintf( stderr, gettext("\tSSL error %d (%s)\n"), sslerr, ldapssl_err2string( sslerr )); } } #endif /* SOLARIS_LDAP_CMD */ return( lderr ); } /* * print referrals to stderr */ void ldaptool_print_referrals( char **refs ) { int i; if ( refs != NULL ) { for ( i = 0; refs[ i ] != NULL; ++i ) { fprintf( stderr, gettext("Referral: %s\n"), refs[ i ] ); } } } /* * print contents of an extended response to stderr * this is mainly to support unsolicited notifications * Returns an LDAP error code (from the extended result). */ int ldaptool_print_extended_response( LDAP *ld, LDAPMessage *res, char *msg ) { char *oid; struct berval *data; if ( ldap_parse_extended_result( ld, res, &oid, &data, 0 ) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { if ( oid != NULL ) { if ( strcmp ( oid, LDAP_NOTICE_OF_DISCONNECTION ) == 0 ) { fprintf( stderr, gettext("%s: Notice of Disconnection\n"), msg ); } else { fprintf( stderr, gettext("%s: OID %s\n"), msg, oid ); } ldap_memfree( oid ); } else { fprintf( stderr, gettext("%s: missing OID\n"), msg ); } if ( data != NULL ) { fprintf( stderr, gettext("%s: Data (length %ld):\n"), msg, data->bv_len ); #if 0 /* XXXmcs: maybe we should display the actual data? */ lber_bprint( data->bv_val, data->bv_len ); #endif ber_bvfree( data ); } } return parse_result( ld, res, NULL, msg, 1 ); } /* * Like ldap_sasl_bind_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_sasl_bind_s( LDAP *ld, const char *dn, const char *mechanism, const struct berval *cred, LDAPControl **serverctrls, LDAPControl **clientctrls, struct berval **servercredp, char *msg ) { int rc, msgid; if ( servercredp != NULL ) { *servercredp = NULL; } if (( rc = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { rc = wait4result( ld, msgid, servercredp, msg ); } return( rc ); } /* * Like ldap_simple_bind_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_simple_bind_s( LDAP *ld, const char *dn, const char *passwd, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { struct berval bv; bv.bv_val = (char *)passwd; /* XXXmcs: had to cast away const */ bv.bv_len = ( passwd == NULL ? 0 : strlen( passwd )); return( ldaptool_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, &bv, serverctrls, clientctrls, NULL, msg )); } /* * Like ldap_add_ext_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_add_ext_s( LDAP *ld, const char *dn, LDAPMod **attrs, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { int rc, msgid; if (( rc = ldap_add_ext( ld, dn, attrs, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { /* * 25-April-2000 Note: the next line used to read: * rc = wait4result( ld, msgid, NULL, msg ); * 'msgid' it was changed to 'LDAP_RES_ANY' in order to receive * unsolicited notifications. */ rc = wait4result( ld, LDAP_RES_ANY, NULL, msg ); } return( rc ); } /* * Like ldap_modify_ext_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_modify_ext_s( LDAP *ld, const char *dn, LDAPMod **mods, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { int rc, msgid; if (( rc = ldap_modify_ext( ld, dn, mods, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { rc = wait4result( ld, msgid, NULL, msg ); } return( rc ); } /* * Like ldap_delete_ext_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_delete_ext_s( LDAP *ld, const char *dn, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { int rc, msgid; if (( rc = ldap_delete_ext( ld, dn, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { rc = wait4result( ld, msgid, NULL, msg ); } return( rc ); } /* * Like ldap_compare_ext_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_compare_ext_s( LDAP *ld, const char *dn, const char *attrtype, const struct berval *bvalue, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { int rc, msgid; if (( rc = ldap_compare_ext( ld, dn, attrtype, bvalue, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { rc = wait4result( ld, msgid, NULL, msg ); } return( rc ); } /* * Like ldap_rename_s() but calls wait4result() to display * any referrals returned and report errors in a consistent way. */ int ldaptool_rename_s( LDAP *ld, const char *dn, const char *newrdn, const char *newparent, int deleteoldrdn, LDAPControl **serverctrls, LDAPControl **clientctrls, char *msg ) { int rc, msgid; if (( rc = ldap_rename( ld, dn, newrdn, newparent, deleteoldrdn, serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } else { rc = wait4result( ld, msgid, NULL, msg ); } return( rc ); } /* * Wait for a result, check for and display errors and referrals. * Also recognize and display "Unsolicited notification" messages. * Returns an LDAP error code. */ static int wait4result( LDAP *ld, int msgid, struct berval **servercredp, char *msg ) { LDAPMessage *res; int rc, received_only_unsolicited = 1; while ( received_only_unsolicited ) { res = NULL; if (( rc = ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res )) == -1 ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); return( ldap_get_lderrno( ld, NULL, NULL )); } /* * Special handling for unsolicited notifications: * 1. Parse and display contents. * 2. go back and wait for another (real) result. */ if ( rc == LDAP_RES_EXTENDED && ldap_msgid( res ) == LDAP_RES_UNSOLICITED ) { rc = ldaptool_print_extended_response( ld, res, "Unsolicited response" ); } else { rc = parse_result( ld, res, servercredp, msg, 1 ); received_only_unsolicited = 0; /* we're done */ } } return( rc ); } static int parse_result( LDAP *ld, LDAPMessage *res, struct berval **servercredp, char *msg, int freeit ) { int rc, lderr, errno; int pw_days=0, pw_hrs=0, pw_mins=0, pw_secs=0; /* for pwpolicy */ char **refs = NULL; LDAPControl **ctrls; if (( rc = ldap_parse_result( ld, res, &lderr, NULL, NULL, &refs, &ctrls, 0 )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); ldap_msgfree( res ); return( rc ); } /* check for authentication response control & PWPOLICY control*/ if ( NULL != ctrls ) { int i; char *s; for ( i = 0; NULL != ctrls[i]; ++i ) { if ( 0 == strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_AUTH_RESPONSE )) { s = ctrls[i]->ldctl_value.bv_val; if ( NULL == s ) { s = "Null"; } else if ( *s == '\0' ) { s = "Anonymous"; } fprintf( stderr, gettext("%s: bound as %s\n"), ldaptool_progname, s ); } if ( 0 == strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRING )) { /* Warn the user that their passwd is to expire */ errno = 0; pw_secs = atoi(ctrls[i]->ldctl_value.bv_val); if ( pw_secs > 0 && errno != ERANGE ) { if ( pw_secs > 86400 ) { pw_days = ( pw_secs / 86400 ); pw_secs = ( pw_secs % 86400 ); } if ( pw_secs > 3600 ) { pw_hrs = ( pw_secs / 3600 ); pw_secs = ( pw_secs % 3600 ); } if ( pw_secs > 60 ) { pw_mins = ( pw_secs / 60 ); pw_secs = ( pw_secs % 60 ); } printf(gettext("%s: Warning ! Your password will expire after "), ldaptool_progname); if ( pw_days ) { printf (gettext("%d days, "), pw_days); } if ( pw_hrs ) { printf (gettext("%d hrs, "), pw_hrs); } if ( pw_mins ) { printf (gettext("%d mins, "), pw_mins); } printf(gettext("%d seconds.\n"), pw_secs); } } } ldap_controls_free( ctrls ); } if ( servercredp != NULL && ( rc = ldap_parse_sasl_bind_result( ld, res, servercredp, 0 )) != LDAP_SUCCESS ) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); ldap_msgfree( res ); return( rc ); } if ( freeit ) { ldap_msgfree( res ); } if ( LDAPTOOL_RESULT_IS_AN_ERROR( lderr )) { ldaptool_print_lderror( ld, msg, LDAPTOOL_CHECK4SSL_IF_APPROP ); } if ( refs != NULL ) { ldaptool_print_referrals( refs ); ldap_value_free( refs ); } return( lderr ); } /* * if -M was passed on the command line, create and return a "Manage DSA IT" * LDAPv3 control. If not, return NULL. */ LDAPControl * ldaptool_create_manage_dsait_control( void ) { LDAPControl *ctl; if ( !send_manage_dsait_ctrl ) { return( NULL ); } if (( ctl = (LDAPControl *)calloc( 1, sizeof( LDAPControl ))) == NULL || ( ctl->ldctl_oid = strdup( LDAP_CONTROL_MANAGEDSAIT )) == NULL ) { perror( "calloc" ); exit( LDAP_NO_MEMORY ); } ctl->ldctl_iscritical = 1; return( ctl ); } /* * if -y "dn" was supplied on the command line, create the control */ LDAPControl * ldaptool_create_proxyauth_control( LDAP *ld ) { LDAPControl *ctl = NULL; int rc; if ( !proxyauth_id) return( NULL ); if ( 2 == proxyauth_version ) { rc = ldap_create_proxiedauth_control( ld, proxyauth_id, &ctl); } else { rc = ldap_create_proxyauth_control( ld, proxyauth_id, 1, &ctl); } if ( rc != LDAP_SUCCESS) { if (ctl) ldap_control_free( ctl); return NULL; } return( ctl ); } #ifndef SOLARIS_LDAP_CMD LDAPControl * ldaptool_create_geteffectiveRights_control ( LDAP *ld, const char *authzid, const char **attrlist) { LDAPControl *ctl = NULL; int rc; rc = ldap_create_geteffectiveRights_control( ld, authzid, attrlist, 1, &ctl); if ( rc != LDAP_SUCCESS) { if (ctl) ldap_control_free( ctl); return NULL; } return( ctl ); } #endif /* SOLARIS_LDAP_CMD */ void ldaptool_add_control_to_array( LDAPControl *ctrl, LDAPControl **array) { int i; for (i=0; i< CONTROL_REQUESTS; i++) { if (*(array + i) == NULL) { *(array + i +1) = NULL; *(array + i) = ctrl; return ; } } fprintf(stderr, gettext("%s: failed to store request control!!!!!!\n"), ldaptool_progname); } /* * Dispose of all controls in array and prepare array for reuse. */ void ldaptool_reset_control_array( LDAPControl **array ) { int i; for ( i = 0; i < CONTROL_REQUESTS; i++ ) { if ( array[i] != NULL ) { ldap_control_free( array[i] ); array[i] = NULL; } } } /* * This function calculates control value and its length. *value can * be pointing to plain value, ":b64encoded value" or "bv_len; ++j ) { if ( !isascii( bvp->bv_val[ j ] )) { is_ascii = 0; break; } } return( is_ascii ); } #ifdef LDAP_DEBUG_MEMORY #define LDAPTOOL_ALLOC_FREED 0xF001 #define LDAPTOOL_ALLOC_INUSE 0xF002 static void * ldaptool_debug_alloc( void *ptr, size_t size ) { int *statusp; void *systemptr; if ( ptr == NULL ) { systemptr = NULL; } else { systemptr = (void *)((char *)ptr - sizeof(int)); } if (( statusp = (int *)realloc( systemptr, size + sizeof(int))) == NULL ) { fprintf( stderr, gettext("%s: realloc( 0x%x, %d) failed\n"), ldaptool_progname, systemptr, size ); return( NULL ); } *statusp = LDAPTOOL_ALLOC_INUSE; return( (char *)statusp + sizeof(int)); } static void * ldaptool_debug_realloc( void *ptr, size_t size ) { void *p; if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: => realloc( 0x%x, %d )\n"), ldaptool_progname, ptr, size ); } p = ldaptool_debug_alloc( ptr, size ); if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: 0x%x <= realloc()\n"), ldaptool_progname, p ); } return( p ); } static void * ldaptool_debug_malloc( size_t size ) { void *p; if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: => malloc( %d)\n"), ldaptool_progname, size ); } p = ldaptool_debug_alloc( NULL, size ); if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: 0x%x <= malloc()\n"), ldaptool_progname, p ); } return( p ); } static void * ldaptool_debug_calloc( size_t nelem, size_t elsize ) { void *p; if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: => calloc( %d, %d )\n"), ldaptool_progname, nelem, elsize ); } if (( p = ldaptool_debug_alloc( NULL, nelem * elsize )) != NULL ) { memset( p, 0, nelem * elsize ); } if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: 0x%x <= calloc()\n"), ldaptool_progname, p ); } return( p ); } static void ldaptool_debug_free( void *ptr ) { int *statusp = (int *)((char *)ptr - sizeof(int)); if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, gettext("%s: => free( 0x%x )\n"), ldaptool_progname, ptr ); } if ( ptr == NULL ) { fprintf( stderr, gettext("%s: bad free( 0x0 ) attempted (NULL pointer)\n"), ldaptool_progname ); } else if ( *statusp != LDAPTOOL_ALLOC_INUSE ) { fprintf( stderr, gettext("%s: bad free( 0x%x ) attempted" " (block not in use; status is %d)\n"), ldaptool_progname, ptr, *statusp ); } else { *statusp = LDAPTOOL_ALLOC_FREED; free( statusp ); } } #endif /* LDAP_DEBUG_MEMORY */ #if defined(NET_SSL) /* * Derive key database path from certificate database path and return a * malloc'd string. * * We just return an exact copy of "certdbpath" unless it ends in "cert.db", * "cert5.db", or "cert7.db". In those cases we strip off everything from * "cert" on and append "key.db", "key5.db", or "key3.db" as appropriate. * Strangely enough cert7.db and key3.db go together. */ static char * certpath2keypath( char *certdbpath ) { char *keydbpath, *appendstr; int len, striplen; if ( certdbpath == NULL ) { return( NULL ); } if (( keydbpath = strdup( certdbpath )) == NULL ) { perror( "strdup" ); exit( LDAP_NO_MEMORY ); } len = strlen( keydbpath ); if ( len > 7 && strcasecmp( "cert.db", keydbpath + len - 7 ) == 0 ) { striplen = 7; appendstr = "key.db"; } else if ( len > 8 && strcasecmp( "cert5.db", keydbpath + len - 8 ) == 0 ) { striplen = 8; appendstr = "key5.db"; } else if ( len > 8 && strcasecmp( "cert7.db", keydbpath + len - 8 ) == 0 ) { striplen = 8; appendstr = "key3.db"; } else { striplen = 0; } if ( striplen > 0 ) { /* * The following code assumes that strlen( appendstr ) < striplen! */ strcpy( keydbpath + len - striplen, appendstr ); } return( keydbpath ); } #ifdef LDAP_TOOL_PKCS11 static char * buildTokenCertName( const char *tokenName, const char *certName) { int tokenlen = strlen(tokenName); int len = tokenlen + strlen(certName) +2; char *result; if (( result = malloc( len )) != NULL) { strcpy(result, tokenName); *(result+tokenlen) = ':'; ++tokenlen; strcpy(result+tokenlen, certName); } else { perror("malloc"); exit( LDAP_NO_MEMORY ); } return result; } static int ldaptool_getcertpath( void *context, char **certlocp ) { *certlocp = ssl_certdbpath; if ( ldaptool_verbose ) { if (ssl_certdbpath) { printf(gettext("ldaptool_getcertpath -- %s\n"), ssl_certdbpath ); } else { printf(gettext("ldaptool_getcertpath -- (null)\n")); } } return LDAP_SUCCESS; } int ldaptool_getcertname( void *context, char **certnamep ) { *certnamep = ssl_certname; if ( ldaptool_verbose ) { if (ssl_certname) { printf(gettext("ldaptool_getcertname -- %s\n"), *certnamep); } else { printf(gettext("ldaptool_getcertname -- (null)\n")); } } return LDAP_SUCCESS; } int ldaptool_getkeypath(void *context, char **keylocp ) { *keylocp = ssl_keydbpath; if ( ldaptool_verbose ) { if (ssl_keydbpath) { printf(gettext("ldaptool_getkeypath -- %s\n"),*keylocp); } else { printf(gettext("ldaptool_getkeypath -- (null)\n")); } } return LDAP_SUCCESS; } int ldaptool_gettokenname( void *context, char **tokennamep ) { *tokennamep = pkcs_token; if ( ldaptool_verbose ) { if (pkcs_token) { printf(gettext("ldaptool_gettokenname -- %s\n"),*tokennamep); } else { printf(gettext("ldaptool_gettokenname -- (null)\n")); } } return LDAP_SUCCESS; } int ldaptool_gettokenpin( void *context, const char *tokennamep, char **tokenpinp) { #if 0 char *localtoken; #endif /* XXXceb this stuff is removed for the time being. * This function should return the pin from ssl_password */ *tokenpinp = ssl_passwd; return LDAP_SUCCESS; #if 0 ldaptool_gettokenname( NULL, &localtoken); if (strcmp( localtoken, tokennamep)) *tokenpinp = pkcs_pin; else *tokenpinp = NULL; if ( ldaptool_verbose ) { if (pkcs_pin) { printf(gettext("ldaptool_getokenpin --%s\n"), tokenpinp); } else { printf(gettext("ldaptool_getokenpin -- (null)\n")); } } return LDAP_SUCCESS; #endif } int ldaptool_getmodpath( void *context, char **modulep ) { *modulep = ssl_secmodpath; if ( ldaptool_verbose ) { if (ssl_secmodpath) { printf(gettext("ldaptool_getmodpath -- %s\n"), *modulep); } else { printf(gettext("ldaptool_getmodpath -- (null)\n")); } } return LDAP_SUCCESS; } int ldaptool_getdonglefilename( void *context, char **filename ) { *filename = ssl_donglefile; if ( ldaptool_verbose ) { if (ssl_donglefile) { printf(gettext("ldaptool_getdonglefilename -- %s\n"), *filename); } else { printf(gettext("ldaptool_getdonglefilename -- (null)\n")); } } return LDAP_SUCCESS; } static int ldaptool_setcallbacks( struct ldapssl_pkcs_fns *pfns) { pfns->pkcs_getcertpath = (int (*)(void *, char **))ldaptool_getcertpath; pfns->pkcs_getcertname = (int (*)(void *, char **))ldaptool_getcertname; pfns->pkcs_getkeypath = (int (*)(void *, char **)) ldaptool_getkeypath; pfns->pkcs_getmodpath = (int (*)(void *, char **)) ldaptool_getmodpath; pfns->pkcs_getpin = (int (*)(void *, const char*, char **)) ldaptool_gettokenpin; pfns->pkcs_gettokenname = (int (*)(void *, char **)) ldaptool_gettokenname; pfns->pkcs_getdonglefilename = (int (*)(void *, char **)) ldaptool_getdonglefilename; pfns->local_structure_id=PKCS_STRUCTURE_ID; return LDAP_SUCCESS; } #ifdef FORTEZZA static int ldaptool_fortezza_init( int exit_on_error ) { int rc, errcode; if ( fortezza_personality == NULL && fortezza_cardmask == 0 ) { /* no FORTEZZA desired */ SSL_EnableGroup( SSL_GroupFortezza, DSFalse ); /* disable FORTEZZA */ return( 0 ); } if (( rc = FortezzaConfigureServer( ldaptool_fortezza_getpin, fortezza_cardmask, fortezza_personality, ldaptool_fortezza_alert, NULL, &errcode, fortezza_krlfile )) < 0 ) { fprintf( stderr, "%s: FORTEZZA initialization failed (error %d - %s)\n", ldaptool_progname, errcode, ldaptool_fortezza_err2string( errcode )); if ( exit_on_error ) { exit( LDAP_LOCAL_ERROR ); } SSL_EnableGroup( SSL_GroupFortezza, DSFalse ); /* disable FORTEZZA */ return( -1 ); } SSL_EnableGroup( SSL_GroupFortezza, DSTrue ); /* enable FORTEZZA */ return( 0 ); } static int ldaptool_fortezza_alert( void *arg, PRBool onOpen, char *string, int value1, void *value2 ) { fprintf( stderr, "%s: FORTEZZA alert: ", ldaptool_progname ); fprintf( stderr, string, value1, value2 ); fprintf( stderr, "\n" ); return( 1 ); } static void * ldaptool_fortezza_getpin( char **passwordp ) { *passwordp = fortezza_pin; return( *passwordp ); } /* * convert a Fortezza error code (as returned by FortezzaConfigureServer() * into a human-readable string. * * Error strings are intentionally similar to those found in * ns/netsite/lib/libadmin/httpcon.c */ static char * ldaptool_fortezza_err2string( int err ) { char *s; switch( err ) { case FORTEZZA_BADPASSWD: s = "invalid pin number"; break; case FORTEZZA_BADCARD: s = "bad or missing card"; break; case FORTEZZA_MISSING_KRL: s = "bad or missing compromised key list"; break; case FORTEZZA_CERT_INIT_ERROR: s = "unable to initialize certificate cache. either a cert on " "the card is bad, or an old FORTEZZA certificate is in a" "readonly database"; break; case FORTEZZA_EXPIRED_CERT: s = "unable to verify certificate"; break; default: s = "unknown error"; } return( s ); } #endif /* FORTEZZA */ #endif /* LDAP_TOOL_PKCS11 */ #endif /* NET_SSL */ int ldaptool_boolean_str2value ( const char *ptr, int strict ) { if (strict) { if ( !(strcasecmp(ptr, "true"))) { return 1; } else if ( !(strcasecmp(ptr, "false"))) { return 0; } else { return (-1); } } else { if ( !(strcasecmp(ptr, "true")) || !(strcasecmp(ptr, "t")) || !(strcmp(ptr, "1")) ) { return (1); } else if ( !(strcasecmp(ptr, "false")) || !(strcasecmp(ptr, "f")) || !(strcmp(ptr, "0")) ) { return (0); } else { return (-1); } } } FILE * ldaptool_open_file(const char *filename, const char *mode) { #ifdef _LARGEFILE64_SOURCE return fopen64(filename, mode); #else return fopen(filename, mode); #endif } #ifdef later /* Functions for list in ldapdelete.c */ void L_Init(Head *list) { if(list) { list->first = NULL; list->last = NULL; list->count = 0; } } void L_Insert(Element *Node, Head *HeadNode) { if (!Node || !HeadNode) return; Node->right = NULL; if (HeadNode->first == NULL) { Node->left= NULL; HeadNode->last = HeadNode->first = Node; } else { Node->left = HeadNode->last; HeadNode->last = Node->left->right = Node; } HeadNode->count++; } void L_Remove(Element *Node, Head *HeadNode) { Element *traverse = NULL; Element *prevnode = NULL; if(!Node || !HeadNode) return; for(traverse = HeadNode->first; traverse; traverse = traverse->right) { if(traverse == Node) { if(HeadNode->first == traverse) { HeadNode->first = traverse->right; } if(HeadNode->last == traverse) { HeadNode->last = prevnode; } traverse = traverse->right; if(prevnode != NULL) { prevnode->right = traverse; } if(traverse != NULL) { traverse->left = prevnode; } HeadNode->count--; return; } else /* traverse != node */ { prevnode = traverse; } } } #endif #ifdef HAVE_SASL_OPTIONS /* * Function checks for valid args, returns an error if not found * and sets SASL params from command line */ static int saslSetParam(char *saslarg) { char *attr = NULL; attr = strchr(saslarg, '='); if (attr == NULL) { fprintf( stderr, gettext("Didn't find \"=\" character in %s\n"), saslarg); return (-1); } *attr = '\0'; attr++; if (!strcasecmp(saslarg, "secProp")) { if ( sasl_secprops != NULL ) { fprintf( stderr, gettext("secProp previously specified\n")); return (-1); } if (( sasl_secprops = strdup(attr)) == NULL ) { perror ("malloc"); exit (LDAP_NO_MEMORY); } } else if (!strcasecmp(saslarg, "realm")) { if ( sasl_realm != NULL ) { fprintf( stderr, gettext("Realm previously specified\n")); return (-1); } if (( sasl_realm = strdup(attr)) == NULL ) { perror ("malloc"); exit (LDAP_NO_MEMORY); } } else if (!strcasecmp(saslarg, "authzid")) { if (sasl_username != NULL) { fprintf( stderr, gettext("Authorization name previously specified\n")); return (-1); } if (( sasl_username = strdup(attr)) == NULL ) { perror ("malloc"); exit (LDAP_NO_MEMORY); } } else if (!strcasecmp(saslarg, "authid")) { if ( sasl_authid != NULL ) { fprintf( stderr, gettext("Authentication name previously specified\n")); return (-1); } if (( sasl_authid = strdup(attr)) == NULL) { perror ("malloc"); exit (LDAP_NO_MEMORY); } } else if (!strcasecmp(saslarg, "mech")) { if ( sasl_mech != NULL ) { fprintf( stderr, gettext("Mech previously specified\n")); return (-1); } if (( sasl_mech = strdup(attr)) == NULL) { perror ("malloc"); exit (LDAP_NO_MEMORY); } } else { fprintf (stderr, gettext("Invalid attribute name %s\n"), saslarg); return (-1); } return 0; } #endif /* HAVE_SASL_OPTIONS */ /* * check for and report input or output error on named stream * return ldap_err or ferror() (ldap_err takes precedence) * assume that fflush() already has been called if needed. * don't want to fflush() an input stream. */ int ldaptool_check_ferror(FILE * stream, const int ldap_err, const char *msg) { int err = 0; if ((err = ferror(stream)) != 0 ) { fprintf(stderr, gettext("%s: ERROR: "), ldaptool_progname); perror(msg); err = LDAP_LOCAL_ERROR; } /* * reporting LDAP error code is more important than * reporting errors from ferror() */ if (ldap_err == LDAP_SUCCESS) { return(err); } else { return(ldap_err); } }