util.c (15615B)
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. 2 3 Mixmaster may be redistributed and modified under certain conditions. 4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 5 ANY KIND, either express or implied. See the file COPYRIGHT for 6 details. 7 8 Utility functions 9 $Id: util.c 934 2006-06-24 13:40:39Z rabbi $ */ 10 11 #include "mix3.h" 12 #include <stdlib.h> 13 #include <string.h> 14 #include <ctype.h> 15 #include <fcntl.h> 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #ifdef POSIX 19 #include <signal.h> 20 #include <errno.h> 21 #include <unistd.h> 22 #include <sys/file.h> 23 #include <termios.h> 24 #else /* end of POSIX */ 25 #include <io.h> 26 #endif /* else if not POSIX */ 27 #ifdef HAVE_GETKEY 28 #include <pc.h> 29 #endif /* HAVE_GETKEY */ 30 #include <assert.h> 31 32 /** string comparison functions. return 1 on match, 0 otherwise ********/ 33 34 int strileft(const char *string, const char *keyword) 35 { 36 register unsigned int i; 37 38 for (i = 0; keyword[i] != '\0'; i++) 39 if (tolower(string[i]) != tolower(keyword[i])) 40 return 0; 41 return 1; 42 } 43 44 int striright(const char *string, const char *keyword) 45 { 46 int l; 47 l = strlen(string) - strlen(keyword); 48 return (l >= 0 ? strieq(string + l, keyword) : -1); 49 } 50 51 int strleft(const char *string, const char *keyword) 52 { 53 register unsigned int i; 54 55 for (i = 0; keyword[i] != '\0'; i++) 56 if (string[i] != keyword[i]) 57 return 0; 58 return 1; 59 } 60 61 int strifind(const char *string, const char *keyword) 62 { 63 register unsigned int i, j; 64 char k; 65 66 k = tolower(keyword[0]); 67 for (i = 0; string[i] != '\0'; i++) { 68 if (tolower(string[i]) == k) { 69 for (j = 1; keyword[j] != '\0'; j++) 70 if (tolower(string[i + j]) != tolower(keyword[j])) 71 goto next; 72 return 1; 73 } 74 next: 75 ; 76 } 77 return 0; 78 } 79 80 int strieq(const char *s1, const char *s2) 81 { 82 register unsigned int i = 0; 83 84 do 85 if (tolower(s1[i]) != tolower(s2[i])) 86 return 0; 87 while (s1[i++] != '\0') ; 88 return 1; 89 } 90 91 int streq(const char *a, const char *b) 92 { 93 return (strcmp(a, b) == 0); 94 } 95 96 int strfind(const char *a, const char *keyword) 97 { 98 return (strstr(a, keyword) != NULL); 99 } 100 101 void strcatn(char *dest, const char *src, int n) 102 { 103 int l; 104 l = strlen(dest); 105 if (l < n) 106 strncpy(dest + l, src, n - l - 1); 107 dest[n-1] = '\0'; 108 } 109 110 /** files **************************************************************/ 111 112 int mixfile(char *path, const char *name) 113 { 114 char *h; 115 assert(path != NULL && name != NULL); 116 117 #ifdef POSIX 118 if (name[0] == '~' && name[1] == DIRSEP && (h = getenv("HOME")) != NULL) { 119 strncpy(path, h, PATHMAX); 120 path[PATHMAX-1] = '\0'; 121 strcatn(path, name + 1, PATHMAX); 122 } else 123 #endif /* POSIX */ 124 if (name[0] == DIRSEP || (isalpha(name[0]) && name[1] == ':') || MIXDIR == NULL) { 125 strncpy(path, name, PATHMAX); 126 path[PATHMAX-1] = '\0'; 127 } else { 128 strncpy(path, MIXDIR, PATHMAX); 129 path[PATHMAX-1] = '\0'; 130 strcatn(path, name, PATHMAX); 131 } 132 return (0); 133 } 134 135 FILE *mix_openfile(const char *name, const char *a) 136 { 137 char path[PATHMAX]; 138 139 mixfile(path, name); 140 return (fopen(path, a)); 141 } 142 143 FILE *openpipe(const char *prog) 144 { 145 FILE *p = NULL; 146 147 #ifdef POSIX 148 p = popen(prog, "w"); 149 #endif /* POSIX */ 150 #ifdef _MSC 151 p = _popen(prog, "w"); 152 #endif /* _MSC */ 153 154 if (p == NULL) 155 errlog(ERRORMSG, "Unable to open pipe to %s\n", prog); 156 return p; 157 } 158 159 int 160 file_to_out(const char *filename) 161 { 162 int len; 163 FILE *fp; 164 char chunk[1024]; 165 166 if ((fp = mix_openfile(filename, "r")) == NULL) 167 return -1; 168 while ((len = fread(chunk, 1, sizeof(chunk), fp)) > 0) 169 { 170 fwrite(chunk, 1, len, stdout); 171 } 172 fclose (fp); 173 return (len == 0 ? 0 : (-1)); 174 } 175 176 int closepipe(FILE *p) 177 { 178 #ifdef POSIX 179 return (pclose(p)); 180 #elif defined(_MSC) /* end of POSIX */ 181 return (_pclose(p)); 182 #else /* end of defined(_MSC) */ 183 return -1; 184 #endif /* else if not defined(_MSC), POSIX */ 185 } 186 187 /** Base 64 encoding ****************************************************/ 188 189 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 190 static byte asctobin[] = 191 { 192 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 193 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 194 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 195 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 196 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 197 0x80, 0x80, 0x80, 0076, 0x80, 0x80, 0x80, 0077, 198 0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073, 199 0074, 0075, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 200 0x80, 0000, 0001, 0002, 0003, 0004, 0005, 0006, 201 0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016, 202 0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026, 203 0027, 0030, 0031, 0x80, 0x80, 0x80, 0x80, 0x80, 204 0x80, 0032, 0033, 0034, 0035, 0036, 0037, 0040, 205 0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050, 206 0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060, 207 0061, 0062, 0063, 0x80, 0x80, 0x80, 0x80, 0x80, 208 209 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 210 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 211 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 212 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 213 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 214 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 215 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 216 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 217 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 218 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 219 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 220 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 221 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 222 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 223 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 224 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 225 }; 226 227 void id_encode(byte id[], byte *s) 228 { 229 sprintf 230 (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 231 id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], 232 id[10], id[11], id[12], id[13], id[14], id[15]); 233 } 234 235 void id_decode(byte *s, byte id[]) 236 { 237 int i, x[16]; 238 239 sscanf 240 (s, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 241 x, x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7, x + 8, 242 x + 9, x + 10, x + 11, x + 12, x + 13, x + 14, x + 15); 243 for (i = 0; i < 16; i++) 244 id[i] = x[i]; 245 } 246 247 int encode(BUFFER *in, int linelen) 248 { 249 byte *b, *e; 250 int i, l, m; 251 unsigned long u; 252 BUFFER *out; 253 254 out = buf_new(); 255 256 l = in->length; 257 if (l % 3 != 0) 258 l += 2; 259 l = l / 3 * 4; 260 261 if (linelen) { 262 l += l / linelen + (l % linelen > 0 ? 1 : 0); 263 } 264 linelen /= 4; /* blocks of 4 characters */ 265 266 buf_prepare(out, l); 267 268 b = in->data; 269 e = out->data; 270 m = in->length - 2; 271 for (i = 0, l = 0; i < m; i += 3) { 272 u = ((unsigned long) b[i] << 16) | ((unsigned long) b[i + 1] << 8) | 273 b[i + 2]; 274 *e++ = bintoasc[(u >> 18) & 0x3f]; 275 *e++ = bintoasc[(u >> 12) & 0x3f]; 276 *e++ = bintoasc[(u >> 6) & 0x3f]; 277 *e++ = bintoasc[u & 0x3f]; 278 if (linelen && ++l >= linelen) { 279 l = 0; 280 *e++ = '\n'; 281 } 282 } 283 if (i < in->length) { 284 *e++ = bintoasc[b[i] >> 2]; 285 *e++ = bintoasc[((b[i] << 4) & 0x30) | ((b[i + 1] >> 4) & 0x0f)]; 286 if (i + 1 == in->length) 287 *e++ = '='; 288 else 289 *e++ = bintoasc[((b[i + 1] << 2) & 0x3c) | ((b[i + 2] >> 6) & 0x03)]; 290 *e++ = '='; 291 ++l; 292 } 293 if (linelen && l != 0) 294 *e++ = '\n'; 295 *e = '\0'; 296 297 assert(out->data + out->length == e); 298 buf_move(in, out); 299 buf_free(out); 300 return (0); 301 } 302 303 int decode(BUFFER *in, BUFFER *out) 304 { 305 int err = 0; 306 register byte c0 = 0, c1 = 0, c2 = 0, c3 = 0; 307 register byte *a, *d, *end; 308 int tempbuf = 0; 309 int i; 310 311 if (in == out) { 312 out = buf_new(); 313 tempbuf = 1; 314 } 315 buf_prepare(out, 3 * (in->length - in->ptr) / 4); 316 317 a = in->data + in->ptr; 318 end = in->data + in->length - 3; 319 d = out->data; 320 i = 0; 321 322 while (a < end) { 323 if ((c0 = asctobin[a[0]]) & 0x80 || 324 (c1 = asctobin[a[1]]) & 0x80 || 325 (c2 = asctobin[a[2]]) & 0x80 || 326 (c3 = asctobin[a[3]]) & 0x80) { 327 if (a[0] == '\n') { /* ignore newline */ 328 a++; 329 continue; 330 } else if (a[0] == '\r' && a[1] == '\n') { /* ignore crlf */ 331 a += 2; 332 continue; 333 } else if (a[0] == '=' && a[1] == '4' && a[2] == '6' && !(asctobin[a[5]] & 0x80) ) { 334 a += 2; /* '=46' at the left of a line really is 'F' */ 335 *a = 'F'; /* fix in memory ... */ 336 continue; 337 } else if (a[2] == '=' || a[3] == '=') { 338 if (a[0] & 0x80 || (c0 = asctobin[a[0]]) & 0x80 || 339 a[1] & 0x80 || (c1 = asctobin[a[1]]) & 0x80) 340 err = -1; 341 else if (a[2] == '=') 342 c2 = 0, i += 1; 343 else if (a[2] & 0x80 || (c2 = asctobin[a[2]]) & 0x80) 344 err = -1; 345 else 346 i += 2; 347 if (err == 0) { 348 /* read the correct final block */ 349 *d++ = (byte) ((c0 << 2) | (c1 >> 4)); 350 *d++ = (byte) ((c1 << 4) | (c2 >> 2)); 351 if (a[3] != '=') 352 *d++ = (byte) ((c2 << 6)); 353 #if 1 354 if (a + 4 < in->data + in->length) { 355 a += 4; 356 continue; /* support Mixmaster 2.0.3 encoding */ 357 } 358 #endif /* 1 */ 359 break; 360 } 361 } 362 err = -1; 363 break; 364 } 365 a += 4; 366 367 *d++ = (byte) ((c0 << 2) | (c1 >> 4)); 368 *d++ = (byte) ((c1 << 4) | (c2 >> 2)); 369 *d++ = (byte) ((c2 << 6) | c3); 370 i += 3; 371 } 372 373 in->ptr = a - in->data; 374 375 assert(i <= out->length); 376 out->length = i; 377 378 if (tempbuf) { 379 buf_move(in, out); 380 buf_free(out); 381 } 382 return (err); 383 } 384 385 LOCK *lockfile(char *filename) 386 { 387 LOCK *l; 388 char name[LINELEN]; 389 390 strcpy(name, "lck"); 391 if (strchr(filename, DIRSEP)) 392 strcatn(name, strrchr(filename, DIRSEP), LINELEN); 393 else 394 strcatn(name, filename, LINELEN); 395 l = malloc(sizeof(LOCK)); 396 397 l->name = malloc(PATHMAX); 398 mixfile(l->name, name); 399 l->f = mix_openfile(l->name, "w+"); 400 if (l->f) 401 lock(l->f); 402 return (l); 403 } 404 405 int unlockfile(LOCK *l) 406 { 407 if (l->f) { 408 unlock(l->f); 409 fclose(l->f); 410 } 411 unlink(l->name); 412 free(l->name); 413 free(l); 414 return (0); 415 } 416 417 int lock(FILE *f) 418 { 419 #ifndef WIN32 420 struct flock lockstruct; 421 422 lockstruct.l_type = F_WRLCK; 423 lockstruct.l_whence = 0; 424 lockstruct.l_start = 0; 425 lockstruct.l_len = 0; 426 return (fcntl(fileno(f), F_SETLKW, &lockstruct)); 427 #else /* end of WIN32 */ 428 return (0); 429 #endif /* else if not WIN32 */ 430 } 431 432 int unlock(FILE *f) 433 { 434 #ifndef WIN32 435 436 struct flock lockstruct; 437 438 lockstruct.l_type = F_UNLCK; 439 lockstruct.l_whence = 0; 440 lockstruct.l_start = 0; 441 lockstruct.l_len = 0; 442 return (fcntl(fileno(f), F_SETLKW, &lockstruct)); 443 #else /* end of not WIN32 */ 444 return (0); 445 #endif /* else if WIN32 */ 446 } 447 448 /* get passphrase ******************************************************/ 449 450 static int getuserpass(BUFFER *b, int mode) 451 { 452 char p[LINELEN]; 453 int fd; 454 int n; 455 456 #ifdef HAVE_TERMIOS 457 struct termios attr; 458 459 #endif /* HAVE_TERMIOS */ 460 461 if (mode == 0) 462 fprintf(stderr, "enter passphrase: "); 463 else 464 fprintf(stderr, "re-enter passphrase: "); 465 fflush(stderr); 466 #ifndef UNIX 467 #ifdef HAVE_GETKEY 468 for (n = 0; p[n] != '\n' && n < LINELEN; n++) { 469 p[n] = getkey(); 470 } 471 p[n] = 0; 472 #else /* end of HAVE_GETKEY */ 473 scanf("%127s", p); 474 #endif /* else if not HAVE_GETKEY */ 475 #else /* end of not UNIX */ 476 fd = open("/dev/tty", O_RDONLY); 477 if (tcgetattr(fd, &attr) != 0) 478 return (-1); 479 attr.c_lflag &= ~ECHO; 480 attr.c_lflag |= ICANON; 481 if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) 482 return (-1); 483 484 n = read(fd, p, LINELEN); 485 486 attr.c_lflag |= ECHO; 487 if (tcsetattr(fd, TCSAFLUSH, &attr) != 0) 488 return (-1); 489 490 close(fd); 491 fprintf(stderr, "\n"); 492 p[n - 1] = 0; 493 #endif /* else if UNIX */ 494 if (mode == 0) 495 buf_appends(b, p); 496 else 497 return (bufeq(b, p)); 498 return (0); 499 } 500 501 static BUFFER *userpass = NULL; 502 503 int user_pass(BUFFER *key) 504 { 505 if (userpass == NULL) { 506 userpass = buf_new(); 507 userpass->sensitive = 1; 508 if (getenv("MIXPASS")) 509 buf_sets(userpass, getenv("MIXPASS")); 510 else if (menu_getuserpass(userpass, 0) == -1) 511 getuserpass(userpass, 0); 512 } 513 buf_set(key, userpass); 514 key->sensitive = 1; 515 return (0); 516 } 517 518 int user_confirmpass(BUFFER *key) 519 { 520 int ok; 521 522 ok = menu_getuserpass(key, 1); 523 if (ok == -1) 524 ok = getuserpass(key, 1); 525 return (ok); 526 } 527 528 void user_delpass(void) 529 { 530 if (userpass) 531 buf_free(userpass); 532 userpass = NULL; 533 } 534 535 int write_pidfile(char *pidfile) 536 { 537 int err = 0; 538 #ifdef POSIX 539 FILE *f; 540 char host[LINELEN], myhostname[LINELEN]; 541 int pid, mypid; 542 int assigned; 543 544 mypid = getpid(); 545 gethostname(myhostname, LINELEN); 546 myhostname[LINELEN-1] = '\0'; 547 548 f = mix_openfile(pidfile, "r+"); 549 if (f != NULL) { 550 assert(LINELEN > 71); 551 assigned = fscanf(f, "%d %70s", &pid, host); 552 if (assigned == 2) { 553 if (strcmp(host, myhostname) == 0) { 554 if (kill (pid, 0) == -1) { 555 if (errno == ESRCH) { 556 fprintf(stderr, "Rewriting stale pid file.\n"); 557 rewind(f); 558 ftruncate(fileno(f), 0); 559 fprintf(f, "%d %s\n", mypid, myhostname); 560 } else { 561 fprintf(stderr, "Pid file exists and process still running.\n"); 562 err = -1; 563 } 564 } else { 565 fprintf(stderr, "Pid file exists and process still running.\n"); 566 err = -1; 567 } 568 } else { 569 /* Pid file was written on another host, fail */ 570 fprintf(stderr, "Pid file exists and was created on another host (%s).\n", host); 571 err = -1; 572 } 573 } else { 574 fprintf(stderr, "Pid file exists and and could not be parsed.\n"); 575 err = -1; 576 } 577 } else { 578 if (errno == ENOENT) { 579 f = mix_openfile(pidfile, "w+"); 580 if (f != NULL) { 581 fprintf(f, "%d %s\n", mypid, myhostname); 582 } else { 583 fprintf(stderr, "Could not open pidfile for writing: %s\n", strerror(errno)); 584 err = -1; 585 } 586 } else { 587 fprintf(stderr, "Could not open pidfile for readwrite: %s\n", strerror(errno)); 588 err = -1; 589 }; 590 } 591 if(f) 592 fclose(f); 593 #endif /* POSIX */ 594 return (err); 595 } 596 597 int clear_pidfile(char *pidfile) 598 { 599 #ifdef POSIX 600 char path[PATHMAX]; 601 602 mixfile(path, pidfile); 603 return (unlink(path)); 604 #else /* end of POSIX */ 605 return (0); 606 #endif /* else if not POSIX */ 607 } 608 609 time_t parse_yearmonthday(char* str) 610 { 611 time_t date; 612 int day, month, year; 613 614 if (sscanf( str, "%d-%d-%d", &year, &month, &day) == 3 ) { 615 struct tm timestruct; 616 char *tz; 617 618 tz = getenv("TZ"); 619 #ifdef HAVE_SETENV 620 setenv("TZ", "GMT", 1); 621 #else /* end of HAVE_SETENV */ 622 putenv("TZ=GMT"); 623 #endif /* else if not HAVE_SETENV */ 624 tzset(); 625 memset(×truct, 0, sizeof(timestruct)); 626 timestruct.tm_mday = day; 627 timestruct.tm_mon = month - 1; 628 timestruct.tm_year = year - 1900; 629 date = mktime(×truct); 630 #ifdef HAVE_SETENV 631 if (tz) 632 setenv("TZ", tz, 1); 633 else 634 unsetenv("TZ"); 635 #else /* end of HAVE_SETENV */ 636 if (tz) { 637 char envstr[LINELEN]; 638 snprintf(envstr, LINELEN, "TZ=%s", tz); 639 putenv(envstr); 640 } else 641 putenv("TZ="); 642 #endif /* else if not HAVE_SETENV */ 643 tzset(); 644 return date; 645 } else 646 return -1; 647 } 648 649 /* functions missing on some systems *************************************/ 650 651 #ifdef __RSXNT__ 652 int fileno(FILE *f) 653 { 654 return (f->_handle); 655 } 656 657 #endif /* __RSXNT__ */ 658 659 #ifdef _MSC /* Visual C lacks dirent */ 660 661 DIR *opendir(const char *name) 662 { 663 DIR *dir; 664 WIN32_FIND_DATA d; 665 char path[PATHMAX]; 666 667 dir = malloc(sizeof(HANDLE)); 668 669 sprintf(path, "%s%c*", name, DIRSEP); 670 *dir = FindFirstFile(path, &d); 671 /* first file found is "." -- can be safely ignored here */ 672 673 if (*dir == INVALID_HANDLE_VALUE) { 674 free(dir); 675 return (NULL); 676 } else 677 return (dir); 678 } 679 680 struct dirent e; 681 struct dirent *readdir(DIR *dir) 682 { 683 WIN32_FIND_DATA d; 684 int ok; 685 686 ok = FindNextFile(*dir, &d); 687 if (ok) { 688 strncpy(e.d_name, d.cFileName, PATHMAX); 689 return (&e); 690 } else 691 return (NULL); 692 } 693 694 int closedir(DIR *dir) 695 { 696 if (dir) { 697 FindClose(*dir); 698 free(dir); 699 return (0); 700 } 701 return (-1); 702 } 703 704 #endif /* _MSC */