|
|
1.1 root 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.55 10/7/87";
23: #endif /* SCCSID */
24:
25: #include "iparams.h"
26:
27: #define eq(msg) (msg[0] == cargv[0][0] && strcmp(msg, cargv[0]) == 0)
28:
29: int cargc;
30: char **cargv;
31:
32: FILE *hfopen();
33: FILE *popen(), *mhopen(), *mailhdr();
34:
35: #define NCARGS 30
36: char *senderof();
37: #ifdef u370
38: static struct hbuf htmp;
39: #endif /* u370 */
40:
41: /*
42: * The global structure is initialized to NOTIFY as the default (if defined)
43: * uid to send mail to for every state. The following conditions are
44: * dealt with (assumes NOTIFY defined):
45: *
46: * 1) LIB/notify exists and is empty (or contains no recognizable control
47: * message types).
48: * Action: force TELLME = "";
49: * 2) LIB/notify contains the control message name "all" and no associated
50: * address.
51: * Action: force TELLME = "";
52: * 3) LIB/notify contains the control message name "all" and has an address.
53: * Action: set TELLME = AlloCpy(address);
54: * 4) LIB/notify contains only some of the known control message types.
55: * Action: initialize all addresses to "" and set declared addresses
56: * to listed address.
57: */
58:
59:
60: control(h)
61: struct hbuf *h;
62: {
63: register char *ctlmsgtext;
64: register struct msgtype *mp;
65:
66: if (strncmp(h->title, "cmsg ", 5) == 0) {
67: register char *cp1, *cp2;
68: cp1 = h->title;
69: cp2 = h->title + 5;
70: while (*cp1++ = *cp2++)
71: ;
72: }
73:
74: if (*h->ctlmsg)
75: ctlmsgtext = h->ctlmsg;
76: else
77: ctlmsgtext = h->title;
78: log("Ctl Msg %s from %s: %s", h->nbuf, h->path, ctlmsgtext);
79: /*
80: * Control messages have the standard format
81: * command [args]
82: * much like shell commands. Each site has the option
83: * of customizing this code to deal with control messages
84: * as they see fit, but we would like to buy back the
85: * code, ifdeffed or otherwise parameterized, to simplify
86: * the maintenence issues.
87: */
88: argparse(ctlmsgtext);
89:
90: /*
91: * We look for a match of the control message name and then
92: * set TELLME to the value parsed from the LIB/notify file
93: * (if any).
94: */
95: for(mp=msgtype; mp->m_name; mp++) {
96: if(eq(mp->m_name) ) { /* hit */
97: #ifdef NOTIFY
98: TELLME = mp->m_who_to; /* reset whom to tell */
99: #endif /* NOTIFY */
100: return (*mp->m_func)(cargc, cargv); /* do it */
101: }
102: }
103: if( !mp->m_name ) {
104: #ifdef NOTIFY
105: TELLME = NOTIFY;
106: #endif /* NOTIFY */
107: c_unknown(h, ctlmsgtext);
108: }
109: return 0;
110: }
111:
112: /*
113: * Parse the string str into separate words in cargc and cargv
114: * as per the usual UNIX convention. Nothing fancy here, just
115: * blanks and tabs separating words.
116: */
117: argparse(str)
118: char *str;
119: {
120: static char *cavpbuf[NCARGS];
121: static char cavbuf[256];
122: char *nextfree = cavbuf;
123:
124: if (str == '\0')
125: error("Control message %s has no title", header.ident);
126: cargc = (*str != '\0');
127: cargv = cavpbuf;
128: cargv[0] = cavbuf;
129:
130: while (*str) {
131: if (*str <= ' ') {
132: /* skip over white space */
133: while (*str != '\0' && *str <= ' ')
134: str++;
135: if (*str == '\0') /* line ends in white space */
136: return;
137: *nextfree++ = 0;
138: cargv[cargc] = nextfree;
139: if (cargc++ >= NCARGS)
140: xerror("Too many arguments to control message %s",
141: header.ident);
142: } else
143: *nextfree++ = *str++;
144: }
145: }
146:
147: /*
148: * ihave <artid> ... <remotesys>
149: * or
150: * ihave <remotesys>
151: * with <artid>s in message body.
152: *
153: * The other system is telling you it has article <artid>, in case
154: * you decide you want it to transmit it to you.
155: * The assumption is that the other system only tells you about articles
156: * in newsgroups you subscribe to.
157: *
158: * We turn the incoming ihave into an outgoing sendme on the fly.
159: * It then gets saved in the SPOOL directory and transmitted to the
160: * remote system. (This way the sendme messages can be batched.)
161: */
162: c_ihave(argc, argv)
163: register char ** argv;
164: {
165: register int i;
166: char list[sizeof header.title];
167: extern char * findhist();
168: extern char * mydomain();
169:
170: if (argc < 2)
171: error("ihave: Too few arguments.");
172: if (strncmp(PATHSYSNAME, argv[argc - 1], SNLN) == 0)
173: return 0;
174: list[0] = '\0';
175: if (argc > 2) {
176: for (i = 1; i < (argc - 1); ++i)
177: if (findhist(argv[i]) == NULL) {
178: (void) strcat(list, " ");
179: (void) strcat(list, argv[i]);
180: }
181: if (list[0] == '\0')
182: return 0;
183: } else {
184: register FILE * outfp;
185: register long outpos, inpos;
186: char myid[256];
187:
188: outfp = xfopen(INFILE, "a");
189: outpos = ftell(outfp);
190: inpos = ftell(infp);
191: while (ftell(infp) < outpos) {
192: if (fgets(myid, sizeof myid, infp) != myid)
193: error("iline: Can't reread article");
194: myid[strlen(myid) - 1] = '\0';
195: if (findhist(myid) == NULL)
196: (void) fprintf(outfp, "%s\n", myid);
197: }
198: if (outpos == ftell(outfp)) { /* if nothing is wanted */
199: (void) fclose(outfp);
200: (void) fseek(infp, inpos, 0);
201: return 0;
202: }
203: (void) fclose(outfp);
204: /*
205: ** The close and open may just be paranoia.
206: */
207: (void) fclose(infp);
208: infp = xfopen(INFILE, "r");
209: (void) fseek(infp, outpos, 0);
210: }
211: /*
212: ** Turn the ihave into a sendme.
213: */
214: (void) sprintf(header.nbuf, "to.%s.ctl", argv[argc - 1]);
215: (void) sprintf(header.title, "sendme%s %s", list, PATHSYSNAME);
216: (void) strcpy(header.ctlmsg, header.title);
217: getident(&header);
218: (void) sprintf(header.from, "%s@%s", "usenet", FROMSYSNAME);
219: (void) strcpy(header.path, NEWSUSR);
220: header.subdate[0] = header.expdate[0] = '\0';
221: dates(&header);
222: /*
223: ** What else of this kind should be done?
224: */
225: header.organization[0] = header.distribution[0] = '\0';
226: header.numlines[0] = '\0';
227: for (i = 0; i < NUNREC && header.unrec[i] != NULL; ++i) {
228: free(header.unrec[i]);
229: header.unrec[i] = NULL;
230: }
231: /*
232: ** Note that we do *not* change the history line
233: ** so that if the "ihave" message comes in again it gets rejected.
234: */
235: return 0;
236: }
237:
238: /*
239: * sendme <artid> ... <remotesys>
240: * or
241: * sendme <remotesys>
242: * with <artid>s in message body.
243: * The other system wants me to send out article <artid>.
244: * Give it to them with no fuss.
245: */
246: #ifdef MULTICAST
247: static int c_mc;
248: static char ** c_sysnames;
249: #endif /* MULTICAST */
250: c_sendme(argc, argv)
251: register char **argv;
252: {
253: struct srec srec;
254:
255: if (argc < 2)
256: error("sendme: Too few arguments.");
257: if (strncmp(PATHSYSNAME, argv[argc - 1], SNLN) == 0)
258: return 0;
259: if (s_find(&srec, argv[argc - 1]) != TRUE)
260: error("sendme: Can't find sys record for %s", argv[argc - 1]);
261: #ifdef MULTICAST
262: c_mc = index(srec.s_flags, 'M') != 0;
263: if (c_mc) {
264: struct srec trec;
265:
266: c_sysnames = &argv[argc - 1];
267: if (s_find(&trec, srec.s_xmit) != TRUE)
268: error("sendme: Can't find sys record for %s for %s",
269: srec.s_xmit, argv[argc - 1]);
270: srec = trec;
271: } else c_sysnames = NULL;
272: #endif /* MULTICAST */
273: /* Send the articles. */
274: if (argc == 2) {
275: register FILE * fp;
276: char buf[256];
277:
278: fp = xfopen(INFILE, "r");
279: while (fgets(buf, sizeof buf, fp) == buf) {
280: buf[strlen(buf) - 1] = '\0'; /* zap trailing '\n' */
281: sendmefunc(buf, &srec);
282: }
283: (void) fclose(fp);
284: } else { /* argc > 2 */
285: register int i;
286:
287: for (i = 1; i < (argc - 1); ++i)
288: sendmefunc(argv[i], &srec);
289: }
290: return 0;
291: }
292:
293: static
294: sendmefunc(id, sp)
295: register char * id;
296: register struct srec * sp;
297: {
298: register FILE * fp;
299: register char * cp;
300: char savedbufname[256];
301: extern char firstbufname[];
302: extern char * dirname();
303: extern char * findfname();
304:
305: cp = findfname(id);
306: if (cp == NULL) {
307: log("System %s wants unavailable article %s.",
308: #ifdef MULTICAST
309: (c_mc ? c_sysnames[0] : sp->s_name), id);
310: #else /* !MULTICAST */
311: sp->s_name, id);
312: #endif /* !MULTICAST */
313: return;
314: }
315: cp = dirname(cp);
316: fp = fopen(cp, "r");
317: if (fp == NULL) {
318: logerr("Article %s unopenable as %s.", id, cp);
319: return;
320: }
321: (void) strcpy(savedbufname, firstbufname);
322: (void) strcpy(firstbufname, cp);
323: #ifdef MULTICAST
324: transmit(sp, fp, FALSE, c_sysnames, c_mc);
325: #else /* !MULTICAST */
326: transmit(sp, fp, FALSE, (char **) NULL, 0);
327: #endif /* !MULTICAST */
328: /* transmit closes fp */
329: (void) strcpy(firstbufname, savedbufname);
330: }
331:
332: /*
333: * newgroup <groupname>
334: * A new newsgroup has been created.
335: * The body of the article, if present, is a description of the
336: * purpose of the newsgroup.
337: *
338: */
339: c_newgroup(argc, argv)
340: char **argv;
341: {
342: FILE *fd;
343: char abuf[BUFLEN], subjline[BUFLEN];
344: int didcreate = 0;
345: register char *p, *q;
346: # ifdef NONEWGROUPS
347: # ifdef ORGDISTRIB
348: /* local or ORGDISTRIB */
349: int can_change = (strcmp(header.distribution, "local") == 0) ||
350: (strcmp(header.distribution, ORGDISTRIB) == 0);
351: # else /* ! ORGDISTRIB */
352: /* local only */
353: int can_change = strcmp(header.distribution, "local") == 0;
354: # endif /* ORGDISTRIB */
355: # else /* ! NONEWGROUPS */
356: int can_change = 1; /* allow changes for all distributions */
357: # endif /* NONEWGROUPS */
358:
359: if (argc < 2)
360: error("newgroup: Too few arguments.");
361:
362: if (header.approved[0] == '\0') {
363: logerr("newgroup: %s not approved", argv[1]);
364: return 1;
365: }
366:
367: lock();
368: /* see if it already exists */
369: (void) rewind(actfp); clearerr(actfp);
370: while(fgets(abuf, BUFLEN, actfp) != NULL) {
371: p = abuf;
372: q = argv[1];
373: while (*p++ == *q++)
374: ;
375: if (*--q == '\0' && *--p == ' ') {
376: /* Now check if it's correctly moderated/unmoderated */
377: while (*p++)
378: ;
379: p -= 3;
380: if (argc > 2 && strcmp(argv[2], "moderated") == 0) {
381: if (*p == 'm') {
382: unlock();
383: return 0;
384: }
385: *p = 'm';
386: } else {
387: if (*p != 'm') {
388: unlock();
389: return 0;
390: }
391: *p = 'y';
392: }
393: # ifdef NOTIFY
394: (void) sprintf(subjline,
395: "Newsgroup %s changed from %smoderated to %smoderated",
396: argv[1], *p=='y' ? "" : "un",
397: *p=='y' ? "un" : "");
398: fd = mailhdr((struct hbuf *)NULL, subjline);
399: if (fd != NULL) {
400: if(can_change)
401: fprintf(fd,
402: "%s has been changed from %smoderated to %smoderated as requested by\n%s\n",
403: argv[1], *p=='y' ? "" : "un",
404: *p=='y' ? "un":"", header.path);
405: else {
406: fprintf(fd,
407: "%s\nhas requested that %s be changed from %smoderated to %smoderated\n",
408: header.path, argv[1],
409: *p=='y' ? "" : "un",
410: *p=='y' ? "un" : "");
411: #ifdef ORGDISTRIB
412: fprintf(fd,
413: "You can accomplish this by re-creating the newsgroup with a distribution\n");
414: fprintf(fd,
415: "of '%s' by executing the command:\n", ORGDISTRIB);
416: fprintf(fd,
417: "%s/inews -d %s -C %s%s\n",
418: LIB, ORGDISTRIB, argv[1],
419: *p=='y' ? "" : " moderated");
420: #else /* !ORGDISTRIB */
421: fprintf(fd,
422: "You can accomplish this by re-creating the newsgroup by executing the command:\n");
423: fprintf(fd, "%s/inews -C %s%s\n",
424: LIB, argv[1],
425: *p=='y' ? "" : " moderated");
426: #endif /* !ORGDISTRIB */
427: }
428: (void) mclose(fd);
429: }
430: # endif /* NOTIFY */
431: # ifdef NONEWGROUPS
432: /*
433: * No permission to change
434: */
435: if(!can_change) {
436: unlock();
437: return 0;
438: }
439: # endif /* NONEWGROUPS */
440: /* The active file was wrong about the state of the
441: * group. Rewrite the active file
442: */
443: (void) fseek(actfp, -2L, 1); /* back up 2 characters */
444: putc(*p, actfp);
445: fflush(actfp);
446: if (*p != 'm')
447: logerr("Newsgroup %s changed from moderated to unmoderated",
448: argv[1]);
449: else
450: logerr("Newsgroup %s changed from unmoderated to moderated",
451: argv[1]);
452: unlock();
453: return 0;
454: }
455: }
456:
457: /* It doesn't already exist, we must create it */
458:
459: if(can_change) {
460: didcreate++;
461: (void) fseek(actfp, 0L, 2); clearerr(actfp);
462: fprintf(actfp, "%s 00000 00001 %c\n", argv[1],
463: (argc > 2 && strcmp(argv[2], "moderated") == 0)
464: ? 'm' : 'y');
465: #if defined(USG) || defined(MG1)
466: /*
467: * U G L Y K L U D G E
468: * This utter piece of tripe is the only way I know of
469: * to get around the fact that ATT BROKE standard IO
470: * in System 5.2. Basically, you can't open a file for
471: * "r+" and then try and write to it. This hack works
472: * on all "real" USG Unix systems, It will probably
473: * break on some obscure look alike that doesnt use the
474: * real ATT stdio.h
475: * also broken in WCW MG-1 42nix 2.0
476: * Don't blame me, blame ATT. stdio should have
477: * already done the following line for us, but it didn't
478: */
479: actfp->_flag |= _IOWRT;
480: #endif /* USG */
481: fflush(actfp);
482: }
483:
484: # ifdef NOTIFY
485: (void) sprintf(subjline, "Newsgroup %s created", argv[1]);
486: fd = mailhdr((struct hbuf *)NULL, subjline);
487: if (fd != NULL) {
488: if (didcreate)
489: fprintf(fd,
490: "A new %snewsgroup called '%s' has been created by %s.\n",
491: argc > 2 ? "moderated " : "", argv[1],
492: header.path);
493: else {
494: fprintf(fd,
495: "%s requested that a new %snewsgroup called '%s' be created.\n",
496: header.path, argc > 2 ? "moderated " : "", argv[1]);
497: fprintf(fd,"It was approved by %s\n\n",header.approved);
498: fprintf(fd,
499: "You can accomplish this by creating the newgroup yourself\n");
500: # ifdef ORGDISTRIB
501: fprintf(fd,"with a distribution of '%s'.\n",
502: ORGDISTRIB);
503: fprintf(fd,
504: "In other words, by executing the command:\n");
505: fprintf(fd, "%s/inews -d %s -C %s %s\n", LIB,
506: ORGDISTRIB, argv[1], argc > 2 ? argv[2] : "");
507: # else /* !ORGDISTRIB */
508: fprintf(fd, "In other words, by executing the command:\n");
509: fprintf(fd, "%s/inews -C %s %s\n", LIB, argv[1],
510: argc > 2 ? argv[2] : "");
511: # endif /* !ORGDISTRIB */
512: }
513: (void) mclose(fd);
514: }
515: # endif /* NOTIFY */
516: unlock();
517: return 0;
518: }
519:
520: /*
521: * rmgroup <groupname>
522: * An old newsgroup is being cancelled on a network wide basis.
523: */
524: c_rmgroup(argc, argv)
525: char **argv;
526: {
527: FILE *fd;
528: int shouldremove = 0;
529: #ifdef NOTIFY
530: char subjline[BUFLEN];
531: #endif /* NOTIFY */
532:
533: if (argc < 2)
534: error("rmgroup: Too few arguments.");
535: if (!validng(argv[1]))
536: return 0;
537: if (header.approved[0] == '\0') {
538: logerr("rmgroup: %s not approved", argv[1]);
539: return 1;
540: }
541:
542: #ifdef MANUALLY
543: #ifdef ORGDISTRIB
544: /*
545: * Allow local as well as organizational removals
546: */
547: if (!strcmp(ORGDISTRIB, header.distribution)
548: || !strcmp("local", header.distribution))
549: #else /* !ORGDISTRIB */
550: if (!strcmp("local", header.distribution))
551: #endif /* !ORGDISTRIB */
552: #endif /* MANUALLY */
553: shouldremove++;
554: #ifdef NOTIFY
555: sprintf(subjline, "Received rmgroup for %s", argv[1]);
556: fd = mailhdr((struct hbuf *)NULL, subjline);
557: if (fd != NULL) {
558: if (shouldremove) {
559: fprintf(fd, "Newsgroup '%s' has been removed by %s.\n\n",
560: argv[1], header.path);
561: # ifdef USG
562: fprintf(fd, "You may need to remove the directory %s by hand\n",
563: dirname(argv[1]));
564: # endif
565: } else {
566: fprintf(fd, "%s requested that newsgroup %s be removed.\n",
567: header.path, argv[1]);
568: fprintf(fd, "You should remove it by hand\n");
569: fprintf(fd, "To do this, execute the command\n");
570: fprintf(fd, "\t%s/rmgroup %s\n", LIB, argv[1]);
571: }
572: (void) mclose(fd);
573: }
574: #endif /* NOTIFY */
575:
576: if (shouldremove) {
577: int pid, status;
578: /* We let the shell do all the work.
579: * See the rmgrp shell script.
580: */
581: lock();
582: (void) sprintf(bfr, "%s/rmgroup", LIB);
583:
584: if (pid = fork()) {
585: status = fwait(pid);
586: } else {
587: register int i;
588: for (i =3; i<20; i++)
589: if (close(i) < 0)
590: break;
591: (void) setuid(duid);
592: execvp(bfr, argv);
593: }
594: unlock();
595: if (status)
596: log("rmgroup status %d", status);
597: }
598: return 0;
599: }
600:
601: /*
602: * cancel <artid>
603: * Cancel the named article
604: */
605: c_cancel(argc, argv)
606: char **argv;
607: {
608: char *line, *p, *q, *r, *poster;
609: char *findhist();
610: register FILE *fp;
611: char whatsisname[BUFLEN], nfilename[BUFLEN];
612: time_t t;
613: int su = 0;
614: #ifndef u370
615: struct hbuf htmp;
616: #endif /* !u370 */
617:
618: if (argc < 2)
619: error("cancel: Too few arguments.");
620: (void) strcpy(whatsisname, senderof(&header));
621: line = findhist(argv[1]);
622: if (line == NULL) {
623: struct tm *tm;
624: log("Can't cancel %s: non-existent", argv[1]);
625: (void) time(&t);
626: tm = localtime(&t);
627: #ifdef USG
628: sprintf(bfr,"%s\t%2.2d/%2.2d/%d %2.2d:%2.2d\tcancelled",
629: #else /* !USG */
630: sprintf(bfr,"%s\t%02d/%02d/%d %02d:%02d\tcancelled",
631: #endif /* !USG */
632: argv[1], tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour,
633: tm->tm_min);
634: savehist(bfr);
635: return -1;
636: }
637:
638: q = index(line, '\t');
639: p = index(q+1, '\t');
640: if (p == NULL || *++p == '\0' || *p == '\n') {
641: *q = '\0';
642: log("Expired article %s", line);
643: return -1;
644: }
645: if (strcmp(p, "cancelled") == 0) {
646: *q = '\0';
647: log("Already Cancelled %s", line);
648: return -1;
649: } else
650: log("Cancelling %s", line);
651: if ((uid == ROOTID||uid == 0) && (
652: #ifdef ORGDISTRIB
653: strcmp(header.distribution, ORGDISTRIB) == 0 ||
654: #endif /* ORGDISTRIB */
655: strcmp(header.distribution, "local") == 0))
656: su = 1;
657: while (*p) {
658: q = index(p, ' ');
659: if (q)
660: *q = '\0';
661: (void) strcpy(nfilename, dirname(p));
662: fp = fopen(nfilename, "r");
663: if (fp == NULL) {
664: log("Can't cancel %s: %s", line, errmsg(errno));
665: return -1;
666: }
667: htmp.unrec[0] = NULL;
668: if (hread(&htmp, fp, TRUE) == NULL) {
669: if (bfr[0] == '/') {
670: fp = fopen(bfr, "r");
671: if (fp == NULL
672: || hread(&htmp, fp, TRUE) == NULL)
673: error("Article is garbled.");
674: } else
675: error("Article is garbled.");
676: }
677: (void) fclose(fp);
678: poster = senderof(&htmp);
679: /* only compare up to '.' or ' ' */
680: r = index(poster,'.');
681: if (r == NULL)
682: r = index(poster,' ');
683: if (r != NULL)
684: *r = '\0';
685: if (!su && strncmp(whatsisname, poster,strlen(poster))) {
686: error("Not contributor: posted by %s, and you are %s", poster, whatsisname);
687: }
688:
689: (void) unlink(nfilename);
690: p = q+1;
691: }
692: return 0;
693: }
694:
695: /*
696: * sendsys (no arguments)
697: *
698: * Mail the sys file to the person submitting the article.
699: * POLICY: the contents of your sys file are public information
700: * and as such, you should not change this code. You may feel
701: * free to arrange for it to manually notify you, in the event
702: * that you want to do something to clean it up before it goes out.
703: * Secret sites on the net are expressly frowned on.
704: *
705: * The purpose of this command is for making a network map. The
706: * details of your link and which newsgroups are forwarded are not
707: * important, in case you want to sanitize them. Since the definition
708: * of USENET is those sites getting net.announce, you can disable this
709: * on sites not getting net articles, but if you take out the list of
710: * forwarded newsgroups, and you have sites that only get local newsgroups,
711: * you should make this clear, or remove those sites from what you send out.
712: */
713: /* ARGSUSED */
714: c_sendsys(argc, argv)
715: char **argv;
716: {
717: register FILE *f, *u;
718: int c;
719:
720: #ifdef NOTIFY
721: f = mailhdr((struct hbuf *)NULL, "sendsys control message");
722: if (f != NULL) {
723: fprintf(f, "%s requested your %s/sys file.\n", header.path, LIB);
724: fprintf(f, "It has been sent.\n");
725: (void) mclose(f);
726: }
727: #endif /* NOTIFY */
728: f = mailhdr(&header, "response to your sendsys request");
729: u = fopen(SUBFILE, "r");
730: if (f != NULL && u != NULL) {
731: while ((c=getc(u)) != EOF)
732: putc(c, f);
733: (void) fclose(u);
734: (void) mclose(f);
735: }
736: return 0;
737: }
738:
739: /*
740: * Send the version number to the right person.
741: */
742: /* ARGSUSED */
743: c_version(argc, argv)
744: char **argv;
745: {
746: register FILE *f;
747:
748: f = mailhdr(&header, "Our news version");
749: if (f == NULL)
750: error("Cannot send back error message");
751: fprintf(f, "Currently running news version %s.\n\n", news_version);
752: fprintf(f, "The header of your message follows:\n\n");
753: (void) hwrite(&header, f);
754: (void) mclose(f);
755: return 0;
756: }
757:
758: /*
759: * Check the active file for old or missing newsgroups
760: * Body of article is list of valid groups
761: */
762: /* ARGSUSED */
763: c_checkgroups(argc, argv)
764: char **argv;
765: {
766: int rc;
767:
768: (void) setuid(geteuid());
769: /* dont change the cat %s| to < %s, it breaks some "unix" systems */
770: (void) sprintf(bfr, "cat %s | %s/checkgroups %s", INFILE, LIB,
771: #ifdef NOTIFY
772: (TELLME && *TELLME) ? TELLME : NEWSUSR );
773: #else /* !NOTIFY */
774: NEWSUSR);
775: #endif /* !NOTIFY */
776: rc = system(bfr);
777: log("system(%s) status %d", bfr, rc);
778: return 0;
779: }
780:
781: /*
782: * An unknown control message has been received.
783: */
784: c_unknown(h, ctlmsgtext)
785: struct hbuf *h;
786: char *ctlmsgtext;
787: {
788: register FILE *f;
789:
790: log("UNKNOWN Ctl Msg %s from %s", ctlmsgtext, h->path);
791: #ifdef NOTIFY
792: f = mailhdr((struct hbuf *)NULL, "Unrecognized Control Message");
793: if (f != NULL) {
794: fprintf(f, "Currently running news version %s.\n\n", news_version);
795: fprintf(f, "The header of the message follows:\n\n");
796: (void) hwrite(h, f);
797: (void) mclose(f);
798: }
799: #endif /* NOTIFY */
800: return 0;
801: }
802:
803: /* ARGSUSED */
804: c_unimp(argc, argv)
805: char **argv;
806: {
807: register FILE *f;
808:
809: #ifdef NOTIFY
810: f = mailhdr((struct hbuf*)NULL, "Unimplemented Control Message");
811: if (f != NULL) {
812: fprintf(f, "Currently running news version B %s.\n\n", news_version);
813: fprintf(f, "The header of the message follows:\n\n");
814: (void) hwrite(&header, f);
815: (void) mclose(f);
816: }
817: #endif /* NOTIFY */
818: return 0;
819: }
820:
821: /*
822: * This is a modified version of popen, made more secure. Rather than
823: * forking off a shell, you get a bare process. You must have exactly
824: * one argument, and the command must be mail (or sendmail if you have it).
825: */
826: #define RDR 0
827: #define WTR 1
828: static int mopen_pid[20];
829: char *replyname();
830:
831: FILE *
832: mhopen(hptr)
833: struct hbuf *hptr;
834: {
835: int p[2];
836: register myside, hisside, pid;
837: char *sendto = "usenet";
838:
839: if (hptr)
840: sendto = replyname(hptr);
841: else {
842: #ifdef NOTIFY
843: if (TELLME)
844: sendto = TELLME;
845: #endif /* NOTIFY */
846: if (sendto == NULL || *sendto == '\0')
847: return NULL;
848: }
849: verifyname(sendto);
850: if(pipe(p) < 0)
851: return NULL;
852: myside = p[WTR];
853: hisside = p[RDR];
854: if((pid = vfork()) == 0) {
855: /* myside and hisside reverse roles in child */
856: (void) close(myside);
857: (void) close(0);
858: (void) dup(hisside);
859: (void) close(hisside);
860: (void) setgid(gid);
861: (void) setuid(uid);
862: #ifdef SENDMAIL
863: execl(SENDMAIL, "sendmail", "-oi", "-oeq", sendto, (char *)NULL);
864: #endif /* SENDMAIL */
865: #ifdef MMDF
866: execl(MMDF, "inews-mail", "-smuxto,cc*", (char *)NULL);
867: #endif /* MMDF */
868: execl("/usr/bin/mailx", "mail", sendto, (char *)NULL);
869: execl("/usr/bin/mail", "mail", sendto, (char *)NULL);
870: execl("/usr/ucb/mail", "mail", sendto, (char *)NULL);
871: execl("/bin/mail", "mail", sendto, (char *)NULL);
872: _exit(1);
873: }
874: if(pid == -1)
875: return NULL;
876: mopen_pid[myside] = pid;
877: (void) close(hisside);
878: return(fdopen(myside, "w"));
879: }
880:
881: mclose(ptr)
882: FILE *ptr;
883: {
884: register f, r, (*hstat)(), (*istat)(), (*qstat)();
885: int status;
886:
887: f = fileno(ptr);
888: (void) fclose(ptr);
889: istat = signal(SIGINT, SIG_IGN);
890: qstat = signal(SIGQUIT, SIG_IGN);
891: hstat = signal(SIGHUP, SIG_IGN);
892: while((r = wait(&status)) != mopen_pid[f] && r != -1)
893: ;
894: if(r == -1)
895: status = -1;
896: signal(SIGINT, istat);
897: signal(SIGQUIT, qstat);
898: signal(SIGHUP, hstat);
899: return status;
900: }
901:
902: /*
903: * mhopen a pipe to mail, write out a std header, and return the file ptr.
904: *
905: * We don't include a From: field because this is probably uucp, i.e.
906: * explicitly routed. Leave it up to the recipient's mailer.
907: * Always include the To: field because if we ge back failed mail, we
908: * might be able to deliver it by hand if we know to wom it was addressed.
909: * By convention, hptr==NULL means to send the message to the local contact person.
910: */
911: FILE *
912: mailhdr(hptr, subject)
913: struct hbuf *hptr;
914: char *subject;
915: {
916: FILE *fp;
917: time_t now;
918: char *to = "usenet";
919: extern char *mydomain();
920:
921: #ifdef NOTIFY
922: if (TELLME && *TELLME)
923: to = TELLME;
924: #endif /* NOTIFY */
925: if (hptr)
926: to = replyname(hptr);
927:
928: if ((fp = mhopen(hptr)) != NULL) {
929: (void) time(&now);
930: fprintf(fp, "Date: %s\n", arpadate(&now));
931: #ifdef MMDF
932: fprintf(fp, "From: The News System <usenet@%s>\n",
933: FROMSYSNAME);
934: #endif /* MMDF */
935: fprintf(fp, "To: %s\n", to);
936: fprintf(fp, "Subject: %s\n", subject);
937: fprintf(fp, "Responding-System: %s\n\n", LOCALSYSNAME);
938: }
939: return fp;
940: }
941:
942: /*
943: * verify that the name mail is being sent to does not contain any
944: * nasty hooks to invoke funny functions from the shell or the like.
945: */
946: verifyname(sendto)
947: char *sendto;
948: {
949: /* Be sure we DO allow alphabetics, !, :, ., -, @. *. */
950: char *nasty = "\"'\\`^|;& <>/~";
951: register char *p;
952:
953: if (sendto[0] <= ' ') {
954: xerror("nasty mail name %s from %s", sendto, header.path);
955: }
956: for (p=sendto; *p; p++) {
957: if (*p == ' ') {
958: *p = 0;
959: break;
960: }
961: }
962: if (strpbrk(sendto, nasty) != NULL)
963: error("nasty mail name %s from %s", sendto, header.path);
964:
965: for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) {
966: if (*++nasty == '.') /* check for .. */
967: error("nasty mail name %s from %s", sendto, header.path);
968: }
969: }
970:
971: /*
972: * Checks to make sure the control message is OK to post.
973: */
974: ctlcheck()
975: {
976: char msg[BUFLEN];
977: char *p;
978:
979: if (!is_ctl)
980: return;
981:
982: if (header.ctlmsg[0])
983: (void) strcpy(msg, header.ctlmsg);
984: else
985: (void) strcpy(msg, header.title);
986:
987: p = index(msg, ' ');
988: if (p)
989: *p = 0;
990:
991: if (strcmp(msg, "ihave") == 0 || strcmp(msg, "sendbad") == 0 ||
992: strcmp(msg, "sendme") == 0) {
993: return; /* no restrictions */
994: } else if (strcmp(msg, "newgroup") == 0) {
995: suser();
996: } else if (strcmp(msg, "rmgroup") == 0) {
997: suser();
998: } else if (strcmp(msg, "sendsys") == 0) {
999: suser();
1000: } else if (strcmp(msg, "checkgroups") == 0) {
1001: suser();
1002: } else if (strcmp(msg, "version") == 0) {
1003: return; /* no restrictions */
1004: } else if (strcmp(msg, "cancel") == 0) {
1005: return; /* no restrictions at this level */
1006: } else if (strcmp(msg, "delsub") == 0) {
1007: if (!PREFIX(header.nbuf, "to.")) {
1008: log("Must be in a 'to.system' newsgroup.");
1009: xxit(0);
1010: }
1011: return;
1012: } else {
1013: log("Unrecognized control message - %s\n", msg);
1014: xxit(0);
1015: }
1016: }
1017:
1018: /* Make sure this guy is special. */
1019: suser()
1020: {
1021: if (uid == 0 || uid == ROOTID)
1022: return;
1023: /*
1024: * We assume that since our real uid is the same as NEWSUSR
1025: * (the euid) we were run by rootid and it did a setuid.
1026: * Too bad we can't set just the effective uid like suid does.
1027: */
1028: if (uid == geteuid())
1029: return;
1030: #ifdef IHCC
1031: printf("Please use the command:\n\ttoolnews providers\n");
1032: printf("then call one of the news people.\n");
1033: #else
1034: printf("Get your local netnews contact to do it for you.\n");
1035: #endif
1036: xxit(0);
1037: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.