/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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 the Initial Developer are Copyright (C) 1998-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * code that is shared by two or more of the LDAP command line tools */ #include "ldaptool.h" #include "fileurl.h" #ifdef LDAP_TOOL_ARGPIN #include "argpin.h" #include "ntuserpin.h" #endif /* LDAP_TOOL_ARGPIN */ #include /* for PR_Cleanup() */ #include #include /* for time() and ctime() */ 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 /* * 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, " -n\t\tshow what would be done but don't actually do it\n" ); fprintf( stderr, " -v\t\trun in verbose mode (diagnostics to standard output)\n" ); if ( two_hosts ) { fprintf( stderr, " -h host\tLDAP server1 name or IP address (default: %s)\n", LDAPTOOL_DEFHOST ); fprintf( stderr, " -p port\tLDAP server1 TCP port number (default: %d)\n", LDAP_PORT ); fprintf( stderr, " -h host\tLDAP server2 name or IP address (default: %s)\n", LDAPTOOL_DEFHOST ); fprintf( stderr, " -p port\tLDAP server2 TCP port number (default: %d)\n", LDAP_PORT ); } else { fprintf( stderr, " -h host\tLDAP server name or IP address (default: %s)\n", LDAPTOOL_DEFHOST ); fprintf( stderr, " -p port\tLDAP server TCP port number (default: %d)\n", LDAP_PORT ); } fprintf( stderr, " -V n\tLDAP protocol version number (%d or %d; default: %d)\n", LDAP_VERSION2, LDAP_VERSION3, LDAP_VERSION3 ); #if defined(NET_SSL) fprintf( stderr, " -Z\t\tmake an SSL-encrypted connection\n" ); fprintf( stderr, " -P pathname\tpath to SSL certificate database (default: current directory)\n" ); fprintf( stderr, " -N\t\tname of certificate to use for SSL client authentication\n" ); fprintf( stderr, " -K pathname\tpath to key database to use for SSL client authentication\n" ); fprintf( stderr, " \t\t(default: path to certificate database provided with -P option)\n" ); #ifdef LDAP_TOOL_PKCS11 fprintf( stderr, " -m pathname\tpath to security module database\n"); #endif /* LDAP_TOOL_PKCS11 */ fprintf( stderr, " -W\t\tSSL key password\n" ); #ifdef LDAP_TOOL_PKCS11 fprintf( stderr, " -Q [token][:certificate name]\tPKCS 11\n" ); fprintf( stderr, " -X pathname\tFORTEZZA compromised key list (CKL)\n" ); fprintf( stderr, " -I pin\tcard password file\n" ); #endif /* LDAP_TOOL_PKCS11 */ #endif /* NET_SSL */ fprintf( stderr, " -D binddn\tbind dn\n" ); fprintf( stderr, " -w passwd\tbind passwd (for simple authentication)\n" ); fprintf( stderr, " -w - \tprompt for bind passwd (for simple authentication)\n" ); fprintf( stderr, " -j file\tread bind passwd from 'file' (for simple authentication)\n" ); fprintf( stderr, " -E\t\task server to expose (report) bind identity\n" ); #ifdef LDAP_DEBUG fprintf( stderr, " -d level\tset LDAP debugging level to `level'\n" ); #endif fprintf( stderr, " -R\t\tdo not automatically follow referrals\n" ); fprintf( stderr, " -O limit\tmaximum number of referral hops to traverse (default: %d)\n", LDAPTOOL_DEFREFHOPLIMIT ); fprintf( stderr, " -M\t\tmanage references (treat them as regular entries)\n" ); fprintf( stderr, " -0\t\tignore LDAP library version mismatches\n" ); #ifndef NO_LIBLCACHE fprintf( stderr, " -C cfgfile\tuse local database described by cfgfile\n" ); #endif fprintf( stderr, " -i charset\tcharacter set for command line input (default taken from locale)\n" ); fprintf( stderr, " -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, " -y proxydn\tDN used for proxy authorization\n" ); #endif fprintf( stderr, " -Y proxyid\tproxied authorization id,\n" ); fprintf( stderr, " \te.g, dn:uid=bjensen,dc=example,dc=com\n" ); fprintf( stderr, " -H\t\tdisplay usage information\n" ); fprintf( stderr, " -J controloid[:criticality[:value|::b64value|:ldctl_value), 1 /* recognize file URLs */, 0 /* always try file */, 1 /* report errors */ ); if ((rc = ldaptool_fileurlerr2ldaperr( rc )) != LDAP_SUCCESS) { fprintf( stderr, "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; default: (*extra_opt_callback)( i, optarg ); } } /* If '-Z' is specified, check if '-P' is specified too. */ if ( isN || isW ) { if ( !isZ ) { printf( "%s: with -N, -W options, please specify -Z\n\n", ldaptool_progname ); return (-1); } } if ( isj && isw ) { fprintf(stderr, "%s: -j and -w options cannot be specified simultaneously\n\n", ldaptool_progname ); return (-1); } if ( (isj || isw) && !isD ) { fprintf(stderr, "%s: with -j, -w options, please specify -D\n\n", ldaptool_progname ); return (-1); } if (prompt_password != 0) { char *password_string = "Enter bind password: "; char pbuf[257]; #if defined(_WIN32) 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, "%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, "%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; } /* * 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( "%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 ); } 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, "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( " LDAP API Extensions:\n", fp ); for ( i = 0; aip->ldapai_extensions[i] != NULL; i++ ) { fprintf( fp, " %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, " %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, " (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) { printf("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){ printf("Security Initialization: Unable to create NTUserPinObj " "(%d)", PR_GetError()); exit( LDAP_LOCAL_ERROR ); } if ((err = SVRCORE_CreateArgPinObj(&ArgPinObj, tokenName, pin, (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success) { printf("Security Initialization: Unable to create ArgPinObj " "(%d)", PR_GetError()); return -1; } SVRCORE_RegisterPinObj((SVRCOREPinObj *)ArgPinObj); } else { if ((err = SVRCORE_CreateNTUserPinObj(&NTUserPinObj)) != SVRCORE_Success){ printf("Security Initialization: Unable to create NTUserPinObj " "(%d)", PR_GetError()); return -1; } if (filename && *filename) { if ((err = SVRCORE_CreateFilePinObj(&FilePinObj, filename)) != SVRCORE_Success) { printf("Security Initialization: Unable to create FilePinObj " "(%d)", PR_GetError()); return -1; } if ((err = SVRCORE_CreateAltPinObj(&AltPinObj, (SVRCOREPinObj *)FilePinObj, (SVRCOREPinObj *)NTUserPinObj)) != SVRCORE_Success) { printf("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( "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 */ rc = PORT_GetError(); fprintf( stderr, "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 */ rc = PORT_GetError(); fprintf( stderr, "SSL initialization failed: error %d (%s)\n", rc, ldapssl_err2string( rc )); exit( LDAP_LOCAL_ERROR ); } #endif /* LDAP_TOOL_PKCS11 */ 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 */ ld = prldap_init( host, port, 0 /* not shared across threads */ ); } #else /* In order to support IPv6, we use NSPR I/O */ ld = prldap_init( host, port, 0 /* not shared across threads */ ); #endif 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; 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 ) { return; } /* * do the bind, backing off one LDAP version if necessary */ conv = ldaptool_local2UTF8( binddn ); /* * 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 */ } 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, "%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 */ } } 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 ); if ( secure && check4ssl != LDAPTOOL_CHECK4SSL_NEVER ) { if ( check4ssl == LDAPTOOL_CHECK4SSL_ALWAYS || ( lderr == LDAP_SERVER_DOWN )) { int sslerr = PORT_GetError(); fprintf( stderr, "\tSSL error %d (%s)\n", sslerr, ldapssl_err2string( sslerr )); } } 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, "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, "%s: Notice of Disconnection\n", msg ); } else { fprintf( stderr, "%s: OID %s\n", msg, oid ); } ldap_memfree( oid ); } else { fprintf( stderr, "%s: missing OID\n", msg ); } if ( data != NULL ) { fprintf( stderr, "%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, "%s: bound as %s\n", ldaptool_progname, s ); } if ( 0 == strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRING )) { /* Warn the user his 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("%s: Warning ! Your password will expire after ", ldaptool_progname); if ( pw_days ) { printf ("%d days, ", pw_days); } if ( pw_hrs ) { printf ("%d hrs, ", pw_hrs); } if ( pw_mins ) { printf ("%d mins, ", pw_mins); } printf("%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 ); } 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, "%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, "%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, "%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, "%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, "%s: => malloc( %d)\n", ldaptool_progname, size ); } p = ldaptool_debug_alloc( NULL, size ); if ( ldaptool_dbg_lvl & LDAP_DEBUG_TRACE ) { fprintf( stderr, "%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, "%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, "%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, "%s: => free( 0x%x )\n", ldaptool_progname, ptr ); } if ( ptr == NULL ) { fprintf( stderr, "%s: bad free( 0x0 ) attempted (NULL pointer)\n", ldaptool_progname ); } else if ( *statusp != LDAPTOOL_ALLOC_INUSE ) { fprintf( stderr, "%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("ldaptool_getcertpath -- %s\n", ssl_certdbpath ); } else { printf("ldaptool_getcertpath -- (null)\n"); } } return LDAP_SUCCESS; } int ldaptool_getcertname( void *context, char **certnamep ) { *certnamep = ssl_certname; if ( ldaptool_verbose ) { if (ssl_certname) { printf("ldaptool_getcertname -- %s\n", *certnamep); } else { printf("ldaptool_getcertname -- (null)\n"); } } return LDAP_SUCCESS; } int ldaptool_getkeypath(void *context, char **keylocp ) { *keylocp = ssl_keydbpath; if ( ldaptool_verbose ) { if (ssl_keydbpath) { printf("ldaptool_getkeypath -- %s\n",*keylocp); } else { printf("ldaptool_getkeypath -- (null)\n"); } } return LDAP_SUCCESS; } int ldaptool_gettokenname( void *context, char **tokennamep ) { *tokennamep = pkcs_token; if ( ldaptool_verbose ) { if (pkcs_token) { printf("ldaptool_gettokenname -- %s\n",*tokennamep); } else { printf("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("ldaptool_getokenpin --%s\n", tokenpinp); } else { printf("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("ldaptool_getmodpath -- %s\n", *modulep); } else { printf("ldaptool_getmodpath -- (null)\n"); } } return LDAP_SUCCESS; } int ldaptool_getdonglefilename( void *context, char **filename ) { *filename = ssl_donglefile; if ( ldaptool_verbose ) { if (ssl_donglefile) { printf("ldaptool_getdonglefilename -- %s\n", *filename); } else { printf("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); } } }