|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T l
Length: 15459 (0x3c63)
Types: TextFile
Names: »loc_child.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z«
└─⟦e5a54fb17⟧
└─⟦this⟧ »pp-5.0/Chans/822-local/loc_child.c«
/* loc_child.c: do the actual delivery */
# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/822-local/RCS/loc_child.c,v 5.0 90/09/20 15:44:55 pp Exp Locker: pp $";
# endif
/*
* $Header: /cs/research/pp/hubris/pp-beta/Chans/822-local/RCS/loc_child.c,v 5.0 90/09/20 15:44:55 pp Exp Locker: pp $
*
* $Log: loc_child.c,v $
* Revision 5.0 90/09/20 15:44:55 pp
* rcsforce : 5.0 public release
*
*/
#include "util.h"
#include "qmgr.h"
#include <sys/wait.h>
#include <sys/file.h>
#include <signal.h>
#include "retcode.h"
#include <sys/stat.h>
#include <varargs.h>
#include "expand.h"
#include "q.h"
#include "loc_user.h"
#include "ap.h"
#define PROTMODE (0022)
/*#define TESTVERSION /* do setuid'ing */
extern char *mailfilter, *sysmailfilter;
extern char *delim1, *delim2, *mboxname;
extern char *envp[];
extern char *env_path[];
extern char *local_user;
extern long message_size;
extern int restrict;
extern Q_struct Qstruct;
extern CHAN *mychan;
extern void expand();
void adios (), advise ();
static char msg_size[20];
static int hdr_fd, body_fd;
static void setstatus (), cleanup (), suckuperrors ();
static int copy (), copynofrom (), readinfile ();
static int do_mailfilter ();
static char *returnpath, *username;
static char *lowerfy ();
static char *return_path ();
#define MAXVARS 100
static Expand variables[MAXVARS];
static int nvars;
#ifdef __STDC__
#define VOLATILE volatile
#else
#define VOLATILE
#endif
int child_process (loc, h_fd, b_fd)
LocUser *loc;
int h_fd, b_fd;
{
int childpid, pid;
union wait status;
PP_TRACE (("child_process (loc, %d, %d)", h_fd, b_fd));
if ((childpid = tryfork ()) == NOTOK)
return NOTOK;
if (childpid) { /* parent */
while ((pid = wait(&status)) != childpid && pid != -1)
continue;
if (pid == -1) {
PP_LOG (LLOG_EXCEPTIONS, ("Pid == -1 something bad"));
return NOTOK;
}
if (WIFEXITED(status))
return status.w_retcode;
PP_LOG (LLOG_EXCEPTIONS, ("processed killed %s",
status.w_coredump ? "core dumped" :
""));
return NOTOK;
}
/* child */
hdr_fd = h_fd;
body_fd = b_fd;
#ifndef TESTVERSION
if (loc -> username &&
initgroups (loc -> username, loc -> gid) == NOTOK)
PP_SLOG (LLOG_EXCEPTIONS, loc -> username,
("Cant initilize groups list for"));
if (setregid (loc -> gid, loc -> gid) == NOTOK ||
setreuid (loc -> uid, loc -> uid) == NOTOK) {
PP_SLOG (LLOG_EXCEPTIONS,
(loc -> username ? loc -> username : "<none>"),
("Can't set uid (channel not setuid?) for uid-=%d id",
loc-> uid ));
_exit (int_Qmgr_status_mtaFailure);
}
#endif
PP_TRACE (("Changing directory to %s", loc -> directory));
if (chdir (loc -> directory) == NOTOK) {
PP_SLOG(LLOG_EXCEPTIONS, loc -> directory,
("Can't change to directory"));
_exit (int_Qmgr_status_mtaFailure);
}
returnpath = return_path (Qstruct.Oaddress -> ad_r822adr);
if (mailfilter && *mailfilter)
setstatus (do_mailfilter (mailfilter, 0, loc));
if (sysmailfilter && *sysmailfilter)
setstatus (do_mailfilter (sysmailfilter, 1, loc));
setstatus (putfile (loc -> mailbox));
_exit (int_Qmgr_status_messageFailure);
return NOTOK;
}
static void setstatus (retval)
int retval;
{
PP_TRACE (("setstatus (%s)", rp_valstr(retval)));
if (rp_isgood (retval)) {
PP_TRACE (("Delivery done"));
_exit (int_Qmgr_status_success);
}
else if (retval == RP_NOOP) {
PP_TRACE (("Trying next method"));
return;
}
else if (retval == RP_AGN) {
PP_TRACE (("Retry later"));
_exit (int_Qmgr_status_messageFailure);
}
PP_TRACE (("Failed"));
_exit (int_Qmgr_status_negativeDR);
}
static char *return_path (str)
char *str;
{
extern int ap_outtype;
char *newaddr = NULLCP;
AP_ptr tree = NULLAP,
group = NULLAP,
name = NULLAP,
local = NULLAP,
domain = NULLAP,
route = NULLAP;
switch (mychan -> ch_ad_order) {
case CH_UK_ONLY:
case CH_UK_PREF:
ap_outtype = AP_PARSE_822 | AP_PARSE_BIG;
break;
default:
return strdup (str);
}
if (ap_s2p (str, &tree, &group, &name, &local, &domain, &route)
== (char *)NOTOK) {
PP_LOG (LLOG_EXCEPTIONS,
("Unable to parse (s2p) Recipient addr %s", str));
return NULLCP;
}
if ((newaddr = ap_p2s (group, name, local, domain, route))
== (char *)NOTOK) {
PP_LOG (LLOG_EXCEPTIONS,
("Unable to parse (p2s) Recipient addr %s", str));
newaddr = NULLCP;
}
ap_free (tree);
return lowerfy(newaddr);
}
static jmp_buf jbuf;
static int do_mailfilter (file, sysflg, loc)
char *file;
int sysflg;
LocUser *loc;
{
struct stat statbuf;
static int n;
char gbuf[30];
PP_TRACE (("do_mailfilter (%s, %d)", file, sysflg));
if (stat (file, &statbuf) == NOTOK) {
PP_TRACE (("No file %s...", file));
return RP_NOOP;
}
if (statbuf.st_mode & PROTMODE) {
PP_NOTICE (("File %s has wrong modes", file));
return RP_NOOP;
}
if (statbuf.st_uid != 0 &&
(sysflg == 0 && statbuf.st_uid != loc -> uid)) {
PP_NOTICE (("File %s not owned by owner or root", file));
return RP_NOOP;
}
if (setjmp (jbuf) == DONE)
return RP_AGN;
reset_syms ();
initialise ();
zapvars (variables, MAXVARS);
if (readinfile (file) != OK)
return RP_AGN;
n = 0;
(void) sprintf (msg_size, "%d", message_size);
variables[n].macro = strdup("size");
variables[n].expansion = strdup (msg_size);
create_var (&variables[n]);
n++;
variables[n].macro = strdup ("return-path");
variables[n].expansion =
strdup (returnpath);
create_var (&variables[n]);
n++;
variables[n].macro = strdup ("mailbox");
variables[n].expansion = strdup (loc -> mailbox);
create_var (&variables[n]);
n++;
variables[n].macro = strdup ("recipient");
variables[n].expansion = strdup (local_user);
create_var (&variables[n]);
n++;
variables[n].macro = strdup ("userid");
if (loc -> username)
variables[n].expansion = strdup (loc -> username);
else {
(void) sprintf (gbuf, "%d", loc -> uid);
variables[n].expansion = strdup (gbuf);
}
create_var (&variables[n]);
n ++;
variables[n].macro = strdup ("groupid");
(void) sprintf (gbuf, "%d", loc -> gid);
variables[n].expansion = strdup (gbuf);
create_var (&variables[n]);
n ++;
variables[n].macro = strdup ("channelname");
variables[n].expansion = strdup (mychan -> ch_name);
create_var (&variables[n]);
n++;
nvars = parse_hdr (hdr_fd, variables + n, MAXVARS - n) + n;
return run ();
}
int putfile (file)
char *file;
{
FILE *fp;
off_t oldlen;
int n;
int exists;
char buffer[BUFSIZ];
install_vars (variables, nvars, MAXVARS);
expand (buffer, file, variables);
PP_TRACE (("putfile %s", buffer));
lseek (hdr_fd, 0L, L_SET);
lseek (body_fd, 0L, L_SET);
exists = access (buffer, 0) == 0;
if ((fp = flckopen (buffer, "a")) == NULL) {
PP_SLOG (LLOG_EXCEPTIONS, buffer, ("Can't open file"));
return RP_AGN;
}
if (!exists)
(void) fchmod (fileno (fp), 0600);
oldlen = lseek (fileno (fp), 0L, L_INCR);
if (oldlen < 0) {
(void) flckclose (fp);
return RP_AGN;
}
n = strlen (delim1);
if (fwrite (delim1, 1, n, fp) != n) {
cleanup (fp, oldlen);
return RP_AGN;
}
fprintf (fp, "Return-Path: <%s>\n",
returnpath);
if (copy (hdr_fd, fp) == NOTOK) {
cleanup (fp, oldlen);
return RP_AGN;
}
putc ('\n', fp);
if (copy (body_fd, fp) == NOTOK) {
cleanup (fp, oldlen);
return RP_AGN;
}
n = strlen (delim2);
if (fwrite (delim2, 1, n, fp) != n) {
cleanup (fp, oldlen);
return RP_AGN;
}
if (fflush (fp) != OK) {
cleanup (fp, oldlen);
return RP_AGN;
}
(void) flckclose (fp);
PP_TRACE (("Message written to file %s", buffer));
return RP_OK;
}
int putunixfile (file)
char *file;
{
FILE *fp;
time_t now;
char *tstr;
off_t oldlen;
int n;
int exists;
char buf[BUFSIZ];
char buffer[BUFSIZ];
install_vars (variables, nvars, MAXVARS);
expand (buffer, file, variables);
PP_TRACE (("putunixfile %s", buffer));
lseek (hdr_fd, 0L, L_SET);
lseek (body_fd, 0L, L_SET);
exists = access (buffer, 0) == 0;
if ((fp = flckopen (buffer, "a")) == NULL) {
PP_SLOG (LLOG_EXCEPTIONS, buffer, ("Can't open file"));
return RP_AGN;
}
if (!exists)
(void) fchmod (fileno (fp), 0600);
oldlen = lseek (fileno (fp), 0L, L_INCR);
if (oldlen < 0) {
(void) flckclose (fp);
return RP_AGN;
}
(void) time (&now);
tstr = ctime (&now);
(void) sprintf (buf, "From %s %s",
local_user, tstr);
n = strlen (buf);
if (fwrite (buf, 1, n, fp) != n) {
cleanup (fp, oldlen);
return RP_AGN;
}
fprintf (fp, "Return-Path: <%s>\n",
returnpath);
if (copynofrom (hdr_fd, fp) == NOTOK) {
cleanup (fp, oldlen);
return RP_AGN;
}
putc ('\n', fp);
if (copynofrom (body_fd, fp) == NOTOK) {
cleanup (fp, oldlen);
return RP_AGN;
}
putc ('\n', fp);
if (fflush (fp) != OK) {
cleanup (fp, oldlen);
return RP_AGN;
}
(void) flckclose (fp);
PP_TRACE (("Message written to file %s", buffer));
return RP_OK;
}
static void cleanup (fp, len)
FILE *fp;
off_t len;
{
int fd;
fd = dup (fileno (fp));
(void) flckclose (fp);
(void) ftruncate (fd, len); /* attempt to undo the damage */
(void) close (fd);
}
static int sigpiped, sigalarmed;
static SFD alarmed (), piped();
static jmp_buf pipe_arlm_jmp;
putpipe (proc)
char *proc;
{
int pid, cpid;
int retval;
SFP oldalarm, oldpipe;
int tofds[2], fromfds[2];
char buffer[BUFSIZ];
VOLATILE int killed = 0;
FILE *fp;
union wait status;
PP_TRACE(("putpipe (%s)", proc));
lseek (hdr_fd, 0L, L_SET);
lseek (body_fd, 0L, L_SET);
if (pipe (tofds) == NOTOK)
return RP_AGN;
if (pipe (fromfds) == NOTOK) {
close (tofds[0]);
close (tofds[1]);
return RP_AGN;
}
if ((pid = tryfork ()) == NOTOK) { /* argggh! So near */
close (tofds[0]);
close (tofds[1]);
close (fromfds[0]);
close (fromfds[1]);
return RP_AGN;
}
if (pid == 0) { /* kid */
int i;
install_vars (variables, nvars, MAXVARS);
expand (buffer, proc, variables);
PP_TRACE (("exec %s", buffer));
if (!restrict)
fillin_var ("PATH", env_path);
(void) close (tofds[1]);
dup2 (tofds[0], 0);
close (tofds[0]);
close (fromfds[0]);
dup2 (fromfds[1], 1);
dup2 (fromfds[1], 2);
close (fromfds[1]);
for (i = getdtablesize (); i > 2; i--)
(void) close (i);
setpgrp (0, getpid ());
#ifdef TIOCNOTTY
if ((i = open ("/dev/tty", O_RDWR, 0)) >= 0) {
(void) ioctl (i, TIOCNOTTY, 0);
(void) close (i);
}
#endif
if (restrict) {
extern char *usrpathname;
char pathname[BUFSIZ];
char *argv[50];
sstr2arg (buffer, 50, argv, " \t\n");
if (index (argv[0], '/')) {
PP_LOG (LLOG_EXCEPTIONS,
("argv[0] contains a '/' '%s'",
argv[0]));
_exit (1);
}
sprintf (pathname, "%s/%s", usrpathname, argv[0]);
execve (pathname, argv, envp);
_exit (1);
}
execle ("/bin/sh", "sh", "-c", buffer, NULLCP, envp);
_exit (1);
}
close (tofds[0]);
close (fromfds[1]);
fp = fdopen (tofds[1], "w");
oldalarm = signal (SIGALRM, alarmed);
oldpipe = signal (SIGPIPE, piped);
sigpiped = 0;
sigalarmed = 0;
alarm (300 + message_size/20);
PP_TRACE (("alarm set for %d secs", 300 + message_size/20));
if (setjmp (pipe_arlm_jmp) != DONE) {
fprintf (fp, "Return-Path: <%s>\n",
returnpath);
copy (hdr_fd, fp);
fputs ("\n", fp);
copy (body_fd, fp);
}
else {
if (sigalarmed)
PP_TRACE (("alarm went off"));
if (sigpiped)
PP_TRACE (("pipe went off"));
}
if (sigpiped) { /* pipe died - reset for timeout */
sigpiped = 0;
if (setjmp (pipe_arlm_jmp) == DONE)
PP_TRACE (("Timeout"));
}
if (sigalarmed) { /* alarm went off - shoot it dead! */
PP_NOTICE (("Process taking too long ... killing"));
killed = 1;
killpg (pid, SIGTERM);
sleep (2);
killpg (pid, SIGKILL);
}
if (fp) {
fclose (fp);
fp = NULL;
}
suckuperrors (fromfds[0]);
while ((cpid = wait (&status)) != pid && pid != -1)
PP_TRACE (("proc %d", cpid));
PP_TRACE (("pid %d returned term=%d, retcode=%d core=%d killed =%d",
pid, status.w_termsig, status.w_retcode,
status.w_coredump, killed));
alarm (0);
suckuperrors (fromfds[0]);
if (!killed && cpid == pid && WIFEXITED (status)) {
if (status.w_retcode == 0)
retval = RP_OK;
else if (rp_gbval(status.w_retcode) == RP_BNO)
retval = RP_BAD;
else retval = RP_AGN;
}
else retval = RP_AGN;
/* restore status */
close (fromfds[0]);
signal (SIGPIPE, oldpipe);
signal (SIGALRM, oldalarm);
return retval;
}
static SFD alarmed ()
{
sigalarmed = 1;
longjmp (pipe_arlm_jmp, DONE);
}
static SFD piped ()
{
sigpiped = 1;
longjmp (pipe_arlm_jmp, DONE);
}
static int copy (fd, fp)
int fd;
FILE *fp;
{
char buf[BUFSIZ];
int n = 0;
PP_TRACE (("copy (%d -> %d)", fd, fileno (fp)));
while (!sigpiped && !sigalarmed &&
(n = read (fd, buf, sizeof buf)) > 0) {
if (fwrite (buf, 1, n, fp) != n)
return NOTOK;
}
return n < 0 ? NOTOK : OK;
}
static int copynofrom (fd, fp)
int fd;
FILE *fp;
{
char buf[BUFSIZ];
int n;
FILE *fp2;
if ((fp2 = fdopen (dup(fd), "r")) == NULL)
return NOTOK;
PP_TRACE (("copy (%d -> %d)", fd, fileno (fp)));
while (!sigpiped && !sigalarmed &&
fgets (buf, sizeof buf, fp2)) {
if (strncmp (buf, "From ", 5) == 0)
putc ('>', fp);
if (fputs (buf, fp) == EOF) {
(void) fclose (fp2);
return NOTOK;
}
}
n = ferror (fp2) || ferror (fp) ? NOTOK : OK;
(void) fclose (fp2);
return n;
}
#ifndef lint
void adios (va_alist)
va_dcl
{
va_list ap;
char buffer[BUFSIZ];
va_start (ap);
asprintf (buffer, ap);
ll_log (pp_log_norm, LLOG_EXCEPTIONS, NULLCP, "%s", buffer);
va_end (ap);
longjmp (jbuf, DONE);
}
#else
/* VARARGS2 */
void adios (what, fmt)
char *what,
*fmt;
{
adios (what, fmt);
}
#endif
#ifndef lint
void advise (va_alist)
va_dcl
{
int code;
va_list ap;
va_start (ap);
code = va_arg (ap, int);
_ll_log (pp_log_norm, code, ap);
va_end (ap);
}
#else
/* VARARGS3 */
void advise (code, what, fmt)
char *what,
*fmt;
int code;
{
advise (code, what, fmt);
}
#endif
static int readinfile (file)
char *file;
{
extern FILE *yyin;
PP_TRACE (("readinfile (%s)", file));
if ((yyin = fopen (file, "r")) == NULL) {
PP_SLOG (LLOG_EXCEPTIONS, file, ("Can't open file"));
return NOTOK;
}
yyparse ();
(void) fclose (yyin);
return OK;
}
static void suckuperrors (fd)
int fd;
{
fd_set rfds, ifds;
char buf[80]; /* smallish */
int n;
struct timeval timer;
timerclear(&timer);
PP_TRACE (("suckuperrors (%d)", fd));
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
#define the_universe_exists 1
while (the_universe_exists) {
ifds = rfds;
if (select (fd + 1, &ifds, NULLFD, NULLFD, &timer) <= 0)
break;
PP_TRACE (("select fired"));
if (FD_ISSET (fd, &ifds)) {
if((n = read (fd, buf, sizeof buf - 1)) > 0) {
buf[n] = 0;
PP_LOG (LLOG_EXCEPTIONS,
("Output from process '%s'", buf));
}
else break;
}
else break;
}
PP_TRACE (("suckuperrors - done"));
}
zapvars (vp, mvp)
Expand *vp;
int mvp;
{
while (mvp --) {
if (vp -> macro) {
free (vp -> macro);
vp -> macro = NULL;
}
if (vp -> expansion) {
free (vp -> expansion);
vp -> expansion = NULL;
}
vp ++;
}
}
/* ARGSUSED */
printit (s)
char *s;
{
return;
}
static char *lowerfy (s)
char *s;
{
register char *cp;
for (cp = s;*cp; cp++)
if (isupper(*cp))
*cp = tolower(*cp);
return s;
}