home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume16
/
deliver
/
part02
/
dfile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-14
|
7KB
|
361 lines
/* $Header: dfile.c,v 1.2 88/08/25 15:23:56 network Exp $
*
* Filter destination(s) through delivery file(s).
*
* $Log: dfile.c,v $
* Revision 1.2 88/08/25 15:23:56 network
* Add third parameter to do_dfile(), so that if the delivery file cannot
* be executed, the given destination can be recorded as an error.
*
* Revision 1.1 88/06/06 09:38:38 chip
* Initial revision
*
*/
#include "deliver.h"
#include <sys/types.h>
#include <sys/stat.h>
/*----------------------------------------------------------------------
* Filter all valid destinations through the global delivery file.
*/
sys_dfile(dac, dav)
int dac;
char **dav;
{
char **fav;
int fac, a, goodnames;
struct stat st;
/*
* If there is no global delivery file, then take all the named
* addresses verbatim and return.
*/
if (stat(sys_deliver, &st) == -1)
{
if (verbose)
message("%s: no system delivery file\n",
progname);
for (a = 0; a < dac; ++a)
(void) dest(dav[a], (char *) NULL);
return;
}
/*
* Collect the arguments for the delivery file.
*/
fav = (char **) zalloc((dac + 3) * sizeof(char **));
fav[0] = shell;
fav[1] = sys_deliver;
fac = 2;
goodnames = 0;
for (a = 0; a < dac; ++a)
{
char *p;
for (p = dav[a]; *p; ++p)
{
if (!isalpha(*p)
&& !isdigit(*p)
&& !strchr("#%-+._", *p))
break;
}
if (*p)
{
/* Invalid name -- note it and go on. */
(void) dest(dav[a], (char *) NULL);
}
else
{
/* Valid name -- let the delivery file handle it. */
fav[fac++] = dav[a];
++goodnames;
}
}
fav[fac] = NULL;
/*
* If there were any good names found, let loose the delivery
* file. Note the meaning of "good" is "well-formed", not "valid".
* Thus the system delivery file has control over the handling of
* all local deliveries, not just those to valid users.
*/
if (goodnames)
(void) do_dfile(eff_ct, fav, (DEST *)NULL);
free((char *) fav);
}
/*----------------------------------------------------------------------
* Filter all user destinations through their local delivery files.
*/
user_dfiles()
{
DEST *d;
int nfound;
/*
* Continue to loop through all addresses until no destination
* that needs expanding can be found.
*/
do {
nfound = 0;
for (d = first_dest(); d; d = next_dest(d))
{
if (d->class == CL_USER
&& d->state == ST_WORKING
&& !d->dfdone)
{
one_dfile(d);
d->dfdone = TRUE;
}
}
} while (nfound > 0);
}
/*----------------------------------------------------------------------
* Run the delivery file (if any) for the specified destination.
*/
one_dfile(d)
DEST *d;
{
CONTEXT *ct;
char *fav[4];
char udel_path[100];
struct stat st;
if ((ct = name_context(d->name)) == NULL)
{
d->state = ST_ERROR;
d->error = "Missing context in user_dfile_one()";
return;
}
/*
* If user's home directory is missing, forget it.
* If user's home directory is writable to the world,
* executing the delivery file would allow a security breach!
* Thanks to Jon Zeeff for this hint...
*/
if (stat(ct->home, &st) == -1
|| (st.st_mode & S_IFMT) != S_IFDIR)
{
if (verbose)
message("%s: home directory %s is missing!\n",
ct->name, ct->home);
return;
}
if (st.st_mode & 02)
{
if (verbose)
message("%s: home directory is writable to the world!\n",
ct->name);
return;
}
/*
* If there is no delivery file to execute, just return.
*/
(void) sprintf(udel_path, "%s/%s", ct->home, user_deliver);
if (stat(udel_path, &st) == -1)
{
if (verbose)
message("%s has no delivery file\n", d->name);
return;
}
/*
* Time to run the file!
* We put this dest on hold, so that it will be ignored unless
* the delivery file names it.
*/
d->state = ST_HOLD;
fav[0] = "sh";
fav[1] = udel_path;
fav[2] = d->name;
fav[3] = NULL;
(void) do_dfile(ct, fav, d);
}
/*----------------------------------------------------------------------
* Process a delivery file.
*/
int
do_dfile(ct, av, d)
CONTEXT *ct;
char **av;
DEST *d;
{
FILE *fp;
char *name, *mailbox;
if (!ct)
return -1;
if (! ok_context(ct))
{
if (d)
{
d->state = ST_ERROR;
d->error = "No permissions for that context";
}
else
message("No permissions to run as %s\n", ct);
return -1;
}
/* Make sure that the temp files are readable to the new process. */
give_temps(ct);
/* Here we go! */
if (verbose)
message("Processing delivery file as %s\n", ct->name);
if ((fp = ct_popenv(ct, "/bin/sh", av, "r")) == NULL)
{
error("can't execute delivery file as %s\n", ct->name);
leave(1);
}
/*
* Read the standard output of the delivery file.
*/
while (dfile_gets(fp, &name, &mailbox) >= 0)
{
DEST *nd;
nd = dest(name, mailbox);
if (nd->state == ST_HOLD)
nd->state = ST_WORKING;
/*
* If the delivery file specified a mailbox, verify
* that the user whose delivery file is running has
* permissions for the requested context.
*/
if ((nd->state == ST_WORKING) && (mailbox != NULL))
{
CONTEXT *nct;
if ((nct = name_context(name)) == NULL)
{
nd->state = ST_ERROR;
nd->error = "Lost context in do_dfile()";
}
else if (! ok_context(nct))
{
nd->state = ST_ERROR;
nd->error = "No permissions for that context";
}
}
}
return ct_pclose(fp);
}
/*----------------------------------------------------------------------
* Get and parse a single delivery file output line.
*/
int
dfile_gets(fp, namep, mailboxp)
FILE *fp;
char **namep;
char **mailboxp;
{
char *p, *q;
static char buf[BUFSIZ];
if (fgets(buf, GETSIZE(buf), fp) == NULL)
return -1;
if ((p = strchr(buf, '\n')) != NULL)
*p = 0;
else
{
int c;
while ((c = fgetc(fp)) != '\n' && c != EOF)
; /* keep reading */
error("invalid line from delivery file: '%s'\n", buf);
return -1;
}
/* Strip out all whitespace and eliminate duplicated slashes */
p = q = buf;
while (*p)
{
if (! isspace(*p))
{
if ((*q++ = *p++) == '/')
{
while (*p == '/')
++p;
}
}
}
*q = 0;
/* Debugging message: display input line */
if (verbose)
message("\t'%s'\n", buf);
if ((p = strchr(buf, ':')) != NULL)
{
*p++ = 0;
if ((q = strchr(p, ':')) != NULL)
*q = 0;
}
*namep = buf;
*mailboxp = p;
return 0;
}
/*----------------------------------------------------------------------
* Make the temp files readable in the given context.
* This is needed because the temps are readable by owner only.
*/
give_temps(ct)
CONTEXT *ct;
{
int t;
if (!ct)
return;
for (t = 0; t < T_MAX; ++t)
{
if (chown(tfile[t], ct->uid, ct->gid) == -1)
syserr("can't chown %s", tfile[t]);
}
}