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