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.
38 #endif /* HAVE_STRING_H */
43 #endif /* HAVE_STDLIB_H */
46 #include <sys/socket.h>
54 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
58 #define max(x, y) (((x) > (y)) ? (x) : (y))
61 static int opieauto_connect FUNCTION_NOARGS
64 struct sockaddr_un sun;
66 char *c, *c2 ="/.opieauto";
67 uid_t myuid = getuid(), myeuid = geteuid();
69 if (!myuid || !myeuid || (myuid != myeuid)) {
71 syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
76 memset(&sun, 0, sizeof(struct sockaddr_un));
77 sun.sun_family = AF_UNIX;
79 if (!(c = getenv("HOME"))) {
81 syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
86 if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
88 syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
93 strcpy(sun.sun_path, c);
94 strcat(sun.sun_path, c2);
96 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
98 syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
106 if (stat(sun.sun_path, &st) < 0) {
108 syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
113 if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
115 syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
120 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
122 syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
134 #endif /* OPIEAUTO */
136 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
141 struct opie_otpkey key;
147 char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
149 #endif /* OPIEAUTO */
151 if (!(challenge = strstr(challenge, "otp-")))
156 if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
159 if ((sequence < 2) || (sequence > 9999))
163 if (opiepasscheck(secret))
166 if (i = opiekeycrunch(algorithm, &key, seed, secret))
169 if (sequence <= OPIE_SEQUENCE_RESTRICT) {
174 char newseed[OPIE_SEED_MAX + 1];
175 struct opie_otpkey newkey;
177 char buf[OPIE_SEED_MAX + 48 + 1];
179 while (sequence-- != 0)
180 opiehash(&key, algorithm);
182 if (opienewseed(strcpy(newseed, seed)) < 0)
185 if (opiekeycrunch(algorithm, &newkey, newseed, secret))
188 for (i = 0; i < 499; i++)
189 opiehash(&newkey, algorithm);
191 strcpy(response, "init-hex:");
192 strcat(response, opiebtoh(buf, &key));
193 if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
194 newseed) >= sizeof(buf)) {
196 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
200 strcat(response, buf);
201 strcat(response, opiebtoh(buf, &newkey));
207 if ((s = opieauto_connect()) >= 0) {
208 if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
210 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
217 if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
219 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
226 window = strtoul(&cmd[3], &c, 10);
227 if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
229 syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
246 j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
248 for (i = j; i > 0; i--)
249 opiehash(&key, algorithm);
254 opiebtoa8(buf, &key);
256 if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
257 seed, buf) >= sizeof(cmd)) {
259 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
265 if (write(s, cmd, i = strlen(cmd)) != i) {
267 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
272 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
274 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
281 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')) {
283 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
288 for (i = sequence - j; i > 0; i--)
289 opiehash(&key, algorithm);
291 opiebtoh(response, &key);
296 if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
297 seed) >= sizeof(cmd))) {
299 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
304 if (write(s, cmd, i = strlen(cmd)) != i) {
306 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
311 if ((i = read(s, cmd, sizeof(cmd))) < 0) {
313 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
321 if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
328 syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
339 syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
348 syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
356 if (!(c2 = strchr(++c, '\n'))) {
359 syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
367 if (!opieatob8(&key, c))
370 opiebtoh(response, &key);
377 while (sequence-- != 0)
378 opiehash(&key, algorithm);
380 opiebtoh(response, &key);
383 #endif /* OPIEAUTO */
390 syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
396 #endif /* OPIEAUTO */