This is auth-passwd.c in view mode; [Download] [Up]
/*
auth-passwd.c
Author: Tatu Ylonen <ylo@cs.hut.fi>
Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
All rights reserved
Created: Sat Mar 18 05:11:38 1995 ylo
Password authentication. This file contains the functions to check whether
the password is valid for the user.
*/
/*
* $Id: auth-passwd.c,v 1.19 1998/07/08 01:44:46 kivinen Exp $
* $Log: auth-passwd.c,v $
* Revision 1.19 1998/07/08 01:44:46 kivinen
* Added one missing space.
*
* Revision 1.18 1998/07/08 00:36:44 kivinen
* Changed to use PASSWD_PATH. Better HPUX TCB AUTH support.
*
* Revision 1.17 1998/06/11 00:03:38 kivinen
* Added username to /bin/password commands.
*
* Revision 1.16 1998/05/23 20:19:40 kivinen
* Removed #define uint32 rpc_unt32, because md5 uint32 is now
* md5_uint32. Changed () -> (void). Changed osf1c2_getprpwent
* function to return true/false. Added
* forced_empty_passwd_change support.
*
* Revision 1.15 1998/05/11 21:27:47 kivinen
* Set correct_passwd to contain 255...255 so even if some
* function doesn't set it, it cannot contain empty password.
*
* Revision 1.14 1998/04/30 01:50:20 kivinen
* Added code that will force /bin/passwd command if password is
* expired.
*
* Revision 1.13 1998/03/27 16:53:09 kivinen
* Added aix authenticate function support.
*
* Revision 1.12 1998/01/02 06:14:31 kivinen
* Fixed kerberos ticket name handling. Added OSF C2 account
* locking and expiration support.
*
* Revision 1.11 1997/04/17 03:57:05 kivinen
* Kept FILE: prefix in kerberos ticket filename as DCE cache
* code requires it (patch from Doug Engert <DEEngert@anl.gov>).
*
* Revision 1.10 1997/04/05 21:45:25 kivinen
* Changed verify_krb_v5_tgt to take *error_code instead of
* error_code.
*
* Revision 1.9 1997/03/27 03:09:20 kivinen
* Added kerberos patches from Glenn Machin.
*
* Revision 1.8 1997/03/26 06:59:18 kivinen
* Changed uid 0 to UID_ROOT.
*
* Revision 1.7 1997/03/19 15:57:21 kivinen
* Added SECURE_RPC, SECURE_NFS and NIS_PLUS support from Andy
* Polyakov <appro@fy.chalmers.se>.
*
* Revision 1.6 1996/10/30 04:22:43 kivinen
* Added #ifdef HAVE_SHADOW_H around shadow.h including.
*
* Revision 1.5 1996/10/29 22:33:59 kivinen
* log -> log_msg.
*
* Revision 1.4 1996/10/08 13:50:44 ttsalo
* Allow long passwords for HP-UX TCB authentication
*
* Revision 1.3 1996/09/08 17:36:51 ttsalo
* Patches for HPUX 10.x shadow passwords from
* vincent@ucthpx.uct.ac.za (Russell Vincent) merged.
*
* Revision 1.2 1996/02/18 21:53:45 ylo
* Test for HAVE_ULTRIX_SHADOW_PASSWORDS instead of ultrix
* (mips-dec-mach3 has ultrix defined, but does not support the
* shadow password stuff).
*
* Revision 1.1.1.1 1996/02/18 21:38:12 ylo
* Imported ssh-1.2.13.
*
* Revision 1.8 1995/09/27 02:10:34 ylo
* Added support for SCO unix shadow passwords.
*
* Revision 1.7 1995/09/10 22:44:41 ylo
* Added OSF/1 C2 extended security stuff.
*
* Revision 1.6 1995/08/21 23:20:29 ylo
* Fixed a typo.
*
* Revision 1.5 1995/08/19 13:15:56 ylo
* Changed securid code to initialize itself only once.
*
* Revision 1.4 1995/08/18 22:42:51 ylo
* Added General Dynamics SecurID support from Donald McKillican
* <dmckilli@qc.bell.ca>.
*
* Revision 1.3 1995/07/13 01:12:34 ylo
* Removed the "Last modified" header.
*
* Revision 1.2 1995/07/13 01:09:50 ylo
* Added cvs log.
*
* $Endlog$
*/
#include "includes.h"
#ifdef HAVE_SCO_ETC_SHADOW
# include <sys/security.h>
# include <sys/audit.h>
# include <prot.h>
#else /* HAVE_SCO_ETC_SHADOW */
#ifdef HAVE_HPUX_TCB_AUTH
# include <sys/types.h>
# include <hpsecurity.h>
# include <prot.h>
#else /* HAVE_HPUX_TCB_AUTH */
#ifdef HAVE_ETC_SHADOW
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif
#endif /* HAVE_ETC_SHADOW */
#endif /* HAVE_HPUX_TCB_AUTH */
#endif /* HAVE_SCO_ETC_SHADOW */
#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT
#include <sys/label.h>
#include <sys/audit.h>
#include <pwdadj.h>
#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
#ifdef HAVE_ULTRIX_SHADOW_PASSWORDS
#include <auth.h>
#include <sys/svcinfo.h>
#endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */
#include "packet.h"
#include "ssh.h"
#include "servconf.h"
#include "xmalloc.h"
#ifdef SECURE_RPC
/*
* refer to ftp://playground.sun.com/pub/rpc/tirpcsrc2.3.tar.Z for
* detailed information about stuff you can't find in manual pages:-)
*/
#ifdef KEYBYTES
#undef KEYBYTES /* conflicts with blowfish.h */
#endif
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
static uid_t uid_keylogged = 0;
#ifdef SECURE_NFS
#include <nfs/export.h>
#include <nfs/nfs.h>
#include <nfs/nfssys.h>
void nfs_revauth(uid_t uid)
{
struct nfs_revauth_args _nfssysarg;
_nfssysarg.authtype = AUTH_DES;
_nfssysarg.uid = uid;
_nfssys (NFS_REVAUTH,&_nfssysarg);
}
#endif /* SECURE_NFS */
/* do /usr/bin/keylogout's job */
/* caller sets effective uid! */
void keylogout(void)
{
char secret [HEXKEYBYTES];
if (!uid_keylogged || uid_keylogged != geteuid())
return;
/* revoke secret key from keyserv(1m) */
memset(secret, '\0', sizeof(secret));
key_setsecret(secret); /* this one is keyserv.1 interface,
but it does the job even for keyserv.2
and takes the only argument:-) */
#ifdef SECURE_NFS
/* as well as from nfs client module */
nfs_revauth(uid_keylogged);
#endif /* SECURE_NFS */
uid_keylogged = 0;
}
void keylogout_atexit (void)
{
if (!uid_keylogged || seteuid(uid_keylogged))
return;
keylogout();
seteuid(UID_ROOT);
}
#ifdef KEY_VERS2 /* keyserv protocol version 2 */
int my_secretkey_is_set(char *netname)
{
return key_secretkey_is_set();
}
#else /* KEY_VERS2 */
/*
* for keyserv.1 we just try to encrypt a session key to talk to ourselves.
* this should fail if keyserv doesn't have our secret key. well, we can't
* say if it's the right one, but we can't do any better anyway:-)
*/
int my_secretkey_is_set(char *netname)
{
des_block block;
memcpy (block.c, netname, sizeof(block.c)); /* well, whatever... */
return (key_encryptsession(netname, &block) == 0);
}
#endif /* KEY_VERS2 */
/* do /usr/bin/keylogin's job */
/* caller sets effective uid! */
int keylogin(const char *passwd)
{
int ret = 0;
char netnam[MAXNETNAMELEN+1], phrase[9];
#ifdef KEY_VERS2
key_netstarg key_setnet_arg;
#define secret key_setnet_arg.st_priv_key
#define public key_setnet_arg.st_pub_key
key_setnet_arg.st_netname = netnam;
#else /* KEY_VERS2 */
char secret[HEXKEYBYTES], public[HEXKEYBYTES];
#endif /* KEY_VERS2 */
if (getnetname(netnam) && /* do i exists? */
!(ret = my_secretkey_is_set(netnam)) && /* is it already set? */
passwd) /* do i have the password? */
{
strncpy(phrase, passwd, 8);
phrase[8] = '\0';
memset(public, '\0', sizeof(public));
memset(secret, '\0', sizeof(secret));
if (getsecretkey(netnam, secret, phrase) && *secret)
{
#ifdef KEY_VERS2
/*
* key_setnet is keyserv.2 interface and is not documented,
* but used by keylogin(1). and it's real mess with return
* values:-( so far, namely up to Solaris 2.5.1, it returns
* 1 on success and -1 when fails.
*/
if (ret = (key_setnet(&key_setnet_arg) > 0))
#else /* KEY_VERS2 */
if (ret = !key_setsecret(secret))
#endif /* KEY_VERS2 */
{
uid_keylogged = geteuid(); /* save it for keylogout */
atexit(keylogout_atexit); /* clean up after ourselves */
}
memset(secret, '\0', sizeof (secret));
}
memset(phrase, '\0', sizeof(phrase));
}
return ret; /* secret key was set by whomever */
}
#endif /* SECURE_RPC */
#ifdef HAVE_SECURID
/* Support for Security Dynamics SecurID card.
Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
#define SECURID_USERS "/etc/securid.users"
#include "sdi_athd.h"
#include "sdi_size.h"
#include "sdi_type.h"
#include "sdacmvls.h"
#include "sdconf.h"
union config_record configure;
static int securid_initialized = 0;
#endif /* HAVE_SECURID */
#ifdef KERBEROS
#if defined(KRB5)
#include <krb5.h>
extern krb5_context ssh_context;
extern krb5_auth_context auth_context;
#else
#include <krb.h>
#endif /* KRB5 */
#endif /* KERBEROS */
#ifdef AFS
#include <afs/param.h>
#include <afs/kautils.h>
#endif /* AFS */
#if defined(KERBEROS) || defined(AFS_KERBEROS)
extern char *ticket;
#endif /* KERBEROS || AFS_KERBEROS */
/* Tries to authenticate the user using password. Returns true if
authentication succeeds. */
#if defined(KERBEROS) && defined(KRB5)
/*
* This routine with some modification is from the MIT V5B6 appl/bsd/login.c
*
* Verify the Kerberos ticket-granting ticket just retrieved for the
* user. If the Kerberos server doesn't respond, assume the user is
* trying to fake us out (since we DID just get a TGT from what is
* supposedly our KDC). If the host/<host> service is unknown (i.e.,
* the local keytab doesn't have it), let her in.
*
* Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
*/
static
int verify_krb_v5_tgt (krb5_context c, krb5_ccache ccache,
krb5_error_code *error_code)
{
char phost[BUFSIZ];
int retval, have_keys;
krb5_principal princ;
krb5_keyblock *kb = 0;
krb5_error_code krbval;
krb5_data packet;
krb5_auth_context auth_context = NULL;
krb5_ticket *ticket = NULL;
/* Set packet.data so that we do not free bogus memory below */
packet.data = 0;
/* get the server principal for the local host */
/* (use defaults of "host" and canonicalized local name) */
krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
if (krbval)
{
*error_code = krbval;
return -1;
}
/* since krb5_sname_to_principal has done the work for us, just
extract the name directly */
strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ);
/* Do we have host/<host> keys? */
/* (use default keytab, kvno IGNORE_VNO to get the first match,
and enctype is currently ignored anyhow.) */
krbval = krb5_kt_read_service_key (c, NULL, princ, 0,
ENCTYPE_DES_CBC_CRC, &kb);
if (kb)
krb5_free_keyblock (c, kb);
/* any failure means we don't have keys at all. */
have_keys = krbval ? 0 : 1;
/* talk to the kdc and construct the ticket */
krbval = krb5_mk_req(c, &auth_context, 0, "host", phost,
0, ccache, &packet);
/* wipe the auth context for mk_req */
if (auth_context)
{
krb5_auth_con_free(c, auth_context);
auth_context = NULL;
}
if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
{
/* we have a service key, so something should be
in the database, therefore this error packet could
have come from an attacker. */
if (have_keys)
{
retval = -1;
goto EGRESS;
}
/* but if it is unknown and we've got no key, we don't
have any security anyhow, so it is ok. */
else
{
retval = 0;
goto EGRESS;
}
}
else
if (krbval)
{
*error_code = krbval;
retval = -1;
goto EGRESS;
}
/* got ticket, try to use it */
krbval = krb5_rd_req(c, &auth_context, &packet,
princ, NULL, NULL, &ticket);
if (krbval)
{
if (!have_keys)
/* The krb5 errors aren't specified well, but I think
these values cover the cases we expect. */
switch (krbval)
{
/* no keytab */
case KRB5_KT_NOTFOUND:
case ENOENT:
/* keytab found, missing entry */
retval = 0;
break;
default:
/* unexpected error: fail */
retval = -1;
break;
}
else
/* Any error here is bad. */
retval = -1;
*error_code = krbval;
goto EGRESS;
}
/*
* The host/<host> ticket has been received _and_ verified.
*/
retval = 1;
/* do cleanup and return */
EGRESS:
if (auth_context)
krb5_auth_con_free(c, auth_context);
if (ticket)
krb5_free_ticket(c, ticket);
if (packet.data)
{
free(packet.data);
packet.data = 0;
}
krb5_free_principal(c, princ);
/* possibly ticket and packet need freeing here as well */
/* memset (&ticket, 0, sizeof (ticket)); */
return retval;
}
krb5_data tgtname = {
0,
KRB5_TGS_NAME_SIZE,
KRB5_TGS_NAME
};
/*
* Preauthentication types should be listed prior to 0.
* The last one tried will be no preauthentication
* Type 5 is compatible with DCE timestamp
* Type 2 is MIT current timestamp implementation
*/
#ifdef KRB5_PADATA_ENC_UNIX_TIME
krb5_preauthtype preauth_list[3] = { KRB5_PADATA_ENC_UNIX_TIME,
KRB5_PADATA_ENC_TIMESTAMP,
0 };
#else
krb5_preauthtype preauth_list[2] = { KRB5_PADATA_ENC_TIMESTAMP,
0 };
#endif
krb5_preauthtype * preauth = preauth_list;
#endif /* KERBEROS */
/* Tries to authenticate the user using password. Returns true if
authentication succeeds. */
#ifdef KERBEROS
int auth_password(const char *server_user, const char *password,
krb5_principal client)
#else /* KERBEROS */
int auth_password(const char *server_user, const char *password)
#endif /* KERBEROS */
{
#if defined(_AIX) && defined(HAVE_AUTHENTICATE)
char *message;
int reenter;
reenter = 1;
if (authenticate(server_user, password, &reenter, &message) == 0)
{
return 1;
}
else
{
return 0;
}
#else /* _AIX41 && HAVE_AUTHENTICATE */
#ifdef KERBEROS
krb5_error_code problem;
int krb5_options = KDC_OPT_RENEWABLE | KDC_OPT_FORWARDABLE;
krb5_deltat rlife = 0;
krb5_principal server = 0;
krb5_creds my_creds;
krb5_timestamp now;
krb5_ccache ccache;
char ccname[80];
int results;
#endif /* KERBEROS */
extern ServerOptions options;
extern char *crypt(const char *key, const char *salt);
struct passwd *pw;
char *encrypted_password;
char correct_passwd[200];
char *saved_pw_name, *saved_pw_passwd;
memset(correct_passwd, 255, sizeof(correct_passwd));
if (*password == '\0' && options.permit_empty_passwd == 0)
{
packet_send_debug("Server does not permit empty password login.");
return 0;
}
/* Get the encrypted password for the user. */
pw = getpwnam(server_user);
if (!pw)
return 0;
saved_pw_name = xstrdup(pw->pw_name);
saved_pw_passwd = xstrdup(pw->pw_passwd);
#if defined(KERBEROS)
if (options.kerberos_authentication)
{
#if defined(KRB5)
sprintf(ccname, "FILE:/tmp/krb5cc_l%d", getpid());
if (problem = krb5_cc_resolve(ssh_context, ccname, &ccache))
goto errout2;
if (problem = krb5_cc_initialize(ssh_context, ccache, client))
goto errout;
problem =
krb5_build_principal_ext(ssh_context, &server,
krb5_princ_realm(ssh_context, client)->length,
krb5_princ_realm(ssh_context, client)->data,
tgtname.length, tgtname.data,
krb5_princ_realm(ssh_context, client)->length,
krb5_princ_realm(ssh_context, client)->data,
0);
if (problem)
goto errout;
memset(&my_creds, 0, sizeof(my_creds));
my_creds.client = client;
my_creds.server = server;
problem = krb5_timeofday(ssh_context, &now);
if (problem)
goto errout;
my_creds.times.starttime = 0; /* start timer when
request gets to KDC */
my_creds.times.endtime = now + 60*60*10; /* 10 hours */
problem = krb5_string_to_deltat("7d", &rlife); /* 7 days renew time */
if (problem || rlife == 0)
goto errout;
my_creds.times.renew_till = now + rlife;
problem = krb5_get_in_tkt_with_password(ssh_context, krb5_options, 0,
NULL, preauth,
password, ccache,
&my_creds, 0);
/* If not successful try no preauthentication */
if (problem)
problem = krb5_get_in_tkt_with_password(ssh_context,
krb5_options, 0,
NULL, 0,
password, ccache,
&my_creds, 0);
krb5_free_principal(ssh_context, server);
server = 0;
if (problem)
goto errout;
else
{
/* Verify tgt just obtained */
results = verify_krb_v5_tgt(ssh_context, ccache, &problem);
if (results >= 0)
{
/* If results is 0 then put out a log message that
the TGT was not verified, pass this back to the
user as well */
if (results == 0)
{
log_msg("TGT for user %s was not verified.", server_user);
packet_send_debug("Kerberos TGT could not be verified.");
}
/* get_name pulls out just the name not the
type */
strcpy(ccname + 5, krb5_cc_get_name(ssh_context, ccache));
(void) chown(ccname + 5, pw->pw_uid, pw->pw_gid);
/* If tgt was passed unlink file */
if (ticket)
{
if (strcmp(ticket,"none"))
/* ticket -> FILE:path */
unlink(ticket + 5);
else
ticket = NULL;
}
ticket = xmalloc(strlen(ccname) + 1);
(void) sprintf(ticket, "%s", ccname);
/* We do not need this so free them up */
xfree(saved_pw_name);
xfree(saved_pw_passwd);
return 1;
}
if (problem == KRB5_KT_NOTFOUND)
{
/* We have potential KDC spoofing here - log it */
log_msg("WARNING: Verification of TGT indicates potential KDC spoofing: user %s address %s", server_user, get_remote_ipaddr());
packet_send_debug("Verification of TGT indicates potential KDC spoofing.");
}
}
errout:
krb5_cc_destroy (ssh_context, ccache);
errout2:
if (problem)
{
log_msg("Password authentication of user %s using Kerberos failed: %s",
server_user, error_message(problem));
if (server)
krb5_free_principal(ssh_context, server);
if (!options.kerberos_or_local_passwd )
{
/* We do not need this so free them up */
xfree(saved_pw_name);
xfree(saved_pw_passwd);
return 0;
}
}
#endif /* KRB5 */
}
#endif /* KERBEROS */
#ifdef HAVE_SECURID
/* Support for Security Dynamics SecurId card.
Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */
{
/*
* the way we decide if this user is a securid user or not is
* to check to see if they are included in /etc/securid.users
*/
int found = 0;
FILE *securid_users = fopen(SECURID_USERS, "r");
char *c;
char su_user[257];
if (securid_users)
{
while (fgets(su_user, sizeof(su_user), securid_users))
{
if (c = strchr(su_user, '\n'))
*c = '\0';
if (strcmp(su_user, server_user) == 0)
{
found = 1;
break;
}
}
}
fclose(securid_users);
if (found)
{
/* The user has a SecurID card. */
struct SD_CLIENT sd_dat, *sd;
log_msg("SecurID authentication for %.100s required.", server_user);
/*
* if no pass code has been supplied, fail immediately: passing
* a null pass code to sd_check causes a core dump
*/
if (*password == '\0')
{
log_msg("No pass code given, authentication rejected.");
return 0;
}
sd = &sd_dat;
if (!securid_initialized)
{
memset(&sd_dat, 0, sizeof(sd_dat)); /* clear struct */
creadcfg(); /* accesses sdconf.rec */
if (sd_init(sd))
packet_disconnect("Cannot contact securid server.");
securid_initialized = 1;
}
return sd_check(password, server_user, sd) == ACM_OK;
}
}
/* If the user has no SecurID card specified, we fall to normal
password code. */
#endif /* HAVE_SECURID */
/* Save the encrypted password. */
strncpy(correct_passwd, saved_pw_passwd, sizeof(correct_passwd));
#ifdef SECURE_RPC
/* try to register secret key for secure RPC */
seteuid(pw->pw_uid); /* just let it fail if ran by user */
keylogin(password);
seteuid(UID_ROOT); /* just let it fail if ran by user */
#endif /* SECURE_RPC */
#ifdef HAVE_OSF1_C2_SECURITY
if (osf1c2_getprpwent(correct_passwd, saved_pw_name,
sizeof(correct_passwd)))
{
if (options.forced_passwd_change)
{
extern char *forced_command;
forced_command = xmalloc(sizeof(PASSWD_PATH) +
strlen(server_user) + 1);
sprintf(forced_command, "%s %s", PASSWD_PATH, server_user);
packet_send_debug("Password expired, forcing it to be changed.");
}
else
{
packet_send_debug("\n\tYour password has expired.");
}
}
#else /* HAVE_OSF1_C2_SECURITY */
/* If we have shadow passwords, lookup the real encrypted password from
the shadow file, and replace the saved encrypted password with the
real encrypted password. */
#if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH)
{
struct pr_passwd *pr = getprpwnam(saved_pw_name);
pr = getprpwnam(saved_pw_name);
if (pr)
{
strncpy(correct_passwd, pr->ufld.fd_encrypt, sizeof(correct_passwd));
endprpwent();
if ( (!pr->uflg.fg_nullpw || !pr->ufld.fd_nullpw)
&& !pr->uflg.fg_pw_admin_num
&& strcmp(correct_passwd,"")==0 )
{
debug("User %.100s not permitted to login with null passwd",
saved_pw_name);
packet_send_debug("\n\tNot permitted null passwd.");
return 0;
}
}
else
{
endprpwent();
return 0;
}
}
#else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */
#ifdef HAVE_ETC_SHADOW
{
struct spwd *sp = getspnam(saved_pw_name);
#if defined(SECURE_RPC) && defined(NIS_PLUS)
if (!geteuid() && pw->pw_uid && /* do we have guts? */
(!sp || !sp->sp_pwdp || !strcmp(sp->sp_pwdp,"*NP*")))
if (seteuid(pw->pw_uid) == UID_ROOT)
{
sp = getspnam(saved_pw_name); /* retry as user */
seteuid(UID_ROOT);
}
#endif /* SECURE_RPC && NIS_PLUS */
if (sp)
strncpy(correct_passwd, sp->sp_pwdp, sizeof(correct_passwd));
endspent();
}
#else /* HAVE_ETC_SHADOW */
#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT
{
struct passwd_adjunct *sp = getpwanam(saved_pw_name);
if (sp)
strncpy(correct_passwd, sp->pwa_passwd, sizeof(correct_passwd));
endpwaent();
}
#else /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
#ifdef HAVE_ETC_SECURITY_PASSWD
{
FILE *f;
char line[1024], looking_for_user[200], *cp;
int found_user = 0;
f = fopen("/etc/security/passwd", "r");
if (f)
{
sprintf(looking_for_user, "%.190s:", server_user);
while (fgets(line, sizeof(line), f))
{
if (strchr(line, '\n'))
*strchr(line, '\n') = 0;
if (strcmp(line, looking_for_user) == 0)
found_user = 1;
else
if (line[0] != '\t' && line[0] != ' ')
found_user = 0;
else
if (found_user)
{
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (strncmp(cp, "password = ", strlen("password = ")) == 0)
{
strncpy(correct_passwd, cp + strlen("password = "),
sizeof(correct_passwd));
correct_passwd[sizeof(correct_passwd) - 1] = 0;
break;
}
}
}
fclose(f);
}
}
#endif /* HAVE_ETC_SECURITY_PASSWD */
#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */
#endif /* HAVE_ETC_SHADOW */
#endif /* HAVE_SCO_ETC_SHADOW */
#endif /* HAVE_OSF1_C2_SECURITY */
/* Check for users with no password. */
if (strcmp(password, "") == 0 && strcmp(correct_passwd, "") == 0)
{
if (options.forced_empty_passwd_change)
{
extern char *forced_command;
forced_command = xmalloc(sizeof(PASSWD_PATH) +
strlen(server_user) + 1);
sprintf(forced_command, "%s %s", PASSWD_PATH, server_user);
packet_send_debug("Password if forced to be set at first login.");
}
else
{
packet_send_debug("Login permitted without a password because the account has no password.");
}
return 1; /* The user has no password and an empty password was tried. */
}
xfree(saved_pw_name);
xfree(saved_pw_passwd);
#ifdef HAVE_ULTRIX_SHADOW_PASSWORDS
{
/* Note: we are assuming that pw from above is still valid. */
struct svcinfo *svp;
svp = getsvc();
if (svp == NULL)
{
error("getsvc() failed in ultrix code in auth_passwd");
return 0;
}
if ((svp->svcauth.seclevel == SEC_UPGRADE &&
strcmp(pw->pw_passwd, "*") == 0) ||
svp->svcauth.seclevel == SEC_ENHANCED)
return authenticate_user(pw, password, "/dev/ttypXX") >= 0;
}
#endif /* HAVE_ULTRIX_SHADOW_PASSWORDS */
/* Encrypt the candidate password using the proper salt. */
#ifdef HAVE_OSF1_C2_SECURITY
encrypted_password = (char *)osf1c2crypt(password,
(correct_passwd[0] && correct_passwd[1]) ?
correct_passwd : "xx");
#else /* HAVE_OSF1_C2_SECURITY */
#if defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH)
encrypted_password = bigcrypt(password,
(correct_passwd[0] && correct_passwd[1]) ?
correct_passwd : "xx");
#else /* defined(HAVE_SCO_ETC_SHADOW) || defined(HAVE_HPUX_TCB_AUTH) */
encrypted_password = crypt(password,
(correct_passwd[0] && correct_passwd[1]) ?
correct_passwd : "xx");
#endif /* HAVE_SCO_ETC_SHADOW */
#endif /* HAVE_OSF1_C2_SECURITY */
/* Authentication is accepted if the encrypted passwords are identical. */
return strcmp(encrypted_password, correct_passwd) == 0;
#endif /* _AIX && HAVE_AUTHENTICATE */
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.