blob: 7eb32e8f2b7e4966fea055c44eae6fadc714449d [file] [log] [blame]
Damien Miller95def091999-11-25 00:26:21 +11001#include "includes.h"
Damien Miller80297751999-11-19 13:03:25 +11002#ifdef SKEY
Damien Miller4af51302000-04-16 11:18:38 +10003RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10004
5#include "ssh.h"
Damien Milleraae6c611999-12-06 11:47:28 +11006#include "packet.h"
Damien Miller5f056372000-04-16 12:31:48 +10007#include <sha1.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +10008
9/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
10
Damien Miller4af51302000-04-16 11:18:38 +100011/*
Damien Milleraae6c611999-12-06 11:47:28 +110012 * try skey authentication,
Damien Miller4af51302000-04-16 11:18:38 +100013 * return 1 on success, 0 on failure, -1 if skey is not available
Damien Milleraae6c611999-12-06 11:47:28 +110014 */
15
Damien Miller4af51302000-04-16 11:18:38 +100016int
Damien Milleraae6c611999-12-06 11:47:28 +110017auth_skey_password(struct passwd * pw, const char *password)
18{
19 if (strncasecmp(password, "s/key", 5) == 0) {
20 char *skeyinfo = skey_keyinfo(pw->pw_name);
21 if (skeyinfo == NULL) {
22 debug("generating fake skeyinfo for %.100s.",
23 pw->pw_name);
24 skeyinfo = skey_fake_keyinfo(pw->pw_name);
25 }
26 if (skeyinfo != NULL)
27 packet_send_debug(skeyinfo);
28 /* Try again. */
29 return 0;
30 } else if (skey_haskey(pw->pw_name) == 0 &&
31 skey_passcheck(pw->pw_name, (char *) password) != -1) {
32 /* Authentication succeeded. */
33 return 1;
34 }
35 /* Fall back to ordinary passwd authentication. */
36 return -1;
37}
Damien Miller4e0dbd01999-12-09 10:57:00 +110038
39/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100040
41#define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \
42 ((x)[3]))
43
44/*
45 * hash_collapse()
46 */
47static u_int32_t
48hash_collapse(s)
Damien Miller4af51302000-04-16 11:18:38 +100049 u_char *s;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100050{
Damien Miller4af51302000-04-16 11:18:38 +100051 int len, target;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100052 u_int32_t i;
53
54 if ((strlen(s) % sizeof(u_int32_t)) == 0)
Damien Miller4af51302000-04-16 11:18:38 +100055 target = strlen(s); /* Multiple of 4 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100056 else
57 target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
Damien Miller4af51302000-04-16 11:18:38 +100058
Damien Millerd4a8b7e1999-10-27 13:42:43 +100059 for (i = 0, len = 0; len < target; len += 4)
Damien Miller4af51302000-04-16 11:18:38 +100060 i ^= ROUND(s + len);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100061
62 return i;
63}
Damien Miller95def091999-11-25 00:26:21 +110064
Damien Millerd4a8b7e1999-10-27 13:42:43 +100065char *
66skey_fake_keyinfo(char *username)
67{
68 int i;
69 u_int ptr;
70 u_char hseed[SKEY_MAX_SEED_LEN], flg = 1, *up;
71 char pbuf[SKEY_MAX_PW_LEN+1];
72 static char skeyprompt[SKEY_MAX_CHALLENGE+1];
73 char *secret = NULL;
74 size_t secretlen = 0;
Damien Miller25e42562000-01-11 10:59:47 +110075 SHA_CTX ctx;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100076 char *p, *u;
Damien Miller25e42562000-01-11 10:59:47 +110077 char md[SHA_DIGEST_LENGTH];
Damien Millerd4a8b7e1999-10-27 13:42:43 +100078
79 /*
80 * Base first 4 chars of seed on hostname.
81 * Add some filler for short hostnames if necessary.
82 */
83 if (gethostname(pbuf, sizeof(pbuf)) == -1)
84 *(p = pbuf) = '.';
85 else
86 for (p = pbuf; *p && isalnum(*p); p++)
87 if (isalpha(*p) && isupper(*p))
88 *p = tolower(*p);
89 if (*p && pbuf - p < 4)
90 (void)strncpy(p, "asjd", 4 - (pbuf - p));
91 pbuf[4] = '\0';
92
93 /* Hash the username if possible */
Damien Miller25e42562000-01-11 10:59:47 +110094 up = malloc(SHA_DIGEST_LENGTH);
95 if (up != NULL) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100096 struct stat sb;
97 time_t t;
98 int fd;
99
Damien Miller25e42562000-01-11 10:59:47 +1100100 SHA1_Init(&ctx);
101 SHA1_Update(&ctx, username, strlen(username));
102 SHA1_End(&ctx, up);
103
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000104 /* Collapse the hash */
105 ptr = hash_collapse(up);
106 memset(up, 0, strlen(up));
107
108 /* See if the random file's there, else use ctime */
109 if ((fd = open(_SKEY_RAND_FILE_PATH_, O_RDONLY)) != -1
110 && fstat(fd, &sb) == 0 &&
111 sb.st_size > (off_t)SKEY_MAX_SEED_LEN &&
112 lseek(fd, ptr % (sb.st_size - SKEY_MAX_SEED_LEN),
113 SEEK_SET) != -1 && read(fd, hseed,
114 SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) {
115 close(fd);
Damien Miller037a0dc1999-12-07 15:38:31 +1100116 fd = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000117 secret = hseed;
118 secretlen = SKEY_MAX_SEED_LEN;
119 flg = 0;
120 } else if (!stat(_PATH_MEM, &sb) || !stat("/", &sb)) {
121 t = sb.st_ctime;
122 secret = ctime(&t);
123 secretlen = strlen(secret);
124 flg = 0;
125 }
Damien Miller037a0dc1999-12-07 15:38:31 +1100126 if (fd != -1)
127 close(fd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000128 }
129
130 /* Put that in your pipe and smoke it */
131 if (flg == 0) {
132 /* Hash secret value with username */
Damien Miller25e42562000-01-11 10:59:47 +1100133 SHA1_Init(&ctx);
134 SHA1_Update(&ctx, secret, secretlen);
135 SHA1_Update(&ctx, username, strlen(username));
136 SHA1_End(&ctx, up);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000137
138 /* Zero out */
139 memset(secret, 0, secretlen);
140
141 /* Now hash the hash */
Damien Miller25e42562000-01-11 10:59:47 +1100142 SHA1_Init(&ctx);
143 SHA1_Update(&ctx, up, strlen(up));
144 SHA1_End(&ctx, up);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000145
146 ptr = hash_collapse(up + 4);
147
148 for (i = 4; i < 9; i++) {
149 pbuf[i] = (ptr % 10) + '0';
150 ptr /= 10;
151 }
152 pbuf[i] = '\0';
153
154 /* Sequence number */
155 ptr = ((up[2] + up[3]) % 99) + 1;
156
Damien Miller25e42562000-01-11 10:59:47 +1100157 memset(up, 0, SHA_DIGEST_LENGTH); /* SHA1 specific */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000158 free(up);
159
160 (void)snprintf(skeyprompt, sizeof skeyprompt,
161 "otp-%.*s %d %.*s",
162 SKEY_MAX_HASHNAME_LEN,
163 skey_get_algorithm(),
164 ptr, SKEY_MAX_SEED_LEN,
165 pbuf);
166 } else {
167 /* Base last 8 chars of seed on username */
168 u = username;
169 i = 8;
170 p = &pbuf[4];
171 do {
172 if (*u == 0) {
173 /* Pad remainder with zeros */
174 while (--i >= 0)
175 *p++ = '0';
176 break;
177 }
178
179 *p++ = (*u++ % 10) + '0';
180 } while (--i != 0);
181 pbuf[12] = '\0';
182
183 (void)snprintf(skeyprompt, sizeof skeyprompt,
184 "otp-%.*s %d %.*s",
185 SKEY_MAX_HASHNAME_LEN,
186 skey_get_algorithm(),
187 99, SKEY_MAX_SEED_LEN, pbuf);
188 }
189 return skeyprompt;
190}
Damien Miller80297751999-11-19 13:03:25 +1100191
Damien Miller95def091999-11-25 00:26:21 +1100192#endif /* SKEY */