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 u

⟦007aae7e7⟧ TextFile

    Length: 13203 (0x3393)
    Types: TextFile
    Names: »uucp_out.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/uucp/uucp_out.c« 

TextFile

/* uucp_out.c: uucp outbound channel */

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/uucp/RCS/uucp_out.c,v 5.0 90/09/20 15:55:37 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/uucp/RCS/uucp_out.c,v 5.0 90/09/20 15:55:37 pp Exp Locker: pp $
 *
 * $Log:	uucp_out.c,v $
 * Revision 5.0  90/09/20  15:55:37  pp
 * rcsforce : 5.0 public release
 * 
 */



#include "util.h"
#include "head.h"
#include "qmgr.h"
#include "q.h"
#include "dr.h"
#include "prm.h"
#include <isode/cmd_srch.h>
#include	<sys/stat.h>
#include	<sys/file.h>
#include	<sys/wait.h>
#include	<signal.h>

#ifdef __STDC__
#define VOLATILE volatile
#else
#define VOLATILE
#endif

extern char	*mquedir,
		*quedfldir,
		*chndfldir,
		*logdfldir,
		*hdr_822_bp;

extern CHAN 	*ch_nm2struct();
extern	char	*loc_dom_mta;
extern int	rfc8222uu();
CHAN 		*mychan;
char		*this_msg = NULL, *this_chan = NULL;
char		*myhostname;
char		*uuxstr;
int		first_successDR;

static struct type_Qmgr_DeliveryStatus *process();
static void set_success();
static char *get_adrstr();
static void dirinit();
static ADDR *getnthrecip();
static LIST_RCHAN *getnthchannel();
static jmp_buf	toplevel;
static int   pipe_signaled;
static int initialise();

static sig_pipe()
{
	pipe_signaled = TRUE;
	longjmp (toplevel, DONE);
}

/* \f

 */
/* main routine */
 
main (argc, argv)
int 	argc;
char	**argv;
{
	sys_init (argv[0]);
	dirinit();
#ifdef PP_DEBUG
	if (argc>1 && (strcmp (argv[1],"debug") == 0))
		debug_channel_control (argc,argv,initialise,process, NULLIFP);
	else
#endif
		channel_control (argc, argv, initialise, process, NULLIFP);
}

/* \f

 */
/* routine to move to correct place in file system */

static void dirinit()
{
	if (chdir (quedfldir) < 0)
		err_abrt (RP_LIO, " Unable to change directory to '%s'",
			  quedfldir);
}

/* \f

 */

static CMD_TABLE uucptbl[] = {
#define TBL_UUXCMD 1
	"uux",	TBL_UUXCMD,
#define TBL_HOST 2
	"host",	TBL_HOST,
	0, -1
	};

/* channel initialise routine */

static int initialise (arg)
struct type_Qmgr_Channel *arg;
{
	char *name, *p;
	char	*argv[20];
	int	i, argc;
	char	buffer[BUFSIZ];

	if (uuxstr) free (uuxstr);
	uuxstr = NULLCP;
	if (myhostname) free (myhostname);
	myhostname = NULLCP;

	name = qb2str (arg);

	if ((mychan = ch_nm2struct (name)) == NULLCHAN) {
		PP_OPER (NULLCP, ("Chan/uucp_out : Channel '%s' not known",name));
		if (name != NULL) free (name);
		return NOTOK;
	}

	if (mychan -> ch_info == NULLCP) {
		PP_OPER (NULLCP, ("%s channel (%s) has no info parameter",
				  mychan -> ch_name, mychan -> ch_show));
		return NOTOK;
	}
	(void) strcpy (buffer, mychan -> ch_info);
	if ((argc = sstr2arg (buffer, 20, argv, ",")) <= 0) {
		PP_LOG (LLOG_EXCEPTIONS, ("Info string unparseable"));
		return NOTOK;
	}

	for (i = 0; i < argc; i++) {
		if ((p = index (argv[i], '=')) == NULL) {
			PP_LOG (LLOG_EXCEPTIONS,
				("Info string for %s not in key=val format",
				 mychan -> ch_name));
			return NOTOK;
		}
		*p++ = '\0';
		switch (cmd_srch (argv[i], uucptbl)) {
		    case TBL_UUXCMD:
			uuxstr = strdup (p);
			break;

		    case TBL_HOST:
			myhostname = strdup (p);
			break;

		    default:
			PP_LOG (LLOG_EXCEPTIONS,
				("Unknown key in chan info for %s '%s'",
				 mychan -> ch_name,
				 argv[i]));
			return NOTOK;
		}
	}
	if (uuxstr == NULLCP) {
		PP_LOG (LLOG_EXCEPTIONS, ("uux not set in info"));
		return NOTOK;
	}
	if (myhostname == NULLCP)
		myhostname = strdup (loc_dom_mta);

	(void) signal (SIGCHLD, SIG_DFL);
	if (name != NULL) free (name);
	return OK;
}

/* \f

 */
/* routine to check if allowed to filter this message through this channel */
static int security_check (msg)
struct type_Qmgr_ProcMsg *msg;
{
 	char 		*msg_file = NULL, *msg_chan = NULL;
	int		result;

	result = TRUE;
	msg_file = qb2str (msg->qid);	
	msg_chan = qb2str (msg->channel);

	if ((mychan == NULLCHAN) || (strcmp (msg_chan,mychan->ch_name) != 0)) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("Chans/shell channel err: '%s'",msg_chan));
		result = FALSE;
	}

	/* free all storage used */
	if (msg_file != NULL) free (msg_file);
	if (msg_chan != NULL) free (msg_chan);
	return result;
}

/* \f

 */
/* routine called to do uucp */

static struct type_Qmgr_DeliveryStatus *process (arg)
struct type_Qmgr_ProcMsg *arg;
{
	struct prm_vars	prm;
	Q_struct	que;
	ADDR		*sender = NULL;
	ADDR		*recips = NULL;
	int 		rcount, retval;
	struct type_Qmgr_UserList 	*ix;
	ADDR				*adr;
	char		*realfrom = NULL;
	bzero ((char *) &que,sizeof (que));
	bzero ((char *) &prm,sizeof (prm));

	delivery_init (arg->users);
	delivery_setall (int_Qmgr_status_messageFailure);
	first_successDR = TRUE;

	if (security_check (arg) != TRUE)
		return deliverystate;

	if (this_msg != NULL) free (this_msg);
	if (this_chan != NULL) free (this_chan);

	this_msg = qb2str (arg->qid);
	this_chan = qb2str (arg->channel);

	PP_LOG (LLOG_NOTICE,
	       ("%s processing msg '%s'",mychan->ch_name,this_msg));

	if (rp_isbad (rd_msg (this_msg,&prm,&que,&sender,&recips,&rcount))) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s rd_msg err: '%s'",mychan->ch_name,this_msg));
		rd_end();
		return deliverystate;
	}

		
	if (getrealfrom (sender, &realfrom) != OK) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s unable to construct real sender message for orig of message '%s'",mychan->ch_name,this_msg));
		rd_end();
		return deliverystate;
	}

	if (arg->users == NULL)
		PP_LOG (LLOG_NOTICE,
			("%s : passed a NULL user list for message '%s'",
			mychan->ch_name,
			this_msg));

	/* check each recipient for processing */
	for (ix = arg->users; ix; ix = ix->next) {
		if ((adr = getnthrecip (&que,ix->RecipientId->parm)) == NULL) {
			PP_LOG (LLOG_EXCEPTIONS,
			      ("%s : failed to find recipient %d of msg '%s'",mychan->ch_name,ix->RecipientId->parm, this_msg));
			delivery_set (ix->RecipientId->parm, int_Qmgr_status_messageFailure);
			continue;
		}

		switch (chan_acheck (adr, mychan, 1, NULLCP)) {
		    case OK:
			if (processMsg (this_msg,adr, realfrom) == NOTOK) {
				PP_LOG (LLOG_EXCEPTIONS,
				       ("%s : failed to process msg '%s' for recip '%d' on channel '%s'",mychan->ch_name,this_msg, adr->ad_no, this_chan));
				delivery_set (adr->ad_no, int_Qmgr_status_messageFailure);
			} else {
				PP_LOG (LLOG_NOTICE,
					 ("%s : processed '%s' for recipient %d",mychan->ch_name,this_msg,adr->ad_no));
				set_success (adr, &que, this_msg);
			}
			break;
		    default:
			break;
		}
	}

	if (rp_isbad (retval = wr_q2dr (&que, this_msg))) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s wr_q2dr failure '%d'",mychan->ch_name,retval));
		delivery_resetDRs (int_Qmgr_status_messageFailure);
	}

	rd_end();
	if (realfrom != NULL) free (realfrom);
	return deliverystate;
}

static void set_success (recip, que, msg)
ADDR		*recip;
Q_struct	*que;
char		*msg;
{
	if (recip->ad_usrreq == AD_USR_CONFIRM ||
	    recip->ad_mtarreq == AD_MTA_CONFIRM ||
	    recip->ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
		set_1dr (que, recip->ad_no,
		       DRR_NO_REASON, -1, NULLCP);
		delivery_set (recip->ad_no, 
			     (first_successDR == TRUE) ? int_Qmgr_status_positiveDR : int_Qmgr_status_successSharedDR);
	} else {
		(void) wr_ad_status (recip, AD_STAT_DONE);
		delivery_set (recip->ad_no, int_Qmgr_status_success);
	}
}

/* \f

 */
static int processMsg (msg,recip, realfrom)
/* returns OK if managed to process msg for recip on mychan */
char	*msg;
ADDR 	*recip;
char	*realfrom;
{
	char 	*origdir = NULL,
		*cmdline = NULL;
	int result = OK;
	struct stat statbuf;

	if (qid2dir (msg, recip, TRUE, &origdir) != OK) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s original directory not found for recipient %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
		result = NOTOK;
	}

	if (result == OK &&
	    mychan->ch_info == NULL) {
		PP_OPER (NULLCP,
			 ("%s uux pathname not given in info string",mychan->ch_name));
		result = NOTOK;
	}

	if (result == OK && 
	    rfc8222uu (recip->ad_outchan->li_mta,recip->ad_r822adr, &cmdline) != OK) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s unable to convert to uucp format address of recip %d of message '%s'",mychan->ch_name,recip->ad_no, msg));
		result = NOTOK;
	}
		
	if ((result == OK) && (doProcess (origdir,msg, cmdline, realfrom) != OK))
		result = NOTOK;

	if (origdir != NULL) free (origdir);
	if (cmdline != NULL) free (cmdline);
	return result;
}

/* \f

 */

static int sigpiped, sigalarmed;
static int alarmed(), piped();
static jmp_buf pipe_alrm_jmp;

static int doProcess (orig, msg, cmdline, realfrom)
/* processes orig directory contents through mychan */
char	*orig,	/* original directory */
	*msg,	/* message */
	*cmdline,/* uucp cmdline */
	*realfrom;/* real sender */
{
	int	fd[2],
		result = OK,
		pid,
		pgmresult,
		margc;
	char	*program = NULL,
		*margv[20];
	SFP	 oldalarm, oldpipe;
	VOLATILE int	killed = 0;
	struct stat statbuf;

	if (pipe (fd) != 0) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s pipe failed",mychan->ch_name));
		return NOTOK;
	}

	if ((margc = sstr2arg (cmdline, 20, margv, " \t")) < 1) 
		return NOTOK;
		
	if (margv[0][0] == '/')
		/* given full path name */
		program = strdup (margv[0]);
	else {
		program = (char *) malloc ((unsigned int) (strlen (chndfldir) + 1 + strlen (margv[0]) + 1));
		sprintf (program,"%s/%s",chndfldir,margv[0]);
	}
	
	if (stat (program, &statbuf) != OK) {
		PP_OPER (NULLCP,
			 ("%s : missing uux program '%s'",mychan -> ch_name, program));
		return NOTOK;
	}
	if ((pid = tryfork()) == 0) {
		/* in child so redirect in- and out-put */
		dup2 (fd[0], 0);
		close (fd[0]);
		close (fd[1]);
		setpgrp (0, getpid());

		execv (program,margv);
		_exit (1);
	} else if (pid == -1) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s: tryfork failed for msg %s",
		       mychan->ch_name,this_msg));
		close (fd[1]);
		result = NOTOK;
	} else {
		union wait 	w;

		oldalarm = signal (SIGALRM, alarmed);
		oldpipe = signal (SIGPIPE, piped);
		sigpiped = 0;
		sigalarmed = 0;

		if (setjmp (pipe_alrm_jmp) != DONE) {
			if (send_to_child (orig, fd[1], realfrom) == NOTOK)
				result = NOTOK;
			close (fd[1]);
		} 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_alrm_jmp) == DONE)
				PP_TRACE (("Timeout"));
		}

		if (sigalarmed) { /* alarm went off */
			PP_NOTICE (("Process taking too long ... killing"));
			killed = 1;
			killpg (pid, SIGTERM);
			sleep (2);
			killpg (pid, SIGKILL);
		}

		while ((pgmresult = wait (&w)) != pid && pgmresult != -1)
			PP_TRACE (("process %d returned", pgmresult));

		PP_TRACE (("pid %d returned term=%d, retcode=%d core = %d killed = %d",
			  pid, w.w_termsig, w.w_retcode,
			  w.w_coredump, killed));
		alarm (0);

		signal (SIGPIPE, oldpipe);
		signal (SIGALRM, oldalarm);

		if ((pgmresult == pid) && (w.w_retcode == 0) && (killed == 0))
			result = OK;
		else 
			result = NOTOK;
	}
	close (fd[0]);

	return result;
}

static int alarmed()
{
	sigalarmed = 1;
	longjmp (pipe_alrm_jmp, DONE);
}

static int piped()
{
	sigpiped = 1;
	longjmp (pipe_alrm_jmp, DONE);
}

/* \f

 */
static int write_to_child (file, fd_out)
char	*file;
int	fd_out;
{
	char	buf[BUFSIZ];
	int	fd_in,
		num;

	if ((fd_in = open (file, O_RDONLY, 0666)) == -1) {
		PP_LOG (LLOG_EXCEPTIONS,
		       ("%s input file err '%s'",mychan->ch_name, file));
		return NOTOK;
	}

	while ((num = read (fd_in, buf, BUFSIZ)) > 0)
		if (write (fd_out, buf, num) == -1)
			return NOTOK;
	return OK;
}
		       
static ADDR *getnthrecip (que, num)
Q_struct	*que;
int		num;
{
	ADDR *ix = que->Raddress;
	int icount = 1;
	if (num == 0)
		return que->Oaddress;
	while ((ix != NULL) && (icount++ < num))
		ix = ix->ad_next;
	return ix;
}

static LIST_RCHAN *getnthchannel (chans,num)
LIST_RCHAN	*chans;
int		num;
{
	LIST_RCHAN	*ix = chans;
	int		icount = 0;

	while ((ix != NULL) && (icount++ < num)) 
		ix = ix->li_next;

	return ix;
}

static char	*get_adrstr (adr)
ADDR	*adr;
{
	char	*key;
	switch (adr->ad_type) {
	    case AD_X400_TYPE:
		key = adr->ad_r400adr;
		break;
	    case AD_822_TYPE:
		key = adr->ad_r822adr;
		break;
	    default:
		key = adr->ad_value;
		break;
	}
	return key;
}

static int is822hdr (file)
char	*file;
{
	char *ix = rindex (file, '/');

	if (ix == NULL
	    || (strncmp ((ix+1),hdr_822_bp,strlen (hdr_822_bp)) != 0))
		return FALSE;
	else
		return TRUE;
}

static int send_to_child (orig, fd, realfrom)
char	*orig;
int	fd;
char	*realfrom;
{
	char	file[FILNSIZE];
	SFP	old_sig;
	char	buf[BUFSIZ];
	time_t	timenow;
	int	len;

	(void) time (&timenow);
	
	msg_rinit (orig);

	pipe_signaled = FALSE;

	/* set signal handler */
	old_sig = signal (SIGPIPE, sig_pipe);

	/* set long jump */
	setjmp (toplevel);
	(void) sprintf (buf, "From %s %.24s remote from %s\n",
			realfrom, ctime (&timenow), myhostname);
	len = strlen (buf);
	if (write (fd, buf, len) != len)
		return NOTOK;
	
	while (pipe_signaled == FALSE
	       && msg_rfile (file) == RP_OK) {
		if (write_to_child (file, fd) == NOTOK) {
			msg_rend ();
			return NOTOK;
		}
		if (is822hdr (file) == TRUE)
			if (write (fd, "\n", 1) != 1)
				return NOTOK;
	}
	
	msg_rend();

	/* unset signal handler */
	signal (SIGPIPE, old_sig);
	return OK;
}