|
|
1.1 root 1: /*
2: * Control message handling code. Deal with messages which are to be
3: * acted on by netnews itself rather than by people.
4: *
5: * See defs.h "news_version" for the real version of netnews.
6: */
7:
8: static char *SccsId = "@(#)control.c 2.20 6/24/83 (this is NOT the netnews version!)";
9:
10: #include "iparams.h"
11:
12: #define eq(msg) (strcmp(msg, cargv[0]) == 0)
13:
14: int cargc;
15: char **cargv;
16:
17: FILE *hfopen();
18: FILE *popen(), *mhopen(), *mailhdr();
19:
20: char *senderof();
21:
22: control(h)
23: struct hbuf *h;
24: {
25: register char *ctlmsgtext;
26: int i;
27:
28: if (*h->ctlmsg)
29: ctlmsgtext = h->ctlmsg;
30: else
31: ctlmsgtext = h->title;
32: log("Ctl Msg %s from %s: %s", h->nbuf, h->path, ctlmsgtext);
33: /*
34: * Control messages have the standard format
35: * command [args]
36: * much like shell commands. Each site has the option
37: * of customizing this code to deal with control messages
38: * as they see fit, but we would like to buy back the
39: * code, ifdeffed or otherwise parameterized, to simplify
40: * the maintenence issues.
41: */
42: argparse(ctlmsgtext);
43:
44: if (eq("ihave"))
45: c_ihave(cargc, cargv);
46: else if (eq("sendme"))
47: c_sendme(cargc, cargv);
48: else if (eq("newgroup"))
49: c_newgroup(cargc, cargv);
50: else if (eq("rmgroup"))
51: c_rmgroup(cargc, cargv);
52: else if (eq("cancel"))
53: c_cancel(cargc, cargv);
54: else if (eq("sendsys"))
55: c_sendsys(cargc, cargv);
56: else if (eq("senduuname"))
57: c_senduuname(cargc, cargv);
58: else if (eq("version"))
59: c_version(cargc, cargv);
60: else if (eq("delsub"))
61: c_unimp(cargc, cargv);
62: else
63: c_unknown(h, ctlmsgtext);
64: }
65:
66: /*
67: * Parse the string str into separate words in cargc and cargv
68: * as per the usual UNIX convention. Nothing fancy here, just
69: * blanks and tabs separating words.
70: */
71: argparse(str)
72: char *str;
73: {
74: static char *cavpbuf[20];
75: static char cavbuf[256];
76: char *nextfree = cavbuf;
77:
78: if (str == 0)
79: xerror("Control message %s has no title", header.ident);
80: cargc = 0;
81: cargv = cavpbuf;
82: cargv[0] = cavbuf;
83:
84: while (*str) {
85: if (*str <= ' ') {
86: *nextfree++ = 0;
87: cargc++;
88: cargv[cargc] = nextfree;
89: /* skip over white space */
90: while (*str > 0 && *str <= ' ')
91: str++;
92: if (*str == 0) /* line ends in white space */
93: return;
94: } else
95: *nextfree++ = *str++;
96: }
97: }
98:
99: /*
100: * ihave <artid> <remotesys>
101: * The other system is telling you it has article <artid>, in case
102: * you decide you want it to transmit it to you.
103: */
104: c_ihave(argc, argv)
105: char **argv;
106: {
107: char tl[256], ng[256];
108:
109: /*
110: * Check that we haven't already seen it (history)
111: * and then send back a "sendme" message if we subscribe.
112: */
113: if (history(argv[1]) == 0) {
114: /* Should probably check SUBFILE and NGFILE here. */
115: sprintf(tl, "sendme %s %s", argv[1], SYSNAME);
116: sprintf(ng, "to.%s.ctl", argv[2]);
117: xmitmsg(argv[2], tl, ng);
118: }
119: }
120:
121: /*
122: * sendme <artid> ... <remotesys>
123: * The other system wants me to send him article <artid>.
124: */
125: c_sendme(argc, argv)
126: char **argv;
127: {
128: struct srec srec;
129: int i;
130: FILE *fp;
131:
132: /* Find the sys record */
133: s_openr();
134: while (s_read(&srec)) {
135: if (strncmp(srec.s_name, argv[argc-1], SNLN))
136: continue;
137: /* It's the right one. Send them. */
138: for (i=1; i<argc-1; i++) {
139: /* transmit checks that other sys subscribes. */
140: fp = hfopen(argv[i]);
141: transmit(&srec, fp, 0);
142: /* transmit does fclose(fp) */
143: }
144: return;
145: }
146: sprintf(bfr, "Cannot find system %s to send article %s to.",
147: argv[argc-1], argv[1]);
148: xerror(bfr);
149: }
150:
151: /*
152: * newgroup <groupname>
153: * A new newsgroup has been created.
154: * The body of the article, if present, is a description of the
155: * purpose of the newsgroup.
156: *
157: * Site dependent. Should make very sure the directory has been
158: * created and properly owned. Might want to update ngfile.
159: * Might want to notify the contact person for this installation.
160: * Default action is to create the newsgroup, if it doesn't already
161: * exist.
162: */
163: c_newgroup(argc, argv)
164: char **argv;
165: {
166: FILE *fd;
167: strcpy(bfr, dirname(argv[1]));
168: if (access(bfr, 0) == 0)
169: return;
170:
171: mknewsg(bfr, argv[1]);
172:
173: /* update ngfile */
174: fd = fopen(NGFILE, "a");
175: fprintf(fd, "%s\n", argv[1]);
176: fclose(fd);
177:
178: #ifdef NOTIFY
179: /*
180: * Sample code to notify the contact person.
181: * Probably should dig up the text of the article
182: * and enclose that, too. It can be found in the
183: * file ARTICLE. Also, there needs to be
184: * an automatic provision to help you add the newsgroup.
185: *
186: * Note that even if you take out the above call to mknewsg,
187: * the newsgroup will still be created by the first article
188: * that comes in on it by a different call to mknewsg in inews.c
189: * (But only if you have AUTONEWNG defined in defs.h, which we
190: * disrecommend.)
191: */
192: fd = mailhdr(NULL, "creation of new newsgroup");
193: if (fd != NULL) {
194: fprintf(fd, "\nA new newsgroup called '%s' has been created by %s.\n\n",
195: argv[1], header.path);
196: mclose(fd);
197: }
198: #endif
199: }
200:
201: /*
202: * rmgroup <groupname>
203: * An old newsgroup is being cancelled on a network wide basis.
204: */
205: c_rmgroup(argc, argv)
206: char **argv;
207: {
208: FILE *fd;
209: char *groupname;
210: char groupdir[128];
211: int rc;
212:
213: groupname = argv[1];
214: verifyname(groupname);
215: if (groupname[0] == '.' || groupname[0] <= ' ')
216: xerror("Illegal group name in rmgroup");
217:
218: strcpy(groupdir, dirname(groupname));
219: if (access(groupdir, 0)) {
220: /*
221: * If the group already is gone, it's a nonfatal error - we
222: * want to propagate the message anyway, since what probably
223: * happened is somebody locally already removed it.
224: */
225: log("Cannot remove newsgroup '%s'", groupname);
226: return;
227: }
228: #ifdef NOTIFY
229: fd = mailhdr(NULL, "rmgroup control message");
230: if (fd != NULL) {
231: # ifndef MANUALLY
232: fprintf(fd, "\nA newsgroup called '%s' has been removed by %s.\n\n",
233: argv[1], header.path);
234: # ifdef USG
235: fprintf(fd, "You may need to remove the directory %s by hand\n",
236: dirname(argv[1]));
237: # endif
238: # else
239: fprintf(fd, "\n%s has requested that newsgroup %s be removed.\n",
240: header.path, argv[1]);
241: fprintf(fd, "You should remove it by hand\n");
242: # endif
243: mclose(fd);
244: }
245: #endif
246:
247: #ifndef MANUALLY
248: /* We let the shell do all the work. See the rmgrp shell script. */
249: setuid(geteuid()); /* otherwise it won't rmdir the dir */
250: sprintf(bfr, "rm -rf %s", groupdir);
251: rc = system(bfr); log("system(%s) status %d", bfr, rc);
252: sprintf(bfr, "cp %s /tmp/$$ ; sed '/^%s /d' </tmp/$$ > %s ; rm /tmp/$$",
253: ACTIVE, groupname, ACTIVE);
254: rc = system(bfr); log("system(%s) status %d", bfr, rc);
255: #endif
256: }
257:
258: /*
259: * cancel <artid>
260: * Cancel the named article
261: */
262: c_cancel(argc, argv)
263: char **argv;
264: {
265: char *line, *p, *q, *r, *s, *rr, *ss, *poster;
266: char *findhist();
267: register FILE *fp;
268: char whatsisname[150];
269: char msgbuf[256];
270: char msgng[64];
271: int su = 0;
272:
273: strcpy(whatsisname, senderof(&header));
274: strcpy(msgng, header.nbuf);
275: line = findhist(argv[1]);
276: if (line)
277: log("Cancelling %s", line);
278: else {
279: log("Can't cancel %s: non-existent", argv[1]);
280: return;
281: }
282:
283: p = index(line, '\t');
284: p = index(p+1, '\t');
285: p++;
286: while (*p) {
287: q = index(p, ' ');
288: if (q)
289: *q = 0;
290: strcpy(filename, dirname(p));
291: fp = xfopen(filename, "r");
292: if (hread(&header, fp, TRUE) == NULL)
293: xerror("Article is garbled.\n");
294: fclose(fp);
295: if((uid==ROOTID||uid==0) && strncmp(msgng,"to.",3) == 0)
296: su = 1;
297: poster = senderof(&header);
298: if (!su && strcmp(whatsisname, poster)) {
299: sprintf(msgbuf, "Not contributor: posted by %s, and you are %s", poster, whatsisname);
300: xerror(msgbuf);
301: }
302:
303: cancel();
304: p = q+1;
305: }
306: }
307:
308: /*
309: * sendsys (no arguments)
310: *
311: * Mail the sys file to the person submitting the article.
312: * POLICY: the contents of your sys file are public information
313: * and as such, you should not change this code. You may feel
314: * free to arrange for it to manually notify you, in the event
315: * that you want to do something to clean it up before it goes out.
316: * Secret sites on the net are expressly frowned on.
317: *
318: * The purpose of this command is for making a network map. The
319: * details of your link and which newsgroups are forwarded are not
320: * important, in case you want to sanitize them. Since the definition
321: * of USENET is those sites getting net.general, you can disable this
322: * on sites not getting net articles, but if you take out the list of
323: * forwarded newsgroups, and you have sites that only get local newsgroups,
324: * you should make this clear, or remove those sites from what you send out.
325: */
326: c_sendsys(argc, argv)
327: char **argv;
328: {
329: char buf[256];
330: FILE *f, *u;
331: int c;
332:
333: #ifdef NOTIFY
334: f = mailhdr(NULL, "sendsys control message");
335: if (f != NULL) {
336: fprintf(f, "\n%s requested your sys file.\n", header.path);
337: fprintf(f, "It has been sent.\n");
338: mclose(f);
339: }
340: #endif
341: f = mailhdr(&header, "Subject: response to your sendsys request\n\n");
342: u = fopen(SUBFILE, "r");
343: if (f != NULL && u != NULL) {
344: while ((c=getc(u)) != EOF)
345: putc(c, f);
346: fclose(u);
347: mclose(f);
348: }
349: }
350:
351: /*
352: * senduuname (no arguments)
353: *
354: * Run the "uuname" command and send it back to the person who submitted
355: * the article. The purpose of this control message is for attempting to
356: * make a uucp net map.
357: *
358: * POLICY: If you view this information as not public (because you have
359: * a connection you consider secret, or know a site that considers itself
360: * secret) you can feel free to change this code in whatever way is
361: * appropriate, so long as it sends some response back to the sender. If
362: * you don't run uucp, this code does not make sense, and so an error
363: * message (or garbage, such as "research") will be mailed back.
364: *
365: * If you wish to add or remove sites from the output of uuname, you
366: * may wish to use the euuname.sh shell script here.
367: */
368: c_senduuname(argc, argv)
369: char **argv;
370: {
371: char buf[256];
372: FILE *fd, *u;
373: int c;
374:
375: #ifdef NOTIFY
376: fd = mailhdr(NULL, "uuname control message");
377: fprintf(fd, "\n%s requested your uuname output\n", header.path);
378: mclose(fd);
379: #endif
380: fd = mailhdr(&header, "response to your senduuname request");
381: #ifdef UUPROG
382: if (UUPROG[0] == '/')
383: strcpy(buf, UUPROG);
384: else
385: sprintf(buf, "%s/%s", LIB, UUPROG);
386: #else
387: strcpy(buf, "uuname");
388: #endif
389: u = popen(buf, "r");
390: if (fd != NULL && u != NULL) {
391: while ((c=getc(u)) != EOF)
392: putc(c, fd);
393: pclose(u);
394: mclose(fd);
395: }
396: }
397:
398: /*
399: * Send the version number to the right person.
400: */
401: c_version(argc, argv)
402: char **argv;
403: {
404: FILE *f;
405:
406: f = mailhdr(&header, "Our news version");
407: if (f == NULL)
408: xerror("Cannot send back error message");
409: fprintf(f, "\nCurrently running news version %s.\n\n", news_version);
410: fprintf(f, "The header of your message follows:\n");
411: hwrite(&header, f);
412: mclose(f);
413: }
414:
415: /*
416: * An unknown control message has been received.
417: */
418: c_unknown(h, ctlmsgtext)
419: struct hbuf *h;
420: char *ctlmsgtext;
421: {
422: FILE *f;
423:
424: log("UNKNOWN Ctl Msg %s from %s", ctlmsgtext, h->path);
425: f = mailhdr(h, "Unrecognized Control Message");
426: if (f == NULL)
427: xerror("Cannot send back error message");
428: fprintf(f, "Currently running news B version %s.\n\n", news_version);
429: fprintf(f, "The header of the message follows:\n");
430: hwrite(h, f);
431: mclose(f);
432: }
433:
434: c_unimp(msg)
435: char *msg;
436: {
437: FILE *f;
438: char buf[256];
439:
440: f = mailhdr(&header, "Unimplemented Control Message");
441: if (f == NULL)
442: xerror("Cannot send back error message");
443: fprintf(f, "Currently running news B version %s.\n\n", news_version);
444: fprintf(f, "The header of the message follows:\n");
445: hwrite(&header, f);
446: mclose(f);
447: }
448:
449: xmitmsg(tosys, title, ng)
450: char *tosys, *title, *ng;
451: {
452: struct hbuf h;
453: struct srec srec;
454: FILE *tfp;
455: char *fname;
456: register int iu;
457:
458: /* Make an article called ARTICLE */
459: sprintf(h.from, "%s@%s%s", "usenet", FULLSYSNAME, MYDOMAIN);
460: strcpy(h.path, NEWSU);
461: strcpy(h.nbuf, ng);
462: strcpy(h.title, title);
463: strcpy(h.ctlmsg, title);
464: strcpy(h.subdate, "");
465: strcpy(h.recdate, "");
466: strcpy(h.expdate, "");
467: getident(&h);
468: dates(&h);
469: for (iu = 0; iu < NUNREC; iu++)
470: h.unrec[iu] = NULL;
471: tfp = xfopen(fname = mktemp("/tmp/xmsgXXXXXX"), "w");
472: hwrite(&h, tfp);
473: fclose(tfp);
474:
475: /* Find the sys record */
476: s_openr();
477: while (s_read(&srec)) {
478: if (strncmp(srec.s_name, tosys, SNLN))
479: continue;
480: tfp = xfopen(fname, "r");
481: transmit(&srec, tfp, 0);
482: unlink(fname);
483: return;
484: }
485: log("Can't find sys record for %s", tosys);
486: xerror("Cannot find sys record");
487: }
488:
489: /*
490: * This is a modified version of popen, made more secure. Rather than
491: * forking off a shell, you get a bare process. You must have exactly
492: * one argument, and the command must be mail.
493: */
494: /* @(#)popen.c 4.1 (Berkeley) 12/21/80 */
495: #include <stdio.h>
496: #include <signal.h>
497: #define RDR 0
498: #define WTR 1
499: static int mopen_pid[20];
500: char *replyname();
501:
502: FILE *
503: mhopen(hptr)
504: struct hbuf *hptr;
505: {
506: int p[2];
507: register myside, hisside, pid;
508: char *sendto = NULL;
509:
510: if (hptr)
511: sendto = replyname(hptr);
512: else {
513: #ifdef NOTIFY
514: if (TELLME && *TELLME)
515: sendto = TELLME;
516: #endif NOTIFY
517: if (sendto == NULL)
518: return NULL;
519: }
520: verifyname(sendto);
521: if(pipe(p) < 0)
522: return NULL;
523: myside = p[WTR];
524: hisside = p[RDR];
525: if((pid = fork()) == 0) {
526: /* myside and hisside reverse roles in child */
527: close(myside);
528: close(0);
529: dup(hisside);
530: close(hisside);
531: execl("/bin/mail", "mail", sendto, 0);
532: execl("/usr/bin/mail", "mail", sendto, 0);
533: execl("/usr/ucb/mail", "mail", sendto, 0);
534: _exit(1);
535: }
536: if(pid == -1)
537: return NULL;
538: mopen_pid[myside] = pid;
539: close(hisside);
540: return(fdopen(myside, "w"));
541: }
542:
543: mclose(ptr)
544: FILE *ptr;
545: {
546: register f, r, (*hstat)(), (*istat)(), (*qstat)();
547: int status;
548:
549: f = fileno(ptr);
550: fclose(ptr);
551: istat = signal(SIGINT, SIG_IGN);
552: qstat = signal(SIGQUIT, SIG_IGN);
553: hstat = signal(SIGHUP, SIG_IGN);
554: while((r = wait(&status)) != mopen_pid[f] && r != -1)
555: ;
556: if(r == -1)
557: status = -1;
558: signal(SIGINT, istat);
559: signal(SIGQUIT, qstat);
560: signal(SIGHUP, hstat);
561: return(status);
562: }
563:
564: /*
565: * mhopen a pipe to mail, write out a std header, and return the file ptr.
566: *
567: * We don't include a From: field because this is probably uucp, i.e.
568: * explicitly routed. Leave it up to the recipient's mailer.
569: * Always include the To: field because if we ge back failed mail, we
570: * might be able to deliver it by hand if we know to wom it was addressed.
571: * By convention, hptr==NULL means to send the message to the local contact person.
572: */
573: FILE *
574: mailhdr(hptr, subject)
575: char *subject;
576: struct hbuf *hptr;
577: {
578: FILE *fp;
579: time_t now;
580: char *to = "nobody";
581:
582: if (hptr)
583: to = replyname(hptr);
584: #ifdef NOTIFY
585: if (TELLME && *TELLME)
586: to = TELLME;
587: #endif NOTIFY
588: if ((fp = mhopen(hptr)) != NULL) {
589: time(&now);
590: fprintf(fp, "Date: %s\n", arpadate(&now));
591: fprintf(fp, "To: %s\n", to);
592: fprintf(fp, "Subject: %s\n", subject);
593: fprintf(fp, "Responding-System: %s%s\n", SYSNAME, MYDOMAIN);
594: }
595: return fp;
596: }
597:
598: /*
599: * verify that the name mail is being sent to does not contain any
600: * nasty hooks to invoke funny functions from the shell or the like.
601: */
602: verifyname(sendto)
603: char *sendto;
604: {
605: /* Be sure we DO allow alphabetics, !, :, ., -, @. *. */
606: char *nasty = "\"'\\`^|;& <>/~";
607: register char *p;
608:
609: if (sendto[0] <= ' ') {
610: log("nasty mail name %s from %s", sendto, header.path);
611: xxit(1);
612: }
613: for (p=sendto; *p; p++) {
614: if (*p == ' ') {
615: *p = 0;
616: break;
617: }
618: }
619: while (*nasty) {
620: if (index(sendto, *nasty++)) {
621: log("nasty mail name %s from %s", sendto, header.path);
622: xxit(1);
623: }
624: }
625: for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) {
626: if (*++nasty == '.') { /* check for .. */
627: log("nasty mail name %s from %s", sendto, header.path);
628: xxit(1);
629: }
630: }
631: }
632:
633: /*
634: * Checks to make sure the control message is OK to post.
635: */
636: ctlcheck()
637: {
638: char msg[150];
639: char *p;
640:
641: if (!is_ctl)
642: return;
643:
644: if (header.ctlmsg[0])
645: strcpy(msg, header.ctlmsg);
646: else
647: strcpy(msg, header.title);
648:
649: p = index(msg, ' ');
650: if (p)
651: *p = 0;
652:
653: if (strcmp(msg, "ihave") == 0) {
654: } else if (strcmp(msg, "sendme") == 0) {
655: return; /* no restrictions */
656: } else if (strcmp(msg, "newgroup") == 0) {
657: suser();
658: } else if (strcmp(msg, "rmgroup") == 0) {
659: suser();
660: checkpass("mTDrcBCy..8Mk");
661: } else if (strcmp(msg, "sendsys") == 0) {
662: suser();
663: } else if (strcmp(msg, "senduuname") == 0) {
664: suser();
665: } else if (strcmp(msg, "version") == 0) {
666: return; /* no restrictions */
667: } else if (strcmp(msg, "cancel") == 0) {
668: return; /* no restrictions at this level */
669: } else if (strcmp(msg, "delsub") == 0) {
670: if (!prefix(header.nbuf, "to.")) {
671: printf("Must be in a 'to.system' newsgroup.");
672: xxit(0);
673: }
674: return;
675: } else {
676: printf("Unrecognized control message - %s\n", msg);
677: xxit(0);
678: }
679: }
680:
681: /* Make sure this guy is special. */
682: suser()
683: {
684: if (uid == 0)
685: return;
686: if (uid == ROOTID)
687: return;
688: /*
689: * We assume that since our real uid is the same as NEWSUSR
690: * (the euid) we were run by rootid and it did a setuid.
691: * Too bad we can't set just the effective uid like suid does.
692: */
693: if (uid == geteuid())
694: return;
695: #ifdef IHCC
696: printf("Please use the command:\n\ttoolnews providers\n");
697: printf("then call one of the news people.\n");
698: #else
699: printf("Get your local netnews contact to do it for you.\n");
700: #endif
701: xxit(0);
702: }
703:
704: /*
705: * Demand a password from the user.
706: */
707: checkpass(encpw)
708: {
709: if (strcmp(encpw, crypt(getpass("Password:"), "mT"))) {
710: printf("Sorry\n");
711: xxit(0);
712: }
713: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.