Aucbarpa.1046 net.sources utcsrgv!utzoo!decvax!ucbvax!C70:ARPAVAX:mark Sun Apr 4 15:17:49 1982 pacman/control.c /* * Control message handling code. Deal with messages which are to be * acted on by netnews itself rather than by people. */ static char *SccsId = "@(#) control.c 2.3 3/18/82"; #include "iparams.h" #define eq(msg) (strcmp(msg, cargv[0]) == 0) int cargc; char **cargv; FILE *hfopen(); FILE *popen(), *mopen(), *mailhdr(); control(h) struct hbuf *h; { int i; log("Ctl Msg %s from %s: %s", h->nbuf, h->path, h->title); /* * Control messages have the standard format * command [args] * much like shell commands. Each site has the option * of customizing this code to deal with control messages * as they see fit, but we would like to buy back the * code, ifdeffed or otherwise parameterized, to simplify * the maintenence issues. */ argparse(h->title); if (eq("ihave")) c_ihave(cargc, cargv); else if (eq("sendme")) c_sendme(cargc, cargv); else if (eq("newgroup")) c_newgroup(cargc, cargv); else if (eq("rmgroup")) c_rmgroup(cargc, cargv); else if (eq("cancel")) c_cancel(cargc, cargv); else if (eq("sendsys")) c_sendsys(cargc, cargv); else if (eq("senduuname")) c_senduuname(cargc, cargv); else c_unknown(h); } /* * Parse the string str into separate words in cargc and cargv * as per the usual UNIX convention. Nothing fancy here, just * blanks and tabs separating words. */ argparse(str) char *str; { static char *cavpbuf[20]; static char cavbuf[256]; char *nextfree = cavbuf; if (str == 0) xerror("Control message %s has no title", header.ident); cargc = 0; cargv = cavpbuf; cargv[0] = cavbuf; while (*str) { if (*str <= ) SKIP /* (*STR { WHITE CARGV[CARGC]="nextfree;" OVER CARGC++; *NEXTFREE++="0;" SPACE */ WHILE> 0 && *str <= ) * /* STR++; (*STR="=" 0) ELSE } * The other system is telling you it has article , in case * you decide you want it to transmit it to you. */ c_ihave(argc, argv) char **argv; { char tl[256], ng[256]; /* * Check that we haven't already seen it (history) * and then send back a "sendme" message if we subscribe. */ if (history(argv[1]) == 0) { /* Should probably check SUBFILE and NGFILE here. */ sprintf(tl, "sendme %s %s", argv[1], SYSNAME); sprintf(ng, "to.%s.ctl", argv[2]); xmitmsg(argv[2], tl, ng); } } /* * sendme * The other system wants me to send him article . */ c_sendme(argc, argv) char **argv; { struct srec srec; FILE *fp; /* Find the sys record */ s_openr(); while (s_read(&srec)) { if (strncmp(srec.s_name, argv[2], SNLN)) continue; /* It's the right one. Send it. */ fp = hfopen(argv[1]); transmit(&srec, fp, 0); return; } sprintf(bfr, "Cannot find system %s to send article %s to.", argv[2], argv[1]); xerror(bfr); } /* * newgroup * A new newsgroup has been created. * The body of the article, if present, is a description of the * purpose of the newsgroup. * * Site dependent. Should make very sure the directory has been * created and properly owned. Might want to update ngfile. * Might want to notify the contact person for this installation. * Default action is to create the newsgroup, if it doesn't already * exist. */ c_newgroup(argc, argv) char **argv; { FILE *fd; sprintf(bfr, "%s/%s", SPOOL, argv[1]); /* * This check will cause us to exit if we already have the newsgroup. * Since propagation happens later, this means we won't forward it, * either. We assume that what happened is some new site had to * do inews -C to submit to a newsgroup that already exists but that * they don't have yet. So we don't want to propagate in this case. */ if (access(bfr, 0) == 0) xerror("newgroup already exists"); mknewsg(bfr); #ifdef UPDATENGFILE /* Sample code to update ngfile */ fd = fopen(NGFILE, "a"); fprintf(fd, "%s\n", argv[1]); fclose(NGFILE); #endif #ifdef NOTIFY /* * Sample code to notify the contact person. * Probably should dig up the text of the article * and enclose that, too. It can be found in the * file ARTICLE. Also, there needs to be * an automatic provision to help you add the newsgroup. * * Note that even if you take out the above call to mknewsg, * the newsgroup will still be created by the first article * that comes in on it by a different call to mknewsg in inews.c */ fd = mailhdr(NOTIFY, "request for new newsgroup"); fprintf(fd, "\nA new newsgroup called '%s' has been created by %s.\n\n", argv[1], header.path); mclose(fd); #endif } /* * rmgroup * An old newsgroup is being cancelled on a network wide basis. */ c_rmgroup(argc, argv) char **argv; { FILE *fd; char *groupname; char groupdir[128]; int rc; #ifdef NOTIFY fd = mailhdr(NOTIFY, "rmgroup control message"); fprintf(fd, "\nA newsgroup called '%s' has been removed by %s.\n\n", argv[1], header.path); #ifdef USG fprintf(fd, "You may need to remove the directory %s/%s by hand\n", SPOOL, argv[1]); #endif mclose(fd); #endif groupname = argv[1]; verifyname(groupname); if (groupname[0] == '.') xerror("Illegal group name in rmgroup"); sprintf(groupdir, "%s/%s", SPOOL, groupname); if (access(groupdir, 0)) { /* * If the group already is gone, it's a nonfatal error - we * want to propagate the message anyway, since what probably * happened is somebody locally already removed it. */ log("Cannot remove newsgroup '%s'", groupname); return; } #ifndef MANUALLY /* We let the shell do all the work. See the rmgrp shell script. */ setuid(geteuid()); /* otherwise it won't rmdir the dir */ sprintf(bfr, "rm -rf %s", groupdir); rc = system(bfr); log("system(%s) status %d", bfr, rc); sprintf(bfr, "cp %s/active /tmp/$$ ; sed '/^%s$/d' %s/active ; rm /tmp/$$", LIB, groupname, LIB); rc = system(bfr); log("system(%s) status %d", bfr, rc); #endif } /* * cancel * Cancel the named article */ c_cancel(argc, argv) char **argv; { char *line, *p, *q, *r, *s; char *findhist(); register FILE *fp; char whatsisname[150]; char msgbuf[256]; char msgng[64]; int su = 0; strcpy(whatsisname, header.path); strcpy(msgng, header.nbuf); line = findhist(argv[1]); if (line) log("Cancelling %s", line); else log("Can't cancel %s: non-existent", argv[1]); p = index(line, '\t'); p = index(p+1, '\t'); p++; while (*p) { q = index(p, ' '); if (q) *q = 0; sprintf(filename, "%s/%s", SPOOL, p); fp = xfopen(filename, "r"); if (hread(&header, fp) == NULL) xerror("Article is garbled.\n"); fclose(fp); printf("uid %d, ROOTID %d, msgng %s\n", uid, ROOTID, msgng); if((uid==ROOTID||uid==0) && strncmp(msgng,"to.",3) == 0) su = 1; r = rindex(header.path, '!'); if (r == 0) { r = header.path; } else { while (r > header.path && *--r != '!') ; if (r > header.path) r++; } printf("header.path '%s', r %x, su %d\n", header.path, r, su); s = rindex(whatsisname, '!'); if (s == 0) s = whatsisname; else { while (s > whatsisname && *--s != '!') ; if (s > whatsisname) s++; } if (!su && strcmp(r, s)) { sprintf(msgbuf, "Not contributor: %s and %s", header.path, whatsisname); xerror(msgbuf); } cancel(); p = q+1; } } /* * sendsys (no arguments) * * Mail the sys file to the person submitting the article. * POLICY: the contents of your sys file are public information * and as such, you should not change this code. You may feel * free to arrange for it to manually notify you, in the event * that you want to do something to clean it up before it goes out. * Secret sites on the net are expressly frowned on. * * The purpose of this command is for making a network map. The * details of your link and which newsgroups are forwarded are not * important, in case you want to sanitize them. Since the definition * of USENET is those sites getting net.general, you can disable this * on sites not getting net articles, but if you take out the list of * forwarded newsgroups, and you have sites that only get local newsgroups, * you should make this clear, or remove those sites from what you send out. */ c_sendsys(argc, argv) char **argv; { char buf[256]; FILE *f, *u; int c; #ifdef NOTIFY f = mailhdr(NOTIFY, "sendsys control message"); fprintf(f, "\n%s requested your sys file.\n", header.path); mclose(f); #endif f = mopen(header.path); fprintf(f, "Subject: response to your sendsys request\n\n"); u = fopen(SUBFILE, "r"); while ((c=getc(u)) != EOF) putc(c, f); fclose(u); mclose(f); } /* * senduuname (no arguments) * * Run the "uuname" command and send it back to the person who submitted * the article. The purpose of this control message is for attempting to * make a uucp net map. * * POLICY: If you view this information as not public (because you have * a connection you consider secret, or know a site that considers itself * secret) you can feel free to change this code in whatever way is * appropriate, so long as it sends some response back to the sender. If * you don't run uucp, this code does not make sense, and so an error * message (or garbage, such as "research") will be mailed back. * * If you wish to add or remove sites from the output of uuname, you * may wish to use the euuname.sh shell script here. */ c_senduuname(argc, argv) char **argv; { char buf[256]; FILE *fd, *u; int c; #ifdef NOTIFY fd = mailhdr(NOTIFY, "uuname control message"); fprintf(fd, "\n%s requested your uuname output\n", header.path); mclose(fd); #endif fd = mailhdr(header.path, "response to your senduuname request"); #ifdef UUNAME if (UUNAME[0] == '/') strcpy(buf, UUNAME); else sprintf(buf, "%s/%s", LIB, UUNAME); #else strcpy(buf, "uuname"); #endif u = popen(buf, "r"); while ((c=getc(u)) != EOF) putc(c, fd); pclose(u); mclose(fd); } /* * An unknown control message has been received. */ c_unknown(h) struct hbuf *h; { FILE *f; log("UNKNOWN Ctl Msg %s from %s", h->title, h->path); f = mailhdr(h->path, "Unrecognized Control Message"); if (f == NULL) xerror("Cannot send back error message"); fprintf(f, "Sent-by: USENET Site %s\n\n", SYSNAME); fprintf(f, "Currently running news B version %s.\n\n", SccsId); fprintf(f, "The header of the message follows:\n"); hwrite(h, f); mclose(f); } c_unimp(msg) char *msg; { FILE *f; char buf[256]; f = mailhdr(header.path, "Unimplemented Control Message"); if (f == NULL) xerror("Cannot send back error message"); fprintf(f, "Sent-by: USENET Site %s\n\n", SYSNAME); fprintf(f, "Currently running news B version %s.\n\n", SccsId); fprintf(f, "The header of the message follows:\n"); hwrite(&header, f); mclose(f); } xmitmsg(tosys, title, ng) char *tosys, *title, *ng; { struct hbuf h; struct srec srec; FILE *tfp; char *fname; /* Make an article called ARTICLE */ strcpy(h.path, NEWSU); strcpy(h.nbuf, ng); strcpy(h.title, title); strcpy(h.subdate, ""); strcpy(h.recdate, ""); strcpy(h.expdate, ""); getident(&h); dates(&h); tfp = xfopen(fname = mktemp("/tmp/xmsgXXXXXX"), "w"); hwrite(&h, tfp); fclose(tfp); /* Find the sys record */ s_openr(); while (s_read(&srec)) { if (strncmp(srec.s_name, tosys, SNLN)) continue; tfp = xfopen(fname, "r"); transmit(&srec, tfp, 0); unlink(fname); return; } log("Can't find sys record for %s", tosys); xerror("Cannot find sys record"); } /* * Given an article ID, find the line in the history file that mentions it. * Return the text of the line, or NULL if not found. A pointer to a * static area is returned. */ char * findhist(artid) char *artid; { static char lbuf[256]; FILE *hfp; char *p; hfp = xfopen(ARTFILE, "r"); while (fgets(lbuf, BUFLEN, hfp) != NULL) { p = index(lbuf, '\t'); if (p == NULL) p = index(lbuf, '\n'); *p = 0; if (strcmp(lbuf, artid) == 0) { fclose(hfp); *p = '\t'; *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */ return(lbuf); } } fclose(hfp); return(NULL); } /* * Hunt up the article "artid", fopen it for read, and return a * file descriptor to it. We look everywhere we can think of. */ FILE * hfopen(artid) char *artid; { char *line, *p, *q; char *findhist(); FILE *rv; char fname[256]; line = findhist(artid); if (line) { /* Look for it stored as an article, where it should be */ p = index(line, '\t'); p = index(p+1, '\t'); p++; while (*p) { q = index(p, ' '); *q = 0; sprintf(fname, "%s/%s", SPOOL, p); rv = fopen(fname, "r"); /* NOT xfopen! */ if (rv != NULL) return rv; p = q+1; } } /* * Last ditch effort - see if we have it archived in with the * cancelled articles. */ sprintf(fname, "%s/%s", CAND, artid); rv = fopen(fname, "r"); if (rv == NULL) xerror("Cannot hfopen article %s", artid); return rv; } /* * This is a modified version of popen, made more secure. Rather than * forking off a shell, you get a bare process. You must have exactly * one argument, and the command must be mail. */ /* @(#)popen.c 4.1 (Berkeley) 12/21/80 */ #include #include #define RDR 0 #define WTR 1 static int mopen_pid[20]; FILE * mopen(sendto) char *sendto; { int p[2]; register myside, hisside, pid; verifyname(sendto); if(pipe(p) /~"; while (*nasty) { if (index(sendto, *nasty++)) { log("nasty mail name %s from %s", sendto, header.path); xxit(1); } } for (nasty = sendto; (nasty = index(nasty, '.')) != NULL; ) { if (*++nasty == '.') { /* check for .. */ log("nasty mail name %s from %s", sendto, header.path); xxit(1); } } } /* * Checks to make sure the control message is OK to post. */ ctlcheck() { char msg[150]; char *p; if (!is_ctl) return; strcpy(msg, header.title); p = index(msg, ' '); if (p) *p = 0; if (strcmp(msg, "ihave") == 0) { } else if (strcmp(msg, "sendme") == 0) { return; /* no restrictions */ } else if (strcmp(msg, "newgroup") == 0) { return; /* no restrictions */ } else if (strcmp(msg, "rmgroup") == 0) { suser(); checkpass("mTnyckAVEMXWk"); } else if (strcmp(msg, "sendsys") == 0) { suser(); } else if (strcmp(msg, "senduuname") == 0) { suser(); } else if (strcmp(msg, "cancel") == 0) { return; /* no restrictions at this level */ } else { printf("Unrecognized control message - %s\n", msg); xxit(0); } } /* Make sure this guy is special. */ suser() { if (uid == 0) return; if (uid == ROOTID) return; printf("Get a guru to do it for you.\n"); xxit(0); } /* * Demand a password from the user. */ checkpass(encpw) { if (strcmp(encpw, crypt(getpass("Password:"), "mT"))) { printf("Sorry\n"); xxit(0); } } ----------------------------------------------------------------- gopher://quux.org/ conversion by John Goerzen of http://communication.ucsd.edu/A-News/ This Usenet Oldnews Archive article may be copied and distributed freely, provided: 1. There is no money collected for the text(s) of the articles. 2. The following notice remains appended to each copy: The Usenet Oldnews Archive: Compilation Copyright (C) 1981, 1996 Bruce Jones, Henry Spencer, David Wiseman.