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 $
40 #endif /* HAVE_STRING_H */
45 #endif /* HAVE_STDLIB_H */
48 #include <sys/socket.h>
56 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
60 #define max(x, y) (((x) > (y)) ? (x) : (y))
63 static int opieauto_connect FUNCTION_NOARGS
66 struct sockaddr_un sun;
68 char *c, *c2 ="/.opieauto";
69 uid_t myuid = getuid(), myeuid = geteuid();
71 if (!myuid || !myeuid || (myuid != myeuid)) {
73 syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
78 memset(&sun, 0, sizeof(struct sockaddr_un));
79 sun.sun_family = AF_UNIX;
81 if (!(c = getenv("HOME"))) {
83 syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
88 if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
90 syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
95 strcpy(sun.sun_path, c);
96 strcat(sun.sun_path, c2);
98 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
100 syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
108 if (stat(sun.sun_path, &st) < 0) {
110 syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
115 if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
117 syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
122 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
124 syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
136 #endif /* OPIEAUTO */
138 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
143 struct opie_otpkey key;
149 char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
151 #endif /* OPIEAUTO */
153 if (!(challenge = strstr(challenge, "otp-")))
158 if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
161 if ((sequence < 2) || (sequence > 9999))
165 if (opiepasscheck(secret))
168 if (i = opiekeycrunch(algorithm, &key, seed, secret))
171 if (sequence <= OPIE_SEQUENCE_RESTRICT) {
176 char newseed[OPIE_SEED_MAX + 1];
177 struct opie_otpkey newkey;
179 char buf[OPIE_SEED_MAX + 48 + 1];
181 while (sequence-- != 0)
182 opiehash(&key, algorithm);
184 if (opienewseed(strcpy(newseed, seed)) < 0)
187 if (opiekeycrunch(algorithm, &newkey, newseed, secret))
190 for (i = 0; i < 499; i++)
191 opiehash(&newkey, algorithm);
193 strcpy(response, "init-hex:");
194 strcat(response, opiebtoh(buf, &key));
195 if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
196 newseed) >= sizeof(buf)) {
198 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
202 strcat(response, buf);
203 strcat(response, opiebtoh(buf, &newkey));
209 if ((s = opieauto_connect()) >= 0) {
210 if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
212 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
219 if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
221 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
228 window = strtoul(&cmd[3], &c, 10);
229 if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
231 syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
248 j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
250 for (i = j; i > 0; i--)
251 opiehash(&key, algorithm);
256 opiebtoa8(buf, &key);
258 if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
259 seed, buf) >= sizeof(cmd)) {
261 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
267 if (write(s, cmd, i = strlen(cmd)) != i) {
269 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
274 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
276 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
283 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')) {
285 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
290 for (i = sequence - j; i > 0; i--)
291 opiehash(&key, algorithm);
293 opiebtoh(response, &key);
298 if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
299 seed) >= sizeof(cmd))) {
301 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
306 if (write(s, cmd, i = strlen(cmd)) != i) {
308 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
313 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
315 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
323 if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
330 syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
341 syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
350 syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
358 if (!(c2 = strchr(++c, '\n'))) {
361 syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
369 if (!opieatob8(&key, c))
372 opiebtoh(response, &key);
379 while (sequence-- != 0)
380 opiehash(&key, algorithm);
382 opiebtoh(response, &key);
385 #endif /* OPIEAUTO */
392 syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
398 #endif /* OPIEAUTO */