home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume16
/
deliver
/
part03
/
main.c
next >
Wrap
C/C++ Source or Header
|
1988-11-14
|
10KB
|
468 lines
/* $Header: main.c,v 1.5 88/09/14 20:00:03 network Exp $
*
* A program to deliver local mail with some flexibility.
*
* $Log: main.c,v $
* Revision 1.5 88/09/14 20:00:03 network
* Add version string, including patchlevel.
*
* Revision 1.4 88/09/14 19:41:54 network
* Portability to System V and BSD.
* General fixup.
*
* Revision 1.3 88/08/30 16:13:54 network
* Remove general subroutines to new module, subs.c.
*
* Revision 1.2 88/08/25 15:29:59 network
* Implement -s and -u options and ENV_SYSDEL and ENV_USERDEL environment
* variables. Tighten up control over effective and real uid/gid.
* In particular, renounce setuid privileges if the system or user delivery
* file is specified.
*
* Revision 1.1 88/06/06 09:38:54 chip
* Initial revision
*
*/
#include "deliver.h"
#include "patchlevel.h"
#include <signal.h>
/*
* External data.
*/
/* Variables set by getopt() [blech] */
extern int optind, opterr;
extern char *optarg;
/*
* Global data
*/
int verbose = FALSE;
int dryrun = FALSE;
int printaddrs = FALSE;
int leavetemps = FALSE;
int boxdelivery = FALSE;
char *progname = "deliver";
char version[32] = "1.0";
char *shell = SHELL;
char *sys_deliver = NULL;
char *user_deliver = NULL;
char *sender = NULL;
char *hostname = NULL;
int eff_uid = -1;
int eff_gid = -1;
int real_uid = -1;
int real_gid = -1;
CONTEXT *eff_ct = NULL;
CONTEXT *real_ct = NULL;
char *ttype[T_MAX] = { "header", "body" };
char *tfile[T_MAX] = { NULL, NULL };
int tfd[T_MAX] = { -1, -1 };
/*----------------------------------------------------------------------
* The Program.
*/
main(argc, argv)
int argc;
char **argv;
{
char *p;
int u, c, errcount, insecure;
/* Make sure that stdout and stderr are interleaved correctly */
(void) Linebuf(stdout);
(void) Linebuf(stderr);
/* Figure out the name used to invoke this program. */
progname = basename(argv[0]);
/* What version of the program is this? */
sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
/* Figure out the name of this host */
if ((hostname = gethost()) == NULL)
{
hostname = "unknown";
error("unable to determine host name; using \"%s\"\n",
hostname);
}
/* Process environment: handle recursive invocation */
if ((p = getenv(ENV_DFLAGS)) != NULL)
{
while (*p)
{
switch (*p++)
{
case 'v':
verbose = TRUE;
break;
case 'd':
verbose = TRUE;
dryrun = TRUE;
break;
case 'A':
printaddrs = TRUE;
dryrun = TRUE;
break;
case 't':
leavetemps = TRUE;
break;
}
}
}
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 */
while ((c = getopt(argc, argv, "vdAtbs:u:r:h:")) != EOF)
{
switch (c)
{
case 'v':
verbose = TRUE;
break;
case 'd':
verbose = TRUE;
dryrun = TRUE;
break;
case 'A':
printaddrs = TRUE;
dryrun = TRUE;
break;
case 't':
leavetemps = TRUE;
break;
case 'b':
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();
}
}
/* If no destinations were given, forget it. */
if (optind >= argc)
{
message("%s: no recipients specified\n", progname);
usage();
}
/* Print a debugging message */
if (verbose)
{
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)
{
message("%s: 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)
{
syserr("%s: can't renounce setuid privileges");
leave(1);
}
}
/* Get the contexts of our effective and real uids. */
if ((eff_ct = uid_context(eff_uid)) == NULL)
error("invalid effective uid %d!?\n", eff_uid);
if ((real_ct = uid_context(real_uid)) == NULL)
error("invalid real uid %d!?\n", real_uid);
if (!eff_ct || !real_ct)
leave(1);
if (verbose)
{
message("effective uid = %s (%d/%d); real uid = %s (%d/%d)\n",
eff_ct->name, eff_ct->uid, eff_ct->gid,
real_ct->name, real_ct->uid, real_ct->gid);
}
/* Let's be sane about the file creation mask. */
u = umask(0);
u &= ~0700; /* Let's not deprive ourselves of permissions. */
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.
* Note that this must be done _after_ copy_message(),
* since that's where the temp files are created.
*/
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...
*/
if (boxdelivery)
{
int a;
if (verbose)
message("mailbox delivery as %s\n", real_ct->name);
/*
* Consider all arguments as mailbox filenames.
*/
for (a = optind; a < argc; ++a)
(void) dest(real_ct->name, argv[a]);
if (verbose)
dumpdests("(should all be mailboxes)");
}
/*
* They're not mailbox names, so they should be mail addresses.
*/
else
{
/*
* Run all destinations though the system delivery file.
* If sys_dfile() doesn't find one, it will call dest()
* on each address.
*/
sys_dfile(argc - optind, argv + optind);
if (verbose)
dumpdests("after running system delivery file");
/*
* Run each user destination through his delivery file.
*/
user_dfiles();
if (verbose)
dumpdests("after running user delivery files");
}
/*
* Drop mail in mailbox(es).
*/
mbox_deliver();
if (verbose)
dumpdests("after delivery to all mailboxes");
/*
* Send mail to UUCP address(es).
*/
uucp_deliver();
if (verbose)
dumpdests("after delivery to UUCP addresses");
/*
* Report any errors, and leave.
*/
errcount = report_errors();
/*
* All done.
*/
leave(errcount ? 1 : 0);
/* NOTREACHED */
}
/*----------------------------------------------------------------------
* Print a usage message and exit.
*/
usage()
{
message("Usage: %s [-b][-A][-d][-v][-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("-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);
}
/*----------------------------------------------------------------------
* Clean up and exit.
*/
leave(code)
int code;
{
if (! leavetemps)
{
int t;
for (t = 0; t < T_MAX; ++t)
{
if (tfile[t] && unlink(tfile[t]) == -1)
syserr("can't unlink %s", tfile[t]);
}
}
exit(code);
}
/*----------------------------------------------------------------------
* Report any errors to stderr.
* Return an error count.
*/
int
report_errors()
{
DEST *d;
int count = 0;
for (d = first_dest(); d; d = next_dest(d))
{
if (d->state != ST_ERROR)
continue;
if (++count == 1)
{
error(
"delivery to the following address(es) failed on host %s\n",
hostname);
}
message("\tuser \"%s\"", d->name);
if (d->class == CL_MBOX)
message(", mailbox \"%s\"", d->mailbox);
message(": %s\n", d->error);
}
return count;
}
/*----------------------------------------------------------------------
* Set up useful environment variables.
*/
setup_environ()
{
char flags[8];
int f = 0;
flags[f++] = '-';
if (verbose)
flags[f++] = (dryrun ? 'd' : 'v');
if (printaddrs)
flags[f++] = 'A';
if (leavetemps)
flags[f++] = 't';
flags[f] = 0;
alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
if (sys_deliver && *sys_deliver)
alloc_env(ENV_SYSDEL, sys_deliver);
if (user_deliver && *user_deliver)
alloc_env(ENV_USERDEL, user_deliver);
if (hostname && *hostname)
alloc_env(ENV_HOSTNAME, hostname);
if (sender && *sender)
alloc_env(ENV_SENDER, sender);
alloc_env(ENV_HEADER, tfile[T_HEADER]);
alloc_env(ENV_BODY, tfile[T_BODY]);
alloc_env("IFS", " \t\n");
}