1: /* 2: ** parse.c This file contains the protocol parser 3: ** 4: ** This program is in the public domain and may be used freely by anyone 5: ** who wants to. 6: ** 7: ** Last update: 23 Feb 1994 8: ** 9: ** Please send bug fixes/bug reports to: Peter Eriksson <pen@lysator.liu.se> 10: */ 11: 12: #ifdef NeXT31 13: # include <libc.h> 14: #endif 15: 16: #include <stdio.h> 17: #include <errno.h> 18: #include <ctype.h> 19: #include <pwd.h> 20: #ifdef ALLOW_FORMAT 21: # include <grp.h> 22: #endif 23: 24: #include <sys/types.h> 25: #include <netinet/in.h> 26: 27: #ifndef HPUX7 28: # include <arpa/inet.h> 29: #endif 30: 31: #ifdef HAVE_KVM 32: # include <kvm.h> 33: #else 34: # include "kernel/kvm.h" 35: #endif 36: 37: #include <sys/types.h> 38: #include <sys/stat.h> 39: 40: #if defined(MIPS) || defined(BSD43) 41: extern int errno; 42: #endif 43: 44: #ifdef SOLARIS 45: # include <string.h> 46: # include <stdlib.h> 47: #endif 48: 49: #include "identd.h" 50: #include "error.h" 51: #include "crypto.h" 52: 53: extern void *malloc(); 54: 55: /* 56: ** This function will eat whitespace characters until 57: ** either a non-whitespace character is read, or EOF 58: ** occurs. This function is only used if the "-m" option 59: ** is enabled. 60: */ 61: static int eat_whitespace() 62: { 63: int c; 64: 65: 66: while ((c = getchar()) != EOF && 67: !(c == '\r' || c == '\n')) 68: ; 69: 70: if (c != EOF) 71: while ((c = getchar()) != EOF && 72: (c == ' ' || c == '\t' || c == '\n' || c == '\r')) 73: ; 74: 75: if (c != EOF) 76: ungetc(c, stdin); 77: 78: return (c != EOF); 79: } 80: 81: 82: #ifdef INCLUDE_EXTENSIONS 83: /* 84: ** Validate an indirect request 85: */ 86: static int valid_fhost(faddr, password) 87: struct in_addr *faddr; 88: char *password; 89: { 90: if (indirect_host == NULL) 91: return 0; 92: 93: if (strcmp(indirect_host, "*") != 0) 94: { 95: if (isdigit(indirect_host[0])) 96: { 97: if (strcmp(inet_ntoa(*faddr), indirect_host)) 98: { 99: syslog(LOG_NOTICE, "valid_fhost: Access Denied for: %s", 100: gethost(faddr)); 101: return 0; 102: } 103: } 104: else 105: { 106: if (strcmp(gethost(faddr), indirect_host)) 107: { 108: syslog(LOG_NOTICE, "valid_fhost: Access Denied for: %s", 109: gethost(faddr)); 110: return 0; 111: } 112: } 113: } 114: 115: if (indirect_password == NULL) 116: return 1; 117: 118: if (strcmp(password, indirect_password)) 119: { 120: syslog(LOG_NOTICE, "valid_fhost: Invalid password from: %s", 121: gethost(faddr)); 122: return 0; 123: } 124: 125: return 1; 126: } 127: #endif 128: 129: /* 130: ** A small routine to check for the existance of the ".noident" 131: ** file in a users home directory. 132: */ 133: static int check_noident(homedir) 134: char *homedir; 135: { 136: char *tmp_path; 137: struct stat sbuf; 138: int rcode; 139: 140: 141: if (!homedir) 142: return 0; 143: 144: tmp_path = (char *) malloc(strlen(homedir) + sizeof("/.noident") + 1); 145: if (!tmp_path) 146: return 0; 147: 148: strcpy(tmp_path, homedir); 149: strcat(tmp_path, "/.noident"); 150: 151: rcode = stat(tmp_path, &sbuf); 152: free(tmp_path); 153: 154: return (rcode == 0); 155: } 156: 157: 158: int parse(fp, laddr, faddr) 159: FILE *fp; 160: struct in_addr *laddr, *faddr; 161: { 162: int uid, try, rcode; 163: struct passwd *pwp; 164: #ifdef ALLOW_FORMAT 165: int pid; 166: char *cmd, *cmd_and_args; 167: struct group *grp; 168: char grname[128]; 169: #endif 170: char lhostaddr[16]; 171: char fhostaddr[16]; 172: char password[33]; 173: #if defined(INCLUDE_EXTENSIONS) || defined(STRONG_LOG) 174: char arg[33]; 175: #endif 176: #ifdef INCLUDE_EXTENSIONS 177: extern int proxy(); 178: int c; 179: #endif 180: struct in_addr laddr2; 181: struct in_addr faddr2; 182: int k_opened; 183: 184: k_opened = 0; 185: 186: 187: if (debug_flag && syslog_flag) 188: syslog(LOG_DEBUG, "In function parse()"); 189: 190: 191: /* 192: ** Get the local/foreign port pair from the luser 193: */ 194: do 195: { 196: if (debug_flag && syslog_flag) 197: syslog(LOG_DEBUG, " Before fscanf()"); 198: 199: faddr2 = *faddr; 200: laddr2 = *laddr; 201: lport = fport = 0; 202: lhostaddr[0] = fhostaddr[0] = password[0] = '\0'; 203: 204: 205: /* Read query from client */ 206: rcode = fscanf(fp, " %d , %d", &lport, &fport); 207: 208: #ifdef INCLUDE_EXTENSIONS 209: /* 210: ** Do additional parsing in case of extended request 211: */ 212: if (rcode == 0) 213: { 214: rcode = fscanf(fp, "%32[^ \t\n\r:]", arg); 215: 216: /* Skip leading space up to EOF, EOL or non-space char */ 217: while ((c = getc(fp)) == ' ' || c == '\t') 218: ; 219: 220: if (rcode <= 0) 221: { 222: #ifdef STRONG_LOG 223: if (syslog_flag) 224: syslog(LOG_NOTICE, "from: %s (%s) INVALID REQUEST", 225: inet_ntoa(*faddr), gethost(faddr)); 226: #endif 227: printf("%d , %d : ERROR : %s\r\n", 228: lport, fport, 229: unknown_flag ? "UNKNOWN-ERROR" : "X-INVALID-REQUEST"); 230: continue; 231: } 232: 233: /* 234: ** Non-standard extended request, returns with Pidentd 235: ** version information 236: */ 237: if (strcmp(arg, "VERSION") == 0) 238: { 239: #ifdef STRONG_LOG 240: if (syslog_flag) 241: syslog(LOG_NOTICE, "from: %s (%s) VERSION REQUEST", 242: inet_ntoa(*faddr), gethost(faddr)); 243: #endif 244: #if defined(__TIME__) && defined(__DATE__) 245: printf("%d , %d : X-VERSION : %s (Compiled: %s %s)\r\n", lport, fport, 246: version, __TIME__, __DATE__); 247: #else 248: printf("%d , %d : X-VERSION : %s\r\n", lport, fport, 249: version); 250: #endif 251: continue; 252: } 253: 254: /* 255: ** Non-standard extended proxy request 256: */ 257: else if (strcmp(arg, "PROXY") == 0 && c == ':') 258: { 259: /* We have a colon char, check for port numbers */ 260: rcode = fscanf(fp, " %d , %d : %15[0-9.] , %15[0-9.]", 261: &lport, &fport, fhostaddr, lhostaddr); 262: 263: if (!(rcode == 3 || rcode == 4)) 264: { 265: #ifdef STRONG_LOG 266: if (syslog_flag) 267: syslog(LOG_NOTICE, "from: %s (%s) INVALID PROXY REQUEST", 268: inet_ntoa(*faddr), gethost(faddr)); 269: #endif 270: 271: printf("%d , %d : ERROR : %s\r\n", 272: lport, fport, 273: unknown_flag ? "UNKNOWN-ERROR" : "X-INVALID-REQUEST"); 274: continue; 275: } 276: 277: if (rcode == 4) 278: laddr2.s_addr = inet_addr(lhostaddr); 279: 280: faddr2.s_addr = inet_addr(fhostaddr); 281: 282: #ifdef STRONG_LOG 283: if (syslog_flag) 284: { 285: char a1[64], a2[64], a3[64]; 286: 287: strcpy(a1, inet_ntoa(*faddr)); 288: strcpy(a2, inet_ntoa(faddr2)); 289: strcpy(a3, inet_ntoa(laddr2)); 290: 291: syslog(LOG_NOTICE, 292: "from: %s (%s) PROXY REQUEST for %d, %d between %s and %s", 293: a1, gethost(faddr), lport, fport, a2, a3); 294: } 295: #endif 296: 297: proxy(&laddr2, &faddr2, lport, fport, NULL); 298: continue; 299: } 300: 301: /* 302: ** Non-standard extended remote indirect request 303: */ 304: else if (strcmp(arg, "REMOTE") == 0 && c == ':') 305: { 306: /* We have a colon char, check for port numbers */ 307: rcode = fscanf(fp, " %d , %d", &lport, &fport); 308: 309: /* Skip leading space up to EOF, EOL or non-space char */ 310: while ((c = getc(fp)) == ' ' || c == '\t') 311: ; 312: 313: if (rcode != 2 || c != ':') 314: { 315: #ifdef STRONG_LOG 316: if (syslog_flag) 317: syslog(LOG_NOTICE, "from: %s (%s) INVALID REMOTE REQUEST", 318: inet_ntoa(*faddr), gethost(faddr)); 319: #endif 320: 321: printf("%d , %d : ERROR : %s\r\n", 322: lport, fport, 323: unknown_flag ? "UNKNOWN-ERROR" : "X-INVALID-REQUEST"); 324: continue; 325: } 326: 327: /* We have a colon char, check for addr and password */ 328: rcode = fscanf(fp, " %15[0-9.] , %32[^ \t\r\n]", 329: fhostaddr, password); 330: if (rcode > 0) 331: rcode += 2; 332: else 333: { 334: #ifdef STRONG_LOG 335: if (syslog_flag) 336: syslog(LOG_NOTICE, 337: "from: %s (%s) INVALID REMOTE REQUEST for %d, %d", 338: inet_ntoa(*faddr), gethost(faddr), lport, fport); 339: #endif 340: printf("%d , %d : ERROR : %s\r\n", 341: lport, fport, 342: unknown_flag ? "UNKNOWN-ERROR" : "X-INVALID-REQUEST"); 343: continue; 344: } 345: 346: /* 347: ** Verify that the host originating the indirect request 348: ** is allowed to do that 349: */ 350: if (!valid_fhost(faddr, password)) 351: { 352: #ifdef STRONG_LOG 353: if (syslog_flag) 354: syslog(LOG_NOTICE, 355: "from: %s (%s) REJECTED REMOTE REQUEST for %d, %d with password %s", 356: inet_ntoa(*faddr), gethost(faddr), lport, fport, 357: password); 358: #endif 359: printf("%d , %d : ERROR : %s\r\n", 360: lport, fport, 361: unknown_flag ? "UNKNOWN-ERROR" : "X-ACCESS-DENIED"); 362: continue; 363: } 364: 365: faddr2.s_addr = inet_addr(fhostaddr); 366: #ifdef STRONG_LOG 367: if (syslog_flag) 368: { 369: char a1[64]; 370: 371: strcpy(a1, inet_ntoa(*faddr)); 372: 373: syslog(LOG_INFO, 374: "from: %s (%s) REMOTE REQUEST for %d, %d from %s with password %s", 375: a1, gethost(faddr), lport, fport, 376: inet_ntoa(faddr2), password); 377: } 378: #endif 379: } 380: 381: else 382: { 383: #ifdef STRONG_LOG 384: if (syslog_flag) 385: syslog(LOG_NOTICE, "from: %s (%s) UNKNOWN REQUEST: %s", 386: inet_ntoa(*faddr), gethost(faddr), arg); 387: #endif 388: 389: printf("%d , %d : ERROR : %s\r\n", 390: lport, fport, 391: unknown_flag ? "UNKNOWN-ERROR" : "X-INVALID-REQUEST"); 392: continue; 393: } 394: } 395: #endif /* EXTENSIONS */ 396: 397: if (rcode < 2 || lport < 1 || lport > 65535 || fport < 1 || fport > 65535) 398: { 399: #ifdef STRONG_LOG 400: if (syslog_flag) 401: { 402: if (rcode > 0) 403: /* we have scanned at least one correct port */ 404: syslog(LOG_NOTICE, 405: "from: %s (%s) for invalid-port(s): %d , %d", 406: inet_ntoa(*faddr), gethost(faddr), lport, fport); 407: else 408: { 409: /* we have scanned nothing at all so try to get the rest */ 410: if (fscanf(fp, "%32[^\n\r]", arg) <= 0) 411: syslog(LOG_NOTICE, "from: %s (%s) EMPTY REQUEST", 412: inet_ntoa(*faddr), gethost(faddr)); 413: else 414: syslog(LOG_NOTICE, "from: %s (%s) INVALID REQUEST: %s", 415: inet_ntoa(*faddr), gethost(faddr), arg); 416: } 417: } 418: #else 419: if (syslog_flag && rcode > 0) 420: syslog(LOG_NOTICE, "scanf: invalid-port(s): %d , %d from %s", 421: lport, fport, gethost(faddr)); 422: #endif 423: 424: printf("%d , %d : ERROR : %s\r\n", 425: lport, fport, 426: unknown_flag ? "UNKNOWN-ERROR" : "INVALID-PORT"); 427: continue; 428: } 429: 430: #ifdef STRONG_LOG 431: if (syslog_flag) 432: { 433: syslog(LOG_INFO, "from: %s ( %s ) for: %d, %d", 434: inet_ntoa(*faddr), gethost(faddr), lport, fport); 435: } 436: #endif 437: 438: if (debug_flag && syslog_flag) 439: syslog(LOG_DEBUG, " After fscanf(), before k_open()"); 440: 441: 442: if (! k_opened) 443: { 444: /* 445: ** Open the kernel memory device and read the nlist table 446: ** 447: ** Of course k_open should not call ERROR (which then exits) 448: ** but maybe use syslog(LOG_ERR) and return non-zero. But I am 449: ** too lazy to change them all ... 450: */ 451: if (k_open() != 0) 452: { 453: if (syslog_flag) syslog(LOG_ERR, "k_open call failed"); 454: printf("%d , %d : ERROR : %s\r\n", 455: lport, fport, 456: unknown_flag ? "UNKNOWN-ERROR" : "X-CANNOT-OPEN-KMEM"); 457: continue; 458: } 459: k_opened = 1; 460: } 461: 462: 463: if (debug_flag && syslog_flag) 464: syslog(LOG_DEBUG, " After k_open(), before k_getuid()"); 465: 466: 467: /* 468: ** Get the specific TCP connection and return the uid - user number. 469: */ 470: 471: #ifdef ALLOW_FORMAT 472: /* Initialize values, for architectures that do not set it */ 473: pid = 0; 474: cmd = ""; 475: cmd_and_args = ""; 476: #endif 477: 478: #define MAX_RETRY 20 479: /* 480: ** Try to fetch the information MAX_RETRY times in case the 481: ** kernel changed beneath us and we missed or took a fault. 482: ** 483: ** Why would we ever fail? Is not there a reliable way for the 484: ** kernel to identify its sockets? Cannot we use that interface? 485: ** 486: ** Used to be 5 times, but often this is not enough on Alpha OSF. 487: */ 488: /* #define SLEEP_BETWEEN_RETRIES 1 */ 489: /* 490: ** If we failed in k_getuid, that is presumably because the OS was 491: ** busy creating or destroying processes. We may want to sleep for 492: ** a random time between retries, hoping for peace and quiet. 493: */ 494: 495: /* k_getuid returns 0 on success, any non-zero on failure. */ 496: 497: for (try = 0; 498: (try < MAX_RETRY && 499: k_getuid(&faddr2, htons(fport), laddr, htons(lport), &uid 500: #ifdef ALLOW_FORMAT 501: , &pid, &cmd, &cmd_and_args 502: #endif 503: ) != 0); 504: try++) 505: #ifdef SLEEP_BETWEEN_RETRIES 506: { 507: /* Seed the generator: lport should be unique (among other concurrent identd's) */ 508: if (try < 1) srandom(lport); 509: /* This gives a max sleep of 0xffff = 65535 microsecs, about 32millisec average */ 510: usleep(random()&0x00ffff); 511: } 512: #else 513: ; 514: #endif 515: 516: if (try >= MAX_RETRY) 517: { 518: if (syslog_flag) 519: syslog(LOG_INFO, "Returned: %d , %d : NO-USER", lport, fport); 520: 521: printf("%d , %d : ERROR : %s\r\n", 522: lport, fport, 523: unknown_flag ? "UNKNOWN-ERROR" : "NO-USER"); 524: continue; 525: } 526: 527: if (try > 0 && syslog_flag) 528: syslog(LOG_NOTICE, "k_getuid retries: %d", try); 529: 530: if (debug_flag && syslog_flag) 531: syslog(LOG_DEBUG, " After k_getuid(), before getpwuid()"); 532: 533: /* 534: ** Then we should try to get the username. If that fails we 535: ** return it as an OTHER identifier 536: */ 537: pwp = getpwuid(uid); 538: 539: if (!pwp || uid != pwp->pw_uid) 540: { 541: if (syslog_flag) 542: syslog(LOG_WARNING, "getpwuid() could not map uid (%d) to name", 543: uid); 544: 545: printf("%d , %d : USERID : OTHER%s%s : %d\r\n", 546: lport, fport, 547: charset_name ? " , " : "", 548: charset_name ? charset_name : "", 549: uid); 550: continue; 551: } 552: 553: #ifdef ALLOW_FORMAT 554: grp = getgrgid(pwp->pw_gid); 555: if (grp && pwp->pw_gid != grp->gr_gid) 556: { 557: if (syslog_flag) 558: syslog(LOG_WARNING, 559: "getgrgid() could not map gid (%d) to name (for uid %d, name %s)", 560: pwp->pw_gid, uid, pwp->pw_name); 561: 562: printf("%d , %d : USERID : OTHER%s%s : %d\r\n", 563: lport, fport, 564: charset_name ? " , " : "", 565: charset_name ? charset_name : "", 566: uid); 567: continue; 568: } 569: if (grp) 570: sprintf (grname, "%.99s", grp->gr_name); 571: else 572: sprintf (grname, "%d", pwp->pw_gid); 573: #endif 574: 575: /* 576: ** Hey! We finally made it!!! 577: */ 578: #ifdef ALLOW_FORMAT 579: if (syslog_flag) 580: syslog(LOG_DEBUG, "Successful lookup: %d , %d : %s.%s\n", 581: lport, fport, pwp->pw_name, grname); 582: #else 583: if (syslog_flag) 584: syslog(LOG_DEBUG, "Successful lookup: %d , %d : %s\n", 585: lport, fport, pwp->pw_name); 586: #endif 587: 588: if (noident_flag && check_noident(pwp->pw_dir)) 589: { 590: if (syslog_flag) 591: syslog(LOG_NOTICE, "User %s requested HIDDEN-USER for host %s: %d, %d", 592: pwp->pw_name, 593: gethost(faddr), 594: lport, fport); 595: 596: printf("%d , %d : ERROR : HIDDEN-USER\r\n", 597: lport, fport); 598: continue; 599: } 600: 601: #ifdef INCLUDE_CRYPT 602: if (crypto_flag) 603: printf("%d , %d : USERID : OTHER%s%s : [%s]\r\n", 604: lport, fport, 605: charset_name ? " , " : "", 606: charset_name ? charset_name : "", 607: make_packet (pwp->pw_uid, laddr, lport, faddr, fport)); 608: else 609: #endif 610: #ifdef ALLOW_FORMAT 611: if (format_flag) 612: { 613: char* cp; 614: char** gmp; 615: long bp; 616: char buff[512]; 617: for (cp = format, bp = 0; *cp != 0; cp++) 618: { 619: if (*cp == '%') 620: { 621: cp++; 622: if (*cp == 0) break; 623: else if (*cp == 'u') sprintf (&buff[bp], "%.*s", 490-bp, pwp->pw_name); 624: else if (*cp == 'U') sprintf (&buff[bp], "%d", pwp->pw_uid); 625: else if (*cp == 'g') sprintf (&buff[bp], "%.*s", 490-bp, grname); 626: else if (*cp == 'G') sprintf (&buff[bp], "%d", pwp->pw_gid); 627: else if (*cp == 'c') sprintf (&buff[bp], "%.*s", 490-bp, cmd); 628: else if (*cp == 'C') sprintf (&buff[bp], "%.*s", 490-bp, cmd_and_args); 629: else if (*cp == 'l') { 630: sprintf (&buff[bp], "%.*s", 490-bp, grname); 631: bp += strlen(&buff[bp]); if (bp >= 490) break; 632: setgrent(); 633: while (grp = getgrent()) { 634: if (grp->gr_gid == pwp->pw_gid) continue; 635: for (gmp = grp->gr_mem; *gmp && **gmp; gmp++) { 636: if (! strcmp(*gmp, pwp->pw_name)) { 637: sprintf (&buff[bp], ",%.*s", 490-bp, grp->gr_name); 638: bp += strlen(&buff[bp]); 639: break; 640: } 641: } 642: if (bp >= 490) break; 643: } 644: endgrent(); 645: } 646: else if (*cp == 'L') { 647: sprintf (&buff[bp], "%d", pwp->pw_gid); 648: bp += strlen(&buff[bp]); if (bp >= 490) break; 649: setgrent(); 650: while (grp = getgrent()) { 651: if (grp->gr_gid == pwp->pw_gid) continue; 652: for (gmp = grp->gr_mem; *gmp && **gmp; gmp++) { 653: if (! strcmp(*gmp, pwp->pw_name)) { 654: sprintf (&buff[bp], ",%d", grp->gr_gid); 655: bp += strlen(&buff[bp]); 656: break; 657: } 658: } 659: if (bp >= 490) break; 660: } 661: endgrent(); 662: } 663: else if (*cp == 'p') sprintf (&buff[bp], "%d", pid); 664: else { buff[bp] = *cp; buff[bp+1] = 0; } 665: bp += strlen(&buff[bp]); if (bp >= 490) break; 666: } 667: else { buff[bp++] = *cp; if (bp >= 490) break; } 668: } 669: if (bp >= 490) { sprintf(&buff[490], "..."); bp = 493; } 670: buff[bp] = 0; 671: printf("%d , %d : USERID : %s%s%s :%s\r\n", 672: lport, fport, 673: other_flag ? "OTHER" : "UNIX", 674: charset_name ? " , " : "", 675: charset_name ? charset_name : "", 676: buff); 677: } 678: else 679: #endif 680: printf("%d , %d : USERID : %s%s%s :%s\r\n", 681: lport, fport, 682: other_flag ? "OTHER" : "UNIX", 683: charset_name ? " , " : "", 684: charset_name ? charset_name : "", 685: pwp->pw_name); 686: 687: } while(fflush(stdout), fflush(stderr), multi_flag && eat_whitespace()); 688: 689: return 0; 690: }