pacman/control.c
mark
mark
Sun Apr 4 15:17:49 AEST 1982
/*
* 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 <= ' ') {
*nextfree++ = 0;
cargc++;
cargv[cargc] = nextfree;
/* skip over white space */
while (*str > 0 && *str <= ' ')
str++;
if (*str == 0) /* line ends in white space */
return;
} else
*nextfree++ = *str++;
}
}
/*
* ihave <artid> <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) < 0)
return NULL;
myside = p[WTR];
hisside = p[RDR];
if((pid = fork()) == 0) {
/* myside and hisside reverse roles in child */
close(myside);
close(0);
dup(hisside);
close(hisside);
execl("/bin/mail", "mail", sendto, 0);
execl("/usr/bin/mail", "mail", sendto, 0);
execl("/usr/ucb/mail", "mail", sendto, 0);
_exit(1);
}
if(pid == -1)
return NULL;
mopen_pid[myside] = pid;
close(hisside);
return(fdopen(myside, "w"));
}
mclose(ptr)
FILE *ptr;
{
register f, r, (*hstat)(), (*istat)(), (*qstat)();
int status;
f = fileno(ptr);
fclose(ptr);
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
hstat = signal(SIGHUP, SIG_IGN);
while((r = wait(&status)) != mopen_pid[f] && r != -1)
;
if(r == -1)
status = -1;
signal(SIGINT, istat);
signal(SIGQUIT, qstat);
signal(SIGHUP, hstat);
return(status);
}
/*
* mopen a pipe to mail, write out a std header, and return th file ptr.
*
* We don't include a From: field because this is probably uucp, i.e.
* explicitly routed. Leave it up to the recipient's mailer.
* Always include the To: field because if we ge back failed mail, we
* might be able to deliver it by hand if we know to wom it was addressed.
*/
FILE *
mailhdr(to, subject)
char *to, *subject;
{
FILE *fp;
time_t now;
if ((fp = mopen(to)) != NULL) {
time(&now);
fprintf(fp, "Date: %s", ctime(&now)); /* not rfc733 format */
fprintf(fp, "To: %s\n", to);
fprintf(fp, "Subject: %s\n", subject);
}
return fp;
}
/*
* verify that the name mail is being sent to does not contain any
* nasty hooks to invoke funny functions from the shell or the like.
*/
verifyname(sendto)
char *sendto;
{
/* Be sure we DO allow alphabetics, !, :, ., -, @. *. */
char *nasty = "\"'\\`^|;& <>/~";
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);
}
}
More information about the Comp.sources.unix
mailing list