|
|
1.1 root 1: /*
2: * inews - insert, receive, and transmit news articles.
3: */
4:
5: static char *SccsId = "@(#)inews.c 2.30 6/24/83";
6:
7: #include "iparams.h"
8:
9: /* local defines for inews */
10:
11: #define OPTION 0 /* pick up an option string */
12: #define STRING 1 /* pick up a string of arguments */
13:
14: #define UNKNOWN 0001 /* possible modes for news program */
15: #define UNPROC 0002 /* Unprocessed input */
16: #define PROC 0004 /* Processed input */
17: #define CANCEL 0010 /* Cancel an article */
18: #define CREATENG 0020 /* Create a new newsgroup */
19:
20: #ifndef SYSBUF
21: char SYSBUF[BUFSIZ]; /* to buffer std out */
22: #endif
23: char forgedname[100]; /* A user specified -f option. */
24:
25: struct { /* options table. */
26: char optlet; /* option character. */
27: char filchar; /* if to pickup string, fill character. */
28: int flag; /* TRUE if have seen this opt. */
29: int oldmode; /* OR of legal input modes. */
30: int newmode; /* output mode. */
31: char *buf; /* string buffer */
32: } *optpt, options[] = { /*
33: optlet filchar flag oldmode newmode buf */
34: 't', ' ', FALSE, UNPROC, UNKNOWN, header.title,
35: 'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf,
36: 'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate,
37: 'p', '\0', FALSE, UNKNOWN,PROC, filename,
38: 'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname,
39: 'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid,
40: 'c', '\0', FALSE, UNKNOWN,CANCEL, filename,
41: 'C', '\0', FALSE, UNKNOWN,CREATENG, header.nbuf,
42: #define Dflag options[8].flag
43: 'D', '\0', FALSE, UNPROC, UNKNOWN, filename,
44: #define hflag options[9].flag
45: 'h', '\0', FALSE, UNPROC, UNKNOWN, filename,
46: '\0', '\0', 0, 0, 0, (char *)NULL
47: };
48:
49: FILE *mailhdr();
50:
51: /*
52: * Authors:
53: * Matt Glickman [email protected]
54: * Mark Horton [email protected]
55: * Stephen Daniels [email protected]
56: * Tom Truscott [email protected]
57: * IHCC version adapted by:
58: * Larry Marek [email protected]
59: */
60: main(argc, argv)
61: int argc;
62: register char **argv;
63: {
64: int state; /* which type of argument to pick up */
65: int tlen, len; /* temps for string processing routine */
66: register char *ptr; /* pointer to rest of buffer */
67: int filchar; /* fill character (state = STRING) */
68: char *user, *home; /* environment temps */
69: struct passwd *pw; /* struct for pw lookup */
70: struct group *gp; /* struct for group lookup */
71: struct srec srec; /* struct for sys file lookup */
72: struct utsname ubuf;
73: register int i;
74: FILE *mfd; /* mail file file-descriptor */
75: char cbuf[BUFLEN]; /* command buffer */
76:
77: /* uuxqt doesn't close all it's files */
78: for (i = 3; !close(i); i++)
79: ;
80: /* set up defaults and initialize. */
81: mode = UNKNOWN;
82: pathinit();
83: ptr = rindex(*argv, '/');
84: if (!ptr)
85: ptr = *argv - 1;
86: if (!strncmp(ptr+1, "rnews", 5))
87: mode = PROC;
88: else if (argc < 2)
89: goto usage;
90:
91: state = OPTION;
92: header.title[0] = header.nbuf[0] = filename[0] = '\0';
93:
94: /* check for existence of special files */
95: if (!rwaccess(ARTFILE)) {
96: mfd = mailhdr(NULL, exists(ARTFILE) ? "Unwritable files!" : "Missing files!");
97: if (mfd != NULL) {
98: fprintf(mfd,"System: %s\n\nThere was a problem with %s!!\n", SYSNAME, ARTFILE);
99: sprintf(cbuf, "touch %s;chmod 666 %s", ARTFILE, ARTFILE);
100: system(cbuf);
101: if (rwaccess(ARTFILE))
102: fprintf(mfd, "The problem has been taken care of.\n");
103: else
104: fprintf(mfd, "Corrective action failed - check suid bits.\n");
105: mclose(mfd);
106: }
107: }
108: if (!rwaccess(ACTIVE)) {
109: mfd = mailhdr(NULL, exists(ACTIVE) ? "Unwritable files!" : "Missing files!");
110: if (mfd != NULL) {
111: fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", SYSNAME, ACTIVE);
112: sprintf(cbuf, "touch %s;chmod 666 %s", ACTIVE, ACTIVE);
113: system(cbuf);
114: if (rwaccess(ACTIVE))
115: fprintf(mfd, "The problem has been taken care of.\n");
116: else
117: fprintf(mfd, "Corrective action failed - check suid bits.\n");
118: mclose(mfd);
119: }
120: }
121: setbuf(stdout, SYSBUF);
122: sigtrap = FALSE; /* true if a signal has been caught */
123: /*
124: signal(SIGQUIT, SIG_IGN);
125: */
126: if (mode != PROC) {
127: signal(SIGHUP, onsig);
128: signal(SIGINT, onsig);
129: }
130: savmask = umask(N_UMASK); /* set up mask */
131: uid = (unsigned) getuid();
132: gid = (unsigned) getgid();
133: duid = geteuid();
134: dgid = getegid();
135: if (uid == 0 && geteuid() == 0) {
136: /*
137: * Must go through with this kludge since
138: * some systems do not honor the setuid bit
139: * when root invokes a setuid program.
140: */
141: if ((pw = getpwnam(NEWSU)) == NULL)
142: xerror("Cannot get NEWSU pw entry");
143:
144: duid = pw->pw_uid;
145: if ((gp = getgrnam(NEWSG)) == NULL)
146: xerror("Cannot get NEWSG gr entry");
147: dgid = gp->gr_gid;
148: setuid(duid);
149: setgid(dgid);
150: }
151:
152: #ifndef IHCC
153: /*
154: * We force the use of 'getuser()' to prevent forgery of articles
155: * by just changing $LOGNAME
156: */
157: if ((user = getenv("USER")) == NULL)
158: user = getenv("LOGNAME");
159: if ((home = getenv("HOME")) == NULL)
160: home = getenv("LOGDIR");
161: #endif
162: if (user == NULL || home == NULL)
163: getuser();
164: else {
165: if (username[0] == 0) {
166: strcpy(username, user);
167: }
168: strcpy(userhome, home);
169: }
170: getuser();
171: strcpy(whatever, username);
172:
173: /* loop once per arg. */
174:
175: ++argv; /* skip first arg, which is prog name. */
176:
177: while (--argc) {
178: if (state == OPTION) {
179: if (**argv != '-') {
180: sprintf(bfr, "Bad option string \"%s\"", *argv);
181: xerror(bfr);
182: }
183: while (*++*argv != '\0') {
184: for (optpt = options; optpt->optlet != '\0'; ++optpt) {
185: if (optpt->optlet == **argv)
186: goto found;
187: }
188: /* unknown option letter */
189: usage:
190: fprintf(stderr, "usage: inews -t title");
191: fprintf(stderr, " [ -n newsgroups ]");
192: fprintf(stderr, " [ -e expiration date ]\n");
193: fprintf(stderr, "\t[ -f sender]\n\n");
194: fprintf(stderr, " inews -p [ filename ]\n");
195: xxit(1);
196:
197: found:;
198: if (optpt->flag == TRUE || (mode != UNKNOWN &&
199: (mode&optpt->oldmode) == 0)) {
200: sprintf(bfr, "Bad %c option", **argv);
201: xerror(bfr);
202: }
203: if (mode == UNKNOWN)
204: mode = optpt->newmode;
205: filchar = optpt->filchar;
206: optpt->flag = TRUE;
207: state = STRING;
208: ptr = optpt->buf;
209: len = BUFLEN;
210: }
211:
212: argv++; /* done with this option arg. */
213:
214: } else {
215:
216: /*
217: * Pick up a piece of a string and put it into
218: * the appropriate buffer.
219: */
220: if (**argv == '-') {
221: state = OPTION;
222: argc++; /* uncount this arg. */
223: continue;
224: }
225:
226: if ((tlen = strlen(*argv)) >= len)
227: xerror("Argument string too long");
228: strcpy(ptr, *argv++);
229: ptr += tlen;
230: if (*(ptr-1) != filchar)
231: *ptr++ = filchar;
232: len -= tlen + 1;
233: *ptr = '\0';
234: }
235: }
236:
237: /*
238: * ALL of the command line has now been processed. (!)
239: */
240:
241: tty = isatty(fileno(stdin));
242: if (!Dflag && mode != PROC && mode != CREATENG) {
243: if (recording(header.nbuf)) {
244: if (!tty)
245: fwait(fsubr(newssave, stdin, NULL));
246: xerror("aborted due to recording");
247: }
248: }
249:
250: /* This code is really intended to be replaced by the control message. */
251: if (mode == CANCEL) {
252: char *p; FILE *f;
253: f = xfopen(filename, "r");
254: hread(&header, f, TRUE);
255: p = index(header.path, ' ');
256: if (p != NULL)
257: *p = 0;
258: p = header.path;
259: if (strncmp(whatever, p, strlen(whatever))
260: && uid != ROOTID && uid != geteuid() && uid)
261: xerror("Not contributor");
262: cancel();
263: xxit(0);
264: }
265:
266: if (*header.nbuf)
267: lcase(header.nbuf);
268: if (mode != PROC) {
269: getident(&header);
270: #ifdef MYORG
271: strcpy(header.organization, MYORG);
272: if (strncmp(header.organization, "Frobozz", 7) == 0)
273: header.organization[0] = '\0';
274: if (ptr = getenv("ORGANIZATION"))
275: strcpy(header.organization, ptr);
276: /*
277: * Note that the organization can also be turned off by
278: * setting it to the null string, either in MYORG or
279: * $ORGANIZATION in the environment.
280: */
281: if (header.organization[0] == '/') {
282: mfd = fopen(header.organization, "r");
283: if (mfd) {
284: fgets(header.organization, sizeof header.organization, mfd);
285: fclose(mfd);
286: }
287: ptr = index(header.organization, '\n');
288: if (ptr)
289: *ptr = 0;
290: }
291: #endif
292: if (hflag) {
293: /* Fill in a few to make frmread return TRUE */
294: strcpy(header.subdate, "today");
295: strcpy(header.path, "me");
296: strcpy(header.oident, "id");
297: /* Allow the user to supply some headers. */
298: hread(&header, stdin, FALSE);
299: /* But there are certain fields we won't let him specify. */
300: if (header.from)
301: strcpy(forgedname, header.from);
302: header.from[0] = '\0';
303: header.path[0] = '\0';
304: header.subdate[0] = '\0';
305: header.sender[0] = '\0';
306: if (strcmp(header.oident, "id") == 0)
307: header.oident[0] = '\0';
308: ngcat(header.nbuf);
309: }
310: if (forgedname[0]) {
311: strcpy(header.from, forgedname);
312: sprintf(header.sender, "%s@%s%s",
313: username, SYSNAME, MYDOMAIN);
314: } else {
315: gensender(&header, username);
316: }
317: strcpy(header.postversion, genversion());
318: }
319:
320: /* Authorize newsgroups. */
321: if (mode == PROC) {
322: checkbatch();
323: signal(SIGHUP, SIG_IGN);
324: signal(SIGINT, SIG_IGN);
325: signal(SIGQUIT, SIG_IGN);
326: if (hread(&header, stdin, TRUE) == NULL)
327: xerror("Inbound news is garbled");
328: input();
329: if (history(&header)) {
330: fprintf(stderr, "Duplicate article %s rejected\n", header.ident);
331: log("Duplicate article %s rejected", header.ident);
332: xxit(0);
333: }
334: }
335: ngcat(header.nbuf);
336:
337: /* Easy way to make control messages, since all.all.ctl is unblessed */
338: if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0)
339: strcpy(header.ctlmsg, &header.title[5]);
340: is_ctl = mode != CREATENG &&
341: (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]);
342: #ifdef DEBUG
343: fprintf(stderr,"is_ctl set to %d\n", is_ctl);
344: #endif
345:
346: /* Must end in comma (NGDELIM) */
347: #define MODGROUPS "mod.all,all.mod,all.announce,"
348: if (ngmatch(header.nbuf, MODGROUPS) && !header.approved[0]) {
349: mfd = mailhdr(&header, "Moderated newsgroup");
350: if (mfd) {
351: fprintf(mfd, "This newsgroup is moderated, and cannot be posted to directly.\n");
352: fprintf(mfd, "Please mail your article to the moderator for posting.\n");
353: hwrite(&header, mfd);
354: if (infp)
355: while ((i = getc(infp)) != EOF)
356: putc(i, mfd);
357: mclose(mfd);
358: }
359: xerror("Unapproved moderated newsgroup\n");
360: }
361:
362: if (mode == PROC) {
363: strcpy(nbuf, header.nbuf);
364: if (s_find(&srec, FULLSYSNAME) == FALSE)
365: xerror("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
366: ngsquash(nbuf, srec.s_nbuf);
367:
368: }
369: else if (mode != CREATENG) {
370: if (!*header.title)
371: xerror("No title");
372: if (!*header.nbuf)
373: strcpy(header.nbuf, DFLTNG);
374: else if (!is_ctl)
375: ngfcheck(FALSE);
376: ngcat(header.nbuf);
377: strcpy(nbuf, header.nbuf);
378: }
379: else { /* mode == CREATENG */
380: ngcat(header.nbuf);
381: strcpy(nbuf, header.nbuf);
382: }
383:
384: for (ptr = nbuf; (ptr = index(ptr, NGDELIM)) != NULL; *ptr++ = '\0')
385: ;
386: if (!is_ctl && header.followid[0] == '\0')
387: for (ptr = nbuf; *ptr;) {
388: if (!exists(dirname(ptr)))
389: ngcheck(ptr);
390: while (*ptr++)
391: ;
392: }
393: else if (mode <= UNPROC)
394: ctlcheck();
395: for (ptr = nbuf; *ptr;) {
396: if (*ptr != '-')
397: goto out;
398: while (*ptr++)
399: ;
400: }
401: xerror("No valid newsgroups in '%s'", header.nbuf);
402: out:
403:
404: /* Determine input. */
405: if (mode != PROC)
406: input();
407:
408: #ifndef VMS
409: /* Go into the background so the user can get on with his business. */
410: if (mode != PROC) {
411: i = fork();
412: if (i != 0)
413: exit(0);
414: }
415: #endif VMS
416:
417: /* Do the actual insertion. */
418: insert();
419: }
420:
421: /*
422: * Create directory named by bfr.
423: * Don't if user doesn't want to.
424: */
425: ngcheck(ngname)
426: char *ngname;
427: {
428: char class[120];
429: char dir[256];
430: char *cp;
431:
432: strcpy(dir, dirname(ngname));
433: if (mode == PROC) {
434: #ifdef AUTONEWNG
435: mknewsg(dir, ngname);
436: #endif
437: return 1;
438: }
439:
440: /*
441: * If a user is trying to input to a non-existent group complain.
442: * First check to see if the newsgroup ever existed. To do this, try
443: * to find the name in the "active" file.
444: */
445: if (mode != CREATENG && !is_ctl) {
446: /* Ick! Figure out if the newsgroup is in the active file. */
447: sprintf(dir, "grep -s '^%s ' %s", ngname, ACTIVE);
448: if ((system(dir) != 0))
449: xerror("There is no such newsgroup as %s.", ngname);
450: else {
451: strcpy(dir, dirname(ngname));
452: mknewsg(dir, ngname);
453: return 0;
454: }
455: }
456: /*
457: * Only certain users are allowed to create newsgroups
458: */
459: if (uid != ROOTID && uid != geteuid() && uid)
460: xerror("Please contact one of the local netnews people\n\tto create this group for you");
461:
462: /* Broadcast the new newsgroup */
463: strcpy(class, ngname);
464: for (cp=class; *cp && *cp!='.'; cp++)
465: ;
466: if (*cp)
467: *cp = 0;
468: else {
469: mknewsg(dir, ngname);
470: exit(0); /* Local newsgroup */
471: }
472: sprintf(bfr, "inews -D -n %s.ctl -t cmsg newgroup %s", ngname, ngname);
473: printf("Please type in a paragraph describing the new newsgroup.\n");
474: printf("End with control D as usual.\n");
475: printf("%s\n", bfr);
476: fflush(stdout);
477: system(bfr);
478: exit(0);
479: }
480:
481: #include <errno.h>
482: char firstbufname[100];
483: /*
484: * Link ARTICLE into dir for ngname and update active file.
485: */
486: localize(ngname)
487: char *ngname;
488: {
489: FILE *fp;
490: struct stat status;
491: char afline[BUFLEN];
492: long ngsize;
493: long fpos;
494: int i, e;
495: extern int errno;
496:
497: lock();
498: actfp = fopen(ACTIVE, "r+");
499: for(;;) {
500: fpos = ftell(actfp);
501: if (fgets(afline, sizeof afline, actfp) == NULL) {
502: unlock();
503: return FALSE; /* No such newsgroup locally */
504: }
505: if (prefix(afline, ngname)) {
506: sscanf(afline, "%s %ld", bfr, &ngsize);
507: if (strcmp(bfr, ngname) == 0) {
508: break;
509: }
510: if (ngsize < 0 || ngsize > 99998) {
511: log("found bad ngsize %d ng %s, setting to 1", ngsize, bfr);
512: ngsize = 1;
513: }
514: }
515: }
516: for (;;) {
517: sprintf(bfr, "%s/%ld", dirname(ngname), ngsize+1);
518: if (link(ARTICLE, bfr) == 0) break;
519: e = errno; /* keep log from clobbering it */
520: fprintf(stderr, "Cannot install article as %s\n", bfr);
521: log("Cannot install article as %s", bfr);
522: if (e != EEXIST) {
523: log("Link into %s failed, errno %d, check dir permissions.", bfr, e);
524: unlock();
525: return FALSE;
526: }
527: ngsize++;
528: }
529:
530: /* Next two lines program around a bug in 4.1BSD stdio. */
531: fclose(actfp);
532: actfp = fopen(ACTIVE, "r+");
533:
534: fseek(actfp, fpos, 0);
535: /* Has to be same size as old because of %05d.
536: * This will overflow with 99999 articles.
537: */
538: fprintf(actfp, "%s %05ld\n", ngname, ngsize+1);
539: fclose(actfp);
540: unlock();
541: if (firstbufname[0] == '\0')
542: strcpy(firstbufname, bfr);
543: sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
544: addhist(bfr);
545: return TRUE;
546: }
547:
548: /*
549: * Localize for each newsgroup and broadcast.
550: */
551: insert()
552: {
553: register char *ptr;
554: register FILE *tfp;
555: int badgroup = 0, goodgroup = 0;
556:
557: /* Fill up the rest of header. */
558: if (mode != PROC) {
559: history(&header);
560: }
561: dates(&header);
562: addhist(header.recdate);
563: addhist("\t");
564: log("%s %s ng %s subj '%s'", mode==PROC ? "received" : "posted", header.ident, header.nbuf, header.title);
565: if (mode==PROC)
566: log("from %s relay %s", header.from, header.relayversion);
567:
568: /* Write article to temp file. */
569: tfp = xfopen(mktemp(ARTICLE), "w");
570: lhwrite(&header, tfp);
571: while (fgets(bfr, BUFLEN, infp) != NULL) {
572: /*
573: if (!strncmp(bfr, "From ", 5))
574: putc('>', tfp);
575: */
576: fputs(bfr, tfp);
577: }
578: fclose(tfp);
579: fclose(infp);
580:
581: if (is_ctl) {
582: control(&header);
583: goodgroup++;
584: if (!localize("control")) {
585: sprintf(bfr, "%s/%s", SPOOL, "control");
586: mknewsg(bfr, "control");
587: if (!localize("control")) {
588: tfp = mailhdr(NULL, "No control newsgroup");
589: if (tfp) {
590: fprintf(tfp, "Can't create newsgroup 'control'.\n");
591: mclose(tfp);
592: }
593: }
594: }
595: } else {
596: for (ptr = nbuf; *ptr;) {
597: if (*ptr == '-') {
598: while (*ptr++)
599: ;
600: continue;
601: }
602: strcpy(bfr, dirname(ptr));
603: if (!exists(bfr)) {
604: #ifdef AUTONEWNG
605: mknewsg(bfr, ptr);
606: #else
607: getapproval(ptr);
608: badgroup++;
609: #endif
610: }
611: else
612: goodgroup++;
613: if (*nbuf)
614: localize(ptr);
615: while (*ptr++)
616: ;
617: }
618: }
619:
620: #ifdef NOFORWARD
621: if (*nbuf)
622: #endif
623: if (goodgroup)
624: broadcast();
625: savehist();
626: xxit(0);
627: }
628:
629: input()
630: {
631: register int empty = TRUE;
632: register char *cp;
633: int c;
634: long chcount = 0;
635: FILE *tmpfp;
636: int consec_newlines = 0;
637: int linecount = 0;
638:
639: tmpfp = xfopen(mktemp(INFILE), "w");
640: if (*filename) {
641: tty = FALSE;
642: infp = xfopen(filename, "r");
643: } else {
644: infp = stdin;
645: }
646: while (!sigtrap && fgets(bfr, BUFLEN, stdin) != NULL) {
647: if (mode == PROC) /* zap trailing empty lines */
648: {
649: if (bfr[0] == '\n') /* 1 empty line, to go */
650: {
651: consec_newlines++; /* count it, in case */
652: continue; /* but don't write it*/
653: }
654: /* foo! a non-empty line. write out all saved lines. */
655: while (consec_newlines > 0)
656: {
657: putc('\n', tmpfp);
658: consec_newlines--;
659: linecount++;
660: }
661: }
662: if (mode != PROC && tty && strcmp(bfr, ".\n") == 0)
663: break;
664: for (cp = bfr; c = *cp; cp++) {
665: if (isprint(c) || isspace(c) || c=='\b')
666: putc(c, tmpfp);
667: if (isprint(c))
668: chcount++;
669: if (c == '\n')
670: linecount++;
671: }
672: empty = FALSE;
673: }
674: if (*filename)
675: fclose(infp);
676:
677: sprintf(bfr, "%s/%s", getenv("HOME"), ".signature");
678: if (mode != PROC && (infp = fopen(bfr, "r"))) {
679: fprintf(tmpfp, "-- \n"); /* To separate */
680: linecount++;
681: while ((c = getc(infp)) != EOF) {
682: putc(c, tmpfp);
683: if (c == '\n')
684: linecount++;
685: }
686: fclose(infp);
687: }
688:
689: fclose(tmpfp);
690: if (sigtrap) {
691: if (tty)
692: printf("Interrupt\n");
693: if (tty && !empty)
694: fwait(fsubr(newssave, (char *) NULL, (char *) NULL));
695: if (!tty)
696: log("Blown away by an interrupt %d", sigtrap);
697: xxit(1);
698: }
699: if (tty)
700: printf("EOT\n");
701: fflush(stdout);
702: infp = fopen(INFILE, "r");
703: if (chcount < 5 && mode <= UNPROC && !is_ctl)
704: xerror("You didn't really want to post THAT!");
705: if (header.numlines[0]) {
706: /*
707: * Check line count if there's already one attached to
708: * the article. Could make this a fatal error -
709: * throwing it away if it got chopped, in hopes that
710: * another copy will come in later with a correct
711: * line count. But that seems a bit much for now.
712: */
713: if (linecount != header.intnumlines)
714: log("linecount expected %d, got %d\n", header.intnumlines, linecount);
715: } else {
716: /* Attach a line count to the article. */
717: header.intnumlines = linecount;
718: sprintf(header.numlines, "%d", linecount);
719: }
720: }
721:
722: /*
723: * Make the directory for a new newsgroup. ngname should be the
724: * full pathname of the directory. Do the other stuff too.
725: * The various games with setuid and chown are to try to make sure
726: * the directory is owned by NEWSUSR and NEWSGRP, which is tough to
727: * do if you aren't root. This will work on a UCB system (which allows
728: * setuid(geteuid()) or a USG system (which allows you to give away files
729: * you own with chown), otherwise you have to change your kernel to allow
730: * one of these things or run with your dirs 777 so that it doesn't matter
731: * who owns them.
732: */
733: mknewsg(fulldir, ngname)
734: char *fulldir;
735: char *ngname;
736: {
737: int pid;
738: register char *p;
739: char sysbuf[200];
740: char parent[200];
741: struct stat sbuf;
742:
743: if (ngname == NULL || !isalpha(ngname[0]))
744: xerror("Tried to make illegal newsgroup %s", ngname);
745:
746: /*
747: * If the parent is 755 and we're on a USG system, the setuid(getuid)
748: * will fail, and since mkdir is suid, and our real uid is random,
749: * the mkdir will fail. So we have to temporarily chmod it to 755.
750: */
751: strcpy(parent, fulldir);
752: p = rindex(parent, '/');
753: if (p)
754: *p = '\0';
755: if (stat(parent, &sbuf) < 0)
756: sbuf.st_mode = 0777;
757: chmod(parent, 0777);
758:
759: if ((pid = fork()) <= 0) {
760: if (setuid(geteuid())) /* This fails on some systems, but
761: * works on 4BSD, and 2BSD. */
762: #ifndef USG
763: umask(0)
764: #endif
765: ;
766: setgid(getegid());
767: /* Create the directory */
768: mkparents(fulldir);
769: sprintf(sysbuf, "mkdir %s", fulldir);
770: exit(system(sysbuf));
771: } else if (fwait(pid)) {
772: sprintf(sysbuf, "Cannot mkdir %s", fulldir);
773: xerror(sysbuf);
774: }
775:
776: chmod(parent, sbuf.st_mode); /* put is back */
777:
778: #ifdef USG
779: # ifndef CHEAP
780: /*
781: * Give away the files we just created, which were assigned to our
782: * REAL uid. This only works on USG systems. It is an alternative
783: * to the setuid call above. The directories we just made are owned
784: * by our real uid, so we have to temporarily set our effective uid
785: * the same to allow the chown. Fortunately, USG lets us setuid back.
786: */
787: setuid(getuid());
788: chown(fulldir, duid, dgid);
789: setuid(duid);
790: # endif
791: #endif
792:
793: /* Update the "active newsgroup" file. */
794: if (ngname && *ngname) {
795: actfp = xfopen(ACTIVE, "a");
796: fprintf(actfp, "%s 00000\n", ngname);
797: fclose(actfp);
798: }
799:
800: log("make newsgroup %s in dir %s", ngname, fulldir);
801: }
802:
803: /*
804: * If any parent directories of this dir don't exist, create them.
805: */
806: mkparents(dirname)
807: char *dirname;
808: {
809: char buf[200], sysbuf[200];
810: register char *p;
811:
812: strcpy(buf, dirname);
813: p = rindex(buf, '/');
814: if (p)
815: *p = '\0';
816: if (exists(buf))
817: return;
818: mkparents(buf);
819: sprintf(sysbuf, "mkdir %s", buf);
820: system(sysbuf);
821: }
822:
823: cancel()
824: {
825: register FILE *fp;
826:
827: log("cancel article %s", filename);
828: fp = xfopen(filename, "r");
829: if (hread(&header, fp, TRUE) == NULL)
830: xerror("Article is garbled.\n");
831: fclose(fp);
832: unlink(filename);
833: }
834:
835: /*
836: * An article has come in that isn't in a newsgroup we know about.
837: * Stash it in the junk directory and notify the local contact person.
838: * Note that such articles are NOT broadcast to our neighbors, on the
839: * assumption that they are a typographical error. We only keep them
840: * here because we might be a new site.
841: */
842: getapproval(ng)
843: char *ng;
844: {
845: FILE *fd;
846:
847: if (localize("junk"))
848: return;
849:
850: sprintf(bfr, "%s/%s", SPOOL, "junk");
851: mknewsg(bfr, "junk");
852: if (localize("junk"))
853: return;
854:
855: fd = mailhdr(NULL, "Strange Newsgroup Received");
856: if (fd != NULL) {
857: fprintf(fd, "\nNewsgroup '%s' has been posted to\nby %s.\n\n",
858: ng, header.from[0] ? header.from : header.path);
859: fprintf(fd, "I was unable to save it in the newsgroup 'junk'\n");
860: fprintf(fd, "I was also unable to create the newsgroup 'junk'\n");
861: mclose(fd);
862: }
863: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.