1 /* generator.c: The opiegenerator() library function.
3 %%% portions-copyright-cmetz-96
4 Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
5 Reserved. The Inner Net License Version 2 applies to these portions of
7 You should have received a copy of the license with this software. If
8 you didn't get a copy, you may request one from <license@inner.net>.
12 Modified by cmetz for OPIE 2.4. Added opieauto code based on
13 previously released test code. Renamed buffer to challenge.
14 Use struct opie_otpkey for keys.
15 Modified by cmetz for OPIE 2.32. If secret=NULL, always return
16 as if opieauto returned "get the secret". Renamed
17 _opieparsechallenge() to __opieparsechallenge(). Check
18 challenge for extended response support and don't send
19 an init-hex response if extended response support isn't
20 indicated in the challenge.
21 Modified by cmetz for OPIE 2.31. Renamed "init" to "init-hex".
22 Removed active attack protection support. Fixed fairly
23 bug in how init response was computed (i.e., dead wrong).
24 Modified by cmetz for OPIE 2.3. Use _opieparsechallenge(). ifdef
25 around string.h. Output hex responses by default, output
26 OTP re-init extended responses (same secret) if sequence
27 number falls below 10.
28 Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
30 Created at NRL for OPIE 2.2.
32 $FreeBSD: src/contrib/opie/libopie/generator.c,v 1.3.6.2 2002/07/15 14:48:47 des Exp $
33 $DragonFly: src/contrib/opie/libopie/generator.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
39 #endif /* HAVE_STRING_H */
44 #endif /* HAVE_STDLIB_H */
47 #include <sys/socket.h>
55 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
59 #define max(x, y) (((x) > (y)) ? (x) : (y))
62 static int opieauto_connect FUNCTION_NOARGS
65 struct sockaddr_un sun;
67 char *c, *c2 ="/.opieauto";
68 uid_t myuid = getuid(), myeuid = geteuid();
70 if (!myuid || !myeuid || (myuid != myeuid)) {
72 syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
77 memset(&sun, 0, sizeof(struct sockaddr_un));
78 sun.sun_family = AF_UNIX;
80 if (!(c = getenv("HOME"))) {
82 syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
87 if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
89 syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
94 strcpy(sun.sun_path, c);
95 strcat(sun.sun_path, c2);
97 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
99 syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
107 if (stat(sun.sun_path, &st) < 0) {
109 syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
114 if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
116 syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
121 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
123 syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
135 #endif /* OPIEAUTO */
137 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
142 struct opie_otpkey key;
148 char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
150 #endif /* OPIEAUTO */
152 if (!(challenge = strstr(challenge, "otp-")))
157 if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
160 if ((sequence < 2) || (sequence > 9999))
164 if (opiepasscheck(secret))
167 if (i = opiekeycrunch(algorithm, &key, seed, secret))
170 if (sequence <= OPIE_SEQUENCE_RESTRICT) {
175 char newseed[OPIE_SEED_MAX + 1];
176 struct opie_otpkey newkey;
178 char buf[OPIE_SEED_MAX + 48 + 1];
180 while (sequence-- != 0)
181 opiehash(&key, algorithm);
183 if (opienewseed(strcpy(newseed, seed)) < 0)
186 if (opiekeycrunch(algorithm, &newkey, newseed, secret))
189 for (i = 0; i < 499; i++)
190 opiehash(&newkey, algorithm);
192 strcpy(response, "init-hex:");
193 strcat(response, opiebtoh(buf, &key));
194 if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
195 newseed) >= sizeof(buf)) {
197 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
201 strcat(response, buf);
202 strcat(response, opiebtoh(buf, &newkey));
208 if ((s = opieauto_connect()) >= 0) {
209 if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
211 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
218 if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
220 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
227 window = strtoul(&cmd[3], &c, 10);
228 if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
230 syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
247 j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
249 for (i = j; i > 0; i--)
250 opiehash(&key, algorithm);
255 opiebtoa8(buf, &key);
257 if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
258 seed, buf) >= sizeof(cmd)) {
260 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
266 if (write(s, cmd, i = strlen(cmd)) != i) {
268 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
273 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
275 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
282 if ((cmd[0] != 'S') || (cmd[1] != '+') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i) || (*(c + i) != '\n')) {
284 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
289 for (i = sequence - j; i > 0; i--)
290 opiehash(&key, algorithm);
292 opiebtoh(response, &key);
297 if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
298 seed) >= sizeof(cmd))) {
300 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
305 if (write(s, cmd, i = strlen(cmd)) != i) {
307 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
312 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
314 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
322 if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
329 syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
340 syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
349 syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
357 if (!(c2 = strchr(++c, '\n'))) {
360 syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
368 if (!opieatob8(&key, c))
371 opiebtoh(response, &key);
378 while (sequence-- != 0)
379 opiehash(&key, algorithm);
381 opiebtoh(response, &key);
384 #endif /* OPIEAUTO */
391 syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
397 #endif /* OPIEAUTO */