DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T l

⟦182e0a787⟧ TextFile

    Length: 15459 (0x3c63)
    Types: TextFile
    Names: »loc_child.c«

Derivation

└─⟦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« 

TextFile

/* 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;
}