|
|
1.1 ! root 1: /* popser.c - the POP service */ ! 2: ! 3: #include "../h/mh.h" ! 4: #include "../h/dropsbr.h" ! 5: #include "../zotnet/bboards.h" ! 6: #include <stdio.h> ! 7: #include "../zotnet/mts.h" ! 8: #include <ctype.h> ! 9: #include <errno.h> ! 10: #include <pwd.h> ! 11: #include <signal.h> ! 12: #include <syslog.h> ! 13: #include <sys/types.h> ! 14: #include <sys/stat.h> ! 15: ! 16: ! 17: #define TRUE 1 ! 18: #define FALSE 0 ! 19: ! 20: #define NVEC 4 ! 21: ! 22: /* */ ! 23: ! 24: extern int errno; ! 25: ! 26: extern int debug; ! 27: extern char myhost[]; ! 28: extern char *myname; ! 29: ! 30: static enum state { ! 31: auth1, auth2, trans, update, halt, error ! 32: } mystate; ! 33: ! 34: ! 35: int user (), pass (); ! 36: #ifdef RPOP ! 37: int rpop (); ! 38: #endif RPOP ! 39: int status (), list (), retrieve (), delete (), reset (); ! 40: int top (); ! 41: #ifdef BPOP ! 42: int xtnd (); ! 43: #endif BPOP ! 44: int quit (); ! 45: ! 46: static struct vector { ! 47: char *v_cmd; ! 48: int v_min, v_max; ! 49: int (*v_vec) (); ! 50: enum state v_valid; ! 51: enum state v_win, v_lose; ! 52: } vectors[] = { ! 53: "user", 1, 1, user, auth1, auth2, auth1, ! 54: "pass", 1, 1, pass, auth2, trans, auth1, ! 55: #ifdef RPOP ! 56: "rpop", 1, 1, rpop, auth2, trans, auth1, ! 57: #endif RPOP ! 58: "quit", 0, 0, NULL, auth1, halt, halt, ! 59: "quit", 0, 0, NULL, auth2, halt, halt, ! 60: ! 61: "stat", 0, 0, status, trans, trans, trans, ! 62: "list", 0, 1, list, trans, trans, trans, ! 63: "retr", 1, 1, retrieve, trans, trans, trans, ! 64: "dele", 1, 1, delete, trans, trans, trans, ! 65: "noop", 0, 0, NULL, trans, trans, trans, ! 66: "rset", 0, 0, reset, trans, trans, trans, ! 67: ! 68: "top", 2, 2, top, trans, trans, trans, ! 69: #ifdef BPOP ! 70: "xtnd", 1, 2, xtnd, trans, trans, trans, ! 71: #endif BPOP ! 72: ! 73: "quit", 0, 0, quit, trans, halt, halt, ! 74: ! 75: NULL ! 76: }; ! 77: ! 78: struct vector *getvector (); ! 79: ! 80: /* */ ! 81: ! 82: #ifdef DPOP ! 83: static int pop_uid; ! 84: static int pop_gid; ! 85: #endif DPOP ! 86: ! 87: static int rproto; ! 88: static char *hostname; ! 89: static char server[BUFSIZ]; ! 90: ! 91: static char username[BUFSIZ]; ! 92: ! 93: static char maildrop[BUFSIZ]; ! 94: static int mode; ! 95: static time_t mtime; ! 96: static FILE *dp; ! 97: ! 98: #ifdef BPOP ! 99: static int xtnded; ! 100: ! 101: static int guest_uid; ! 102: static int guest_gid; ! 103: ! 104: static struct bboard *BBhead = NULL; ! 105: static struct bboard *BBtail = NULL; ! 106: ! 107: static long BBtime = 0L; ! 108: ! 109: struct bboard *getbbaux (); ! 110: #endif BPOP ! 111: ! 112: ! 113: struct Msg { /* Msgs[0] contains info for entire maildrop */ ! 114: struct drop m_drop; ! 115: #define m_id m_drop.d_id ! 116: #define m_size m_drop.d_size ! 117: #define m_start m_drop.d_start ! 118: #define m_stop m_drop.d_stop ! 119: ! 120: unsigned m_flags; ! 121: #define MNULL 0x00 ! 122: #define MDELE 0x01 ! 123: #define MREAD 0x02 ! 124: }; ! 125: ! 126: static int nMsgs = 0; ! 127: static struct Msg *Msgs = NULL; ! 128: ! 129: static int nmsgs; ! 130: static int dmsgs; ! 131: ! 132: ! 133: #define TRM "." ! 134: #define TRMLEN (sizeof TRM - 1) ! 135: #define IAC 255 ! 136: ! 137: int pipeser (); ! 138: ! 139: FILE *input; ! 140: FILE *output; ! 141: ! 142: ! 143: void padvise (), padios (); ! 144: long lseek (); ! 145: char *crypt (); ! 146: ! 147: /* */ ! 148: ! 149: popinit () { ! 150: #ifdef BPOP ! 151: padvise (NULLCP, LOG_INFO, "initialize list of BBoards"); ! 152: ! 153: BBhead = BBtail = NULL; ! 154: while (getbbaux (NULLCP)) ! 155: continue; ! 156: #endif BPOP ! 157: } ! 158: ! 159: popassert () { ! 160: #ifdef BPOP ! 161: register char **p; ! 162: register struct bboard *bb, ! 163: *bp; ! 164: ! 165: if (BBtime == getbbtime ()) ! 166: return; ! 167: ! 168: padvise (NULLCP, LOG_INFO, "list of BBoards has changed"); ! 169: ! 170: for (bb = BBhead; bb; bb = bp) { ! 171: bp = bb -> bb_next; ! 172: ! 173: if (bb -> bb_name) ! 174: free (bb -> bb_name); ! 175: if (bb -> bb_file) ! 176: free (bb -> bb_file); ! 177: if (bb -> bb_archive) ! 178: free (bb -> bb_archive); ! 179: if (bb -> bb_info) ! 180: free (bb -> bb_info); ! 181: if (bb -> bb_map) ! 182: free (bb -> bb_map); ! 183: if (bb -> bb_passwd) ! 184: free (bb -> bb_passwd); ! 185: if (bb -> bb_date) ! 186: free (bb -> bb_date); ! 187: if (bb -> bb_addr) ! 188: free (bb -> bb_addr); ! 189: if (bb -> bb_request) ! 190: free (bb -> bb_request); ! 191: if (bb -> bb_relay) ! 192: free (bb -> bb_relay); ! 193: ! 194: for (p = bb -> bb_aka; *p; p++) ! 195: free (*p); ! 196: free ((char *) bb -> bb_aka); ! 197: ! 198: for (p = bb -> bb_leader; *p; p++) ! 199: free (*p); ! 200: free ((char *) bb -> bb_leader); ! 201: ! 202: for (p = bb -> bb_dist; *p; p++) ! 203: free (*p); ! 204: free ((char *) bb -> bb_dist); ! 205: ! 206: free ((char *) bb); ! 207: } ! 208: ! 209: BBhead = BBtail = NULL; ! 210: while (getbbaux (NULLCP)) ! 211: continue; ! 212: #endif BPOP ! 213: } ! 214: ! 215: /* */ ! 216: ! 217: pop (in, out, priv, rhost) ! 218: int in, ! 219: out, ! 220: priv; ! 221: char *rhost; ! 222: { ! 223: char buffer[BUFSIZ], ! 224: *vec[NVEC + 1]; ! 225: #if defined (DPOP) || defined (BPOP) ! 226: register struct passwd *pw; ! 227: #endif defined (DPOP) || defined (BPOP) ! 228: register struct vector *v; ! 229: ! 230: m_foil (NULLCP); ! 231: mts_init (myname); ! 232: ! 233: rproto = priv; ! 234: hostname = rhost; ! 235: (void) sprintf (server, "%s %s server", myhost, priv ? "RPOP" : "POP"); ! 236: ! 237: if ((input = fdopen (in, "r")) == NULL ! 238: || (output = fdopen (out, "w")) == NULL) {/* you lose big */ ! 239: (void) respond (NOTOK, "%s loses on initialization", server); ! 240: return; ! 241: } ! 242: (void) signal (SIGPIPE, pipeser); ! 243: ! 244: #ifdef DPOP ! 245: if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1)) { ! 246: (void) respond (NOTOK, "%s loses on DB initialization -- %s", ! 247: server, pw ? getbberr () : "POP user-id unknown"); ! 248: return; ! 249: } ! 250: pop_uid = pw -> pw_uid; ! 251: pop_gid = pw -> pw_gid; ! 252: #endif DPOP ! 253: #ifdef BPOP ! 254: if ((pw = getpwnam (popbbuser)) && pw -> pw_uid) { ! 255: guest_uid = pw -> pw_uid; ! 256: guest_gid = pw -> pw_gid; ! 257: } ! 258: else ! 259: guest_uid = guest_gid = 0; ! 260: #endif BPOP ! 261: ! 262: (void) respond (OK, "%s ready (Comments to: PostMaster@%s)", ! 263: server, myhost); ! 264: ! 265: for (mystate = auth1; mystate != halt && mystate != error;) ! 266: switch (getline (buffer, sizeof buffer, input)) { ! 267: case OK: ! 268: if ((v = getvector (buffer, vec)) == NULL) ! 269: continue; ! 270: mystate = (v -> v_vec ? (v -> v_vec) (vec) ! 271: : respond (OK, NULLCP)) == OK ! 272: ? v -> v_win ! 273: : v -> v_lose; ! 274: break; ! 275: ! 276: case NOTOK: ! 277: case DONE: ! 278: mystate = error; ! 279: (void) respond (NOTOK, "%s signing off", server); ! 280: break; ! 281: } ! 282: } ! 283: ! 284: /* */ ! 285: ! 286: static int user (vec) ! 287: register char **vec; ! 288: { ! 289: make_lower (username, vec[1]); ! 290: ! 291: return respond (OK, "password required for %s", username); ! 292: } ! 293: ! 294: /* */ ! 295: ! 296: static int pass (vec) ! 297: register char **vec; ! 298: { ! 299: int guest = 0; ! 300: #ifndef DPOP ! 301: register struct passwd *pw; ! 302: #else DPOP ! 303: register struct bboard *pw; ! 304: #endif DPOP ! 305: ! 306: #ifndef DPOP ! 307: #ifdef BPOP ! 308: if (isguest ()) { ! 309: #ifdef TRUSTED ! 310: static passwd gw; ! 311: ! 312: gw.pw_name = popbbuser; ! 313: gw.pw_uid = guest_uid; ! 314: pw = &gw; ! 315: #endif TRUSTED ! 316: guest = 1; ! 317: goto anonymous; ! 318: } ! 319: #endif BPOP ! 320: if ((pw = getpwnam (username)) == NULL ! 321: || *pw -> pw_passwd == NULL ! 322: || strcmp (crypt (vec[1], pw -> pw_passwd), pw -> pw_passwd)) { ! 323: #ifdef TRUSTED ! 324: trusted (0, hostname, NULLCP, 0, pw ? pw -> pw_name : username, ! 325: pw && pw -> pw_uid == 0, "pop", "tcp", NULL); ! 326: #endif TRUSTED ! 327: return respond (NOTOK, "login incorrect"); ! 328: } ! 329: #else DPOP ! 330: #ifdef BPOP ! 331: if (isguest ()) { ! 332: #ifdef TRUSTED ! 333: static bboard gw; ! 334: ! 335: gw.bb_name = popbbuser; ! 336: pw = &gw; ! 337: #endif TRUSTED ! 338: guest = 1; ! 339: goto anonymous; ! 340: } ! 341: #endif BPOP ! 342: if (((pw = getbbnam (username)) == NULL ! 343: && (pw = getbbaka (username)) == NULL) ! 344: || *pw -> bb_passwd == NULL ! 345: || strcmp (crypt (vec[1], pw -> bb_passwd), pw -> bb_passwd)) { ! 346: #ifdef TRUSTED ! 347: trusted (0, hostname, NULLCP, 0, pw ? pw -> bb_name : username, ! 348: 0, "pop", "tcp", NULL); ! 349: #endif TRUSTED ! 350: return respond (NOTOK, "login incorrect"); ! 351: } ! 352: #endif DPOP ! 353: ! 354: #ifdef BPOP ! 355: anonymous: ; ! 356: #endif BPOP ! 357: #ifdef TRUSTED ! 358: if (trusted (1, hostname, NULLCP, 0, myhost, ! 359: #ifndef DPOP ! 360: pw -> pw_name, pw -> pw_uid == 0, ! 361: #else DPOP ! 362: pw -> bb_name, 0, ! 363: #endif DPOP ! 364: "pop", "tcp", NULL) ! 365: == 0) ! 366: return respond (NOTOK, "permission denied"); ! 367: #endif TRUSTED ! 368: return setup (pw, guest); ! 369: } ! 370: ! 371: /* */ ! 372: ! 373: #ifdef BPOP ! 374: static isguest () { ! 375: int i; ! 376: register char *cp; ! 377: char buffer[BUFSIZ]; ! 378: register FILE *fp; ! 379: ! 380: if (strcmp (username, popbbuser) || !guest_uid) ! 381: return FALSE; ! 382: if (popbblist == NULL || (fp = fopen (popbblist, "r")) == NULL) ! 383: return TRUE; ! 384: ! 385: i = FALSE; ! 386: if (hostname) ! 387: while (fgets (buffer, sizeof buffer, fp)) { ! 388: if (cp = index (buffer, '\n')) ! 389: *cp = NULL; ! 390: if (strcmp (buffer, hostname) == 0) { ! 391: i = TRUE; ! 392: break; ! 393: } ! 394: } ! 395: ! 396: (void) fclose (fp); ! 397: ! 398: return i; ! 399: } ! 400: #endif BPOP ! 401: ! 402: /* */ ! 403: ! 404: #ifdef RPOP ! 405: static int rpop (vec) ! 406: register char **vec; ! 407: { ! 408: #ifndef DPOP ! 409: register struct passwd *pw; ! 410: #else DPOP ! 411: register int hostok = 0; ! 412: register char *bp, ! 413: *cp; ! 414: char buffer[BUFSIZ]; ! 415: register struct bboard *pw; ! 416: #endif DPOP ! 417: ! 418: #ifndef DPOP ! 419: if (!rproto || (pw = getpwnam (username)) == NULL) { ! 420: #ifdef TRUSTED ! 421: trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp", ! 422: NULL); ! 423: #endif TRUSTED ! 424: return respond (NOTOK, "login incorrect"); ! 425: } ! 426: if (chdir (pw -> pw_dir) == NOTOK && chdir ("/") == NOTOK) ! 427: return respond (NOTOK, "no remote directory"); ! 428: if (ruserok (hostname, pw -> pw_uid == 0, vec[1], username) == NOTOK) { ! 429: #ifdef TRUSTED ! 430: trusted (0, hostname, vec[1], 0, pw -> pw_name, ! 431: pw -> pw_uid == 0, "rpop", "tcp", NULL); ! 432: #endif TRUSTED ! 433: return respond (NOTOK, "permission denied"); ! 434: } ! 435: #else DPOP ! 436: if (!rproto ! 437: || ((pw = getbbnam (username)) == NULL ! 438: && (pw = getbbaka (username)) == NULL)) { ! 439: #ifdef TRUSTED ! 440: trusted (0, hostname, vec[1], 0, username, 0, "rpop", "tcp", ! 441: NULL); ! 442: #endif TRUSTED ! 443: return respond (NOTOK, "login incorrect"); ! 444: } ! 445: /* ! 446: * hacked by Dave Cohrs Tue Feb 4 14:12:15 CST 1986 ! 447: * to allow the hostname to be a list: user@host1,user@host2 ! 448: * NOTE: the separator must be a comma -- no spaces are allowed ! 449: */ ! 450: (void) sprintf (buffer, "%s@%s", vec[1], hostname); ! 451: for (bp = pw -> bb_addr; bp; bp = cp) { ! 452: if ((cp = index (bp, ','))) ! 453: *cp = NULL; ! 454: hostok = strcmp (bp, buffer) == 0; ! 455: if (cp) ! 456: *cp++ = ','; ! 457: if (hostok) ! 458: break; ! 459: } ! 460: if (!hostok) { ! 461: #ifdef TRUSTED ! 462: trusted (0, hostname, vec[1], 0, pw -> bb_name, 0, "rpop", ! 463: "tcp", NULL); ! 464: #endif TRUSTED ! 465: return respond (NOTOK, "permission denied"); ! 466: } ! 467: #endif DPOP ! 468: ! 469: #ifdef TRUSTED ! 470: if (trusted (1, hostname, vec[1], 0, username, ! 471: #ifndef DPOP ! 472: pw -> pw_uid == 0, ! 473: #else DPOP ! 474: 0, ! 475: #endif DPOP ! 476: "rpop", "tcp", NULL) ! 477: == 0) ! 478: return respond (NOTOK, "permission denied"); ! 479: #endif TRUSTED ! 480: return setup (pw, FALSE); ! 481: } ! 482: #endif RPOP ! 483: ! 484: /* */ ! 485: ! 486: static int setup (pw, guest) ! 487: #ifndef DPOP ! 488: register struct passwd *pw; ! 489: #else DPOP ! 490: register struct bboard *pw; ! 491: #endif DPOP ! 492: int guest; ! 493: { ! 494: #ifdef BPOP ! 495: if (guest) { ! 496: (void) setgid (guest_gid); ! 497: (void) initgroups (popbbuser, guest_gid); ! 498: (void) setuid (guest_uid); ! 499: } ! 500: else { ! 501: #endif BPOP ! 502: #ifndef DPOP ! 503: (void) setgid (pw -> pw_gid); ! 504: (void) initgroups (pw -> pw_name, pw -> pw_gid); ! 505: (void) setuid (pw -> pw_uid); ! 506: #else DPOP ! 507: (void) setgid (pop_gid); ! 508: (void) initgroups (POPUID, pop_gid); ! 509: (void) setuid (pop_uid); ! 510: #endif DPOP ! 511: #ifdef BPOP ! 512: } ! 513: #endif BPOP ! 514: ! 515: #ifndef DPOP ! 516: (void) sprintf (maildrop, "%s/%s", ! 517: mmdfldir && *mmdfldir ? mmdfldir : pw -> pw_dir, ! 518: mmdflfil && *mmdflfil ? mmdflfil : pw -> pw_name); ! 519: #else DPOP ! 520: (void) strcpy (maildrop, pw -> bb_file); ! 521: #endif DPOP ! 522: ! 523: if (setupaux (guest) == NOTOK) ! 524: return NOTOK; ! 525: ! 526: return respond (OK, ! 527: nmsgs ? "maildrop has %d message%s (%d octets)" : "maildrop empty", ! 528: nmsgs, nmsgs != 1 ? "s" : NULL, Msgs[0].m_size); ! 529: } ! 530: ! 531: /* */ ! 532: ! 533: static int setupaux (readonly) ! 534: int readonly; ! 535: { ! 536: register int i, ! 537: msgp; ! 538: struct stat st; ! 539: ! 540: #ifdef BPOP ! 541: xtnded = 0; ! 542: #endif BPOP ! 543: if ((dp = readonly ? fopen (maildrop, "r") : lkfopen (maildrop, "r")) ! 544: == NULL) ! 545: switch (errno) { ! 546: case ENOENT: ! 547: m_gMsgs (msgp = 0); ! 548: goto no_mail; ! 549: ! 550: default: ! 551: nmsgs = dmsgs = 0; ! 552: return respond (NOTOK, "unable to %s maildrop: \"%s\"", ! 553: readonly ? "read" : "lock", maildrop); ! 554: } ! 555: ! 556: if (fstat (fileno (dp), &st) != NOTOK) { ! 557: mode = (int) (st.st_mode & 0777), mtime = st.st_mtime; ! 558: msgp = read_map (maildrop, (long) st.st_size); ! 559: } ! 560: else { ! 561: mode = 0600, mtime = 0; ! 562: msgp = 0; ! 563: } ! 564: ! 565: if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1) ! 566: m_gMsgs (0); ! 567: ! 568: no_mail: ; ! 569: dmsgs = 0; ! 570: nmsgs = msgp; ! 571: ! 572: Msgs[0].m_flags = readonly ? MREAD : MNULL; ! 573: Msgs[0].m_size = 0; ! 574: for (i = 1; i <= nmsgs; i++) { ! 575: if (Msgs[i].m_size == 0) ! 576: Msgs[i].m_size = mbx_size (i); ! 577: Msgs[0].m_size += Msgs[i].m_size; ! 578: Msgs[i].m_flags = MNULL; ! 579: } ! 580: ! 581: return OK; ! 582: } ! 583: ! 584: /* */ ! 585: ! 586: static int read_map (file, pos) ! 587: char *file; ! 588: long pos; ! 589: { ! 590: register int i, ! 591: msgp; ! 592: register struct drop *pp, ! 593: *mp; ! 594: struct drop *rp; ! 595: ! 596: if (debug) ! 597: padvise (NULLCP, LOG_DEBUG, "read_map (%s, %ld)", file, pos); ! 598: ! 599: if ((i = map_read (file, pos, &rp, debug)) == 0) ! 600: return 0; ! 601: ! 602: m_gMsgs (i); ! 603: ! 604: msgp = 1; ! 605: for (pp = rp; i-- > 0; msgp++, pp++) { ! 606: mp = &Msgs[msgp].m_drop; ! 607: mp -> d_id = pp -> d_id; ! 608: mp -> d_size = pp -> d_size; ! 609: mp -> d_start = pp -> d_start; ! 610: mp -> d_stop = pp -> d_stop; ! 611: } ! 612: free ((char *) rp); ! 613: ! 614: return (msgp - 1); ! 615: } ! 616: ! 617: /* */ ! 618: ! 619: static int read_file (pos, msgp) ! 620: register long pos; ! 621: register int msgp; ! 622: { ! 623: register int i; ! 624: register struct drop *pp, ! 625: *mp; ! 626: struct drop *rp; ! 627: ! 628: if (debug) ! 629: padvise (NULLCP, LOG_DEBUG, "read_file (%ld, %d)", ! 630: pos, msgp); ! 631: ! 632: if ((i = mbx_read (dp, pos, &rp, debug)) <= 0) ! 633: return (msgp - 1); ! 634: ! 635: m_gMsgs ((msgp - 1) + i); ! 636: ! 637: for (pp = rp; i-- > 0; msgp++, pp++) { ! 638: mp = &Msgs[msgp].m_drop; ! 639: mp -> d_id = 0; ! 640: mp -> d_size = pp -> d_size; ! 641: mp -> d_start = pp -> d_start; ! 642: mp -> d_stop = pp -> d_stop; ! 643: } ! 644: free ((char *) rp); ! 645: ! 646: return (msgp - 1); ! 647: } ! 648: ! 649: /* */ ! 650: ! 651: static m_gMsgs (n) ! 652: int n; ! 653: { ! 654: if (debug) ! 655: padvise (NULLCP, LOG_DEBUG, "m_gMsgs (%d) 0x%x %d", ! 656: n, Msgs, nMsgs); ! 657: ! 658: if (Msgs == NULL) { ! 659: nMsgs = n + MAXFOLDER / 2; ! 660: Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs); ! 661: if (Msgs == NULL) ! 662: padios (NULLCP, "unable to allocate Msgs structure"); ! 663: return; ! 664: } ! 665: ! 666: if (nMsgs >= n) ! 667: return; ! 668: ! 669: nMsgs = n + MAXFOLDER / 2; ! 670: Msgs = (struct Msg *) realloc ((char *) Msgs, ! 671: (unsigned) (nMsgs + 2) * sizeof *Msgs); ! 672: if (Msgs == NULL) ! 673: padios (NULLCP, "unable to reallocate Msgs structure"); ! 674: } ! 675: ! 676: /* */ ! 677: ! 678: static int mbx_size (m) ! 679: register int m; ! 680: { ! 681: register int i; ! 682: register long pos; ! 683: ! 684: (void) fseek (dp, Msgs[m].m_start, 0); ! 685: for (i = 0, pos = Msgs[m].m_stop - Msgs[m].m_start; pos > 0; i++, pos--) ! 686: if (fgetc (dp) == '\n') ! 687: i++; ! 688: ! 689: return i; ! 690: } ! 691: ! 692: /* */ ! 693: ! 694: /* ARGSUSED */ ! 695: ! 696: static int status (vec) ! 697: char **vec; ! 698: { ! 699: return respond (OK, "%d %d", nmsgs - dmsgs, Msgs[0].m_size); ! 700: } ! 701: ! 702: ! 703: static int list (vec) ! 704: register char **vec; ! 705: { ! 706: register int i; ! 707: ! 708: if (vec[1]) { ! 709: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) ! 710: return respond (NOTOK, "no such message: \"%s\"", vec[1]); ! 711: if (Msgs[i].m_flags & MDELE) ! 712: return respond (NOTOK, "message %d is deleted", i); ! 713: ! 714: #ifndef BPOP ! 715: return respond (OK, "%d %d", i, Msgs[i].m_size); ! 716: #else BPOP ! 717: return respond (OK, xtnded ? "%d %d %d" : "%d %d", ! 718: i, Msgs[i].m_size, Msgs[i].m_id); ! 719: #endif BPOP ! 720: } ! 721: ! 722: (void) respond (OK, "%d message%s (%d octets)", ! 723: nmsgs - dmsgs, nmsgs - dmsgs != 1 ? "s" : NULL, ! 724: Msgs[0].m_size); ! 725: for (i = 1; i <= nmsgs; i++) ! 726: if (!(Msgs[i].m_flags & MDELE)) ! 727: #ifndef BPOP ! 728: multiline ("%d %d", i, Msgs[i].m_size); ! 729: #else BPOP ! 730: multiline (xtnded ? "%d %d %d" : "%d %d", ! 731: i, Msgs[i].m_size, Msgs[i].m_id); ! 732: #endif BPOP ! 733: multiend (); ! 734: ! 735: return OK; ! 736: } ! 737: ! 738: /* */ ! 739: ! 740: static int retrieve (vec) ! 741: register char **vec; ! 742: { ! 743: register int i; ! 744: register long pos; ! 745: register char *cp; ! 746: char buffer[BUFSIZ]; ! 747: ! 748: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) ! 749: return respond (NOTOK, "no such message: \"%s\"", vec[1]); ! 750: if (Msgs[i].m_flags & MDELE) ! 751: return respond (NOTOK, "message %d is deleted", i); ! 752: ! 753: (void) respond (OK, "%d octets", Msgs[i].m_size); ! 754: ! 755: for ((void) fseek (dp, pos = Msgs[i].m_start, 0); ! 756: fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop; ! 757: pos += (long) (cp - buffer + 1)) { ! 758: if (*(cp = buffer + strlen (buffer) - 1) == '\n') ! 759: *cp = NULL; ! 760: multiline ("%s", buffer); ! 761: } ! 762: multiend (); ! 763: ! 764: return OK; ! 765: } ! 766: ! 767: /* */ ! 768: ! 769: static int delete (vec) ! 770: register char **vec; ! 771: { ! 772: register int i; ! 773: ! 774: if (Msgs[0].m_flags & MREAD) ! 775: return respond (NOTOK, "maildrop is read-only"); ! 776: ! 777: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) ! 778: return respond (NOTOK, "no such message: \"%s\"", vec[1]); ! 779: if (Msgs[i].m_flags & MDELE) ! 780: return respond (NOTOK, "message %d is deleted", i); ! 781: ! 782: Msgs[i].m_flags |= MDELE; ! 783: Msgs[0].m_size -= Msgs[i].m_size; ! 784: dmsgs++; ! 785: ! 786: return respond (OK, "message %d deleted (%d octets)", i, Msgs[i].m_size); ! 787: } ! 788: ! 789: ! 790: static int reset (vec) ! 791: char **vec; ! 792: { ! 793: register int i; ! 794: ! 795: for (i = 1; i <= nmsgs; i++) ! 796: if (Msgs[i].m_flags & MDELE) { ! 797: Msgs[i].m_flags &= ~MDELE; ! 798: Msgs[0].m_size += Msgs[i].m_size; ! 799: dmsgs--; ! 800: } ! 801: ! 802: return status (vec); ! 803: } ! 804: ! 805: /* */ ! 806: ! 807: static int top (vec) ! 808: register char **vec; ! 809: { ! 810: register int i, ! 811: j, ! 812: body, ! 813: lines; ! 814: register long pos; ! 815: register char *cp; ! 816: char buffer[BUFSIZ]; ! 817: ! 818: if ((i = atoi (vec[1])) <= 0 || i > nmsgs) ! 819: return respond (NOTOK, "no such message: \"%s\"", vec[1]); ! 820: if (Msgs[i].m_flags & MDELE) ! 821: return respond (NOTOK, "message %d is deleted", i); ! 822: if ((j = atoi (vec[2])) <= 0) ! 823: return respond (NOTOK, "bad number: \"%s\"", vec[2]); ! 824: ! 825: (void) respond (OK, vec[0]); ! 826: ! 827: body = lines = 0; ! 828: for ((void) fseek (dp, pos = Msgs[i].m_start, 0); ! 829: fgets (buffer, sizeof buffer, dp) != NULL && pos < Msgs[i].m_stop; ! 830: pos += (long) (cp - buffer + 1)) { ! 831: if (*(cp = buffer + strlen (buffer) - 1) == '\n') ! 832: *cp = NULL; ! 833: if (body) { ! 834: if (lines++ >= j) ! 835: break; ! 836: } ! 837: else ! 838: if (*buffer == NULL) ! 839: body++; ! 840: multiline ("%s", buffer); ! 841: } ! 842: multiend (); ! 843: ! 844: return OK; ! 845: } ! 846: ! 847: /* */ ! 848: ! 849: #ifdef BPOP ! 850: static int xtnd (vec) ! 851: register char **vec; ! 852: { ! 853: make_lower (vec[1], vec[1]); ! 854: ! 855: if (strcmp (vec[1], "bboards") == 0 || strcmp (vec[1], "archive") == 0) ! 856: return xtnd1 (vec); ! 857: if (strcmp (vec[1], "x-bboards") == 0) ! 858: return xtnd2 (vec); ! 859: ! 860: return respond (NOTOK, "unknown XTND command: \"%s\"", vec[1]); ! 861: } ! 862: ! 863: ! 864: static int xtnd1 (vec) ! 865: register char **vec; ! 866: { ! 867: register struct bboard *bb; ! 868: ! 869: if (vec[2]) { ! 870: make_lower (vec[2], vec[2]); ! 871: if ((bb = getbbaux (vec[2])) == NULL) ! 872: return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]); ! 873: ! 874: if (quitaux (NULLVP) == NOTOK) ! 875: return NOTOK; ! 876: (void) strcpy (maildrop, ! 877: strcmp (vec[1], "bboards") ? bb -> bb_archive : bb -> bb_file); ! 878: if (setupaux (TRUE) == NOTOK) ! 879: return NOTOK; ! 880: xtnded++; ! 881: (void) respond (OK, "%s", vec[1]); ! 882: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); ! 883: } ! 884: else { ! 885: if (strcmp (vec[1], "bboards")) ! 886: return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]); ! 887: ! 888: (void) respond (OK, "%s", vec[1]); ! 889: for (bb = BBhead; bb; bb = bb -> bb_next) { ! 890: getbbmax (bb); ! 891: if (!(bb -> bb_flags & BB_INVIS)) ! 892: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); ! 893: } ! 894: while (bb = getbbaux (NULLCP)) ! 895: if (!(bb -> bb_flags & BB_INVIS)) ! 896: multiline ("%s %d", bb -> bb_name, bb -> bb_maxima); ! 897: } ! 898: multiend (); ! 899: ! 900: return OK; ! 901: } ! 902: ! 903: /* */ ! 904: ! 905: static int xtnd2 (vec) ! 906: register char **vec; ! 907: { ! 908: register char *cp, ! 909: **ap; ! 910: char buffer[BUFSIZ]; ! 911: register struct bboard *bb; ! 912: ! 913: if (vec[2] == NULL) ! 914: return respond (NOTOK, "too few arguments to XTND \"%s\"", vec[1]); ! 915: ! 916: make_lower (vec[2], vec[2]); ! 917: if ((bb = getbbaux (vec[2])) == NULL) ! 918: return respond (NOTOK, "unknown BBoard: \"%s\"", vec[2]); ! 919: ! 920: (void) respond (OK, "%s", vec[1]); ! 921: multiline ("%s", bb -> bb_name); ! 922: ! 923: cp = buffer; ! 924: for (ap = bb -> bb_aka; *ap; ap++) { ! 925: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); ! 926: cp += strlen (cp); ! 927: } ! 928: multiline ("%s", buffer); ! 929: ! 930: multiline ("%s", bb -> bb_file); ! 931: multiline ("%s", bb -> bb_archive); ! 932: multiline ("%s", bb -> bb_info); ! 933: multiline ("%s", bb -> bb_map); ! 934: multiline ("%s", bb -> bb_passwd); ! 935: ! 936: cp = buffer; ! 937: for (ap = bb -> bb_leader; *ap; ap++) { ! 938: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); ! 939: cp += strlen (cp); ! 940: } ! 941: multiline ("%s", buffer); ! 942: ! 943: multiline ("%s", bb -> bb_addr); ! 944: multiline ("%s", bb -> bb_request); ! 945: multiline ("%s", bb -> bb_relay); ! 946: ! 947: cp = buffer; ! 948: for (ap = bb -> bb_dist; *ap; ap++) { ! 949: (void) sprintf (cp, cp != buffer ? " %s" : "%s", *ap); ! 950: cp += strlen (cp); ! 951: } ! 952: multiline ("%s", buffer); ! 953: ! 954: getbbmax (bb); ! 955: multiline ("0%o %d", bb -> bb_flags, bb -> bb_maxima); ! 956: multiline ("%s", bb -> bb_date); ! 957: ! 958: multiend (); ! 959: ! 960: return OK; ! 961: } ! 962: ! 963: /* */ ! 964: ! 965: static struct bboard *getbbaux (s) ! 966: register char *s; ! 967: { ! 968: register struct bboard *bb; ! 969: struct stat st; ! 970: ! 971: if (BBhead == NULL) ! 972: if (setbbinfo (BBOARDS, BBDB, 1)) ! 973: BBtime = getbbtime (); ! 974: else ! 975: return NULL; ! 976: ! 977: if (s != NULLCP) ! 978: for (bb = BBhead; bb; bb = bb -> bb_next) ! 979: if (strcmp (bb -> bb_name, s) == 0) { ! 980: if (debug) ! 981: padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from cache", ! 982: bb -> bb_name); ! 983: getbbmax (bb); ! 984: return bb; ! 985: } ! 986: ! 987: while (bb = getbbent ()) { ! 988: if ((bb = getbbcpy (bb)) == NULL) ! 989: return NULL; ! 990: ! 991: if (access (bb -> bb_file, 04) == NOTOK && errno == EACCES) ! 992: bb -> bb_flags |= BB_INVIS; ! 993: bb -> bb_mtime = stat (bb -> bb_info, &st) != NOTOK ? st.st_mtime : 0L; ! 994: ! 995: if (BBtail != NULL) ! 996: BBtail -> bb_next = bb; ! 997: if (BBhead == NULL) ! 998: BBhead = bb; ! 999: BBtail = bb; ! 1000: ! 1001: if (s == NULL || strcmp (bb -> bb_name, s) == 0) { ! 1002: if (s && debug) ! 1003: padvise (NULLCP, LOG_DEBUG, "getbbaux: \"%s\" from scratch", ! 1004: bb -> bb_name); ! 1005: return bb; ! 1006: } ! 1007: } ! 1008: ! 1009: return NULL; ! 1010: } ! 1011: ! 1012: /* */ ! 1013: ! 1014: static getbbmax (bb) ! 1015: register struct bboard *bb; ! 1016: { ! 1017: int i; ! 1018: register char *cp; ! 1019: char buffer[BUFSIZ]; ! 1020: struct stat st; ! 1021: register FILE * fp; ! 1022: ! 1023: if (debug) ! 1024: padvise (NULLCP, LOG_DEBUG, "getbbmax: \"%s\", 0%o, %d, %s", ! 1025: bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date); ! 1026: ! 1027: if (!(bb -> bb_flags & BB_INVIS) ! 1028: && access (bb -> bb_file, 04) == NOTOK && errno == EACCES) ! 1029: bb -> bb_flags |= BB_INVIS; ! 1030: ! 1031: if (stat (bb -> bb_info, &st) == NOTOK ! 1032: || bb -> bb_mtime == st.st_mtime ! 1033: || (fp = fopen (bb -> bb_info, "r")) == NULL) ! 1034: return; ! 1035: bb -> bb_mtime = st.st_mtime; ! 1036: ! 1037: if (fgets (buffer, sizeof buffer, fp) && (i = atoi (buffer)) > 0) ! 1038: bb -> bb_maxima = i; ! 1039: if (!feof (fp) && fgets (buffer, sizeof buffer, fp)) { ! 1040: if (bb -> bb_date) ! 1041: free (bb -> bb_date); ! 1042: if (cp = index (buffer, '\n')) ! 1043: *cp = NULL; ! 1044: bb -> bb_date = getcpy (buffer); ! 1045: } ! 1046: ! 1047: (void) fclose (fp); ! 1048: ! 1049: if (debug) ! 1050: padvise (NULLCP, LOG_DEBUG, "updated: \"%s\", 0%o, %d, %s", ! 1051: bb -> bb_name, bb -> bb_flags, bb -> bb_maxima, bb -> bb_date); ! 1052: } ! 1053: #endif BPOP ! 1054: ! 1055: /* */ ! 1056: ! 1057: static int quit (vec) ! 1058: char **vec; ! 1059: { ! 1060: int d, ! 1061: n; ! 1062: ! 1063: d = dmsgs, n = nmsgs; ! 1064: ! 1065: if (quitaux (vec) == NOTOK) ! 1066: return NOTOK; ! 1067: ! 1068: #ifdef BPOP ! 1069: if (xtnded) ! 1070: return respond (OK, "%s signing off", server); ! 1071: #endif BPOP ! 1072: ! 1073: if (n == d) ! 1074: return respond (OK, "%s signing off (maildrop empty)", server); ! 1075: ! 1076: return respond (OK, ! 1077: n ? "%s signing off (%d message%s, %d octets left)" ! 1078: : "%s signing off (maildrop empty)", ! 1079: server, n - d, n - d != 1 ? "s" : NULL, Msgs[0].m_size); ! 1080: } ! 1081: ! 1082: ! 1083: static int quitaux (vec) ! 1084: char **vec; ! 1085: { ! 1086: int i; ! 1087: ! 1088: if (dp == NULL) ! 1089: return OK; ! 1090: ! 1091: i = quitfile (vec); ! 1092: ! 1093: nmsgs = dmsgs = 0; ! 1094: (void) lkfclose (dp, maildrop); ! 1095: dp = NULL; ! 1096: ! 1097: return i; ! 1098: } ! 1099: ! 1100: /* */ ! 1101: ! 1102: /* ARGSUSED */ ! 1103: ! 1104: static int quitfile (vec) ! 1105: char **vec; ! 1106: { ! 1107: register int i, ! 1108: md; ! 1109: char tmpfil[BUFSIZ], ! 1110: map1[BUFSIZ], ! 1111: map2[BUFSIZ]; ! 1112: struct stat st; ! 1113: ! 1114: if (dmsgs == 0 || (Msgs[0].m_flags & MREAD)) ! 1115: return OK; ! 1116: ! 1117: if (fstat (fileno (dp), &st) == NOTOK) ! 1118: return respond (NOTOK, "unable to stat file"); ! 1119: if (mtime != st.st_mtime) ! 1120: return respond (NOTOK, "new messages have arrived, no update"); ! 1121: mode = (int) (st.st_mode & 0777); ! 1122: ! 1123: if (nmsgs == dmsgs) { ! 1124: i = truncate (maildrop, 0); ! 1125: (void) unlink (map_name (maildrop));/* XXX */ ! 1126: if (i == NOTOK) ! 1127: return respond (NOTOK, "unable to zero %s", maildrop); ! 1128: return OK; ! 1129: } ! 1130: ! 1131: (void) strcpy (tmpfil, m_backup (maildrop)); ! 1132: if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK) ! 1133: return respond (NOTOK, "unable to create temporary file"); ! 1134: ! 1135: for (i = 1; i <= nmsgs; i++) ! 1136: if (!(Msgs[i].m_flags & MDELE) ! 1137: && mbx_write (tmpfil, md, dp, Msgs[i].m_id, Msgs[i].m_start, ! 1138: Msgs[i].m_stop, TRUE, debug) == NOTOK) { ! 1139: (void) mbx_close (tmpfil, md); ! 1140: (void) unlink (tmpfil); ! 1141: return respond (NOTOK, "error writing temporary file"); ! 1142: } ! 1143: (void) mbx_close (tmpfil, md); ! 1144: ! 1145: if ((i = rename (tmpfil, maildrop)) == OK) { ! 1146: (void) strcpy (map1, map_name (tmpfil)); ! 1147: (void) strcpy (map2, map_name (maildrop)); ! 1148: if (rename (map1, map2) == NOTOK) { ! 1149: (void) unlink (map1); ! 1150: (void) unlink (map2); ! 1151: } ! 1152: } ! 1153: ! 1154: if (i == NOTOK) ! 1155: return respond (NOTOK, "unable to rename maildrop"); ! 1156: ! 1157: return OK; ! 1158: } ! 1159: ! 1160: /* */ ! 1161: ! 1162: static struct vector *getvector (bp, vec) ! 1163: register char *bp, ! 1164: **vec; ! 1165: { ! 1166: register int i; ! 1167: register struct vector *v; ! 1168: ! 1169: for (i = 0; i < NVEC; i++) { ! 1170: while (isspace (*bp)) ! 1171: *bp++ = NULL; ! 1172: if (*bp == NULL) { ! 1173: vec[i] = NULL; ! 1174: break; ! 1175: } ! 1176: vec[i] = bp; ! 1177: while (!isspace (*bp)) ! 1178: bp++; ! 1179: } ! 1180: i--; ! 1181: vec[NVEC] = NULL; ! 1182: ! 1183: if (*bp != NULL) { ! 1184: (void) respond (NOTOK, "too many arguments"); ! 1185: return NULL; ! 1186: } ! 1187: if (*vec[0] == NULL) { ! 1188: (void) respond (NOTOK, "null command"); ! 1189: return NULL; ! 1190: } ! 1191: make_lower (vec[0], vec[0]); ! 1192: ! 1193: for (v = vectors; v -> v_cmd; v++) ! 1194: if (strcmp (v -> v_cmd, vec[0]) == 0 && v -> v_valid == mystate) { ! 1195: if (i < v -> v_min || v -> v_max < i) { ! 1196: (void) respond (NOTOK, "too %s arguments to \"%s\"", ! 1197: i < v -> v_min ? "few" : "many", vec[0]); ! 1198: return NULL; ! 1199: } ! 1200: else ! 1201: return v; ! 1202: } ! 1203: ! 1204: (void) respond (NOTOK, "unknown command: \"%s\"", vec[0]); ! 1205: return NULL; ! 1206: } ! 1207: ! 1208: /* */ ! 1209: ! 1210: /* VARARGS2 */ ! 1211: ! 1212: static int respond (code, fmt, a, b, c, d) ! 1213: char *fmt, ! 1214: *a, ! 1215: *b, ! 1216: *c, ! 1217: *d; ! 1218: int code; ! 1219: { ! 1220: register char *bp; ! 1221: char buffer[BUFSIZ]; ! 1222: ! 1223: bp = buffer; ! 1224: bp += strlen (sprintf (bp, "%s%s", code == OK ? "+OK" : "-ERR", ! 1225: fmt ? " " : NULL)); ! 1226: if (fmt) ! 1227: bp += strlen (sprintf (bp, fmt, a, b, c, d)); ! 1228: putline (buffer, output); ! 1229: ! 1230: return code; ! 1231: } ! 1232: ! 1233: ! 1234: /* VARARGS1 */ ! 1235: ! 1236: static multiline (fmt, a, b, c, d) ! 1237: char *fmt, ! 1238: *a, ! 1239: *b, ! 1240: *c, ! 1241: *d; ! 1242: { ! 1243: register char *cp; ! 1244: char buffer[BUFSIZ + TRMLEN]; ! 1245: ! 1246: (void) strcpy (buffer, TRM); ! 1247: cp = sprintf (buffer + TRMLEN, fmt, a, b, c, d); ! 1248: if (strncmp (cp, TRM, TRMLEN) == 0) ! 1249: cp = buffer; ! 1250: ! 1251: putline (cp, output); ! 1252: } ! 1253: ! 1254: ! 1255: static multiend () { ! 1256: putline (TRM, output); ! 1257: } ! 1258: ! 1259: /* */ ! 1260: ! 1261: static int getline (s, n, iop) ! 1262: register char *s; ! 1263: register int n; ! 1264: register FILE *iop; ! 1265: { ! 1266: register int c; ! 1267: register char *p; ! 1268: ! 1269: p = s; ! 1270: while (--n > 0 && (c = fgetc (iop)) != EOF) { ! 1271: while (c == IAC) { ! 1272: (void) fgetc (iop); ! 1273: c = fgetc (iop); ! 1274: } ! 1275: if ((*p++ = c) == '\n') ! 1276: break; ! 1277: } ! 1278: if (ferror (iop)) ! 1279: return NOTOK; ! 1280: if (c == EOF && p == s) ! 1281: return DONE; ! 1282: *p++ = NULL; ! 1283: if (debug) ! 1284: padvise (NULLCP, LOG_DEBUG, "<--- %s", s); ! 1285: ! 1286: return OK; ! 1287: } ! 1288: ! 1289: ! 1290: static putline (s, iop) ! 1291: register char *s; ! 1292: register FILE *iop; ! 1293: { ! 1294: (void) fprintf (iop, "%s\r\n", s); ! 1295: if (debug) ! 1296: padvise (NULLCP, LOG_DEBUG, "---> %s", s); ! 1297: ! 1298: (void) fflush (iop); ! 1299: } ! 1300: ! 1301: ! 1302: /* ARGSUSED */ ! 1303: ! 1304: static int pipeser (sig, code, sc) ! 1305: int sig; ! 1306: long code; ! 1307: struct sigcontext *sc; ! 1308: { ! 1309: padvise (NULLCP, LOG_WARNING, "lost connection"); ! 1310: ! 1311: _exit (NOTOK); ! 1312: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.