freebsd-nq/crypto/openssh/auth-skey.c
2000-05-15 05:24:25 +00:00

187 lines
4.1 KiB
C

/* $FreeBSD$ */
#include "includes.h"
RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $");
#include <sys/sysctl.h>
#include "ssh.h"
#include "packet.h"
#include <sha.h>
/*
* try skey authentication,
* return 1 on success, 0 on failure, -1 if skey is not available
*/
int
auth_skey_password(struct passwd * pw, const char *password)
{
if (strncasecmp(password, "s/key", 5) == 0) {
char *skeyinfo = opie_keyinfo(pw->pw_name);
if (skeyinfo == NULL) {
debug("generating fake skeyinfo for %.100s.",
pw->pw_name);
skeyinfo = skey_fake_keyinfo(pw->pw_name);
}
if (skeyinfo != NULL)
packet_send_debug(skeyinfo);
/* Try again. */
return 0;
} else if (opie_haskey(pw->pw_name) == 0 &&
opie_passverify(pw->pw_name, (char *) password) != -1) {
/* Authentication succeeded. */
return 1;
}
/* Fall back to ordinary passwd authentication. */
return -1;
}
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
#define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \
((x)[3]))
/*
* hash_collapse()
*/
static u_int32_t
hash_collapse(s)
u_char *s;
{
int len, target;
u_int32_t i;
if ((strlen(s) % sizeof(u_int32_t)) == 0)
target = strlen(s); /* Multiple of 4 */
else
target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
for (i = 0, len = 0; len < target; len += 4)
i ^= ROUND(s + len);
return i;
}
char *
skey_fake_keyinfo(char *username)
{
int i;
u_int ptr;
u_char hseed[OPIE_SEED_MAX], flg = 1, *up;
char pbuf[OPIE_SECRET_MAX+1];
static char skeyprompt[OPIE_CHALLENGE_MAX+1];
char *secret = NULL;
size_t secretlen = 0;
SHA1_CTX ctx;
char *p, *u;
int mib[2];
size_t size;
struct timeval boottime;
/*
* Base first 2 chars of seed on hostname.
* Add some filler for short hostnames if necessary.
*/
if (gethostname(pbuf, sizeof(pbuf)) == -1)
*(p = pbuf) = '.';
else
for (p = pbuf; *p && isalnum(*p); p++)
if (isalpha(*p) && isupper(*p))
*p = tolower(*p);
if (*p && pbuf - p < 2)
(void)strncpy(p, "asjd", 2 - (pbuf - p));
pbuf[2] = '\0';
/* Hash the username if possible */
if ((up = SHA1_Data(username, strlen(username), NULL)) != NULL) {
struct stat sb;
time_t t;
/* Collapse the hash */
ptr = hash_collapse(up);
memset(up, 0, strlen(up));
/*
* Seed the fake challenge with the system boot time,
* otherwise use ctime.
*
* XXX This should be a random source which is constant
* over short time periods, but changes over timescales on
* the order of a week.
*/
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTTIME;
size = sizeof(boottime);
if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
boottime.tv_sec != 0) {
secret = (char *)&boottime;
secretlen = size/sizeof(char);
flg = 0;
} else if (!stat(_PATH_MEM, &sb) || !stat("/", &sb)) {
t = sb.st_ctime;
secret = ctime(&t);
secretlen = strlen(secret);
flg = 0;
}
}
/* Put that in your pipe and smoke it */
if (flg == 0) {
/* Hash secret value with username */
SHA1_Init(&ctx);
SHA1_Update(&ctx, secret, secretlen);
SHA1_Update(&ctx, username, strlen(username));
SHA1_End(&ctx, up);
/* Zero out */
memset(secret, 0, secretlen);
/* Now hash the hash */
SHA1_Init(&ctx);
SHA1_Update(&ctx, up, strlen(up));
SHA1_End(&ctx, up);
ptr = hash_collapse(up + 4);
for (i = 2; i < 6; i++) {
pbuf[i] = (ptr % 10) + '0';
ptr /= 10;
}
pbuf[i] = '\0';
/* Sequence number */
ptr = ((up[2] + up[3]) % 499) + 1;
memset(up, 0, 20); /* SHA1 specific */
free(up);
(void)snprintf(skeyprompt, sizeof skeyprompt,
"opt-%.*s %d %.*s ext",
OPIE_HASHNAME_MAX,
opie_get_algorithm(),
ptr, OPIE_SEED_MAX,
pbuf);
} else {
/* Base last 4 chars of seed on username */
u = username;
i = 4;
p = &pbuf[2];
do {
if (*u == 0) {
/* Pad remainder with zeros */
while (--i >= 0)
*p++ = '0';
break;
}
*p++ = (*u++ % 10) + '0';
} while (--i != 0);
pbuf[6] = '\0';
(void)snprintf(skeyprompt, sizeof skeyprompt,
"opt-md5 %d %.*s ext",
499, OPIE_SEED_MAX, pbuf);
}
return skeyprompt;
}