blob: 9ec17049438603c6e6e132c346863eb4473ff1d2 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001#include "includes.h"
2RCSID("$Id: auth-skey.c,v 1.2 1999/10/16 20:57:52 deraadt Exp $");
3
4#include "ssh.h"
5#include <sha1.h>
6
7/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
8
9
10#define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \
11 ((x)[3]))
12
13/*
14 * hash_collapse()
15 */
16static u_int32_t
17hash_collapse(s)
18 u_char *s;
19{
20 int len, target;
21 u_int32_t i;
22
23 if ((strlen(s) % sizeof(u_int32_t)) == 0)
24 target = strlen(s); /* Multiple of 4 */
25 else
26 target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
27
28 for (i = 0, len = 0; len < target; len += 4)
29 i ^= ROUND(s + len);
30
31 return i;
32}
33char *
34skey_fake_keyinfo(char *username)
35{
36 int i;
37 u_int ptr;
38 u_char hseed[SKEY_MAX_SEED_LEN], flg = 1, *up;
39 char pbuf[SKEY_MAX_PW_LEN+1];
40 static char skeyprompt[SKEY_MAX_CHALLENGE+1];
41 char *secret = NULL;
42 size_t secretlen = 0;
43 SHA1_CTX ctx;
44 char *p, *u;
45
46 /*
47 * Base first 4 chars of seed on hostname.
48 * Add some filler for short hostnames if necessary.
49 */
50 if (gethostname(pbuf, sizeof(pbuf)) == -1)
51 *(p = pbuf) = '.';
52 else
53 for (p = pbuf; *p && isalnum(*p); p++)
54 if (isalpha(*p) && isupper(*p))
55 *p = tolower(*p);
56 if (*p && pbuf - p < 4)
57 (void)strncpy(p, "asjd", 4 - (pbuf - p));
58 pbuf[4] = '\0';
59
60 /* Hash the username if possible */
61 if ((up = SHA1Data(username, strlen(username), NULL)) != NULL) {
62 struct stat sb;
63 time_t t;
64 int fd;
65
66 /* Collapse the hash */
67 ptr = hash_collapse(up);
68 memset(up, 0, strlen(up));
69
70 /* See if the random file's there, else use ctime */
71 if ((fd = open(_SKEY_RAND_FILE_PATH_, O_RDONLY)) != -1
72 && fstat(fd, &sb) == 0 &&
73 sb.st_size > (off_t)SKEY_MAX_SEED_LEN &&
74 lseek(fd, ptr % (sb.st_size - SKEY_MAX_SEED_LEN),
75 SEEK_SET) != -1 && read(fd, hseed,
76 SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) {
77 close(fd);
78 secret = hseed;
79 secretlen = SKEY_MAX_SEED_LEN;
80 flg = 0;
81 } else if (!stat(_PATH_MEM, &sb) || !stat("/", &sb)) {
82 t = sb.st_ctime;
83 secret = ctime(&t);
84 secretlen = strlen(secret);
85 flg = 0;
86 }
87 }
88
89 /* Put that in your pipe and smoke it */
90 if (flg == 0) {
91 /* Hash secret value with username */
92 SHA1Init(&ctx);
93 SHA1Update(&ctx, secret, secretlen);
94 SHA1Update(&ctx, username, strlen(username));
95 SHA1End(&ctx, up);
96
97 /* Zero out */
98 memset(secret, 0, secretlen);
99
100 /* Now hash the hash */
101 SHA1Init(&ctx);
102 SHA1Update(&ctx, up, strlen(up));
103 SHA1End(&ctx, up);
104
105 ptr = hash_collapse(up + 4);
106
107 for (i = 4; i < 9; i++) {
108 pbuf[i] = (ptr % 10) + '0';
109 ptr /= 10;
110 }
111 pbuf[i] = '\0';
112
113 /* Sequence number */
114 ptr = ((up[2] + up[3]) % 99) + 1;
115
116 memset(up, 0, 20); /* SHA1 specific */
117 free(up);
118
119 (void)snprintf(skeyprompt, sizeof skeyprompt,
120 "otp-%.*s %d %.*s",
121 SKEY_MAX_HASHNAME_LEN,
122 skey_get_algorithm(),
123 ptr, SKEY_MAX_SEED_LEN,
124 pbuf);
125 } else {
126 /* Base last 8 chars of seed on username */
127 u = username;
128 i = 8;
129 p = &pbuf[4];
130 do {
131 if (*u == 0) {
132 /* Pad remainder with zeros */
133 while (--i >= 0)
134 *p++ = '0';
135 break;
136 }
137
138 *p++ = (*u++ % 10) + '0';
139 } while (--i != 0);
140 pbuf[12] = '\0';
141
142 (void)snprintf(skeyprompt, sizeof skeyprompt,
143 "otp-%.*s %d %.*s",
144 SKEY_MAX_HASHNAME_LEN,
145 skey_get_algorithm(),
146 99, SKEY_MAX_SEED_LEN, pbuf);
147 }
148 return skeyprompt;
149}