generator.c revision 303975
1/* generator.c: The opiegenerator() library function. 2 3%%% portions-copyright-cmetz-96 4Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights 5Reserved. The Inner Net License Version 2 applies to these portions of 6the software. 7You should have received a copy of the license with this software. If 8you didn't get a copy, you may request one from <license@inner.net>. 9 10 History: 11 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. 29 Bug fixes. 30 Created at NRL for OPIE 2.2. 31 32$FreeBSD: releng/11.0/contrib/opie/libopie/generator.c 257264 2013-10-28 18:24:31Z sbruno $ 33*/ 34 35#include "opie_cfg.h" 36#if HAVE_STRING_H 37#include <string.h> 38#endif /* HAVE_STRING_H */ 39#if OPIEAUTO 40#include <errno.h> 41#if HAVE_STDLIB_H 42#include <stdlib.h> 43#endif /* HAVE_STDLIB_H */ 44#include <sys/stat.h> 45 46#include <sys/socket.h> 47#include <sys/un.h> 48#endif /* OPIEAUTO */ 49#if DEBUG 50#include <syslog.h> 51#endif /* DEBUG */ 52#include <stdio.h> 53#include "opie.h" 54 55static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 56 57#if OPIEAUTO 58#ifndef max 59#define max(x, y) (((x) > (y)) ? (x) : (y)) 60#endif /* max */ 61 62static int opieauto_connect FUNCTION_NOARGS 63{ 64 int s; 65 struct sockaddr_un sun; 66 char buffer[1024]; 67 char *c, *c2 ="/.opieauto"; 68 uid_t myuid = getuid(), myeuid = geteuid(); 69 70 if (!myuid || !myeuid || (myuid != myeuid)) { 71#if DEBUG 72 syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed"); 73#endif /* DEBUG */ 74 return -1; 75 }; 76 77 memset(&sun, 0, sizeof(struct sockaddr_un)); 78 sun.sun_family = AF_UNIX; 79 80 if (!(c = getenv("HOME"))) { 81#if DEBUG 82 syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?"); 83#endif /* DEBUG */ 84 return -1; 85 }; 86 87 if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) { 88#if DEBUG 89 syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c); 90#endif /* DEBUG */ 91 return -1; 92 }; 93 94 strcpy(sun.sun_path, c); 95 strcat(sun.sun_path, c2); 96 97 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { 98#if DEBUG 99 syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno); 100#endif /* DEBUG */ 101 return -1; 102 }; 103 104 { 105 struct stat st; 106 107 if (stat(sun.sun_path, &st) < 0) { 108#if DEBUG 109 syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno); 110#endif /* DEBUG */ 111 goto ret; 112 }; 113 114 if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) { 115#if DEBUG 116 syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno); 117#endif /* DEBUG */ 118 goto ret; 119 }; 120 121 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) { 122#if DEBUG 123 syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n"); 124#endif /* DEBUG */ 125 goto ret; 126 }; 127 }; 128 129 return s; 130 131ret: 132 close(s); 133 return -1; 134}; 135#endif /* OPIEAUTO */ 136 137int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response) 138{ 139 int algorithm; 140 int sequence; 141 char *seed; 142 struct opie_otpkey key; 143 int i; 144 int exts; 145#if OPIEAUTO 146 int s; 147 int window; 148 char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1]; 149 char *c; 150#endif /* OPIEAUTO */ 151 152 if (!(challenge = strstr(challenge, "otp-"))) 153 return 1; 154 155 challenge += 4; 156 157 if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts)) 158 return 1; 159 160 if ((sequence < 2) || (sequence > 9999)) 161 return 1; 162 163 if (*secret) { 164 if (opiepasscheck(secret)) 165 return -2; 166 167 if (i = opiekeycrunch(algorithm, &key, seed, secret)) 168 return i; 169 170 if (sequence <= OPIE_SEQUENCE_RESTRICT) { 171 if (!(exts & 1)) 172 return 1; 173 174 { 175 char newseed[OPIE_SEED_MAX + 1]; 176 struct opie_otpkey newkey; 177 char *c; 178 char buf[OPIE_SEED_MAX + 48 + 1]; 179 180 while (sequence-- != 0) 181 opiehash(&key, algorithm); 182 183 if (opienewseed(strcpy(newseed, seed)) < 0) 184 return -1; 185 186 if (opiekeycrunch(algorithm, &newkey, newseed, secret)) 187 return -1; 188 189 for (i = 0; i < 499; i++) 190 opiehash(&newkey, algorithm); 191 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)) { 196#ifdef DEBUG 197 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex"); 198#endif /* DEBUG */ 199 return -1; 200 } 201 strcat(response, buf); 202 strcat(response, opiebtoh(buf, &newkey)); 203 }; 204 }; 205 }; 206 207#if OPIEAUTO 208 if ((s = opieauto_connect()) >= 0) { 209 if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) { 210#if DEBUG 211 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno); 212#endif /* DEBUG */ 213 close(s); 214 s = -1; 215 goto l0; 216 }; 217 cmd[i] = 0; 218 if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) { 219#if DEBUG 220 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd); 221#endif /* DEBUG */ 222 close(s); 223 s = -1; 224 goto l0; 225 }; 226 227 window = strtoul(&cmd[3], &c, 10); 228 if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) { 229#if DEBUG 230 syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd); 231#endif /* DEBUG */ 232 close(s); 233 s = -1; 234 goto l0; 235 }; 236 }; 237 238l0: 239 if (*secret) { 240 int j; 241 242 if (s < 0) { 243 j = 0; 244 goto l1; 245 }; 246 247 j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT); 248 249 for (i = j; i > 0; i--) 250 opiehash(&key, algorithm); 251 252 { 253 char buf[16+1]; 254 255 opiebtoa8(buf, &key); 256 257 if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence, 258 seed, buf) >= sizeof(cmd)) { 259#if DEBUG 260 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n"); 261#endif /* DEBUG */ 262 goto l1; 263 } 264 } 265 266 if (write(s, cmd, i = strlen(cmd)) != i) { 267#if DEBUG 268 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno); 269#endif /* DEBUG */ 270 goto l1; 271 }; 272 273 if ((i = read(s, cmd, sizeof(cmd))) < 0) { 274#if DEBUG 275 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno); 276#endif /* DEBUG */ 277 }; 278 close(s); 279 280 cmd[i] = 0; 281 i = strlen(seed); 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')) { 283#if DEBUG 284 syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd); 285#endif /* DEBUG */ 286 }; 287 288l1: 289 for (i = sequence - j; i > 0; i--) 290 opiehash(&key, algorithm); 291 292 opiebtoh(response, &key); 293 } else { 294 if (s < 0) 295 goto l2; 296 297 if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence, 298 seed) >= sizeof(cmd))) { 299#if DEBUG 300 syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n"); 301#endif /* DEBUG */ 302 goto l2; 303 } 304 305 if (write(s, cmd, i = strlen(cmd)) != i) { 306#if DEBUG 307 syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno); 308#endif /* DEBUG */ 309 goto l2; 310 }; 311 312 if ((i = read(s, cmd, sizeof(cmd))) < 0) { 313#if DEBUG 314 syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno); 315#endif /* DEBUG */ 316 goto l2; 317 }; 318 close(s); 319 320 i = strlen(seed); 321 322 if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) { 323#if DEBUG 324 if (c) 325 *c = 0; 326 else 327 cmd[3] = 0; 328 329 syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd); 330#endif /* DEBUG */ 331 goto l2; 332 }; 333 334 c += i; 335 336 if (cmd[1] == '-') { 337#if DEBUG 338 if (*c != '\n') { 339 *c = 0; 340 syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd); 341 }; 342#endif /* DEBUG */ 343 goto l2; 344 }; 345 346 if (cmd[1] != '+') { 347#if DEBUG 348 *c = 0; 349 syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd); 350#endif /* DEBUG */ 351 goto l2; 352 }; 353 354 { 355 char *c2; 356 357 if (!(c2 = strchr(++c, '\n'))) { 358#if DEBUG 359 *c = 0; 360 syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd); 361#endif /* DEBUG */ 362 goto l2; 363 }; 364 365 *c2++ = 0; 366 }; 367 368 if (!opieatob8(&key, c)) 369 goto l2; 370 371 opiebtoh(response, &key); 372 }; 373 374 if (s >= 0) 375 close(s); 376#else /* OPIEAUTO */ 377 if (*secret) { 378 while (sequence-- != 0) 379 opiehash(&key, algorithm); 380 381 opiebtoh(response, &key); 382 } else 383 return -2; 384#endif /* OPIEAUTO */ 385 386 return 0; 387 388#if OPIEAUTO 389l2: 390#if DEBUG 391 syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n"); 392#endif /* DEBUG */ 393 if (s >= 0) 394 close(s); 395 396 return -2; 397#endif /* OPIEAUTO */ 398}; 399