1: /* 2: * This software is Copyright (c) 1986 by Rick Adams. 3: * 4: * Permission is hereby granted to copy, reproduce, redistribute or 5: * otherwise use this software as long as: there is no monetary 6: * profit gained specifically from the use or reproduction or this 7: * software, it is not sold, rented, traded or otherwise marketed, and 8: * this copyright notice is included prominently in any copy 9: * made. 10: * 11: * The author make no claims as to the fitness or correctness of 12: * this software for any use whatsoever, and it is provided as is. 13: * Any use of this software is at the user's own risk. 14: * 15: * Control message handling code. Deal with messages which are to be 16: * acted on by netnews itself rather than by people. 17: * 18: * See defs.h "news_version" for the real version of netnews. 19: */ 20: 21: #ifdef SCCSID 22: static char *SccsId = "@(#)control.c 2.43 3/19/86"; 23: #endif /* SCCSID */ 24: 25: #include "iparams.h" 26: 27: #define eq(msg) (strcmp(msg, cargv[0]) == 0) 28: 29: int cargc; 30: char **cargv; 31: 32: FILE *hfopen(); 33: FILE *popen(), *mhopen(), *mailhdr(); 34: 35: char *senderof(); 36: #ifdef u370 37: static struct hbuf htmp; 38: #endif /* u370 */ 39: 40: control(h) 41: struct hbuf *h; 42: { 43: register char *ctlmsgtext; 44: 45: if (strncmp(h->title, "cmsg ", 5) == 0) { 46: register char *cp1, *cp2; 47: cp1 = h->title; 48: cp2 = h->title + 5; 49: while (*cp1++ = *cp2++) 50: ; 51: } 52: 53: if (*h->ctlmsg) 54: ctlmsgtext = h->ctlmsg; 55: else 56: ctlmsgtext = h->title; 57: log("Ctl Msg %s from %s: %s", h->nbuf, h->path, ctlmsgtext); 58: /* 59: * Control messages have the standard format 60: * command [args] 61: * much like shell commands. Each site has the option 62: * of customizing this code to deal with control messages 63: * as they see fit, but we would like to buy back the 64: * code, ifdeffed or otherwise parameterized, to simplify 65: * the maintenence issues. 66: */ 67: argparse(ctlmsgtext); 68: 69: if (eq("cancel")) 70: return c_cancel(cargc, cargv); 71: else if (eq("newgroup")) 72: c_newgroup(cargc, cargv); 73: else if (eq("ihave")) 74: c_ihave(cargc, cargv); 75: else if (eq("sendme")) 76: c_sendme(cargc, cargv); 77: else if (eq("sendbad")) 78: c_sendme(cargc, cargv); 79: else if (eq("rmgroup")) 80: c_rmgroup(cargc, cargv); 81: else if (eq("sendsys")) 82: c_sendsys(cargc, cargv); 83: else if (eq("senduuname")) 84: c_senduuname(cargc, cargv); 85: else if (eq("version")) 86: c_version(cargc, cargv); 87: else if (eq("checkgroups")) 88: c_checkgroups(cargc, cargv); 89: else if (eq("delsub")) 90: c_unimp(cargc, cargv); 91: else 92: c_unknown(h, ctlmsgtext); 93: return 0; 94: } 95: 96: /* 97: * Parse the string str into separate words in cargc and cargv 98: * as per the usual UNIX convention. Nothing fancy here, just 99: * blanks and tabs separating words. 100: */ 101: argparse(str) 102: char *str; 103: { 104: static char *cavpbuf[20]; 105: static char cavbuf[256]; 106: char *nextfree = cavbuf; 107: 108: if (str == '\0') 109: xerror("Control message %s has no title", header.ident); 110: cargc = (*str != '\0'); 111: cargv = cavpbuf; 112: cargv[0] = cavbuf; 113: 114: while (*str) { 115: if (*str <= ' ') { 116: *nextfree++ = 0; 117: cargv[cargc] = nextfree; 118: cargc++; 119: /* skip over white space */ 120: while (*str != '\0' && *str <= ' ') 121: str++; 122: if (*str == '\0') /* line ends in white space */ 123: return; 124: } else 125: *nextfree++ = *str++; 126: } 127: } 128: 129: /* 130: * ihave <artid> <remotesys> 131: * The other system is telling you it has article <artid>, in case 132: * you decide you want it to transmit it to you. 133: */ 134: c_ihave(argc, argv) 135: char **argv; 136: { 137: char tl[256], ng[256]; 138: #ifndef u370 139: struct hbuf htmp; 140: #endif /* !u370 */ 141: 142: if (argc < 2) 143: xerror("ihave: Not enough arguments."); 144: /* 145: * Check that we haven't already seen it (history) 146: * and then send back a "sendme" message if we subscribe. 147: */ 148: (void) strncpy(htmp.ident, argv[1], BUFLEN); 149: if (history(&htmp) == 0) { 150: /* Should probably check SUBFILE here. */ 151: (void) sprintf(tl, "sendme %s %s", argv[1], FULLSYSNAME); 152: (void) sprintf(ng, "to.%s.ctl", argv[2]); 153: xmitmsg(argv[2], tl, ng); 154: } 155: } 156: 157: /* 158: * sendme <artid> ... <remotesys> 159: * The other system wants me to send him article <artid>. 160: */ 161: c_sendme(argc, argv) 162: char **argv; 163: { 164: int i; 165: FILE *fp; 166: struct srec srec; 167: #ifndef u370 168: struct hbuf htmp; 169: #endif /* !u370 */ 170: 171: if (argc < 2) 172: xerror("sendme: Not enough arguments."); 173: /* Don't ask for it from myself */ 174: if (strncmp(FULLSYSNAME, argv[argc], SNLN) == 0) 175: return; 176: /* Find the sys record */ 177: s_openr(); 178: while (s_read(&srec)) { 179: if (strncmp(srec.s_name, argv[argc], SNLN)) 180: continue; 181: /* It's the right one. Send them. */ 182: for (i=1; i<argc; i++) { 183: fp = hfopen(argv[i]); 184: htmp.unrec[0] = NULL; 185: if (hread(&htmp, fp, TRUE) == NULL) { 186: if (bfr[0] == '/') { 187: fp = xfopen(bfr, "r"); 188: if (hread(&htmp, fp, TRUE) == NULL) 189: xerror("Article %s is garbled.", bfr); 190: } else 191: xerror("Article %s is garbled.", argv[i]); 192: } 193: (void) fseek(fp, 0L, 0); 194: if (strcmp(argv[0], "sendme") == 0) { 195: /* check that other sys subscribes. */ 196: if (!ngmatch(htmp.nbuf, srec.s_nbuf) || 197: !(htmp.distribution[0] == '\0' || 198: ngmatch(htmp.distribution, srec.s_nbuf))) 199: continue; 200: } 201: transmit(&srec, fp, 0, (char **)0, 0); 202: /* transmit does fclose(fp) */ 203: } 204: return; 205: } 206: xerror("Cannot find system %s to send article %s to.", argv[argc], 207: argv[1]); 208: } 209: 210: /* 211: * newgroup <groupname> 212: * A new newsgroup has been created. 213: * The body of the article, if present, is a description of the 214: * purpose of the newsgroup. 215: * 216: */ 217: c_newgroup(argc, argv) 218: char **argv; 219: { 220: FILE *fd; 221: int didcreate = 0; 222: 223: if (argc < 1) 224: xerror("newgroup: Not enough arguments."); 225: if (validng(argv[1])) 226: return; 227: if (header.approved[0] == '\0') 228: xerror("newgroup: %s not approved", argv[1]); 229: 230: #ifndef NONEWGROUPS 231: #ifdef ORGDISTRIB 232: if (!strcmp(ORGDISTRIB, header.distribution)) { 233: didcreate++; 234: #endif /* ORGDISTRIB */ 235: actfp = xfopen(ACTIVE, "a"); 236: fprintf(actfp, "%s 00000 00001 y\n", argv[1]); 237: (void) fclose(actfp); 238: #ifdef ORGDISTRIB 239: } 240: #endif /* ORGDISTRIB */ 241: #endif /* !NONEWGROUPS */ 242: 243: #ifdef NOTIFY 244: fd = mailhdr((struct hbuf *)NULL, "creation of new newsgroup"); 245: if (fd != NULL) { 246: if (didcreate) 247: fprintf(fd, "A new newsgroup called '%s' has been created by %s.\n", 248: argv[1], header.path); 249: else 250: fprintf(fd, "%s requested that a new newsgroup called '%s' be created.\n", 251: header.path, argv[1]); 252: fprintf(fd, "It was approved by %s\n\n", header.approved); 253: #ifdef ORGDISTRIB 254: fprintf(fd, "You can accomplish this by sending a newgroup control message with a\n"); 255: fprintf(fd, "distribution code of %s; in other words, by executing the command:\n", ORGDISTRIB); 256: fprintf(fd, "%s/inews -n net.news -d %s -t \"cmsg newgroup %s\"\n", 257: LIB, ORGDISTRIB, argv[1]); 258: #endif /* ORGDISTRIB */ 259: (void) mclose(fd); 260: } 261: } 262: #endif /* NOTIFY */ 263: 264: 265: /* 266: * rmgroup <groupname> 267: * An old newsgroup is being cancelled on a network wide basis. 268: */ 269: c_rmgroup(argc, argv) 270: char **argv; 271: { 272: FILE *fd; 273: int shouldremove = 0; 274: 275: if (argc < 1) 276: xerror("rmgroup: Not enough arguments."); 277: if (!validng(argv[1])) 278: return; 279: if (header.approved[0] == '\0') 280: xerror("rmgroup: %s not approved", argv[1]); 281: 282: #ifndef MANUALLY 283: #ifdef ORGDISTRIB 284: if (!strcmp(ORGDISTRIB, header.distribution)) 285: #endif /* ORGDISTRIB */ 286: shouldremove++; 287: #endif /* !MANUALLY */ 288: #ifdef NOTIFY 289: fd = mailhdr((struct hbuf *)NULL, "rmgroup control message"); 290: if (fd != NULL) { 291: if (shouldremove) { 292: fprintf(fd, "A newsgroup called '%s' has been removed by %s.\n\n", 293: argv[1], header.path); 294: # ifdef USG 295: fprintf(fd, "You may need to remove the directory %s by hand\n", 296: dirname(argv[1])); 297: # endif 298: } else { 299: fprintf(fd, "%s has requested that newsgroup %s be removed.\n", 300: header.path, argv[1]); 301: fprintf(fd, "You should remove it by hand\n"); 302: fprintf(fd, "To do this, execute the command\n"); 303: fprintf(fd, "\t%s/rmgroup %s\n", LIB, argv[1]); 304: } 305: (void) mclose(fd); 306: } 307: #endif /* NOTIFY */ 308: 309: if (shouldremove) { 310: int rc; 311: /* We let the shell do all the work. 312: * See the rmgrp shell script. */ 313: (void) setuid(geteuid()); /* otherwise it won't rmdir the dir */ 314: (void) sprintf(bfr, "exec %s/rmgroup %s", LIB, argv[1]); 315: rc = system(bfr); 316: log("system(%s) status %d", bfr, rc); 317: } 318: } 319: 320: /* 321: * cancel <artid> 322: * Cancel the named article 323: */ 324: c_cancel(argc, argv) 325: char **argv; 326: { 327: char *line, *p, *q, *r, *poster; 328: char *findhist(); 329: register FILE *fp; 330: char whatsisname[BUFLEN], nfilename[BUFLEN]; 331: time_t t; 332: int su = 0; 333: #ifndef u370 334: struct hbuf htmp; 335: #endif /* !u370 */ 336: 337: if (argc < 1) 338: xerror("cancel: Not enough arguments."); 339: (void) strcpy(whatsisname, senderof(&header)); 340: line = findhist(argv[1]); 341: if (line == NULL) { 342: struct tm *tm; 343: log("Can't cancel %s: non-existent", argv[1]); 344: (void) time(&t); 345: tm = localtime(&t); 346: #ifdef USG 347: sprintf(bfr,"%s\t%2.2d/%2.2d/%d %2.2d:%2.2d\tcancelled", 348: #else /* !USG */ 349: sprintf(bfr,"%s\t%02d/%02d/%d %02d:%02d\tcancelled", 350: #endif /* !USG */ 351: argv[1], tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour, 352: tm->tm_min); 353: savehist(bfr); 354: return 1; 355: } 356: 357: q = index(line, '\t'); 358: p = index(q+1, '\t'); 359: if (p == NULL || *++p == '\0' || *p == '\n') { 360: *q = '\0'; 361: log("Expired article %s", line); 362: return 1; 363: } 364: if (strcmp(p, "cancelled") == 0) { 365: *q = '\0'; 366: log("Already Cancelled %s", line); 367: return 1; 368: } else 369: log("Cancelling %s", line); 370: if ((uid == ROOTID||uid == 0) && strcmp(header.distribution, "local") == 0) 371: su = 1; 372: while (*p) { 373: q = index(p, ' '); 374: if (q) 375: *q = '\0'; 376: (void) strcpy(nfilename, dirname(p)); 377: fp = fopen(nfilename, "r"); 378: if (fp == NULL) { 379: log("Already Cancelled %s", line); 380: return 1; 381: } 382: htmp.unrec[0] = NULL; 383: if (hread(&htmp, fp, TRUE) == NULL) { 384: if (bfr[0] == '/') { 385: fp = fopen(bfr, "r"); 386: if (fp == NULL 387: || hread(&htmp, fp, TRUE) == NULL) 388: xerror("Article is garbled."); 389: } else 390: xerror("Article is garbled."); 391: } 392: (void) fclose(fp); 393: poster = senderof(&htmp); 394: /* only compare up to '.' or ' ' */ 395: r = index(poster,'.'); 396: if (r == NULL) 397: r = index(poster,' '); 398: if (r != NULL) 399: *r = '\0'; 400: if (!su && strncmp(whatsisname, poster,strlen(poster))) { 401: xerror("Not contributor: posted by %s, and you are %s", poster, whatsisname); 402: } 403: 404: (void) unlink(nfilename); 405: p = q+1; 406: } 407: return 0; 408: } 409: 410: /* 411: * sendsys (no arguments) 412: * 413: * Mail the sys file to the person submitting the article. 414: * POLICY: the contents of your sys file are public information 415: * and as such, you should not change this code. You may feel 416: * free to arrange for it to manually notify you, in the event 417: * that you want to do something to clean it up before it goes out. 418: * Secret sites on the net are expressly frowned on. 419: * 420: * The purpose of this command is for making a network map. The 421: * details of your link and which newsgroups are forwarded are not 422: * important, in case you want to sanitize them. Since the definition 423: * of USENET is those sites getting net.announce, you can disable this 424: * on sites not getting net articles, but if you take out the list of 425: * forwarded newsgroups, and you have sites that only get local newsgroups, 426: * you should make this clear, or remove those sites from what you send out. 427: */ 428: /* ARGSUSED */ 429: c_sendsys(argc, argv) 430: char **argv; 431: { 432: register FILE *f, *u; 433: int c; 434: 435: #ifdef NOTIFY 436: f = mailhdr((struct hbuf *)NULL, "sendsys control message"); 437: if (f != NULL) { 438: fprintf(f, "%s requested your %s/sys file.\n", header.path, LIB); 439: fprintf(f, "It has been sent.\n"); 440: (void) mclose(f); 441: } 442: #endif 443: f = mailhdr(&header, "response to your sendsys request"); 444: u = fopen(SUBFILE, "r"); 445: if (f != NULL && u != NULL) { 446: while ((c=getc(u)) != EOF) 447: putc(c, f); 448: (void) fclose(u); 449: (void) mclose(f); 450: } 451: } 452: 453: /* 454: * senduuname (no arguments) 455: * 456: * Run the "uuname" command and send it back to the person who submitted 457: * the article. The purpose of this control message is for attempting to 458: * make a uucp net map. 459: * 460: * POLICY: If you view this information as not public (because you have 461: * a connection you consider secret, or know a site that considers itself 462: * secret) you can feel free to change this code in whatever way is 463: * appropriate, so long as it sends some response back to the sender. If 464: * you don't run uucp, this code does not make sense, and so an error 465: * message (or garbage, such as "research") will be mailed back. 466: * 467: * If you wish to add or remove sites from the output of uuname, you 468: * may wish to use the euuname.sh shell script here. 469: */ 470: /* ARGSUSED */ 471: c_senduuname(argc, argv) 472: char **argv; 473: { 474: char buf[256]; 475: FILE *fd, *u; 476: int c; 477: 478: #ifdef NOTIFY 479: fd = mailhdr((struct hbuf *)NULL, "uuname control message"); 480: fprintf(fd, "%s requested your uuname output\n", header.path); 481: (void) mclose(fd); 482: #endif 483: fd = mailhdr(&header, "response to your senduuname request"); 484: #ifdef UUPROG 485: if (UUPROG[0] == '/') 486: (void) strcpy(buf, UUPROG); 487: else 488: (void) sprintf(buf, "%s/%s", LIB, UUPROG); 489: #else 490: (void) strcpy(buf, "uuname"); 491: #endif 492: u = popen(buf, "r"); 493: if (fd != NULL && u != NULL) { 494: while ((c=getc(u)) != EOF) 495: putc(c, fd); 496: (void) pclose(u); 497: (void) mclose(fd); 498: } 499: } 500: 501: /* 502: * Send the version number to the right person. 503: */ 504: /* ARGSUSED */ 505: c_version(argc, argv) 506: char **argv; 507: { 508: register FILE *f; 509: 510: f = mailhdr(&header, "Our news version"); 511: if (f == NULL) 512: xerror("Cannot send back error message"); 513: fprintf(f, "Currently running news version %s.\n\n", news_version); 514: fprintf(f, "The header of your message follows:\n\n"); 515: (void) hwrite(&header, f); 516: (void) mclose(f); 517: } 518: 519: /* 520: * Check the active file for old or missing newsgroups 521: * Body of article is list of valid groups 522: */ 523: /* ARGSUSED */ 524: c_checkgroups(argc, argv) 525: char **argv; 526: { 527: int rc; 528: 529: (void) setuid(geteuid()); 530: /* dont change the cat %s| to < %s, it breaks some "unix" systems */ 531: (void) sprintf(bfr, "cat %s | %s/checkgroups %s", INFILE, LIB, 532: #ifdef NOTIFY 533: (TELLME && *TELLME) ? TELLME : NEWSUSR ); 534: #else /* !NOTIFY */ 535: NEWSUSR); 536: #endif /* !NOTIFY */ 537: rc = system(bfr); 538: log("system(%s) status %d", bfr, rc); 539: } 540: 541: /* 542: * An unknown control message has been received. 543: */ 544: c_unknown(h, ctlmsgtext) 545: struct hbuf *h; 546: char *ctlmsgtext; 547: { 548: register FILE *f; 549: 550: log("UNKNOWN Ctl Msg %s from %s", ctlmsgtext, h->path); 551: #ifdef NOTIFY 552: f = mailhdr((struct hbuf *)NULL, "Unrecognized Control Message"); 553: if (f != NULL) { 554: fprintf(f, "Currently running news version %s.\n\n", news_version); 555: fprintf(f, "The header of the message follows:\n\n"); 556: (void) hwrite(h, f); 557: (void) mclose(f); 558: } 559: #endif /* NOTIFY */ 560: } 561: 562: /* ARGSUSED */ 563: c_unimp(argc, argv) 564: char **argv; 565: { 566: register FILE *f; 567: 568: #ifdef NOTIFY 569: f = mailhdr((struct hbuf*)NULL, "Unimplemented Control Message"); 570: if (f != NULL) { 571: fprintf(f, "Currently running news version B %s.\n\n", news_version); 572: fprintf(f, "The header of the message follows:\n\n"); 573: (void) hwrite(&header, f); 574: (void) mclose(f); 575: } 576: #endif /* NOTIFY */ 577: } 578: 579: xmitmsg(tosys, title, ng) 580: char *tosys, *title, *ng; 581: { 582: #ifndef u370 583: struct hbuf htmp; 584: #endif /* !u370 */ 585: struct srec srec; 586: FILE *tfp; 587: char *fname; 588: 589: /* Make an article called ARTICLE */ 590: (void) sprintf(htmp.from, "%s@%s%s", "usenet", FULLSYSNAME, MYDOMAIN); 591: (void) strcpy(htmp.path, NEWSUSR); 592: (void) strcpy(htmp.nbuf, ng); 593: (void) strcpy(htmp.title, title); 594: (void) strcpy(htmp.ctlmsg, title); 595: (void) strcpy(htmp.subdate, ""); 596: (void) strcpy(htmp.expdate, ""); 597: getident(&htmp); 598: dates(&htmp); 599: tfp = xfopen(fname = mktemp("/tmp/xmsgXXXXXX"), "w"); 600: hwrite(&htmp, tfp); 601: (void) fclose(tfp); 602: 603: /* Find the sys record */ 604: s_openr(); 605: while (s_read(&srec)) { 606: if (strncmp(srec.s_name, tosys, SNLN)) 607: continue; 608: tfp = xfopen(fname, "r"); 609: (void) transmit(&srec, tfp, 0, (char **)0, 0); 610: (void) unlink(fname); 611: return; 612: } 613: log("Can't find sys record for %s", tosys); 614: xerror("Cannot find sys record"); 615: } 616: 617: /* 618: * This is a modified version of popen, made more secure. Rather than 619: * forking off a shell, you get a bare process. You must have exactly 620: * one argument, and the command must be mail (or sendmail if you have it). 621: */ 622: #define RDR 0 623: #define WTR 1 624: static int mopen_pid[20]; 625: char *replyname(); 626: 627: FILE * 628: mhopen(hptr) 629: struct hbuf *hptr; 630: { 631: int p[2]; 632: register myside, hisside, pid; 633: char *sendto = "usenet"; 634: 635: if (hptr) 636: sendto = replyname(hptr); 637: else { 638: #ifdef NOTIFY 639: if (TELLME && *TELLME) 640: sendto = TELLME; 641: #endif /* NOTIFY */ 642: if (sendto == NULL) 643: return NULL; 644: } 645: verifyname(sendto); 646: if(pipe(p) < 0) 647: return NULL; 648: myside = p[WTR]; 649: hisside = p[RDR]; 650: if((pid = fork()) == 0) { 651: /* myside and hisside reverse roles in child */ 652: (void) close(myside); 653: (void) close(0); 654: (void) dup(hisside); 655: (void) close(hisside); 656: (void) setgid(gid); 657: (void) setuid(uid); 658: #ifdef SENDMAIL 659: execl(SENDMAIL, "sendmail", "-oi", "-oeq", sendto, (char *)NULL); 660: #endif /* SENDMAIL */ 661: #ifdef MMDF 662: execl(MMDF, "inews-mail", "-smuxto,cc*", (char *)NULL); 663: #endif /* MMDF */ 664: execl("/bin/mail", "mail", sendto, (char *)NULL); 665: execl("/usr/bin/mail", "mail", sendto, (char *)NULL); 666: execl("/usr/ucb/mail", "mail", sendto, (char *)NULL); 667: _exit(1); 668: } 669: if(pid == -1) 670: return NULL; 671: mopen_pid[myside] = pid; 672: (void) close(hisside); 673: return(fdopen(myside, "w")); 674: } 675: 676: mclose(ptr) 677: FILE *ptr; 678: { 679: register f, r, (*hstat)(), (*istat)(), (*qstat)(); 680: int status; 681: 682: f = fileno(ptr); 683: (void) fclose(ptr); 684: istat = signal(SIGINT, SIG_IGN); 685: qstat = signal(SIGQUIT, SIG_IGN); 686: hstat = signal(SIGHUP, SIG_IGN); 687: while((r = wait(&status)) != mopen_pid[f] && r != -1) 688: ; 689: if(r == -1) 690: status = -1; 691: signal(SIGINT, istat); 692: signal(SIGQUIT, qstat); 693: signal(SIGHUP, hstat); 694: return status; 695: } 696: 697: /* 698: * mhopen a pipe to mail, write out a std header, and return the file ptr. 699: * 700: * We don't include a From: field because this is probably uucp, i.e. 701: * explicitly routed. Leave it up to the recipient's mailer. 702: * Always include the To: field because if we ge back failed mail, we 703: * might be able to deliver it by hand if we know to wom it was addressed. 704: * By convention, hptr==NULL means to send the message to the local contact person. 705: */ 706: FILE * 707: mailhdr(hptr, subject) 708: struct hbuf *hptr; 709: char *subject; 710: { 711: FILE *fp; 712: time_t now; 713: char *to = "usenet"; 714: 715: #ifdef NOTIFY 716: if (TELLME && *TELLME) 717: to = TELLME; 718: #endif /* NOTIFY */ 719: if (hptr) 720: to = replyname(hptr); 721: 722: if ((fp = mhopen(hptr)) != NULL) { 723: (void) time(&now); 724: fprintf(fp, "Date: %s\n", arpadate(&now)); 725: #ifdef MMDF 726: fprintf(fp, "From: The News System <usenet@%s%s>\n", 727: FULLSYSNAME, MYDOMAIN); 728: #endif /* MMDF */ 729: fprintf(fp, "To: %s\n", to); 730: fprintf(fp, "Subject: %s\n", subject); 731: #ifdef HIDDENNET 732: if (strcmp(LOCALSYSNAME, FULLSYSNAME)) 733: fprintf(fp, "Responding-System: %s.%s%s\n\n", 734: LOCALSYSNAME, FULLSYSNAME, MYDOMAIN); 735: #endif /* !HIDDENNET */ 736: fprintf(fp, "Responding-System: %s%s\n\n", 737: FULLSYSNAME, MYDOMAIN); 738: } 739: return fp; 740: } 741: 742: /* 743: * verify that the name mail is being sent to does not contain any 744: * nasty hooks to invoke funny functions from the shell or the like. 745: */ 746: verifyname(sendto) 747: char *sendto; 748: { 749: /* Be sure we DO allow alphabetics, !, :, ., -, @. *. */ 750: char *nasty = "\"'\\`^|;& <>/~"; 751: register char *p; 752: 753: if (sendto[0] <= ' ') { 754: log("nasty mail name %s from %s", sendto, header.path); 755: xxit(1); 756: } 757: for (p=sendto; *p; p++) { 758: if (*p == ' ') { 759: *p = 0; 760: break; 761: } 762: } 763: if (strpbrk(sendto, nasty) != NULL) 764: xerror("nasty mail name %s from %s", sendto, header.path); 765: 766: for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) { 767: if (*++nasty == '.') /* check for .. */ 768: xerror("nasty mail name %s from %s", sendto, header.path); 769: } 770: } 771: 772: /* 773: * Checks to make sure the control message is OK to post. 774: */ 775: ctlcheck() 776: { 777: char msg[BUFLEN]; 778: char *p; 779: 780: if (!is_ctl) 781: return; 782: 783: if (header.ctlmsg[0]) 784: (void) strcpy(msg, header.ctlmsg); 785: else 786: (void) strcpy(msg, header.title); 787: 788: p = index(msg, ' '); 789: if (p) 790: *p = 0; 791: 792: if (strcmp(msg, "ihave") == 0) { 793: } else if (strcmp(msg, "sendme") == 0) { 794: return; /* no restrictions */ 795: } else if (strcmp(msg, "newgroup") == 0) { 796: suser(); 797: } else if (strcmp(msg, "rmgroup") == 0) { 798: suser(); 799: } else if (strcmp(msg, "sendsys") == 0) { 800: suser(); 801: } else if (strcmp(msg, "senduuname") == 0) { 802: suser(); 803: } else if (strcmp(msg, "checkgroups") == 0) { 804: suser(); 805: } else if (strcmp(msg, "version") == 0) { 806: return; /* no restrictions */ 807: } else if (strcmp(msg, "cancel") == 0) { 808: return; /* no restrictions at this level */ 809: } else if (strcmp(msg, "delsub") == 0) { 810: if (!prefix(header.nbuf, "to.")) { 811: printf("Must be in a 'to.system' newsgroup."); 812: xxit(0); 813: } 814: return; 815: } else { 816: printf("Unrecognized control message - %s\n", msg); 817: xxit(0); 818: } 819: } 820: 821: /* Make sure this guy is special. */ 822: suser() 823: { 824: if (uid == 0 || uid == ROOTID) 825: return; 826: /* 827: * We assume that since our real uid is the same as NEWSUSR 828: * (the euid) we were run by rootid and it did a setuid. 829: * Too bad we can't set just the effective uid like suid does. 830: */ 831: if (uid == geteuid()) 832: return; 833: #ifdef IHCC 834: printf("Please use the command:\n\ttoolnews providers\n"); 835: printf("then call one of the news people.\n"); 836: #else 837: printf("Get your local netnews contact to do it for you.\n"); 838: #endif 839: xxit(0); 840: }