chip@ateng.ateng.com (Chip Salzenberg) (11/29/88)
This is an offical patch for deliver 1.00. Please apply it. Patch number: 2 Date: 18 Nov 1988 Priority: MEDIUM Changes: Improved signal handling now allows SIGINT etc. to abort message when stdin is a tty. (Signals are then disabled for delivery.) Make sure all environment variables are always provided. Trust some users to specify delivery files. Index: patchlevel.h Prereq: 1 *************** *** 1 **** ! #define PATCHLEVEL 1 --- 1 ---- ! #define PATCHLEVEL 2 Index: config.h *************** *** 1,8 **** ! /* $Header: config.h,v 1.3 88/09/14 19:41:35 network Exp $ * * Deliver configuration. * * $Log: config.h,v $ * Revision 1.3 88/09/14 19:41:35 network * Portability to System V and BSD. * General fixup. --- 1,13 ---- ! /* $Header: config.h,v 1.4 88/11/18 12:16:39 network Exp $ * * Deliver configuration. * * $Log: config.h,v $ + * Revision 1.4 88/11/18 12:16:39 network + * patch2: Improved signal handling. + * patch2: Make sure all environment variables are always provided. + * patch2: Some users can be trusted to specify delivery files. + * * Revision 1.3 88/09/14 19:41:35 network * Portability to System V and BSD. * General fixup. *************** *** 15,20 **** --- 20,45 ---- * Initial revision * */ + + /*---------------------------------------------------------------------- + * Trusted users. + * Deliver permits "trusted" users to specify delivery filenames + * without renouncing setuid privileges. Essentially, these users + * are given the root password. Beware! + */ + + #define TRUSTED_USERS "root", "uucp" + + /*---------------------------------------------------------------------- + * Signal flag type. + * Variables of this type may be set by signal catching routines. + */ + + #ifdef __STDC__ + #define SIGFLAG sig_atomic_t + #else + #define SIGFLAG short /* or "volatile short" for aggressive optimizers */ + #endif /*---------------------------------------------------------------------- * Various kinds of mailbox locking. Index: copymsg.c *************** *** 1,9 **** ! /* $Header: copymsg.c,v 1.1 88/06/06 09:38:13 chip Exp $ * * Take the message from standard input and write it to two temp files, * one for the header (including the empty line) and one for the body. * * $Log: copymsg.c,v $ * Revision 1.1 88/06/06 09:38:13 chip * Initial revision * --- 1,14 ---- ! /* $Header: copymsg.c,v 1.2 88/11/18 12:17:40 network Exp $ * * Take the message from standard input and write it to two temp files, * one for the header (including the empty line) and one for the body. * * $Log: copymsg.c,v $ + * Revision 1.2 88/11/18 12:17:40 network + * patch2: Improved signal handling. + * patch2: Make sure all environment variables are always provided. + * patch2: Some users can be trusted to specify delivery files. + * * Revision 1.1 88/06/06 09:38:13 chip * Initial revision * *************** *** 37,43 **** { char buf[BUFSIZ]; FILE *dfp[T_MAX]; ! char *p, *fsender, *fremote, *osender, *oremote; long now; int t, b, empty_line; int ret = 0; --- 42,48 ---- { char buf[BUFSIZ]; FILE *dfp[T_MAX]; ! char *p, *fsender, *fremote; long now; int t, b, empty_line; int ret = 0; *************** *** 115,148 **** /* * Write a From_ line to the header file. - * If the user specified a sender name, use it; - * else if we found a From_ line, use the sender found therein; - * else use the user name of our real UID. */ ! if (sender && *sender) ! { ! osender = sender; ! oremote = NULL; ! } else if (fsender) { ! osender = fsender; ! oremote = fremote; } else ! { ! osender = real_ct->name; ! oremote = NULL; ! } (void) fputs("From ", dfp[T_HEADER]); ! if (oremote) ! { ! (void) fputs(oremote, dfp[T_HEADER]); ! (void) fputc('!', dfp[T_HEADER]); ! } ! (void) fputs(osender, dfp[T_HEADER]); (void) fputc(' ', dfp[T_HEADER]); (void) time(&now); (void) fputs(ctime(&now), dfp[T_HEADER]); --- 120,159 ---- /* * Write a From_ line to the header file. */ ! /* if caller specified sender, use it */ ! if (sender) ! ; /* fine */ ! ! /* else if we found a From_ line, use it */ else if (fsender) { ! if (fremote) ! { ! sender = zalloc(strlen(fremote) + sizeof("!") ! + strlen(fsender)); ! (void) sprintf(sender, "%s!%s", fremote, fsender); ! } ! else ! sender = copystr(fsender); } + + /* else use our real ID */ else ! sender = real_ct->name; + /* debugging message */ + + if (verbose) + message("copy_msg: sender is \"%s\"\n", sender); + + /* + * Finally! Write the From_ line. + */ + (void) fputs("From ", dfp[T_HEADER]); ! (void) fputs(sender, dfp[T_HEADER]); (void) fputc(' ', dfp[T_HEADER]); (void) time(&now); (void) fputs(ctime(&now), dfp[T_HEADER]); *************** *** 151,157 **** * Copy the rest of the header (if any). */ ! for (; !feof(stdin); b = FALSE) { if (!b) { --- 162,168 ---- * Copy the rest of the header (if any). */ ! for (; !feof(stdin) && !ferror(stdin); b = FALSE) { if (!b) { *************** *** 217,223 **** */ empty_line = FALSE; ! for (; !feof(stdin); b = FALSE) { if (!b) { --- 228,234 ---- */ empty_line = FALSE; ! for (; !feof(stdin) && !ferror(stdin); b = FALSE) { if (!b) { *************** *** 242,247 **** --- 253,259 ---- while (!strchr(buf, '\n') && !feof(stdin) + && !ferror(stdin) && fgets(buf, GETSIZE(buf), stdin)) (void) fputs(buf, dfp[T_BODY]); } Index: deliver.h *************** *** 1,8 **** ! /* $Header: deliver.h,v 1.4 88/10/13 12:19:18 network Exp $ * * General pull-it-together include file. * * $Log: deliver.h,v $ * Revision 1.4 88/10/13 12:19:18 network * patch1: add "-n" option, and general bug fixes. * --- 1,13 ---- ! /* $Header: deliver.h,v 1.5 88/11/18 12:16:55 network Exp $ * * General pull-it-together include file. * * $Log: deliver.h,v $ + * Revision 1.5 88/11/18 12:16:55 network + * patch2: Improved signal handling. + * patch2: Make sure all environment variables are always provided. + * patch2: Some users can be trusted to specify delivery files. + * * Revision 1.4 88/10/13 12:19:18 network * patch1: add "-n" option, and general bug fixes. * *************** *** 54,59 **** --- 59,67 ---- extern CONTEXT *eff_ct; /* Context of effective uid */ extern CONTEXT *real_ct; /* Context of real uid */ + extern int trust_user; /* Do we trust the user that called us? */ + extern int trust_delfiles; /* Do we trust the delivery files? */ + /* Temp file indices: */ #define T_HEADER 0 /* Temp file for message header */ #define T_BODY 1 /* Temp file for message body */ *************** *** 62,67 **** --- 70,77 ---- extern char *ttype[T_MAX]; /* Temp file types (for messages) */ extern char *tfile[T_MAX]; /* Temp file names */ extern int tfd[T_MAX]; /* Temp file fd's */ + + extern SIGFLAG got_sig; /* We caught a signal and should exit */ /*---------------------------------------------------------------------- * Global functions Index: main.c *************** *** 1,8 **** ! /* $Header: main.c,v 1.6 88/10/13 12:19:27 network Exp $ * * A program to deliver local mail with some flexibility. * * $Log: main.c,v $ * Revision 1.6 88/10/13 12:19:27 network * patch1: add "-n" option, and general bug fixes. * --- 1,13 ---- ! /* $Header: main.c,v 1.7 88/11/18 12:17:17 network Exp $ * * A program to deliver local mail with some flexibility. * * $Log: main.c,v $ + * Revision 1.7 88/11/18 12:17:17 network + * patch2: Improved signal handling. + * patch2: Make sure all environment variables are always provided. + * patch2: Some users can be trusted to specify delivery files. + * * Revision 1.6 88/10/13 12:19:27 network * patch1: add "-n" option, and general bug fixes. * *************** *** 41,46 **** --- 46,58 ---- extern char *optarg; /* + * Local data + */ + + static char sys_default[] = SYS_DELIVER; + static char user_default[] = USER_DELIVER; + + /* * Global data */ *************** *** 55,62 **** char version[32] = "1.0"; char *shell = SHELL; ! char *sys_deliver = NULL; ! char *user_deliver = NULL; char *sender = NULL; char *hostname = NULL; --- 67,74 ---- char version[32] = "1.0"; char *shell = SHELL; ! char *sys_deliver = sys_default; ! char *user_deliver = user_default; char *sender = NULL; char *hostname = NULL; *************** *** 68,77 **** --- 80,101 ---- CONTEXT *eff_ct = NULL; CONTEXT *real_ct = NULL; + int tty_input = FALSE; + SIGFLAG got_sig = FALSE; + + int trust_user = FALSE; + int trust_delfiles = FALSE; + char *ttype[T_MAX] = { "header", "body" }; char *tfile[T_MAX] = { NULL, NULL }; int tfd[T_MAX] = { -1, -1 }; + /* + * Local functions. + */ + + static int sighup(), sigint(), sigquit(); + /*---------------------------------------------------------------------- * The Program. */ *************** *** 81,87 **** char **argv; { char *p; ! int u, c, errcount; /* Make sure that stdout and stderr are interleaved correctly */ --- 105,111 ---- char **argv; { char *p; ! int u, c, errcount, copy; /* Make sure that stdout and stderr are interleaved correctly */ *************** *** 105,110 **** --- 129,147 ---- hostname); } + /* Find effective and real uids and gids. */ + + eff_uid = geteuid(); + eff_gid = getegid(); + real_uid = getuid(); + real_gid = getgid(); + + if (eff_uid != real_uid && eff_uid != 0) + { + error("if setuid, must be setuid root\n"); + leave(1); + } + /* Process environment: handle recursive invocation */ if ((p = getenv(ENV_DFLAGS)) != NULL) *************** *** 133,145 **** } } } ! if ((p = getenv(ENV_SYSDEL)) != NULL) sys_deliver = p; ! if ((p = getenv(ENV_USERDEL)) != NULL) user_deliver = p; ! if ((p = getenv(ENV_SENDER)) != NULL) sender = p; ! if ((p = getenv(ENV_HOSTNAME)) != NULL) hostname = p; /* Parse command line arguments */ --- 170,183 ---- } } } ! ! if ((p = getenv(ENV_SYSDEL)) != NULL && *p) sys_deliver = p; ! if ((p = getenv(ENV_USERDEL)) != NULL && *p) user_deliver = p; ! if ((p = getenv(ENV_SENDER)) != NULL && *p) sender = p; ! if ((p = getenv(ENV_HOSTNAME)) != NULL && *p) hostname = p; /* Parse command line arguments */ *************** *** 169,184 **** boxdelivery = TRUE; break; case 's': ! sys_deliver = optarg; break; case 'u': ! user_deliver = optarg; break; case 'r': ! sender = optarg; break; case 'h': ! hostname = optarg; break; case '?': usage(); --- 207,226 ---- boxdelivery = TRUE; break; case 's': ! if (*optarg) ! sys_deliver = optarg; break; case 'u': ! if (*optarg) ! user_deliver = optarg; break; case 'r': ! if (*optarg) ! sender = optarg; break; case 'h': ! if (*optarg) ! hostname = optarg; break; case '?': usage(); *************** *** 199,224 **** { message("%s %s running on host %s\n", progname, version, hostname); - if (sender && *sender) - message("Sender is %s\n", sender); } ! /* Find effective and real uids and gids. */ ! eff_uid = geteuid(); ! eff_gid = getegid(); ! real_uid = getuid(); ! real_gid = getgid(); ! if (eff_uid != real_uid && eff_uid != 0) ! { ! error("if setuid, must be setuid root\n"); ! leave(1); ! } /* Renounce special privileges if something insecure was requested. */ ! if (sys_deliver || user_deliver) { if (setgid(eff_gid = real_gid) == -1 || setuid(eff_uid = real_uid) == -1) --- 241,262 ---- { message("%s %s running on host %s\n", progname, version, hostname); } ! /* Do we trust our caller? */ ! if (trusted_uid(real_uid)) ! trust_user = TRUE; ! /* Do we trust our delivery files? */ + if (strcmp(sys_default, sys_deliver) == 0 + && strcmp(user_default, user_deliver) == 0) + trust_delfiles = TRUE; + /* Renounce special privileges if something insecure was requested. */ ! if (!trust_user && !trust_delfiles) { if (setgid(eff_gid = real_gid) == -1 || setuid(eff_uid = real_uid) == -1) *************** *** 253,273 **** u |= 022; /* Let's be reasonably paranoid about writing. */ (void) umask(u); ! /* Turn off all intrusive signals (unless we're not delivering). */ ! if (! dryrun) ! { ! (void) signal(SIGHUP, SIG_IGN); ! (void) signal(SIGINT, SIG_IGN); ! (void) signal(SIGQUIT, SIG_IGN); ! } /* * Create the temporary files and write the message to them. */ ! if (copy_message() < 0) leave(1); /* * Set up useful environment variables. --- 291,337 ---- u |= 022; /* Let's be reasonably paranoid about writing. */ (void) umask(u); ! /* ! * Where is the message coming from? ! */ ! if (isatty(0)) ! tty_input = TRUE; /* + * If we are not going to deliver, or if we are receiving the + * message from a tty, catch signals so we can remove temp files. + * Otherwise, ignore signals. + */ + + if (dryrun || tty_input) + catch_sigs(); + else + ignore_sigs(); + + /* * Create the temporary files and write the message to them. */ ! copy = copy_message(); ! ! /* ! * No more signals... ! */ ! ! ignore_sigs(); ! ! /* ! * ... but if we had already caught a signal, ! * or if copy_msg() had a problem, leave. ! */ ! ! if ((copy < 0) || got_sig) ! { ! if (got_sig) ! error("caught signal - exiting\n"); leave(1); + } /* * Set up useful environment variables. *************** *** 278,294 **** setup_environ(); /* - * Assign the default delivery file names. - * Note that this must be after setup_environ(), or else the - * environment won't reflect specified/unspecified options. - */ - - if (!sys_deliver) - sys_deliver = SYS_DELIVER; - if (!user_deliver) - user_deliver = USER_DELIVER; - - /* * Perhaps we should consider all arguments as mailbox names... */ --- 342,347 ---- *************** *** 389,405 **** usage() { message("Usage: %s [-b][-A][-d][-v][-n][-t][-r from][-h host] args\n", progname); ! message("-b All arguments are mailbox filenames.\n"); ! message(" (Default: arguments are user names.)\n"); ! message("-A Resolve addresses but do not deliver.\n"); ! message("-d Be verbose but do not deliver.\n"); ! message("-v Be verbose and deliver.\n"); ! message("-n Do not run any delivery files.\n"); ! message("-t Do not remote temp files before exiting.\n"); ! message("-r from Specify the address to appear in the \"From \" line.\n"); ! message("-h host Specify the host name.\n"); ! message(" (This option overrides any \"From \" line in the input.)\n"); ! message("args Either user addresses or mailboxes (-b).\n"); leave(1); } --- 442,459 ---- usage() { message("Usage: %s [-b][-A][-d][-v][-n][-t][-r from][-h host] args\n", progname); ! message("-b All arguments are mailbox filenames.\n"); ! message(" (Default: arguments are user names.)\n"); ! message("-A Resolve addresses but do not deliver.\n"); ! message("-d Be verbose but do not deliver.\n"); ! message("-v Be verbose and deliver.\n"); ! message("-n Do not run any delivery files.\n"); ! message("-t Do not remote temp files before exiting.\n"); ! message("-s file Specify the system delivery filename.\n"); ! message("-u file Specify the user delivery filename.\n"); ! message("-r from Specify the address to appear in the \"From \" line.\n"); ! message("-h host Specify the host name.\n"); ! message("args Either user addresses or mailboxes (-b).\n"); leave(1); } *************** *** 425,430 **** --- 479,530 ---- } /*---------------------------------------------------------------------- + * Catch signals. + */ + + catch_sigs() + { + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + (void) signal(SIGHUP, sighup); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void) signal(SIGINT, sigint); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + (void) signal(SIGQUIT, sigquit); + } + + /*---------------------------------------------------------------------- + * Ignore signals. + */ + + ignore_sigs() + { + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + } + + static int + sighup() + { + (void) signal(SIGHUP, sighup); + got_sig = TRUE; + } + + static int + sigint() + { + (void) signal(SIGINT, sigint); + got_sig = TRUE; + } + + static int + sigquit() + { + (void) signal(SIGQUIT, sigquit); + got_sig = TRUE; + } + + /*---------------------------------------------------------------------- * Report any errors to stderr. * Return an error count. */ *************** *** 454,459 **** --- 554,580 ---- } return count; + } + + /*---------------------------------------------------------------------- + * Is the given uid trusted? + */ + + int + trusted_uid(uid) + int uid; + { + CONTEXT *ct; + char **n; + static char *t[] = { TRUSTED_USERS, 0 }; + + for (n = t; *n; ++n) + { + if ((ct = name_context(*n)) != NULL && uid == ct->uid) + return TRUE; + } + + return FALSE; } /*---------------------------------------------------------------------- -- Chip Salzenberg <chip@ateng.com> or <uunet!ateng!chip> A T Engineering Me? Speak for my company? Surely you jest! Beware of programmers carrying screwdrivers.