mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
b5494457d8
This could cause problems on odd systems. The generic headers should be extended as needed to include necessary system headers or, if necessary, make explicit declarations. Extended ac/string.h header to look for string.h/strings.h if STDC_HEADERS is not defined. Also provide basic declarations for str*() functions. This could cause problems on odd systems. Extended ac/unistd.h header to define basic declaration for misc functions that might be missing from headers. This includes externs for getenv(), getopt(), mktemp(), tempname(). Protect fax500.h from multiple inclusion. Moved includes of system/generic headers back to source files. Made mail500 helper functions static. Fixed includes of ctype.h, signal.h, etc. to use generics. lutil/tempname.c: was including stdlib.h twice, one should stdio.h. Wrapped <sys/resource.h> with HAVE_SYS_RESOURCE_H. lber/io.c/ber_get_next(): Changed noctets back to signed. Used with BerRead which expects signed int as second arg and returns signed int.
435 lines
9.9 KiB
C
435 lines
9.9 KiB
C
/*
|
|
* Copyright (c) 1991, 1992 Regents of the University of Michigan.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this notice is preserved and that due credit is given
|
|
* to the University of Michigan at Ann Arbor. The name of the University
|
|
* may not be used to endorse or promote products derived from this
|
|
* software without specific prior written permission. This software
|
|
* is provided ``as is'' without express or implied warranty.
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <ac/ctype.h>
|
|
#include <ac/krb.h>
|
|
#include <ac/string.h>
|
|
#include <ac/time.h>
|
|
#include <ac/unistd.h>
|
|
|
|
#ifdef HAVE_PWD_H
|
|
#include <pwd.h>
|
|
#endif
|
|
|
|
#include <lber.h>
|
|
#include <ldap.h>
|
|
#include <ldapconfig.h>
|
|
|
|
#include "ud.h"
|
|
|
|
#ifdef HAVE_KERBEROS
|
|
static char tktpath[20]; /* ticket file path */
|
|
static int kinit();
|
|
static int valid_tgt();
|
|
#endif
|
|
|
|
static void set_bound_dn(char *s);
|
|
|
|
|
|
int
|
|
auth( char *who, int implicit )
|
|
{
|
|
int rc; /* return code from ldap_bind() */
|
|
char *passwd = NULL; /* returned by mygetpass() */
|
|
char **rdns; /* for fiddling with the DN */
|
|
int authmethod;
|
|
int name_provided; /* was a name passed in? */
|
|
#ifdef HAVE_GETPWUID
|
|
struct passwd *pw; /* for getting user id */
|
|
#else
|
|
char *user;
|
|
#endif
|
|
char uidname[20];
|
|
#ifdef HAVE_KERBEROS
|
|
char **krbnames; /* for kerberos names */
|
|
int kinited, ikrb;
|
|
char buf[5];
|
|
extern int krb_debug;
|
|
#endif
|
|
LDAPMessage *mp; /* returned from find() */
|
|
static char prompt[MED_BUF_SIZE]; /* place for us to sprintf the prompt */
|
|
static char name[MED_BUF_SIZE]; /* place to store the user's name */
|
|
static char password[MED_BUF_SIZE]; /* password entered by user */
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_TRACE)
|
|
fprintf(stderr, "auth(%s, NULL)\n", who);
|
|
#endif
|
|
name_provided = ( who != NULL );
|
|
|
|
/*
|
|
* The user needs to bind. If <who> is not specified, we
|
|
* assume that authenticating as user id is what user wants.
|
|
*/
|
|
if (who == NULL && implicit) {
|
|
uidname[0] = '\0';
|
|
|
|
#ifdef HAVE_GETPWUID
|
|
if ((pw = getpwuid((uid_t)geteuid())) != (struct passwd *) NULL) {
|
|
sprintf(uidname, "uid=%s", pw->pw_name);
|
|
}
|
|
#else
|
|
user = getenv("USER");
|
|
if(user == NULL) user = getenv("USERNAME");
|
|
if(user == NULL) user = getenv("LOGNAME");
|
|
|
|
if(user != NULL) {
|
|
sprintf(uidname, "uid=%s", user);
|
|
}
|
|
#endif
|
|
|
|
if(uidname[0] != '\0') {
|
|
who = uidname;
|
|
}
|
|
}
|
|
|
|
if ( who == NULL ) {
|
|
if ( implicit )
|
|
printf( "You must first authenticate yourself to the Directory.\n" );
|
|
#ifdef UOFM
|
|
printf(" What is your name or uniqname? ");
|
|
#else
|
|
printf(" What is your name or user id? ");
|
|
#endif
|
|
fflush(stdout);
|
|
fetch_buffer(name, sizeof(name), stdin);
|
|
if (name[0] == '\0')
|
|
return( -1 );
|
|
who = name;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (debug & D_AUTHENTICAT)
|
|
printf(" Authenticating as \"%s\"\n", who);
|
|
#endif
|
|
|
|
/*
|
|
* Bail out if the name is bogus. If not, strip off the junk
|
|
* at the start of the DN, build a prompt, and get a password
|
|
* from the user. Then perform the ldap_bind().
|
|
*/
|
|
if ((mp = find(who, TRUE)) == NULL) {
|
|
(void) ldap_msgfree(mp);
|
|
printf(" I could not find \"%s\" in the Directory.\n", who);
|
|
printf(" I used a search base of ");
|
|
printbase("", search_base);
|
|
printf("\n");
|
|
#ifdef DEBUG
|
|
if (debug & D_AUTHENTICAT)
|
|
printf(" Could not find \"%s\"\n", who);
|
|
#endif
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Fill in the Entry structure. May be handy later.
|
|
*/
|
|
(void) parse_answer(mp);
|
|
|
|
rdns = ldap_explode_dn(Entry.DN, TRUE);
|
|
printf(" Authenticating to the directory as \"%s\"...\n", *rdns );
|
|
|
|
#ifdef HAVE_KERBEROS
|
|
/*
|
|
* First, if the user has a choice of auth methods, ask which
|
|
* one they want to use. if they want kerberos, ask which
|
|
* krbname they want to bind as.
|
|
*/
|
|
|
|
if ( (krbnames = ldap_get_values( ld, mp, "krbName" )) != NULL ) {
|
|
int choice, hassimple;
|
|
|
|
hassimple = (ldap_compare_s( ld, Entry.DN,
|
|
"userPassword", "x" ) == LDAP_COMPARE_FALSE);
|
|
(void) ldap_msgfree(mp);
|
|
|
|
/* if we're running as a server (e.g., out of inetd) */
|
|
if ( ! isatty( 1 ) ) {
|
|
strcpy( tktpath, "/tmp/ud_tktXXXXXX" );
|
|
mktemp( tktpath );
|
|
krb_set_tkt_string( tktpath );
|
|
}
|
|
|
|
kinited = valid_tgt( krbnames );
|
|
|
|
if ( hassimple && !kinited ) {
|
|
printf(" Which password would you like to use?\n");
|
|
printf(" 1 -> LDAP password\n");
|
|
#ifdef UOFM
|
|
printf(" 2 -> UMICH password (aka Uniqname or Kerberos password)\n");
|
|
#else
|
|
printf(" 2 -> Kerberos password\n");
|
|
#endif
|
|
|
|
do {
|
|
printf(" Enter 1 or 2: ");
|
|
fflush(stdout);
|
|
|
|
fetch_buffer(buf, sizeof(buf), stdin);
|
|
choice = atoi(buf);
|
|
} while (choice != 1 && choice != 2);
|
|
|
|
authmethod = (choice == 1 ? LDAP_AUTH_SIMPLE :
|
|
LDAP_AUTH_KRBV4);
|
|
} else {
|
|
authmethod = LDAP_AUTH_KRBV4;
|
|
}
|
|
} else {
|
|
authmethod = LDAP_AUTH_SIMPLE;
|
|
(void) ldap_msgfree(mp);
|
|
}
|
|
|
|
/*
|
|
* if they are already kinited, we don't need to ask for a
|
|
* password.
|
|
*/
|
|
|
|
if ( authmethod == LDAP_AUTH_KRBV4 ) {
|
|
if ( ! kinited ) {
|
|
if ( krbnames[1] != NULL ) {
|
|
int i;
|
|
|
|
/* ask which one to use */
|
|
#ifdef UOFM
|
|
printf(" Which UMICH (aka Kerberos or uniqname) name would you like to use?\n");
|
|
#else
|
|
printf(" Which Kerberos name would you like to use?\n");
|
|
#endif
|
|
for ( i = 0; krbnames[i] != NULL; i++ ) {
|
|
printf( " %d -> %s\n", i + 1,
|
|
krbnames[i] );
|
|
}
|
|
do {
|
|
printf(" Enter a number between 1 and %d: ", i );
|
|
fflush( stdout );
|
|
|
|
fetch_buffer(buf, sizeof(buf), stdin);
|
|
ikrb = atoi(buf) - 1;
|
|
} while ( ikrb > i - 1 || ikrb < 0 );
|
|
} else {
|
|
ikrb = 0;
|
|
}
|
|
|
|
/* kinit */
|
|
if ( kinit( krbnames[ikrb] ) != 0 ) {
|
|
(void) ldap_value_free(rdns);
|
|
(void) ldap_value_free(krbnames);
|
|
return(-1);
|
|
}
|
|
}
|
|
} else {
|
|
#endif
|
|
authmethod = LDAP_AUTH_SIMPLE;
|
|
sprintf(prompt, " Enter your LDAP password: ");
|
|
do {
|
|
passwd = mygetpass(prompt);
|
|
} while (passwd != NULL && *passwd == '\0');
|
|
if (passwd == NULL) {
|
|
(void) ldap_value_free(rdns);
|
|
return(0);
|
|
}
|
|
#ifdef HAVE_KERBEROS
|
|
}
|
|
(void) ldap_value_free(krbnames);
|
|
#endif
|
|
ldap_flush_cache( ld );
|
|
rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod);
|
|
if (rc != LDAP_SUCCESS) {
|
|
int ld_errno;
|
|
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
|
|
if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
|
|
fprintf(stderr, " Entry has no password\n");
|
|
else if (ld_errno == LDAP_INVALID_CREDENTIALS)
|
|
#ifdef HAVE_KERBEROS
|
|
if ( authmethod == LDAP_AUTH_KRBV4 ) {
|
|
fprintf(stderr, " The Kerberos credentials are invalid.\n");
|
|
} else {
|
|
#endif
|
|
fprintf(stderr, " The password you provided is incorrect.\n");
|
|
#ifdef HAVE_KERBEROS
|
|
}
|
|
#endif
|
|
else
|
|
ldap_perror(ld, "ldap_bind_s" );
|
|
(void) ldap_bind_s(ld, default_bind_object,
|
|
(char *) NULL, LDAP_AUTH_SIMPLE);
|
|
if (default_bind_object == NULL)
|
|
set_bound_dn(NULL);
|
|
else
|
|
set_bound_dn(default_bind_object);
|
|
bind_status = UD_NOT_BOUND;
|
|
if (verbose)
|
|
printf(" Authentication failed.\n\n");
|
|
(void) ldap_value_free(rdns);
|
|
return(-1);
|
|
}
|
|
else if (verbose)
|
|
printf(" Authentication successful.\n\n");
|
|
else
|
|
printf("\n");
|
|
set_bound_dn(Entry.DN);
|
|
bind_status = UD_BOUND;
|
|
if (passwd != NULL)
|
|
(void) strcpy(password, passwd);
|
|
(void) ldap_value_free(rdns);
|
|
return(0);
|
|
}
|
|
|
|
#ifdef HAVE_KERBEROS
|
|
|
|
#define FIVEMINS ( 5 * 60 )
|
|
#define TGT "krbtgt"
|
|
|
|
static void
|
|
str2upper( char *s )
|
|
{
|
|
char *p;
|
|
|
|
for ( p = s; *p != '\0'; ++p ) {
|
|
*p = TOUPPER( *p );
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
valid_tgt( char **names )
|
|
{
|
|
int i;
|
|
char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
|
|
CREDENTIALS cred;
|
|
|
|
for ( i = 0; names[i] != NULL; i++ ) {
|
|
if ( kname_parse( name, inst, realm, names[i] ) != KSUCCESS ) {
|
|
fprintf( stderr, "Bad format for krbName %s\n",
|
|
names[i] );
|
|
fprintf( stderr, "Contact x500@umich.edu\n" );
|
|
return( 0 );
|
|
}
|
|
|
|
#ifdef HAVE_AFS_KERBEROS
|
|
/*
|
|
* realm must be uppercase for krb_ routines
|
|
*/
|
|
str2upper( realm );
|
|
#endif /* HAVE_AFS_KERBEROS */
|
|
|
|
/*
|
|
* check ticket file for a valid ticket granting ticket
|
|
* my check is: have ticket granting ticket and it is good for
|
|
* at least 5 more minutes
|
|
*/
|
|
if ( krb_get_cred( TGT, realm, realm,
|
|
&cred ) == KSUCCESS && time( 0 ) + FIVEMINS <
|
|
cred.issue_date + (u_char)cred.lifetime * FIVEMINS ) {
|
|
return( 1 );
|
|
}
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static char *kauth_name;
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
krbgetpass( char *user, char *inst, char *realm, char *pw, C_Block key )
|
|
{
|
|
char *p, lcrealm[ REALM_SZ ], prompt[256], *passwd;
|
|
|
|
#ifdef UOFM
|
|
sprintf(prompt, " Enter the UMICH password (same as Uniqname or Kerberos password)\n for %s: ", kauth_name );
|
|
#else
|
|
sprintf(prompt, " Enter Kerberos password for %s: ", kauth_name );
|
|
#endif
|
|
do {
|
|
passwd = mygetpass(prompt);
|
|
} while (passwd != NULL && *passwd == '\0');
|
|
if (passwd == NULL) {
|
|
return(-1);
|
|
}
|
|
|
|
#ifdef HAVE_AFS_KERBEROS
|
|
strcpy( lcrealm, realm );
|
|
for ( p = lcrealm; *p != '\0'; ++p ) {
|
|
*p = TOLOWER( *p );
|
|
}
|
|
|
|
ka_StringToKey( passwd, lcrealm, key );
|
|
#else /* HAVE_AFS_KERBEROS */
|
|
string_to_key( passwd, key );
|
|
#endif /* HAVE_AFS_KERBEROS */
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
kinit( char *kname )
|
|
{
|
|
int rc;
|
|
char name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
|
|
|
|
kauth_name = kname;
|
|
|
|
if ( kname_parse( name, inst, realm, kname ) != KSUCCESS ) {
|
|
fprintf( stderr, "Bad format for krbName %s\n",
|
|
kname );
|
|
fprintf( stderr, "Contact x500@umich.edu\n" );
|
|
return( -1 );
|
|
}
|
|
|
|
#ifdef HAVE_AFS_KERBEROS
|
|
/*
|
|
* realm must be uppercase for krb_ routines
|
|
*/
|
|
str2upper( realm );
|
|
#endif /* HAVE_AFS_KERBEROS */
|
|
|
|
rc = krb_get_in_tkt( name, inst, realm, TGT, realm,
|
|
DEFAULT_TKT_LIFE, krbgetpass, NULL, NULL );
|
|
|
|
if ( rc != KSUCCESS ) {
|
|
switch ( rc ) {
|
|
case SKDC_CANT:
|
|
fprintf( stderr, "Can't contact Kerberos server for %s\n", realm );
|
|
break;
|
|
default:
|
|
fprintf( stderr, "%s: %s\n", name, krb_err_txt[ rc ] );
|
|
break;
|
|
}
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
void
|
|
destroy_tickets( void )
|
|
{
|
|
if ( *tktpath != '\0' ) {
|
|
unlink( tktpath );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
set_bound_dn( char *s )
|
|
{
|
|
if (bound_dn != NULL)
|
|
Free(bound_dn);
|
|
bound_dn = (s == NULL) ? NULL : strdup(s);
|
|
}
|