RetroZilla/directory/c-sdk/ldap/clients/tools/common.c
2015-10-20 23:03:22 -04:00

2203 lines
57 KiB
C

/* ***** 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 <nspr.h> /* for PR_Cleanup() */
#include <stdlib.h>
#include <time.h> /* 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|:<fileurl]]\n" );
fprintf( stderr, "\t\tcriticality is a boolean value (default is false)\n" );
}
/* globals */
char *ldaptool_charset = "";
char *ldaptool_host = LDAPTOOL_DEFHOST;
char *ldaptool_host2 = LDAPTOOL_DEFHOST;
int ldaptool_port = LDAP_PORT;
int ldaptool_port2 = LDAP_PORT;
int ldaptool_verbose = 0;
int ldaptool_not = 0;
FILE *ldaptool_fp = NULL;
FILE *password_fp = NULL;
char *ldaptool_progname = "";
char *ldaptool_nls_lang = NULL;
char *proxyauth_id = NULL;
int proxyauth_version = 2; /* use newer proxy control */
LDAPControl *ldaptool_request_ctrls[CONTROL_REQUESTS] = {0};
#ifdef LDAP_DEBUG
int ldaptool_dbg_lvl = 0;
#endif /* LDAP_DEBUG */
/* statics */
static char *binddn = NULL;
static char *passwd = NULL;
static int send_auth_response_ctrl = 0;
static int user_specified_port = 0;
static int user_specified_port2 = 0;
static int chase_referrals = 1;
static int lib_version_mismatch_is_fatal = 1;
static int ldversion = -1; /* use default */
static int refhoplim = LDAPTOOL_DEFREFHOPLIMIT;
static int send_manage_dsait_ctrl = 0;
static int prompt_password = 0;
#ifndef NO_LIBLCACHE
static char *cache_config_file = NULL;
#endif /* !NO_LIBLCACHE */
#if defined(NET_SSL)
static int secure = 0;
static int isZ = 0;
static int isN = 0;
static int isW = 0;
static int isw = 0;
static int isD = 0;
static int isj = 0;
static char *ssl_certdbpath = LDAPTOOL_DEFCERTDBPATH;
static char *ssl_keydbpath = LDAPTOOL_DEFKEYDBPATH;
/*
static char *ssl_keyname = NULL;
*/
static char *ssl_certname = NULL;
static char *ssl_passwd = NULL;
#ifdef LDAP_TOOL_PKCS11
static char *ssl_secmodpath = NULL;
static char *pkcs_token = NULL;
static char *ssl_donglefile = NULL;
#if 0
static char *pkcs_pin = NULL;
#endif
static struct ldapssl_pkcs_fns local_pkcs_fns =
{0,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL };
#ifdef FORTEZZA
static uint32 fortezza_cardmask = 0;
static char *fortezza_personality = NULL;
static char *fortezza_krlfile = NULL;
static char *fortezza_pin = NULL;
#endif /* FORTEZZA */
#endif /* LDAP_TOOL_PKCS11 */
#endif /* NET_SSL */
/*
* Handle general initialization and options that are common to all of
* the LDAP tools.
* Handle options that are common to all of the LDAP tools.
* Note the the H option is included here but handled via the
* extra_opt_callback function (along with any "extra_opts" ).
*
* Return: final value for optind or -1 if usage should be displayed (for
* some fatal errors, we call exit here).
*/
int
ldaptool_process_args( int argc, char **argv, char *extra_opts,
int two_hosts, void (*extra_opt_callback)( int option, char *optarg ))
{
int rc, i, hostnum;
char *optstring, *common_opts;
extern char *optarg;
extern int optind;
LDAPAPIInfo ldai;
char *ctrl_arg, *ctrl_oid=NULL, *ctrl_value=NULL;
int ctrl_criticality=0, vlen;
LDAPControl *ldctrl;
/*
* Set program name global based on argv[0].
*/
if (( ldaptool_progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
ldaptool_progname = argv[ 0 ];
} else {
++ldaptool_progname;
}
#ifdef LDAPTOOL_DEBUG_MEMORY
{
struct ldap_memalloc_fns mafns = {
ldaptool_debug_malloc,
ldaptool_debug_calloc,
ldaptool_debug_realloc,
ldaptool_debug_free
};
ldap_set_option( NULL, LDAP_OPT_MEMALLOC_FN_PTRS, &mafns );
}
#endif /* LDAPTOOL_DEBUG_MEMORY */
#ifdef LDAP_DEBUG
i = LDAP_DEBUG_ANY;
ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, (void *) &i);
#endif
/*
* Perform a sanity check on the revision of the LDAP API library to
* make sure it is at least as new as the one we were compiled against.
* If the API implementation is from the same vendor as we were compiled
* against, we also check to make sure the vendor version is at least
* as new as the library we were compiled against.
*
* Version differences are fatal unless the -0 option is passed on the
* tool command line (that's a zero, not an oh). We check for the
* presence of -0 in a crude way to it must appear by itself in argv.
*/
for ( i = 1; i < argc; ++i ) {
if ( strcmp( argv[i], "-0" ) == 0 ) {
lib_version_mismatch_is_fatal = 0;
break;
}
}
memset( &ldai, 0, sizeof(ldai));
ldai.ldapai_info_version = LDAP_API_INFO_VERSION;
if (( rc = ldap_get_option( NULL, LDAP_OPT_API_INFO, &ldai )) != 0 ) {
fprintf( stderr, "%s: unable to retrieve LDAP library version"
" information;\n\tthis program requires an LDAP library that"
" implements revision\n\t%d or greater of the LDAP API.\n",
ldaptool_progname, LDAP_API_VERSION );
if ( lib_version_mismatch_is_fatal ) {
exit( LDAP_LOCAL_ERROR );
}
} else if ( ldai.ldapai_api_version < LDAP_API_VERSION ) {
fprintf( stderr, "%s: this program requires an LDAP library that"
" implements revision\n\t%d or greater of the LDAP API;"
" running with revision %d.\n",
ldaptool_progname, LDAP_API_VERSION, ldai.ldapai_api_version );
if ( lib_version_mismatch_is_fatal ) {
exit( LDAP_LOCAL_ERROR );
}
} else if ( strcmp( ldai.ldapai_vendor_name, LDAP_VENDOR_NAME ) == 0
&& ldai.ldapai_vendor_version < LDAP_VENDOR_VERSION ) {
fprintf( stderr, "%s: this program requires %s's LDAP\n"
"\tlibrary version %2.2f or greater; running with"
" version %2.2f.\n",
ldaptool_progname, LDAP_VENDOR_NAME,
(float)LDAP_VENDOR_VERSION / 100,
(float)ldai.ldapai_vendor_version / 100 );
if ( lib_version_mismatch_is_fatal ) {
exit( LDAP_LOCAL_ERROR );
}
}
/*
* Process command line options.
*/
if ( extra_opts == NULL ) {
extra_opts = "";
}
common_opts = "nvEMRHZ0d:D:f:h:j:I:K:N:O:P:p:Q:W:w:V:X:m:i:k:y:Y:J:";
/* note: optstring must include room for liblcache "C:" option */
if (( optstring = (char *) malloc( strlen( extra_opts ) + strlen( common_opts )
+ 3 )) == NULL ) {
perror( "malloc" );
exit( LDAP_NO_MEMORY );
}
#ifdef NO_LIBLCACHE
sprintf( optstring, "%s%s", common_opts, extra_opts );
#else
sprintf( optstring, "%s%sC:", common_opts, extra_opts );
#endif
hostnum = 0;
while ( (i = getopt( argc, argv, optstring )) != EOF ) {
switch( i ) {
case 'n': /* do Not do any LDAP operations */
++ldaptool_not;
break;
case 'v': /* verbose mode */
++ldaptool_verbose;
break;
case 'd':
#ifdef LDAP_DEBUG
ldaptool_dbg_lvl = atoi( optarg ); /* */
ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
(void *)&ldaptool_dbg_lvl);
ldaptool_dbg_lvl |= LDAP_DEBUG_ANY;
ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL,
(void *)&ldaptool_dbg_lvl);
#else /* LDAP_DEBUG */
fprintf( stderr, "compile with -DLDAP_DEBUG for debugging\n" );
#endif /* LDAP_DEBUG */
break;
case 'R': /* don't automatically chase referrals */
chase_referrals = 0;
break;
#ifndef NO_LIBLCACHE
case 'C': /* search local database */
cache_config_file = strdup( optarg );
break;
#endif
case 'f': /* input file */
if ( optarg[0] == '-' && optarg[1] == '\0' ) {
ldaptool_fp = stdin;
} else if (( ldaptool_fp = fopen( optarg, "r" )) == NULL ) {
perror( optarg );
exit( LDAP_PARAM_ERROR );
}
break;
case 'h': /* ldap host */
if ( hostnum == 0 ) {
ldaptool_host = strdup( optarg );
} else {
ldaptool_host2 = strdup( optarg );
}
++hostnum;
break;
case 'D': /* bind DN */
isD = 1;
binddn = strdup( optarg );
break;
case 'E': /* expose bind identity via auth. response control */
++send_auth_response_ctrl;
break;
case 'p': /* ldap port */
if ( !user_specified_port ) {
++user_specified_port;
ldaptool_port = atoi( optarg );
} else {
++user_specified_port2;
ldaptool_port2 = atoi( optarg );
}
break;
#if defined(NET_SSL)
case 'P': /* path to security database */
secure = 1; /* do SSL encryption */
ssl_certdbpath = strdup( optarg );
if (NULL== ssl_keydbpath)
{
ssl_keydbpath = certpath2keypath( ssl_certdbpath );
}
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;
case 'K': /* location of key database */
/* if keydb path is not null, then it was probably strdup by the
* cert db option. free it first
*/
if (ssl_keydbpath)
free( ssl_keydbpath);
ssl_keydbpath = strdup( optarg );
if (NULL == ssl_keydbpath)
{
perror("malloc");
exit( LDAP_NO_MEMORY );
}
break;
case 'W': /* SSL key password */
ssl_passwd = strdup( optarg );
if (NULL == ssl_passwd)
{
perror("malloc");
exit( LDAP_NO_MEMORY );
}
isW = 1;
break;
#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;
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 from file */
isj = 1;
if ((password_fp = fopen( optarg, "r" )) == NULL ) {
fprintf(stderr, "%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, "%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;
case 'Y': /* new (version 2 ) proxied authorization control */
/*FALLTHRU*/
proxyauth_id = strdup(optarg);
if (NULL == proxyauth_id)
{
perror( "malloc" );
exit( LDAP_NO_MEMORY );
}
break;
case '0': /* zero -- override LDAP library version check */
break; /* already handled above */
case 'J':
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, "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 "<fileurl".
*/
static int
calculate_ctrl_value( const char *value,
char **ctrl_value, int *vlen)
{
int b64;
if (*value == ':') {
value++;
b64 = 1;
} else {
b64 = 0;
}
*ctrl_value = (char *)value;
if ( b64 ) {
if (( *vlen = ldif_base64_decode( (char *)value,
(unsigned char *)value )) < 0 ) {
fprintf( stderr,
"Unable to decode base64 control value \"%s\"\n", value);
return( -1 );
}
} else {
*vlen = (int)strlen(*ctrl_value);
}
return( 0 );
}
/*
* Parse the optarg from -J option of ldapsearch
* and within LDIFfile for ldapmodify. Take ctrl_arg
* (the whole string) and divide it into oid, criticality
* and value. This function breaks down original ctrl_arg
* with '\0' in places. Also, calculate length of valuestring.
*/
int
ldaptool_parse_ctrl_arg(char *ctrl_arg, char sep,
char **ctrl_oid, int *ctrl_criticality,
char **ctrl_value, int *vlen)
{
char *s, *p, *d;
int strict;
/* Initialize passed variables with default values */
*ctrl_oid = *ctrl_value = NULL;
*ctrl_criticality = 0;
*vlen = 0;
strict = (sep == ' ' ? 1 : 0);
if(!(s=strchr(ctrl_arg, sep))) {
/* Possible values of ctrl_arg are
* oid[:value|::b64value|:<fileurl] within LDIF, i.e. sep=' '
* oid from command line option, i.e. sep=':'
*/
if (sep == ' ') {
if (!(s=strchr(ctrl_arg, ':'))) {
*ctrl_oid = ctrl_arg;
}
else {
/* ctrl_arg is of oid:[value|:b64value|<fileurl]
* form in the LDIF record. So, grab the oid and then
* jump to continue the parsing of ctrl_arg.
* 's' is pointing just after oid ends.
*/
*s++ = '\0';
*ctrl_oid = ctrl_arg;
return (calculate_ctrl_value( s, ctrl_value, vlen ));
}
} else {
/* oid - from command line option, i.e. sep=':' */
*ctrl_oid = ctrl_arg;
}
}
else {
/* Possible values of ctrl_arg are
* oid:criticality[:value|::b64value|:<fileurl] - command line
* oid criticality[:value|::b64value|:<fileurl] - LDIF
* And 's' is pointing just after oid ends.
*/
if (*(s+1) == '\0') {
fprintf( stderr, "missing value\n" );
return( -1 );
}
*s = '\0';
*ctrl_oid = ctrl_arg;
p = ++s;
if(!(s=strchr(p, ':'))) {
if ( (*ctrl_criticality = ldaptool_boolean_str2value(p, strict))
== -1 ) {
fprintf( stderr, "Invalid criticality value\n" );
return( -1 );
}
}
else {
if (*(s+1) == '\0') {
fprintf( stderr, "missing value\n" );
return ( -1 );
}
*s++ = '\0';
if ( (*ctrl_criticality = ldaptool_boolean_str2value(p, strict))
== -1 ) {
fprintf( stderr, "Invalid criticality value\n" );
return ( -1 );
}
return (calculate_ctrl_value( s, ctrl_value, vlen ));
}
}
return( 0 );
}
/*
* callback function for LDAP bind credentials
*/
static int
LDAP_CALL
LDAP_CALLBACK
get_rebind_credentials( LDAP *ld, char **whop, char **credp,
int *methodp, int freeit, void* arg )
{
if ( !freeit ) {
*whop = binddn;
*credp = passwd;
*methodp = LDAP_AUTH_SIMPLE;
}
return( LDAP_SUCCESS );
}
/*
* return pointer to pathname to temporary directory.
* First we see if the environment variable "TEMP" is set and use it.
* Then we see if the environment variable "TMP" is set and use it.
* If this fails, we use "/tmp" on UNIX and fail on Windows.
*/
char *
ldaptool_get_tmp_dir( void )
{
char *p;
int offset;
if (( p = getenv( "TEMP" )) == NULL && ( p = getenv( "TMP" )) == NULL ) {
#ifdef _WINDOWS
fprintf( stderr, "%s: please set the TEMP environment variable.\n",
ldaptool_progname );
exit( LDAP_LOCAL_ERROR );
#else
return( "/tmp" ); /* last resort on UNIX */
#endif
}
/*
* remove trailing slash if present
*/
offset = strlen( p ) - 1;
if ( p[offset] == '/'
#ifdef _WINDOWS
|| p[offset] == '\\'
#endif
) {
if (( p = strdup( p )) == NULL ) {
perror( "strdup" );
exit( LDAP_NO_MEMORY );
}
p[offset] = '\0';
}
return( p );
}
int
ldaptool_berval_is_ascii( const struct berval *bvp )
{
unsigned long j;
int is_ascii = 1; /* optimistic */
for ( j = 0; j < bvp->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);
}
}
}