|
|
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 u
Length: 13203 (0x3393)
Types: TextFile
Names: »uucp_out.c«
└─⟦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«
/* 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;
}