/* $FreeBSD$ */ #include "includes.h" RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $"); #include #include "ssh.h" #include "packet.h" #include /* * 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; }