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 } <ARTID WHITE RETURN; ENDS *NEXTFREE++="*str++;" SPACE */ LINE IF IN IHAVE> <REMOTESYS>
* The other system is telling you it has article <ARTID>, 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 <ARTID> <REMOTESYS>
* The other system wants me to send him article <ARTID>.
*/
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 <GROUPNAME>
* 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 <GROUPNAME>
* 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' </TMP/$$> %s/active ; rm /tmp/$$",
               LIB, groupname, LIB);
       rc = system(bfr); log("system(%s) status %d", bfr, rc);
#endif
}

/*
* cancel <ARTID>
* 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 <STDIO.H>
#include <SIGNAL.H>
#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 <[email protected]>
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.