From 955eb5e1fb25fc64c2c34501c3d9426057e3b1f8 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 15 Jul 2019 17:24:25 -0700 Subject: 10167 unable to check out illumos-gate on Windows Reviewed by: Andy Fiddaman Reviewed by: Yuri Pankov Reviewed by: Andrew Stormont Approved by: Dan McDonald --- usr/src/cmd/sendmail/Makefile | 6 +- usr/src/cmd/sendmail/aux/Makefile | 125 ---- usr/src/cmd/sendmail/aux/editmap.c | 422 ----------- usr/src/cmd/sendmail/aux/etrn.pl | 273 ------- usr/src/cmd/sendmail/aux/mail.local.c | 1225 -------------------------------- usr/src/cmd/sendmail/aux/mailcompat.c | 339 --------- usr/src/cmd/sendmail/aux/mailq.c | 62 -- usr/src/cmd/sendmail/aux/mailstats.c | 369 ---------- usr/src/cmd/sendmail/aux/makemap.c | 528 -------------- usr/src/cmd/sendmail/aux/mconnect.c | 240 ------- usr/src/cmd/sendmail/aux/praliases.c | 399 ----------- usr/src/cmd/sendmail/aux/rfc2047.c | 289 -------- usr/src/cmd/sendmail/aux/smrsh.c | 442 ------------ usr/src/cmd/sendmail/aux/vacation.c | 1158 ------------------------------ usr/src/cmd/sendmail/util/Makefile | 125 ++++ usr/src/cmd/sendmail/util/editmap.c | 422 +++++++++++ usr/src/cmd/sendmail/util/etrn.pl | 273 +++++++ usr/src/cmd/sendmail/util/mail.local.c | 1225 ++++++++++++++++++++++++++++++++ usr/src/cmd/sendmail/util/mailcompat.c | 339 +++++++++ usr/src/cmd/sendmail/util/mailq.c | 62 ++ usr/src/cmd/sendmail/util/mailstats.c | 369 ++++++++++ usr/src/cmd/sendmail/util/makemap.c | 528 ++++++++++++++ usr/src/cmd/sendmail/util/mconnect.c | 240 +++++++ usr/src/cmd/sendmail/util/praliases.c | 399 +++++++++++ usr/src/cmd/sendmail/util/rfc2047.c | 289 ++++++++ usr/src/cmd/sendmail/util/smrsh.c | 442 ++++++++++++ usr/src/cmd/sendmail/util/vacation.c | 1158 ++++++++++++++++++++++++++++++ 27 files changed, 5875 insertions(+), 5873 deletions(-) delete mode 100644 usr/src/cmd/sendmail/aux/Makefile delete mode 100644 usr/src/cmd/sendmail/aux/editmap.c delete mode 100644 usr/src/cmd/sendmail/aux/etrn.pl delete mode 100644 usr/src/cmd/sendmail/aux/mail.local.c delete mode 100644 usr/src/cmd/sendmail/aux/mailcompat.c delete mode 100644 usr/src/cmd/sendmail/aux/mailq.c delete mode 100644 usr/src/cmd/sendmail/aux/mailstats.c delete mode 100644 usr/src/cmd/sendmail/aux/makemap.c delete mode 100644 usr/src/cmd/sendmail/aux/mconnect.c delete mode 100644 usr/src/cmd/sendmail/aux/praliases.c delete mode 100644 usr/src/cmd/sendmail/aux/rfc2047.c delete mode 100644 usr/src/cmd/sendmail/aux/smrsh.c delete mode 100644 usr/src/cmd/sendmail/aux/vacation.c create mode 100644 usr/src/cmd/sendmail/util/Makefile create mode 100644 usr/src/cmd/sendmail/util/editmap.c create mode 100644 usr/src/cmd/sendmail/util/etrn.pl create mode 100644 usr/src/cmd/sendmail/util/mail.local.c create mode 100644 usr/src/cmd/sendmail/util/mailcompat.c create mode 100644 usr/src/cmd/sendmail/util/mailq.c create mode 100644 usr/src/cmd/sendmail/util/mailstats.c create mode 100644 usr/src/cmd/sendmail/util/makemap.c create mode 100644 usr/src/cmd/sendmail/util/mconnect.c create mode 100644 usr/src/cmd/sendmail/util/praliases.c create mode 100644 usr/src/cmd/sendmail/util/rfc2047.c create mode 100644 usr/src/cmd/sendmail/util/smrsh.c create mode 100644 usr/src/cmd/sendmail/util/vacation.c (limited to 'usr/src/cmd/sendmail') diff --git a/usr/src/cmd/sendmail/Makefile b/usr/src/cmd/sendmail/Makefile index 604b8d2959..ff427c0fde 100644 --- a/usr/src/cmd/sendmail/Makefile +++ b/usr/src/cmd/sendmail/Makefile @@ -23,14 +23,16 @@ # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright 2019 Garrett D'Amore +# # cmd/sendmail/Makefile # # Makefile for top level sendmail source directory # # static libraries (db, libsm, libsmdb, libsmutil) must be built before -# src and aux -SUBDIRS= cf lib db libsm libsmdb libsmutil .WAIT src aux +# src and util +SUBDIRS= cf lib db libsm libsmdb libsmutil .WAIT src util include ../Makefile.cmd diff --git a/usr/src/cmd/sendmail/aux/Makefile b/usr/src/cmd/sendmail/aux/Makefile deleted file mode 100644 index 455879af02..0000000000 --- a/usr/src/cmd/sendmail/aux/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# cmd/sendmail/aux/Makefile -# -include ../../Makefile.cmd -include ../Makefile.cmd - -PROG= mailstats mconnect vacation mailcompat praliases - -LIBPROG= mail.local smrsh - -USRSBINPROG= etrn makemap editmap - -LIBSMTPSMPROG= mailq - -# $(PROG) by default -CLOBBERFILES= $(LIBPROG) $(USRSBINPROG) $(LIBSMTPSMPROG) - -OBJS= $(PROG:%=%.o) - -.PARALLEL: $(OBJS) $(PROG) $(LIBPROG) $(USRSBINPROG) - -SRCS= $(PROG:%=%.c) - -editmap := LDLIBS += -lldap -mail.local := LDLIBS += -lsocket -lnsl -lmail -lldap -mailq := LDLIBS += -lsecdb -mailstats := LDLIBS += -lldap -makemap := LDLIBS += -lldap -mconnect := LDLIBS += -lsocket -lnsl -praliases := LDLIBS += -lldap -smrsh := LDLIBS += -lldap -vacation := LDLIBS += -lldap -$(ROOTLIBSMTPSM)/mailq := FILEMODE = 4555 - -INCPATH= -I../src -I../db -I../include - -ENVDEF= -DNOT_SENDMAIL -SUNENVDEF= -DSUN_EXTENSIONS -DUSE_VENDOR_CF_PATH -DBMDEF= -DNDBM -DNEWDB - -CPPFLAGS = $(INCPATH) $(ENVDEF) $(SUNENVDEF) $(DBMDEF) $(CPPFLAGS.sm) - -# Nearly every support application provides sleep(). This isn't incompatible -# with libc, but can be confined to the applications themselves. -LDFLAGS += $(MAPFILE.NGB:%=-M%) - -.KEEP_STATE: - -all: $(PROG) $(LIBSMTPSMPROG) $(LIBPROG) $(USRSBINPROG) - -convtime.o: ../src/convtime.c - $(COMPILE.c) ../src/convtime.c - $(POST_PROCESS_O) - -vacation: vacation.o convtime.o rfc2047.o ../libsm/libsm.a - $(LINK.c) vacation.o convtime.o rfc2047.o -o $@ $(LDLIBS) \ - ../libsm/libsm.a - $(POST_PROCESS) - -mail.local: mail.local.o ../libsmutil/libsmutil.a ../libsm/libsm.a - $(LINK.c) mail.local.o -o $@ $(LDLIBS) ../libsmutil/libsmutil.a \ - ../libsm/libsm.a - $(POST_PROCESS) - -smrsh: smrsh.o ../libsm/libsm.a - $(LINK.c) smrsh.o -o $@ $(LDLIBS) ../libsm/libsm.a - $(POST_PROCESS) - -makemap: makemap.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ - ../db/libdb.a ../libsm/libsm.a - $(LINK.c) makemap.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ - ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a - $(POST_PROCESS) - -editmap: editmap.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ - ../db/libdb.a ../libsm/libsm.a - $(LINK.c) editmap.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ - ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a - $(POST_PROCESS) - -praliases: praliases.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ - ../libsm/libsm.a - $(LINK.c) praliases.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ - ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a - $(POST_PROCESS) - -mailstats: mailstats.o ../libsmutil/libsmutil.a ../libsm/libsm.a - $(LINK.c) mailstats.o -o $@ $(LDLIBS) ../libsmutil/libsmutil.a \ - ../libsm/libsm.a - $(POST_PROCESS) - -install: all $(ROOTPROG) $(ROOTLIB)/mail.local $(ROOTLIB)/smrsh \ - $(ROOTLIBSMTPSM)/mailq $(ROOTUSRSBIN)/makemap \ - $(ROOTUSRSBIN)/etrn $(ROOTUSRSBIN)/editmap - -clean: - $(RM) $(OBJS) *.o - -lint: lint_PROG - - -include ../../Makefile.targ diff --git a/usr/src/cmd/sendmail/aux/editmap.c b/usr/src/cmd/sendmail/aux/editmap.c deleted file mode 100644 index a86a24d456..0000000000 --- a/usr/src/cmd/sendmail/aux/editmap.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1992 Eric P. Allman. All rights reserved. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include -#ifndef lint -SM_UNUSED(static char copyright[]) = -"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ - Copyright (c) 1992, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* ! lint */ - -#ifndef lint -SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.25 2007/05/11 18:50:35 ca Exp $"; -#endif /* ! lint */ - - -#include -#ifndef ISC_UNIX -# include -#endif /* ! ISC_UNIX */ -#include -#include -#include -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include -#include -#include -#include -#include - -uid_t RealUid; -gid_t RealGid; -char *RealUserName; -uid_t RunAsUid; -gid_t RunAsGid; -char *RunAsUserName; -int Verbose = 2; -bool DontInitGroups = false; -uid_t TrustedUid = 0; -BITMAP256 DontBlameSendmail; - -#define BUFSIZE 1024 -#define ISSEP(c) (isascii(c) && isspace(c)) - - -static void usage __P((char *)); - -static void -usage(progname) - char *progname; -{ - fprintf(stderr, - "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n", - progname); - exit(EX_USAGE); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - char *progname; - char *cfile; - bool verbose = false; - bool query = false; - bool update = false; - bool remove = false; - bool inclnull = false; - bool foldcase = true; - unsigned int nops = 0; - int exitstat; - int opt; - char *typename = NULL; - char *mapname = NULL; - char *keyname = NULL; - char *value = NULL; - int mode; - int smode; - int putflags = 0; - long sff = SFF_ROOTOK|SFF_REGONLY; - struct passwd *pw; - SMDB_DATABASE *database; - SMDB_DBENT db_key, db_val; - SMDB_DBPARAMS params; - SMDB_USER_INFO user_info; -#if HASFCHOWN - FILE *cfp; - char buf[MAXLINE]; -#endif /* HASFCHOWN */ - static char rnamebuf[MAXNAME]; /* holds RealUserName */ - extern char *optarg; - extern int optind; - - memset(¶ms, '\0', sizeof params); - params.smdbp_cache_size = 1024 * 1024; - - progname = strrchr(argv[0], '/'); - if (progname != NULL) - progname++; - else - progname = argv[0]; - cfile = _PATH_SENDMAILCF; - - clrbitmap(DontBlameSendmail); - RunAsUid = RealUid = getuid(); - RunAsGid = RealGid = getgid(); - pw = getpwuid(RealUid); - if (pw != NULL) - (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); - else - (void) sm_snprintf(rnamebuf, sizeof rnamebuf, - "Unknown UID %d", (int) RealUid); - RunAsUserName = RealUserName = rnamebuf; - user_info.smdbu_id = RunAsUid; - user_info.smdbu_group_id = RunAsGid; - (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, - SMDB_MAX_USER_NAME_LEN); - -#define OPTIONS "C:fquxvN" - while ((opt = getopt(argc, argv, OPTIONS)) != -1) - { - switch (opt) - { - case 'C': - cfile = optarg; - break; - - case 'f': - foldcase = false; - break; - - case 'q': - query = true; - nops++; - break; - - case 'u': - update = true; - nops++; - break; - - case 'x': - remove = true; - nops++; - break; - - case 'v': - verbose = true; - break; - - case 'N': - inclnull = true; - break; - - default: - usage(progname); - assert(0); /* NOTREACHED */ - } - } - - if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) - sff |= SFF_NOSLINK; - if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) - sff |= SFF_NOHLINK; - if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) - sff |= SFF_NOWLINK; - - argc -= optind; - argv += optind; - if ((nops != 1) || - (query && argc != 3) || - (remove && argc != 3) || - (update && argc <= 3)) - { - usage(progname); - assert(0); /* NOTREACHED */ - } - - typename = argv[0]; - mapname = argv[1]; - keyname = argv[2]; - if (update) - value = argv[3]; - - if (foldcase) - { - char *p; - - for (p = keyname; *p != '\0'; p++) - { - if (isascii(*p) && isupper(*p)) - *p = tolower(*p); - } - } - - -#if HASFCHOWN - /* Find TrustedUser value in sendmail.cf */ - if ((cfp = fopen(cfile, "r")) == NULL) - { - fprintf(stderr, "%s: %s: %s\n", progname, - cfile, sm_errstring(errno)); - exit(EX_NOINPUT); - } - while (fgets(buf, sizeof(buf), cfp) != NULL) - { - register char *b; - - if ((b = strchr(buf, '\n')) != NULL) - *b = '\0'; - - b = buf; - switch (*b++) - { - case 'O': /* option */ - if (strncasecmp(b, " TrustedUser", 12) == 0 && - !(isascii(b[12]) && isalnum(b[12]))) - { - b = strchr(b, '='); - if (b == NULL) - continue; - while (isascii(*++b) && isspace(*b)) - continue; - if (isascii(*b) && isdigit(*b)) - TrustedUid = atoi(b); - else - { - TrustedUid = 0; - pw = getpwnam(b); - if (pw == NULL) - fprintf(stderr, - "TrustedUser: unknown user %s\n", b); - else - TrustedUid = pw->pw_uid; - } - -# ifdef UID_MAX - if (TrustedUid > UID_MAX) - { - fprintf(stderr, - "TrustedUser: uid value (%ld) > UID_MAX (%ld)", - (long) TrustedUid, - (long) UID_MAX); - TrustedUid = 0; - } -# endif /* UID_MAX */ - break; - } - /* FALLTHROUGH */ - - default: - continue; - } - } - (void) fclose(cfp); -#endif /* HASFCHOWN */ - - if (query) - { - mode = O_RDONLY; - smode = S_IRUSR; - } - else - { - mode = O_RDWR | O_CREAT; - sff |= SFF_CREAT|SFF_NOTEXCL; - smode = S_IWUSR; - } - - params.smdbp_num_elements = 4096; - - errno = smdb_open_database(&database, mapname, mode, smode, sff, - typename, &user_info, ¶ms); - if (errno != SMDBE_OK) - { - char *hint; - - if (errno == SMDBE_UNSUPPORTED_DB_TYPE && - (hint = smdb_db_definition(typename)) != NULL) - fprintf(stderr, - "%s: Need to recompile with -D%s for %s support\n", - progname, hint, typename); - else - fprintf(stderr, - "%s: error opening type %s map %s: %s\n", - progname, typename, mapname, - sm_errstring(errno)); - exit(EX_CANTCREAT); - } - - (void) database->smdb_sync(database, 0); - - if (geteuid() == 0 && TrustedUid != 0) - { - errno = database->smdb_set_owner(database, TrustedUid, -1); - if (errno != SMDBE_OK) - { - fprintf(stderr, - "WARNING: ownership change on %s failed %s", - mapname, sm_errstring(errno)); - } - } - - exitstat = EX_OK; - if (query) - { - memset(&db_key, '\0', sizeof db_key); - memset(&db_val, '\0', sizeof db_val); - - db_key.data = keyname; - db_key.size = strlen(keyname); - if (inclnull) - db_key.size++; - - errno = database->smdb_get(database, &db_key, &db_val, 0); - if (errno != SMDBE_OK) - { - /* XXX - Need to distinguish between not found */ - fprintf(stderr, - "%s: couldn't find key %s in map %s\n", - progname, keyname, mapname); - exitstat = EX_UNAVAILABLE; - } - else - { - printf("%.*s\n", (int) db_val.size, - (char *) db_val.data); - } - } - else if (update) - { - memset(&db_key, '\0', sizeof db_key); - memset(&db_val, '\0', sizeof db_val); - - db_key.data = keyname; - db_key.size = strlen(keyname); - if (inclnull) - db_key.size++; - db_val.data = value; - db_val.size = strlen(value); - if (inclnull) - db_val.size++; - - errno = database->smdb_put(database, &db_key, &db_val, - putflags); - if (errno != SMDBE_OK) - { - fprintf(stderr, - "%s: error updating (%s, %s) in map %s: %s\n", - progname, keyname, value, mapname, - sm_errstring(errno)); - exitstat = EX_IOERR; - } - } - else if (remove) - { - memset(&db_key, '\0', sizeof db_key); - memset(&db_val, '\0', sizeof db_val); - - db_key.data = keyname; - db_key.size = strlen(keyname); - if (inclnull) - db_key.size++; - - errno = database->smdb_del(database, &db_key, 0); - - switch (errno) - { - case SMDBE_NOT_FOUND: - fprintf(stderr, - "%s: key %s doesn't exist in map %s\n", - progname, keyname, mapname); - /* Don't set exitstat */ - break; - case SMDBE_OK: - /* All's well */ - break; - default: - fprintf(stderr, - "%s: couldn't remove key %s in map %s (error)\n", - progname, keyname, mapname); - exitstat = EX_IOERR; - break; - } - } - else - { - assert(0); /* NOT REACHED */ - } - - /* - ** Now close the database. - */ - - errno = database->smdb_close(database); - if (errno != SMDBE_OK) - { - fprintf(stderr, "%s: close(%s): %s\n", - progname, mapname, sm_errstring(errno)); - exitstat = EX_IOERR; - } - smdb_free_database(database); - - exit(exitstat); - /* NOTREACHED */ - return exitstat; -} diff --git a/usr/src/cmd/sendmail/aux/etrn.pl b/usr/src/cmd/sendmail/aux/etrn.pl deleted file mode 100644 index fc067b1a6a..0000000000 --- a/usr/src/cmd/sendmail/aux/etrn.pl +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/perl5/bin/perl -w -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (the "License"). -# You may not use this file except in compliance with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# Copyright (c) 1996-2000 by John T. Beck -# All rights reserved. -# -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -require 5.8.4; # minimal Perl version required -use strict; -use warnings; -use English; - -use Socket; -use Getopt::Std; -our ($opt_v, $opt_b); - -# system requirements: -# must have 'hostname' program. - -my $port = 'smtp'; -select(STDERR); - -chop(my $name = `hostname || uname -n`); - -my ($hostname) = (gethostbyname($name))[0]; - -my $usage = "Usage: $PROGRAM_NAME [-bv] host [args]"; -getopts('bv'); -my $verbose = $opt_v; -my $boot_check = $opt_b; -my $server = shift(@ARGV); -my @hosts = @ARGV; -die $usage unless $server; -my @cwfiles = (); -my $alarm_action = ""; - -if (!@hosts) { - push(@hosts, $hostname); - - open(CF, "){ - # look for a line starting with "Fw" - if (/^Fw.*$/) { - my $cwfile = $ARG; - chop($cwfile); - my $optional = /^Fw-o/; - # extract the file name - $cwfile =~ s,^Fw[^/]*,,; - - # strip the options after the filename - $cwfile =~ s/ [^ ]+$//; - - if (-r $cwfile) { - push (@cwfiles, $cwfile); - } else { - die "$cwfile is not readable" unless $optional; - } - } - # look for a line starting with "Cw" - if (/^Cw(.*)$/) { - my @cws = split (' ', $1); - while (@cws) { - my $thishost = shift(@cws); - push(@hosts, $thishost) - unless $thishost =~ "$hostname|localhost"; - } - } - } - close(CF); - - for my $cwfile (@cwfiles) { - if (open(CW, "<$cwfile")) { - while () { - next if /^\#/; - my $thishost = $ARG; - chop($thishost); - push(@hosts, $thishost) - unless $thishost =~ $hostname; - } - close(CW); - } else { - die "open $cwfile: $ERRNO"; - } - } - # Do this automatically if no client hosts are specified. - $boot_check = "yes"; -} - -my ($proto) = (getprotobyname('tcp'))[2]; -($port) = (getservbyname($port, 'tcp'))[2] - unless $port =~ /^\d+/; - -if ($boot_check) { - # first connect to localhost to verify that we can accept connections - print "verifying that localhost is accepting SMTP connections\n" - if ($verbose); - my $localhost_ok = 0; - ($name, my $laddr) = (gethostbyname('localhost'))[0, 4]; - (!defined($name)) && die "gethostbyname failed, unknown host $server"; - - # get a connection - my $sinl = sockaddr_in($port, $laddr); - my $save_errno = 0; - for (my $num_tries = 1; $num_tries < 5; $num_tries++) { - socket(S, &PF_INET, &SOCK_STREAM, $proto) - || die "socket: $ERRNO"; - if (connect(S, $sinl)) { - &alarm("sending 'quit' to $server"); - print S "quit\n"; - alarm(0); - $localhost_ok = 1; - close(S); - alarm(0); - last; - } - print STDERR "localhost connect failed ($num_tries)\n"; - $save_errno = $ERRNO; - sleep(1 << $num_tries); - close(S); - alarm(0); - } - if (! $localhost_ok) { - die "could not connect to localhost: $save_errno\n"; - } -} - -# look it up - -($name, my $thataddr) = (gethostbyname($server))[0, 4]; -(!defined($name)) && die "gethostbyname failed, unknown host $server"; - -# get a connection -my $sinr = sockaddr_in($port, $thataddr); -socket(S, &PF_INET, &SOCK_STREAM, $proto) - || die "socket: $ERRNO"; -print "server = $server\n" if (defined($verbose)); -&alarm("connect to $server"); -if (! connect(S, $sinr)) { - die "cannot connect to $server: $ERRNO\n"; -} -alarm(0); -select((select(S), $OUTPUT_AUTOFLUSH = 1)[0]); # don't buffer output to S - -# read the greeting -&alarm("greeting with $server"); -while () { - alarm(0); - print if $verbose; - if (/^(\d+)([- ])/) { - # SMTP's initial greeting response code is 220. - if ($1 != 220) { - &alarm("giving up after bad response from $server"); - &read_response($2, $verbose); - alarm(0); - print STDERR "$server: NOT 220 greeting: $ARG" - if ($verbose); - } - last if ($2 eq " "); - } else { - print STDERR "$server: NOT 220 greeting: $ARG" - if ($verbose); - close(S); - } - &alarm("greeting with $server"); -} -alarm(0); - -&alarm("sending ehlo to $server"); -&ps("ehlo $hostname"); -my $etrn_support = 0; -while () { - if (/^250([- ])ETRN(.+)$/) { - $etrn_support = 1; - } - print if $verbose; - last if /^\d+ /; -} -alarm(0); - -if ($etrn_support) { - print "ETRN supported\n" if ($verbose); - &alarm("sending etrn to $server"); - while (@hosts) { - $server = shift(@hosts); - &ps("etrn $server"); - while () { - print if $verbose; - last if /^\d+ /; - } - sleep(1); - } -} else { - print "\nETRN not supported\n\n" -} - -&alarm("sending 'quit' to $server"); -&ps("quit"); -while () { - print if $verbose; - last if /^\d+ /; -} -close(S); -alarm(0); - -select(STDOUT); -exit(0); - -# print to the server (also to stdout, if -v) -sub ps -{ - my ($p) = @_; - print ">>> $p\n" if $verbose; - print S "$p\n"; -} - -sub alarm -{ - ($alarm_action) = @_; - alarm(10); - $SIG{ALRM} = 'handle_alarm'; -} - -sub handle_alarm -{ - &giveup($alarm_action); -} - -sub giveup -{ - my $reason = @_; - (my $pk, my $file, my $line); - ($pk, $file, $line) = caller; - - print "Timed out during $reason\n" if $verbose; - exit(1); -} - -# read the rest of the current smtp daemon's response (and toss it away) -sub read_response -{ - (my $done, $verbose) = @_; - (my @resp); - print my $s if $verbose; - while (($done eq "-") && ($s = ) && ($s =~ /^\d+([- ])/)) { - print $s if $verbose; - $done = $1; - push(@resp, $s); - } - return @resp; -} diff --git a/usr/src/cmd/sendmail/aux/mail.local.c b/usr/src/cmd/sendmail/aux/mail.local.c deleted file mode 100644 index 0d04d3c58c..0000000000 --- a/usr/src/cmd/sendmail/aux/mail.local.c +++ /dev/null @@ -1,1225 +0,0 @@ -/* - * Copyright (c) 1998 Sendmail, Inc. All rights reserved. - * Copyright (c) 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level - * of the sendmail distribution. - */ - -/* - * Copyright 1994-2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1990, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifndef lint -static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/98"; -static char sccsi2[] = "%W% (Sun) %G%"; -#endif /* not lint */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __STDC__ -#include -#else -#include -#endif - -#include - -#include -#include - -#include -#include - -/* -** If you don't have flock, you could try using lockf instead. -*/ - -#ifdef LDA_USE_LOCKF -# define flock(a, b) lockf(a, b, 0) -# ifdef LOCK_EX -# undef LOCK_EX -# endif /* LOCK_EX */ -# define LOCK_EX F_LOCK -#endif /* LDA_USE_LOCKF */ - -#ifndef LOCK_EX -# include -#endif /* ! LOCK_EX */ - -#ifndef MAILER_DAEMON -# define MAILER_DAEMON "MAILER-DAEMON" -#endif - -typedef int bool; - -#define FALSE 0 -#define TRUE 1 - -bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */ -static int eval = EX_OK; /* sysexits.h error value. */ -static int lmtpmode = 0; -bool bouncequota = FALSE; /* permanent error when over quota */ - -#define _PATH_MAILDIR "/var/mail" -#define _PATH_LOCTMP "/tmp/local.XXXXXX" -#define _PATH_LOCHTMP "/tmp/lochd.XXXXXX" -#define FALSE 0 -#define TRUE 1 -#define MAXLINE 2048 - -static void deliver(int, int, char *, bool); -static void e_to_sys(int); -static void err(const char *fmt, ...); -static void notifybiff(char *); -static void store(char *, int); -static void usage(void); -static void vwarn(); -static void warn(const char *fmt, ...); -static void mailerr(const char *, const char *, ...); -static void sigterm_handler(); - -static char unix_from_line[MAXLINE]; -static int ulen; -static int content_length; -static int bfd, hfd; /* temp file */ -static uid_t src_uid, targ_uid, saved_uid; -static int sigterm_caught; - -int -main(argc, argv) - int argc; - char *argv[]; -{ - struct passwd *pw; - int ch; - uid_t uid; - char *from; - struct group *grpptr; - void dolmtp(); - - openlog("mail.local", 0, LOG_MAIL); - - from = NULL; - pw = NULL; - sigterm_caught = FALSE; - - (void) sigset(SIGTERM, sigterm_handler); - - while ((ch = getopt(argc, argv, "7bdf:r:l")) != EOF) - switch (ch) { - case '7': /* Do not advertise 8BITMIME */ - EightBitMime = FALSE; - break; - - case 'b': /* bounce mail when over quota. */ - bouncequota = TRUE; - break; - - case 'd': /* Backward compatible. */ - break; - case 'f': - case 'r': /* Backward compatible. */ - if (from != NULL) { - warn("multiple -f options"); - usage(); - } - from = optarg; - break; - case 'l': - lmtpmode++; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - notifybiff(NULL); /* initialize biff structures */ - - /* - * We expect sendmail will invoke us with saved id 0 - * We then do setgid and setuid defore delivery - * setgid to mail group - */ - if ((grpptr = getgrnam("mail")) != NULL) - (void) setgid(grpptr->gr_gid); - saved_uid = geteuid(); - - if (lmtpmode) { - if (saved_uid != 0) { - warn("only super-user can use -l option"); - exit(EX_CANTCREAT); - } - dolmtp(bouncequota); - } - - if (!*argv) - usage(); - - /* - * If from not specified, use the name from getlogin() if the - * uid matches, otherwise, use the name from the password file - * corresponding to the uid. - */ - uid = getuid(); - if (!from && (!(from = getlogin()) || - !(pw = getpwnam(from)) || pw->pw_uid != uid)) - from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; - src_uid = pw ? pw->pw_uid : uid; - - /* - * There is no way to distinguish the error status of one delivery - * from the rest of the deliveries. So, if we failed hard on one - * or more deliveries, but had no failures on any of the others, we - * return a hard failure. If we failed temporarily on one or more - * deliveries, we return a temporary failure regardless of the other - * failures. This results in the delivery being reattempted later - * at the expense of repeated failures and multiple deliveries. - */ - - for (store(from, 0); *argv; ++argv) - deliver(hfd, bfd, *argv, bouncequota); - return (eval); -} - -void -sigterm_handler() -{ - sigterm_caught = TRUE; - (void) sigignore(SIGTERM); -} - -char * -parseaddr(s) - char *s; -{ - char *p; - int len; - - if (*s++ != '<') - return NULL; - - p = s; - - /* at-domain-list */ - while (*p == '@') { - p++; - if (*p == '[') { - p++; - while (isascii(*p) && - (isalnum(*p) || *p == '.' || - *p == '-' || *p == ':')) - p++; - if (*p++ != ']') - return NULL; - } else { - while ((isascii(*p) && isalnum(*p)) || - strchr(".-_", *p)) - p++; - } - if (*p == ',' && p[1] == '@') - p++; - else if (*p == ':' && p[1] != '@') - p++; - else - return NULL; - } - - s = p; - - /* local-part */ - if (*p == '\"') { - p++; - while (*p && *p != '\"') { - if (*p == '\\') { - if (!*++p) - return NULL; - } - p++; - } - if (!*p++) - return NULL; - } else { - while (*p && *p != '@' && *p != '>') { - if (*p == '\\') { - if (!*++p) - return NULL; - } else { - if (*p <= ' ' || (*p & 128) || - strchr("<>()[]\\,;:\"", *p)) - return NULL; - } - p++; - } - } - - /* @domain */ - if (*p == '@') { - p++; - if (*p == '[') { - p++; - while (isascii(*p) && - (isalnum(*p) || *p == '.' || - *p == '-' || *p == ':')) - p++; - if (*p++ != ']') - return NULL; - } else { - while ((isascii(*p) && isalnum(*p)) || - strchr(".-_", *p)) - p++; - } - } - - if (*p++ != '>') - return NULL; - if (*p && *p != ' ') - return NULL; - len = p - s - 1; - - if (*s == '\0' || len <= 0) - { - s = MAILER_DAEMON; - len = strlen(s); - } - - p = malloc(len + 1); - if (p == NULL) { - printf("421 4.3.0 memory exhausted\r\n"); - exit(EX_TEMPFAIL); - } - - strncpy(p, s, len); - p[len] = '\0'; - return p; -} - -char * -process_recipient(addr) - char *addr; -{ - if (getpwnam(addr) == NULL) { - return "550 5.1.1 user unknown"; - } - - return NULL; -} - -#define RCPT_GROW 30 - -void -dolmtp(bouncequota) - bool bouncequota; -{ - char *return_path = NULL; - char **rcpt_addr = NULL; - int rcpt_num = 0; - int rcpt_alloc = 0; - bool gotlhlo = FALSE; - char myhostname[MAXHOSTNAMELEN]; - char buf[4096]; - char *err; - char *p; - int i; - - gethostname(myhostname, sizeof myhostname - 1); - - printf("220 %s LMTP ready\r\n", myhostname); - for (;;) { - if (sigterm_caught) { - for (; rcpt_num > 0; rcpt_num--) - printf("451 4.3.0 shutting down\r\n"); - exit(EX_OK); - } - fflush(stdout); - if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { - exit(EX_OK); - } - p = buf + strlen(buf) - 1; - if (p >= buf && *p == '\n') - *p-- = '\0'; - if (p >= buf && *p == '\r') - *p-- = '\0'; - - switch (buf[0]) { - - case 'd': - case 'D': - if (strcasecmp(buf, "data") == 0) { - if (rcpt_num == 0) { - printf("503 5.5.1 No recipients\r\n"); - continue; - } - store(return_path, rcpt_num); - if (bfd == -1 || hfd == -1) - continue; - - for (i = 0; i < rcpt_num; i++) { - p = strchr(rcpt_addr[i], '+'); - if (p != NULL) - *p++ = '\0'; - deliver(hfd, bfd, rcpt_addr[i], - bouncequota); - } - close(bfd); - close(hfd); - goto rset; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'l': - case 'L': - if (strncasecmp(buf, "lhlo ", 5) == 0) - { - /* check for duplicate per RFC 1651 4.2 */ - if (gotlhlo) - { - printf("503 %s Duplicate LHLO\r\n", - myhostname); - continue; - } - gotlhlo = TRUE; - printf("250-%s\r\n", myhostname); - if (EightBitMime) - printf("250-8BITMIME\r\n"); - printf("250-ENHANCEDSTATUSCODES\r\n"); - printf("250 PIPELINING\r\n"); - continue; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'm': - case 'M': - if (strncasecmp(buf, "mail ", 5) == 0) { - if (return_path != NULL) { - printf("503 5.5.1 Nested MAIL command\r\n"); - continue; - } - if (strncasecmp(buf+5, "from:", 5) != 0 || - ((return_path = parseaddr(buf+10)) == NULL)) { - printf("501 5.5.4 Syntax error in parameters\r\n"); - continue; - } - printf("250 2.5.0 ok\r\n"); - continue; - } - goto syntaxerr; - - case 'n': - case 'N': - if (strcasecmp(buf, "noop") == 0) { - printf("250 2.0.0 ok\r\n"); - continue; - } - goto syntaxerr; - - case 'q': - case 'Q': - if (strcasecmp(buf, "quit") == 0) { - printf("221 2.0.0 bye\r\n"); - exit(EX_OK); - } - goto syntaxerr; - - case 'r': - case 'R': - if (strncasecmp(buf, "rcpt ", 5) == 0) { - if (return_path == NULL) { - printf("503 5.5.1 Need MAIL command\r\n"); - continue; - } - if (rcpt_num >= rcpt_alloc) { - rcpt_alloc += RCPT_GROW; - rcpt_addr = (char **) - realloc((char *)rcpt_addr, - rcpt_alloc * sizeof(char **)); - if (rcpt_addr == NULL) { - printf("421 4.3.0 memory exhausted\r\n"); - exit(EX_TEMPFAIL); - } - } - if (strncasecmp(buf+5, "to:", 3) != 0 || - ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) { - printf("501 5.5.4 Syntax error in parameters\r\n"); - continue; - } - if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) { - printf("%s\r\n", err); - continue; - } - rcpt_num++; - printf("250 2.1.5 ok\r\n"); - continue; - } - else if (strcasecmp(buf, "rset") == 0) { - printf("250 2.0.0 ok\r\n"); - - rset: - while (rcpt_num > 0) { - free(rcpt_addr[--rcpt_num]); - } - if (return_path != NULL) - free(return_path); - return_path = NULL; - continue; - } - goto syntaxerr; - - case 'v': - case 'V': - if (strncasecmp(buf, "vrfy ", 5) == 0) { - printf("252 2.3.3 try RCPT to attempt delivery\r\n"); - continue; - } - goto syntaxerr; - - default: - syntaxerr: - printf("500 5.5.2 Syntax error\r\n"); - continue; - } - } -} - -static void -store(from, lmtprcpts) - char *from; - int lmtprcpts; -{ - FILE *fp = NULL; - time_t tval; - bool fullline = TRUE; /* current line is terminated */ - bool prevfl; /* previous line was terminated */ - char line[MAXLINE]; - FILE *bfp, *hfp; - char *btn, *htn; - int in_header_section; - int newfd; - - bfd = -1; - hfd = -1; - btn = strdup(_PATH_LOCTMP); - if ((bfd = mkstemp(btn)) == -1 || (bfp = fdopen(bfd, "w+")) == NULL) { - if (bfd != -1) - (void) close(bfd); - if (lmtprcpts) { - printf("451 4.3.0 unable to open temporary file\r\n"); - return; - } else { - mailerr("451 4.3.0", "unable to open temporary file"); - exit(eval); - } - } - (void) unlink(btn); - free(btn); - - if (lmtpmode) { - printf("354 go ahead\r\n"); - fflush(stdout); - } - - htn = strdup(_PATH_LOCHTMP); - if ((hfd = mkstemp(htn)) == -1 || (hfp = fdopen(hfd, "w+")) == NULL) { - if (hfd != -1) - (void) close(hfd); - e_to_sys(errno); - err("unable to open temporary file"); - } - (void) unlink(htn); - free(htn); - - in_header_section = TRUE; - content_length = 0; - fp = hfp; - - line[0] = '\0'; - while (fgets(line, sizeof(line), stdin) != (char *)NULL) - { - size_t line_len = 0; - int peek; - - prevfl = fullline; /* preserve state of previous line */ - while (line[line_len] != '\n' && line_len < sizeof(line) - 2) - line_len++; - line_len++; - - /* Check for dot-stuffing */ - if (prevfl && lmtprcpts && line[0] == '.') - { - if (line[1] == '\n' || - (line[1] == '\r' && line[2] == '\n')) - goto lmtpdot; - memcpy(line, line + 1, line_len); - line_len--; - } - - /* Check to see if we have the full line from fgets() */ - fullline = FALSE; - if (line_len > 0) - { - if (line[line_len - 1] == '\n') - { - if (line_len >= 2 && - line[line_len - 2] == '\r') - { - line[line_len - 2] = '\n'; - line[line_len - 1] = '\0'; - line_len--; - } - fullline = TRUE; - } - else if (line[line_len - 1] == '\r') - { - /* Did we just miss the CRLF? */ - peek = fgetc(stdin); - if (peek == '\n') - { - line[line_len - 1] = '\n'; - fullline = TRUE; - } - else - (void) ungetc(peek, stdin); - } - } - else - fullline = TRUE; - - if (prevfl && line[0] == '\n' && in_header_section) { - in_header_section = FALSE; - if (fflush(fp) == EOF || ferror(fp)) { - if (lmtprcpts) { - while (lmtprcpts--) - printf("451 4.3.0 temporary file write error\r\n"); - fclose(fp); - return; - } else { - mailerr("451 4.3.0", - "temporary file write error"); - fclose(fp); - exit(eval); - } - } - fp = bfp; - continue; - } - - if (in_header_section) { - if (strncasecmp("Content-Length:", line, 15) == 0) { - continue; /* skip this header */ - } - } else - content_length += strlen(line); - (void) fwrite(line, sizeof(char), line_len, fp); - if (ferror(fp)) { - if (lmtprcpts) { - while (lmtprcpts--) - printf("451 4.3.0 temporary file write error\r\n"); - fclose(fp); - return; - } else { - mailerr("451 4.3.0", - "temporary file write error"); - fclose(fp); - exit(eval); - } - } - } - if (sigterm_caught) { - if (lmtprcpts) - while (lmtprcpts--) - printf("451 4.3.0 shutting down\r\n"); - else - mailerr("451 4.3.0", "shutting down"); - fclose(fp); - exit(eval); - } - - if (lmtprcpts) { - /* Got a premature EOF -- toss message and exit */ - exit(EX_OK); - } - - /* If message not newline terminated, need an extra. */ - if (!strchr(line, '\n')) { - (void) putc('\n', fp); - content_length++; - } - - lmtpdot: - - /* Output a newline; note, empty messages are allowed. */ - (void) putc('\n', fp); - - if (fflush(fp) == EOF || ferror(fp)) { - if (lmtprcpts) { - while (lmtprcpts--) { - printf("451 4.3.0 temporary file write error\r\n"); - } - fclose(fp); - return; - } else { - mailerr("451 4.3.0", "temporary file write error"); - fclose(fp); - exit(eval); - } - } - - if ((newfd = dup(bfd)) >= 0) { - fclose(bfp); - bfd = newfd; - } - if ((newfd = dup(hfd)) >= 0) { - fclose(hfp); - hfd = newfd; - } - (void) time(&tval); - (void) snprintf(unix_from_line, sizeof (unix_from_line), "From %s %s", - from, ctime(&tval)); - ulen = strlen(unix_from_line); -} - -static void -handle_error(err_num, bouncequota, path) - int err_num; - bool bouncequota; - char *path; -{ -#ifdef EDQUOT - if (err_num == EDQUOT && bouncequota) { - mailerr("552 5.2.2", "%s: %s", path, sm_errstring(err_num)); - } else -#endif /* EDQUOT */ - mailerr("450 4.2.0", "%s: %s", path, sm_errstring(err_num)); -} - -static void -deliver(hfd, bfd, name, bouncequota) - int hfd; - int bfd; - char *name; - bool bouncequota; -{ - struct stat fsb, sb; - int mbfd = -1, nr, nw = 0, off; - char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; - off_t curoff, cursize; - int len; - struct passwd *pw = NULL; - - /* - * Disallow delivery to unknown names -- special mailboxes - * can be handled in the sendmail aliases file. - */ - if ((pw = getpwnam(name)) == NULL) { - eval = EX_TEMPFAIL; - mailerr("451 4.3.0", "cannot lookup name: %s", name); - return; - } - endpwent(); - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - return; - } - - /* mailbox may be NFS mounted, seteuid to user */ - targ_uid = pw->pw_uid; - (void) seteuid(targ_uid); - - if ((saved_uid != 0) && (src_uid != targ_uid)) { - /* - * If saved_uid == 0 (root), anything is OK; this is - * as it should be. But to prevent a random user from - * calling "mail.local foo" in an attempt to hijack - * foo's mail-box, make sure src_uid == targ_uid o/w. - */ - warn("%s: wrong owner (is %d, should be %d)", - name, src_uid, targ_uid); - eval = EX_CANTCREAT; - return; - } - - path[0] = '\0'; - (void) snprintf(path, sizeof (path), "%s/%s", _PATH_MAILDIR, name); - - /* - * If the mailbox is linked or a symlink, fail. There's an obvious - * race here, that the file was replaced with a symbolic link after - * the lstat returned, but before the open. We attempt to detect - * this by comparing the original stat information and information - * returned by an fstat of the file descriptor returned by the open. - * - * NB: this is a symptom of a larger problem, that the mail spooling - * directory is writeable by the wrong users. If that directory is - * writeable, system security is compromised for other reasons, and - * it cannot be fixed here. - * - * If we created the mailbox, set the owner/group. If that fails, - * just return. Another process may have already opened it, so we - * can't unlink it. Historically, binmail set the owner/group at - * each mail delivery. We no longer do this, assuming that if the - * ownership or permissions were changed there was a reason. - * - * XXX - * open(2) should support flock'ing the file. - */ -tryagain: - /* should check lock status, but... maillock return no value */ - maillock(name, 10); - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err0; - } - - if (lstat(path, &sb)) { - mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, - S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); - if (mbfd != -1) - (void) fchmod(mbfd, 0660); - - - if (mbfd == -1) { - if (errno == EEXIST) { - mailunlock(); - goto tryagain; - } - } - } else if (sb.st_nlink != 1) { - mailerr("550 5.2.0", "%s: too many links", path); - goto err0; - } else if (!S_ISREG(sb.st_mode)) { - mailerr("550 5.2.0", "%s: irregular file", path); - goto err0; - } else { - mbfd = open(path, O_APPEND|O_WRONLY, 0); - if (mbfd != -1 && - (fstat(mbfd, &fsb) || fsb.st_nlink != 1 || - S_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev || - sb.st_ino != fsb.st_ino)) { - eval = EX_TEMPFAIL; - mailerr("550 5.2.0", - "%s: fstat: file changed after open", path); - goto err1; - } - } - - if (mbfd == -1) { - mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); - goto err0; - } - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err0; - } - - /* Get the starting offset of the new message for biff. */ - curoff = lseek(mbfd, (off_t)0, SEEK_END); - (void) snprintf(biffmsg, sizeof (biffmsg), "%s@%ld\n", name, curoff); - - /* Copy the message into the file. */ - if (lseek(hfd, (off_t)0, SEEK_SET) == (off_t)-1) { - mailerr("450 4.2.0", "temporary file: %s", strerror(errno)); - goto err1; - } - /* Copy the message into the file. */ - if (lseek(bfd, (off_t)0, SEEK_SET) == (off_t)-1) { - mailerr("450 4.2.0", "temporary file: %s", strerror(errno)); - goto err1; - } - if ((write(mbfd, unix_from_line, ulen)) != ulen) { - handle_error(errno, bouncequota, path); - goto err2; - } - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err2; - } - - while ((nr = read(hfd, buf, sizeof (buf))) > 0) - for (off = 0; off < nr; nr -= nw, off += nw) - if ((nw = write(mbfd, buf + off, nr)) < 0) - { - handle_error(errno, bouncequota, path); - goto err2; - } - if (nr < 0) { - handle_error(errno, bouncequota, path); - goto err2; - } - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err2; - } - - (void) snprintf(buf, sizeof (buf), "Content-Length: %d\n\n", - content_length); - len = strlen(buf); - if (write(mbfd, buf, len) != len) { - handle_error(errno, bouncequota, path); - goto err2; - } - - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err2; - } - - while ((nr = read(bfd, buf, sizeof (buf))) > 0) { - for (off = 0; off < nr; nr -= nw, off += nw) - if ((nw = write(mbfd, buf + off, nr)) < 0) { - handle_error(errno, bouncequota, path); - goto err2; - } - if (sigterm_caught) { - mailerr("451 4.3.0", "shutting down"); - goto err2; - } - } - if (nr < 0) { - handle_error(errno, bouncequota, path); - goto err2; - } - - /* Flush to disk, don't wait for update. */ - if (fsync(mbfd)) { - handle_error(errno, bouncequota, path); -err2: if (mbfd >= 0) - (void)ftruncate(mbfd, curoff); -err1: (void)close(mbfd); -err0: mailunlock(); - (void)seteuid(saved_uid); - return; - } - - /* - ** Save the current size so if the close() fails below - ** we can make sure no other process has changed the mailbox - ** between the failed close and the re-open()/re-lock(). - ** If something else has changed the size, we shouldn't - ** try to truncate it as we may do more harm then good - ** (e.g., truncate a later message delivery). - */ - - if (fstat(mbfd, &sb) < 0) - cursize = 0; - else - cursize = sb.st_size; - - /* Close and check -- NFS doesn't write until the close. */ - if (close(mbfd)) - { - handle_error(errno, bouncequota, path); - mbfd = open(path, O_WRONLY, 0); - if (mbfd < 0 || - cursize == 0 - || flock(mbfd, LOCK_EX) < 0 || - fstat(mbfd, &sb) < 0 || - sb.st_size != cursize || - sb.st_nlink != 1 || - !S_ISREG(sb.st_mode) || - sb.st_dev != fsb.st_dev || - sb.st_ino != fsb.st_ino || - sb.st_uid != fsb.st_uid) - { - /* Don't use a bogus file */ - if (mbfd >= 0) - { - (void) close(mbfd); - mbfd = -1; - } - } - - /* Attempt to truncate back to pre-write size */ - goto err2; - } else - notifybiff(biffmsg); - - mailunlock(); - - (void)seteuid(saved_uid); - - if (lmtpmode) { - printf("250 2.1.5 %s OK\r\n", name); - } -} - -static void -notifybiff(msg) - char *msg; -{ - static struct sockaddr_in addr; - static int f = -1; - struct hostent *hp; - struct servent *sp; - int len; - - if (msg == NULL) { - /* Be silent if biff service not available. */ - if ((sp = getservbyname("biff", "udp")) == NULL) - return; - if ((hp = gethostbyname("localhost")) == NULL) { - warn("localhost: %s", strerror(errno)); - return; - } - addr.sin_family = hp->h_addrtype; - (void) memmove(&addr.sin_addr, hp->h_addr, hp->h_length); - addr.sin_port = sp->s_port; - return; - } - - if (addr.sin_family == 0) - return; /* did not initialize */ - - if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - warn("socket: %s", strerror(errno)); - return; - } - len = strlen(msg) + 1; - if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof (addr)) - != len) - warn("sendto biff: %s", strerror(errno)); -} - -static void -usage() -{ - eval = EX_USAGE; - err("usage: mail.local [-l] [-f from] user ..."); -} - -static void -/*VARARGS2*/ -#ifdef __STDC__ -mailerr(const char *hdr, const char *fmt, ...) -#else -mailerr(hdr, fmt, va_alist) - const char *hdr; - const char *fmt; - va_dcl -#endif -{ - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - if (lmtpmode) - { - if (hdr != NULL) - printf("%s ", hdr); - vprintf(fmt, ap); - printf("\r\n"); - } - else - { - e_to_sys(errno); - vwarn(fmt, ap); - } -} - -static void -/*VARARGS1*/ -#ifdef __STDC__ -err(const char *fmt, ...) -#else -err(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - vwarn(fmt, ap); - va_end(ap); - - exit(eval); -} - -static void -/*VARARGS1*/ -#ifdef __STDC__ -warn(const char *fmt, ...) -#else -warn(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - vwarn(fmt, ap); - va_end(ap); -} - -static void -vwarn(fmt, ap) - const char *fmt; - va_list ap; -{ - /* - * Log the message to stderr. - * - * Don't use LOG_PERROR as an openlog() flag to do this, - * it's not portable enough. - */ - if (eval != EX_USAGE) - (void) fprintf(stderr, "mail.local: "); - (void) vfprintf(stderr, fmt, ap); - (void) fprintf(stderr, "\n"); - - /* Log the message to syslog. */ - vsyslog(LOG_ERR, fmt, ap); -} - -/* - * e_to_sys -- - * Guess which errno's are temporary. Gag me. - */ -static void -e_to_sys(num) - int num; -{ - /* Temporary failures override hard errors. */ - if (eval == EX_TEMPFAIL) - return; - - switch (num) /* Hopefully temporary errors. */ - { -#ifdef EDQUOT - case EDQUOT: /* Disc quota exceeded */ - if (bouncequota) - { - eval = EX_UNAVAILABLE; - break; - } -#endif /* EDQUOT */ -#ifdef EAGAIN - /* FALLTHROUGH */ - case EAGAIN: /* Resource temporarily unavailable */ -#endif -#ifdef EBUSY - case EBUSY: /* Device busy */ -#endif -#ifdef EPROCLIM - case EPROCLIM: /* Too many processes */ -#endif -#ifdef EUSERS - case EUSERS: /* Too many users */ -#endif -#ifdef ECONNABORTED - case ECONNABORTED: /* Software caused connection abort */ -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: /* Connection refused */ -#endif -#ifdef ECONNRESET - case ECONNRESET: /* Connection reset by peer */ -#endif -#ifdef EDEADLK - case EDEADLK: /* Resource deadlock avoided */ -#endif -#ifdef EFBIG - case EFBIG: /* File too large */ -#endif -#ifdef EHOSTDOWN - case EHOSTDOWN: /* Host is down */ -#endif -#ifdef EHOSTUNREACH - case EHOSTUNREACH: /* No route to host */ -#endif -#ifdef EMFILE - case EMFILE: /* Too many open files */ -#endif -#ifdef ENETDOWN - case ENETDOWN: /* Network is down */ -#endif -#ifdef ENETRESET - case ENETRESET: /* Network dropped connection on reset */ -#endif -#ifdef ENETUNREACH - case ENETUNREACH: /* Network is unreachable */ -#endif -#ifdef ENFILE - case ENFILE: /* Too many open files in system */ -#endif -#ifdef ENOBUFS - case ENOBUFS: /* No buffer space available */ -#endif -#ifdef ENOMEM - case ENOMEM: /* Cannot allocate memory */ -#endif -#ifdef ENOSPC - case ENOSPC: /* No space left on device */ -#endif -#ifdef EROFS - case EROFS: /* Read-only file system */ -#endif -#ifdef ESTALE - case ESTALE: /* Stale NFS file handle */ -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: /* Connection timed out */ -#endif -#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) - case EWOULDBLOCK: /* Operation would block. */ -#endif - eval = EX_TEMPFAIL; - break; - default: - eval = EX_UNAVAILABLE; - break; - } -} diff --git a/usr/src/cmd/sendmail/aux/mailcompat.c b/usr/src/cmd/sendmail/aux/mailcompat.c deleted file mode 100644 index aefc3dcfe5..0000000000 --- a/usr/src/cmd/sendmail/aux/mailcompat.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 1983, 1984, 1986, 1986, 1987, 1988, 1989 AT&T - * All Rights Reserved - */ - -/* - * Vacation - * Copyright (c) 1983 Eric P. Allman - * Berkeley, California - * - * Copyright (c) 1983 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "conf.h" - -/* - * MAILCOMPAT -- Deliver mail to a user's mailbox with the "From's" stuffed. - */ - -typedef int bool; - -#define FALSE 0 -#define TRUE 1 - -bool Debug = FALSE; -char *myname; /* person who is to have their mail filtered */ -char *homedir; /* home directory of said person */ -char *AliasList[MAXLINE]; /* list of aliases to allow */ -char *fromp; -char *fromuser; -int AliasCount = 0; - -static char *newstr(); - -int ask(char *); -int sendmessage(char *); -void AutoInstall(void); -void usrerr(const char *, ...); - -int -main(argc, argv) - int argc; - char **argv; -{ - register char *p; - struct passwd *pw; - extern char *getfrom(); - - /* process arguments */ - while (--argc > 0 && (p = *++argv) != NULL && *p == '-') - { - switch (*++p) - { - case 'd': /* debug */ - Debug = TRUE; - break; - default: - usrerr("Unknown flag -%s", p); - exit(EX_USAGE); - } - } - - /* verify recipient argument */ - if (argc != 1) - { - if (argc == 0) - AutoInstall(); - else - usrerr("Usage: mailcompat username (or) mailcompat -r"); - exit(EX_USAGE); - } - - myname = p; - /* find user's home directory */ - pw = getpwnam(myname); - if (pw == NULL) - { - usrerr("user: %s look up failed, name services outage ?", myname); - exit(EX_TEMPFAIL); - } - homedir = newstr(pw->pw_dir); - - /* read message from standard input (just from line) */ - fromuser = getfrom(&fromp); - return (sendmessage(fromuser)); -} - -/* -** sendmessage -- read message from standard input do the from stuffing -** and forward to /bin/mail, Being sure to delete any -** content-length headers (/bin/mail recalculates them). -** -** -** Parameters: -** none. -** -** -** Side Effects: -** Reads first line from standard input. -*/ - -#define L_HEADER "Content-Length:" -#define LL_HEADER 15 - -int -sendmessage(from) -char *from; -{ - static char line[MAXLINE]; - static char command[MAXLINE]; - bool in_body = FALSE; - FILE *mail_fp; - static char user_name[L_cuserid]; - - if (from == NULL) - from = cuserid(user_name); - - snprintf(command, sizeof (command), "/bin/mail -f %s -d %s", from, - myname); - mail_fp = popen(command, "w"); - - /* read the line */ - while (fgets(line, sizeof line, stdin) != NULL) - { - if (line[0] == (char)'\n') /* end of mail headers */ - in_body = TRUE; - if (in_body && (strncmp(line, "From ", 5) == 0)) - fprintf(mail_fp, ">"); - if (in_body || (strncasecmp(line, L_HEADER, LL_HEADER) != 0)) - fputs(line, mail_fp); - } - return (pclose(mail_fp)); -} - -char * -getfrom(shortp) -char **shortp; -{ - static char line[MAXLINE]; - register char *p, *start, *at, *bang; - char saveat; - - /* read the from line */ - if (fgets(line, sizeof line, stdin) == NULL || - strncmp(line, "From ", 5) != NULL) - { - usrerr("No initial From line"); - exit(EX_USAGE); - } - - /* find the end of the sender address and terminate it */ - start = &line[5]; - p = strchr(start, ' '); - if (p == NULL) - { - usrerr("Funny From line '%s'", line); - exit(EX_USAGE); - } - *p = '\0'; - - /* - * Strip all but the rightmost UUCP host - * to prevent loops due to forwarding. - * Start searching leftward from the leftmost '@'. - * a!b!c!d yields a short name of c!d - * a!b!c!d@e yields a short name of c!d@e - * e@a!b!c yields the same short name - */ -#ifdef VDEBUG -printf("start='%s'\n", start); -#endif /* VDEBUG */ - *shortp = start; /* assume whole addr */ - if ((at = strchr(start, '@')) == NULL) /* leftmost '@' */ - at = p; /* if none, use end of addr */ - saveat = *at; - *at = '\0'; - if ((bang = strrchr(start, '!')) != NULL) { /* rightmost '!' */ - char *bang2; - *bang = '\0'; - if ((bang2 = strrchr(start, '!')) != NULL) /* 2nd rightmost '!' */ - *shortp = bang2 + 1; /* move past ! */ - *bang = '!'; - } - *at = saveat; -#ifdef VDEBUG -printf("place='%s'\n", *shortp); -#endif /* VDEBUG */ - - /* return the sender address */ - return newstr(start); -} - -/* -** USRERR -- print user error -** -** Parameters: -** f -- format. -** -** Returns: -** none. -** -** Side Effects: -** none. -*/ - -void -usrerr(const char *f, ...) -{ - va_list alist; - - va_start(alist, f); - (void) fprintf(stderr, "mailcompat: "); - (void) vfprintf(stderr, f, alist); - (void) fprintf(stderr, "\n"); - va_end(alist); -} - -/* -** NEWSTR -- copy a string -** -** Parameters: -** s -- the string to copy. -** -** Returns: -** A copy of the string. -** -** Side Effects: -** none. -*/ - -char * -newstr(s) - char *s; -{ - char *p; - size_t psize = strlen(s) + 1; - - p = malloc(psize); - if (p == NULL) - { - usrerr("newstr: cannot alloc memory"); - exit(EX_OSERR); - } - strlcpy(p, s, psize); - return (p); -} - -/* - * When invoked with no arguments, we fall into an automatic installation - * mode, stepping the user through a default installation. - */ -void -AutoInstall() -{ - char forward[MAXLINE]; - char line[MAXLINE]; - static char user_name[L_cuserid]; - FILE *f; - - myname = cuserid(user_name); - homedir = getenv("HOME"); - if (homedir == NULL) { - usrerr("Home directory unknown"); - exit(EX_CONFIG); - } - - printf("This program can be used to store your mail in a format\n"); - printf("that you can read with SunOS 4.X based mail readers\n"); - (void) strlcpy(forward, homedir, sizeof (forward)); - (void) strlcat(forward, "/.forward", sizeof (forward)); - f = fopen(forward, "r"); - if (f) { - printf("You have a .forward file in your home directory"); - printf(" containing:\n"); - while (fgets(line, MAXLINE, f)) - printf(" %s", line); - fclose(f); - if (!ask("Would you like to remove it and disable the mailcompat feature")) - exit(0); - if (unlink(forward)) - perror("Error removing .forward file:"); - else - printf("Back to normal reception of mail.\n"); - exit(0); - } - - printf("To enable the mailcompat feature a \".forward\" "); - printf("file is created.\n"); - if (!ask("Would you like to enable the mailcompat feature")) { - printf("OK, mailcompat feature NOT enabled.\n"); - exit(0); - } - f = fopen(forward, "w"); - if (f == NULL) { - perror("Error opening .forward file"); - exit(EX_USAGE); - } - fprintf(f, "\"|/usr/bin/mailcompat %s\"\n", myname); - fclose(f); - printf("Mailcompat feature ENABLED."); - printf("Run mailcompat with no arguments to remove it\n"); -} - - -/* - * Ask the user a question until we get a reasonable answer - */ -int -ask(prompt) - char *prompt; -{ - char line[MAXLINE]; - - for (;;) { - printf("%s? ", prompt); - fflush(stdout); - fgets(line, sizeof (line), stdin); - if (line[0] == 'y' || line[0] == 'Y') - return (TRUE); - if (line[0] == 'n' || line[0] == 'N') - return (FALSE); - printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n"); - } - /* NOTREACHED */ -} diff --git a/usr/src/cmd/sendmail/aux/mailq.c b/usr/src/cmd/sendmail/aux/mailq.c deleted file mode 100644 index 4fadd88ff0..0000000000 --- a/usr/src/cmd/sendmail/aux/mailq.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _PATH_SENDMAIL_BIN "/usr/lib/smtp/sendmail/sendmail" - -int -main(int argc, char *argv[], char *envp[]) -{ - struct passwd *pw = getpwuid(getuid()); - char **newargv; - int j; - - if (pw && chkauthattr(MAILQ_AUTH, pw->pw_name)) { - /* The extra 2 is 1 for the "-bp" + 1 for the terminator. */ - newargv = (char **)malloc((argc + 2) * sizeof (char *)); - if (newargv == NULL) - exit(EX_UNAVAILABLE); - newargv[0] = _PATH_SENDMAIL_BIN; - newargv[1] = "-bp"; - for (j = 1; j <= argc; j++) - newargv[j + 1] = argv[j]; - (void) execve(_PATH_SENDMAIL_BIN, newargv, envp); - perror("Cannot exec " _PATH_SENDMAIL_BIN); - exit(EX_OSERR); - } - (void) fputs("No authorization to run mailq; " - "see mailq(1) for details.\n", stderr); - return (EX_NOPERM); -} diff --git a/usr/src/cmd/sendmail/aux/mailstats.c b/usr/src/cmd/sendmail/aux/mailstats.c deleted file mode 100644 index 6c5f9a18f8..0000000000 --- a/usr/src/cmd/sendmail/aux/mailstats.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1983 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - * - */ - -#include - -SM_IDSTR(copyright, -"@(#) Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1988, 1993\n\ - The Regents of the University of California. All rights reserved.\n") - -SM_IDSTR(id, "@(#)$Id: mailstats.c,v 8.100 2002/06/27 23:24:06 gshapiro Exp $") - -#include -#include -#include -#include -#include -#include -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include - -#include -#include -#include -#include -#include - - -#define MNAMELEN 20 /* max length of mailer name */ - -int -main(argc, argv) - int argc; - char **argv; -{ - register int i; - int mno; - int save_errno; - int ch, fd; - char *sfile; - char *cfile; - SM_FILE_T *cfp; - bool mnames; - bool progmode; - bool trunc; - long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0; - long dismsgs = 0; - long quarmsgs = 0; - time_t now; - char mtable[MAXMAILERS][MNAMELEN + 1]; - char sfilebuf[MAXPATHLEN]; - char buf[MAXLINE]; - struct statistics stats; - extern char *ctime(); - extern char *optarg; - extern int optind; - - cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); - sfile = NULL; - mnames = true; - progmode = false; - trunc = false; - while ((ch = getopt(argc, argv, "cC:f:opP")) != -1) - { - switch (ch) - { - case 'c': - cfile = getcfname(0, 0, SM_GET_SUBMIT_CF, NULL); - break; - - case 'C': - cfile = optarg; - break; - - case 'f': - sfile = optarg; - break; - - case 'o': - mnames = false; - break; - - case 'p': - trunc = true; - /* FALLTHROUGH */ - - case 'P': - progmode = true; - break; - - case '?': - default: - usage: - (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, - "usage: mailstats [-C cffile] [-c] [-P] [-f stfile] [-o] [-p]\n"); - exit(EX_USAGE); - } - } - argc -= optind; - argv += optind; - - if (argc != 0) - goto usage; - - if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, - NULL)) == NULL) - { - save_errno = errno; - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "mailstats: "); - errno = save_errno; - sm_perror(cfile); - exit(EX_NOINPUT); - } - - mno = 0; - (void) sm_strlcpy(mtable[mno++], "prog", MNAMELEN + 1); - (void) sm_strlcpy(mtable[mno++], "*file*", MNAMELEN + 1); - (void) sm_strlcpy(mtable[mno++], "*include*", MNAMELEN + 1); - - while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) - { - register char *b; - char *s; - register char *m; - - b = strchr(buf, '#'); - if (b == NULL) - b = strchr(buf, '\n'); - if (b == NULL) - b = &buf[strlen(buf)]; - while (isascii(*--b) && isspace(*b)) - continue; - *++b = '\0'; - - b = buf; - switch (*b++) - { - case 'M': /* mailer definition */ - break; - - case 'O': /* option -- see if .st file */ - if (sm_strncasecmp(b, " StatusFile", 11) == 0 && - !(isascii(b[11]) && isalnum(b[11]))) - { - /* new form -- find value */ - b = strchr(b, '='); - if (b == NULL) - continue; - while (isascii(*++b) && isspace(*b)) - continue; - } - else if (*b++ != 'S') - { - /* something else boring */ - continue; - } - - /* this is the S or StatusFile option -- save it */ - if (sm_strlcpy(sfilebuf, b, sizeof sfilebuf) >= - sizeof sfilebuf) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "StatusFile filename too long: %.30s...\n", - b); - exit(EX_CONFIG); - } - if (sfile == NULL) - sfile = sfilebuf; - /* FALLTHROUGH */ - - default: - continue; - } - - if (mno >= MAXMAILERS) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "Too many mailers defined, %d max.\n", - MAXMAILERS); - exit(EX_SOFTWARE); - } - m = mtable[mno]; - s = m + MNAMELEN; /* is [MNAMELEN + 1] */ - while (*b != ',' && !(isascii(*b) && isspace(*b)) && - *b != '\0' && m < s) - *m++ = *b++; - *m = '\0'; - for (i = 0; i < mno; i++) - { - if (strcmp(mtable[i], mtable[mno]) == 0) - break; - } - if (i == mno) - mno++; - } - (void) sm_io_close(cfp, SM_TIME_DEFAULT); - for (; mno < MAXMAILERS; mno++) - mtable[mno][0] = '\0'; - - if (sfile == NULL) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "mailstats: no statistics file located\n"); - exit(EX_OSFILE); - } - - fd = open(sfile, O_RDONLY, 0600); - if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0) - { - save_errno = errno; - (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, "mailstats: "); - errno = save_errno; - sm_perror(sfile); - exit(EX_NOINPUT); - } - if (i == 0) - { - (void) sleep(1); - if ((i = read(fd, &stats, sizeof stats)) < 0) - { - save_errno = errno; - (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, - "mailstats: "); - errno = save_errno; - sm_perror(sfile); - exit(EX_NOINPUT); - } - else if (i == 0) - { - memset((ARBPTR_T) &stats, '\0', sizeof stats); - (void) time(&stats.stat_itime); - } - } - if (i != 0) - { - if (stats.stat_magic != STAT_MAGIC) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "mailstats: incorrect magic number in %s\n", - sfile); - exit(EX_OSERR); - } - else if (stats.stat_version != STAT_VERSION) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "mailstats version (%d) incompatible with %s version (%d)\n", - STAT_VERSION, sfile, - stats.stat_version); - - exit(EX_OSERR); - } - else if (i != sizeof stats || stats.stat_size != sizeof(stats)) - { - (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, - "mailstats: file size changed.\n"); - exit(EX_OSERR); - } - } - - if (progmode) - { - (void) time(&now); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%ld %ld\n", - (long) stats.stat_itime, (long) now); - } - else - { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "Statistics from %s", - ctime(&stats.stat_itime)); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " msgsqur"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", - mnames ? " Mailer" : ""); - } - for (i = 0; i < MAXMAILERS; i++) - { - if (stats.stat_nf[i] || stats.stat_nt[i] || - stats.stat_nq[i] || - stats.stat_nr[i] || stats.stat_nd[i]) - { - char *format; - - if (progmode) - format = "%2d %8ld %10ld %8ld %10ld %6ld %6ld"; - else - format = "%2d %8ld %10ldK %8ld %10ldK %6ld %6ld"; - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - format, i, - stats.stat_nf[i], - stats.stat_bf[i], - stats.stat_nt[i], - stats.stat_bt[i], - stats.stat_nr[i], - stats.stat_nd[i]); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " %6ld", stats.stat_nq[i]); - if (mnames) - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " %s", - mtable[i]); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); - frmsgs += stats.stat_nf[i]; - frbytes += stats.stat_bf[i]; - tomsgs += stats.stat_nt[i]; - tobytes += stats.stat_bt[i]; - rejmsgs += stats.stat_nr[i]; - dismsgs += stats.stat_nd[i]; - quarmsgs += stats.stat_nq[i]; - } - } - if (progmode) - { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " T %8ld %10ld %8ld %10ld %6ld %6ld", - frmsgs, frbytes, tomsgs, tobytes, rejmsgs, - dismsgs); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " %6ld", quarmsgs); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " C %8ld %8ld %6ld\n", - stats.stat_cf, stats.stat_ct, - stats.stat_cr); - (void) close(fd); - if (trunc) - { - fd = open(sfile, O_RDWR | O_TRUNC, 0600); - if (fd >= 0) - (void) close(fd); - } - } - else - { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "============================================================="); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "========"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " T %8ld %10ldK %8ld %10ldK %6ld %6ld", - frmsgs, frbytes, tomsgs, tobytes, rejmsgs, - dismsgs); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " %6ld", quarmsgs); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - " C %8ld %10s %8ld %10s %6ld\n", - stats.stat_cf, "", stats.stat_ct, "", - stats.stat_cr); - } - exit(EX_OK); - /* NOTREACHED */ - return EX_OK; -} diff --git a/usr/src/cmd/sendmail/aux/makemap.c b/usr/src/cmd/sendmail/aux/makemap.c deleted file mode 100644 index 3b4ab68ba5..0000000000 --- a/usr/src/cmd/sendmail/aux/makemap.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (c) 1998-2002, 2004, 2008 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1992 Eric P. Allman. All rights reserved. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include - -SM_IDSTR(copyright, -"@(#) Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ - Copyright (c) 1992, 1993\n\ - The Regents of the University of California. All rights reserved.\n") - -SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.179 2008/04/14 02:06:16 ca Exp $") - -#include -#ifndef ISC_UNIX -# include -#endif /* ! ISC_UNIX */ -#include -#include -#include -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include -#include -#include -#include - -uid_t RealUid; -gid_t RealGid; -char *RealUserName; -uid_t RunAsUid; -gid_t RunAsGid; -char *RunAsUserName; -int Verbose = 2; -bool DontInitGroups = false; -uid_t TrustedUid = 0; -BITMAP256 DontBlameSendmail; - -#define BUFSIZE 1024 -#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep) - -static void usage __P((char *)); - -static void -usage(progname) - char *progname; -{ - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n", - progname); - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n", - (int) strlen(progname), ""); - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - " %*s [-u] [-v] type mapname\n", - (int) strlen(progname), ""); - exit(EX_USAGE); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - char *progname; - char *cfile; - bool inclnull = false; - bool notrunc = false; - bool allowreplace = false; - bool allowempty = false; - bool verbose = false; - bool foldcase = true; - bool unmake = false; - char sep = '\0'; - char comment = '#'; - int exitstat; - int opt; - char *typename = NULL; - char *mapname = NULL; - unsigned int lineno; - int st; - int mode; - int smode; - int putflags = 0; - long sff = SFF_ROOTOK|SFF_REGONLY; - struct passwd *pw; - SMDB_DATABASE *database; - SMDB_CURSOR *cursor; - SMDB_DBENT db_key, db_val; - SMDB_DBPARAMS params; - SMDB_USER_INFO user_info; - char ibuf[BUFSIZE]; -#if HASFCHOWN - SM_FILE_T *cfp; - char buf[MAXLINE]; -#endif /* HASFCHOWN */ - static char rnamebuf[MAXNAME]; /* holds RealUserName */ - extern char *optarg; - extern int optind; - - memset(¶ms, '\0', sizeof params); - params.smdbp_cache_size = 1024 * 1024; - - progname = strrchr(argv[0], '/'); - if (progname != NULL) - progname++; - else - progname = argv[0]; - cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); - - clrbitmap(DontBlameSendmail); - RunAsUid = RealUid = getuid(); - RunAsGid = RealGid = getgid(); - pw = getpwuid(RealUid); - if (pw != NULL) - (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); - else - (void) sm_snprintf(rnamebuf, sizeof rnamebuf, - "Unknown UID %d", (int) RealUid); - RunAsUserName = RealUserName = rnamebuf; - user_info.smdbu_id = RunAsUid; - user_info.smdbu_group_id = RunAsGid; - (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, - SMDB_MAX_USER_NAME_LEN); - -#define OPTIONS "C:D:Nc:deflorst:uv" - while ((opt = getopt(argc, argv, OPTIONS)) != -1) - { - switch (opt) - { - case 'C': - cfile = optarg; - break; - - case 'N': - inclnull = true; - break; - - case 'c': - params.smdbp_cache_size = atol(optarg); - break; - - case 'd': - params.smdbp_allow_dup = true; - break; - - case 'e': - allowempty = true; - break; - - case 'f': - foldcase = false; - break; - - case 'D': - comment = *optarg; - break; - - case 'l': - smdb_print_available_types(); - exit(EX_OK); - break; - - case 'o': - notrunc = true; - break; - - case 'r': - allowreplace = true; - break; - - case 's': - setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail); - setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail); - setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail); - setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail); - break; - - case 't': - if (optarg == NULL || *optarg == '\0') - { - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "Invalid separator\n"); - break; - } - sep = *optarg; - break; - - case 'u': - unmake = true; - break; - - case 'v': - verbose = true; - break; - - default: - usage(progname); - /* NOTREACHED */ - } - } - - if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) - sff |= SFF_NOSLINK; - if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) - sff |= SFF_NOHLINK; - if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) - sff |= SFF_NOWLINK; - - argc -= optind; - argv += optind; - if (argc != 2) - { - usage(progname); - /* NOTREACHED */ - } - else - { - typename = argv[0]; - mapname = argv[1]; - } - -#if HASFCHOWN - /* Find TrustedUser value in sendmail.cf */ - if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, - NULL)) == NULL) - { - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s", - cfile, sm_errstring(errno)); - exit(EX_NOINPUT); - } - while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) - { - register char *b; - - if ((b = strchr(buf, '\n')) != NULL) - *b = '\0'; - - b = buf; - switch (*b++) - { - case 'O': /* option */ - if (strncasecmp(b, " TrustedUser", 12) == 0 && - !(isascii(b[12]) && isalnum(b[12]))) - { - b = strchr(b, '='); - if (b == NULL) - continue; - while (isascii(*++b) && isspace(*b)) - continue; - if (isascii(*b) && isdigit(*b)) - TrustedUid = atoi(b); - else - { - TrustedUid = 0; - pw = getpwnam(b); - if (pw == NULL) - (void) sm_io_fprintf(smioerr, - SM_TIME_DEFAULT, - "TrustedUser: unknown user %s\n", b); - else - TrustedUid = pw->pw_uid; - } - -# ifdef UID_MAX - if (TrustedUid > UID_MAX) - { - (void) sm_io_fprintf(smioerr, - SM_TIME_DEFAULT, - "TrustedUser: uid value (%ld) > UID_MAX (%ld)", - (long) TrustedUid, - (long) UID_MAX); - TrustedUid = 0; - } -# endif /* UID_MAX */ - break; - } - /* FALLTHROUGH */ - - default: - continue; - } - } - (void) sm_io_close(cfp, SM_TIME_DEFAULT); -#endif /* HASFCHOWN */ - - if (!params.smdbp_allow_dup && !allowreplace) - putflags = SMDBF_NO_OVERWRITE; - - if (unmake) - { - mode = O_RDONLY; - smode = S_IRUSR; - } - else - { - mode = O_RDWR; - if (!notrunc) - { - mode |= O_CREAT|O_TRUNC; - sff |= SFF_CREAT; - } - smode = S_IWUSR; - } - - params.smdbp_num_elements = 4096; - - errno = smdb_open_database(&database, mapname, mode, smode, sff, - typename, &user_info, ¶ms); - if (errno != SMDBE_OK) - { - char *hint; - - if (errno == SMDBE_UNSUPPORTED_DB_TYPE && - (hint = smdb_db_definition(typename)) != NULL) - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: Need to recompile with -D%s for %s support\n", - progname, hint, typename); - else - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: error opening type %s map %s: %s\n", - progname, typename, mapname, - sm_errstring(errno)); - exit(EX_CANTCREAT); - } - - (void) database->smdb_sync(database, 0); - - if (!unmake && geteuid() == 0 && TrustedUid != 0) - { - errno = database->smdb_set_owner(database, TrustedUid, -1); - if (errno != SMDBE_OK) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "WARNING: ownership change on %s failed %s", - mapname, sm_errstring(errno)); - } - } - - /* - ** Copy the data - */ - - exitstat = EX_OK; - if (unmake) - { - errno = database->smdb_cursor(database, &cursor, 0); - if (errno != SMDBE_OK) - { - - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: cannot make cursor for type %s map %s\n", - progname, typename, mapname); - exit(EX_SOFTWARE); - } - - memset(&db_key, '\0', sizeof db_key); - memset(&db_val, '\0', sizeof db_val); - - for (lineno = 0; ; lineno++) - { - errno = cursor->smdbc_get(cursor, &db_key, &db_val, - SMDB_CURSOR_GET_NEXT); - if (errno != SMDBE_OK) - break; - - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "%.*s%c%.*s\n", - (int) db_key.size, - (char *) db_key.data, - (sep != '\0') ? sep : '\t', - (int) db_val.size, - (char *)db_val.data); - - } - (void) cursor->smdbc_close(cursor); - } - else - { - lineno = 0; - while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf) - != NULL) - { - register char *p; - - lineno++; - - /* - ** Parse the line. - */ - - p = strchr(ibuf, '\n'); - if (p != NULL) - *p = '\0'; - else if (!sm_io_eof(smioin)) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: %s: line %u: line too long (%ld bytes max)\n", - progname, mapname, lineno, - (long) sizeof ibuf); - exitstat = EX_DATAERR; - continue; - } - - if (ibuf[0] == '\0' || ibuf[0] == comment) - continue; - if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0])) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: %s: line %u: syntax error (leading space)\n", - progname, mapname, lineno); - exitstat = EX_DATAERR; - continue; - } - - memset(&db_key, '\0', sizeof db_key); - memset(&db_val, '\0', sizeof db_val); - db_key.data = ibuf; - - for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++) - { - if (foldcase && isascii(*p) && isupper(*p)) - *p = tolower(*p); - } - db_key.size = p - ibuf; - if (inclnull) - db_key.size++; - - if (*p != '\0') - *p++ = '\0'; - while (*p != '\0' && ISSEP(*p)) - p++; - if (!allowempty && *p == '\0') - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: %s: line %u: no RHS for LHS %s\n", - progname, mapname, lineno, - (char *) db_key.data); - exitstat = EX_DATAERR; - continue; - } - - db_val.data = p; - db_val.size = strlen(p); - if (inclnull) - db_val.size++; - - /* - ** Do the database insert. - */ - - if (verbose) - { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "key=`%s', val=`%s'\n", - (char *) db_key.data, - (char *) db_val.data); - } - - errno = database->smdb_put(database, &db_key, &db_val, - putflags); - switch (errno) - { - case SMDBE_KEY_EXIST: - st = 1; - break; - - case 0: - st = 0; - break; - - default: - st = -1; - break; - } - - if (st < 0) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: %s: line %u: key %s: put error: %s\n", - progname, mapname, lineno, - (char *) db_key.data, - sm_errstring(errno)); - exitstat = EX_IOERR; - } - else if (st > 0) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: %s: line %u: key %s: duplicate key\n", - progname, mapname, - lineno, - (char *) db_key.data); - exitstat = EX_DATAERR; - } - } - } - - /* - ** Now close the database. - */ - - errno = database->smdb_close(database); - if (errno != SMDBE_OK) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: close(%s): %s\n", - progname, mapname, sm_errstring(errno)); - exitstat = EX_IOERR; - } - smdb_free_database(database); - - exit(exitstat); - - /* NOTREACHED */ - return exitstat; -} diff --git a/usr/src/cmd/sendmail/aux/mconnect.c b/usr/src/cmd/sendmail/aux/mconnect.c deleted file mode 100644 index 3a4f1fa0e1..0000000000 --- a/usr/src/cmd/sendmail/aux/mconnect.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * mconnect.c - A program to test out SMTP connections. - * Usage: mconnect [host] - * ... SMTP dialog - * ^C or ^D or QUIT - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -union bigsockaddr -{ - struct sockaddr sa; /* general version */ - struct sockaddr_in sin; /* INET family */ - struct sockaddr_in6 sin6; /* INET/IPv6 */ -}; - -static struct sgttyb TtyBuf; -static int raw = 0; - -/* ARGSUSED */ -static void -finis(sig) - int sig; -{ - if (raw) - (void) ioctl(0, TIOCSETP, &TtyBuf); - exit(0); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - union bigsockaddr SendmailAddress; - register int s; - char *host = NULL; - int pid; - int on = 1; - struct servent *sp; - char buf[1000]; - register FILE *f; - register struct hostent *hp; - in_port_t port = 0; - int err; - char buf6[INET6_ADDRSTRLEN]; - int addr_num = 0; - int addrlen; - - (void) ioctl(0, TIOCGETP, &TtyBuf); - (void) signal(SIGINT, finis); - - while (--argc > 0) - { - register char *p; - - p = *++argv; - if (*p == '-') - { - switch (*++p) - { - case 'h': /* host */ - break; - - case 'p': /* port */ - port = htons(atoi(*++argv)); - argc--; - break; - - case 'r': /* raw connection */ - raw = 1; - break; - } - } else if (host == NULL) - host = p; - } - if (host == NULL) - host = "localhost"; - - bzero(&SendmailAddress, sizeof (SendmailAddress)); - hp = getipnodebyname(host, AF_INET6, AI_DEFAULT|AI_ALL, &err); - if (hp == NULL) - { - (void) fprintf(stderr, "mconnect: unknown host %s\r\n", host); - exit(0); - } - - if (port == 0) { - sp = getservbyname("smtp", "tcp"); - if (sp != NULL) - port = sp->s_port; - } - - for (;;) { - bcopy(hp->h_addr_list[addr_num], - &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ); - if (IN6_IS_ADDR_V4MAPPED(&SendmailAddress.sin6.sin6_addr)) { - SendmailAddress.sa.sa_family = AF_INET; - SendmailAddress.sin.sin_port = port; - bcopy(&hp->h_addr_list[addr_num][IN6ADDRSZ - INADDRSZ], - &SendmailAddress.sin.sin_addr, INADDRSZ); - addrlen = sizeof (struct sockaddr_in); - } else { - SendmailAddress.sa.sa_family = AF_INET6; - SendmailAddress.sin6.sin6_port = port; - addrlen = sizeof (struct sockaddr_in6); - } - - s = socket(SendmailAddress.sa.sa_family, SOCK_STREAM, 0); - if (s < 0) - { - perror("socket"); - exit(-1); - } - (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, - sizeof (on)); - if (SendmailAddress.sa.sa_family == AF_INET) - (void) printf("connecting to host %s (%s), port %d\r\n", - host, inet_ntoa(SendmailAddress.sin.sin_addr), - ntohs(SendmailAddress.sin.sin_port)); - else - (void) printf("connecting to host %s (%s), port %d\r\n", - host, inet_ntop(AF_INET6, - SendmailAddress.sin6.sin6_addr.s6_addr, - buf6, sizeof (buf6)), - ntohs(SendmailAddress.sin6.sin6_port)); - if (connect(s, (struct sockaddr *)&SendmailAddress, - addrlen) >= 0) - break; - if (hp->h_addr_list[++addr_num] != NULL) { - (void) printf("connect failed (%s), next address ...\n", - strerror(errno)); - bcopy(hp->h_addr_list[addr_num], - &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ); - if (IN6_IS_ADDR_V4MAPPED( - &SendmailAddress.sin6.sin6_addr)) { - SendmailAddress.sa.sa_family = AF_INET; - bcopy(&hp->h_addr_list[addr_num] - [IN6ADDRSZ - INADDRSZ], - &SendmailAddress.sin.sin_addr, - INADDRSZ); - addrlen = sizeof (struct sockaddr_in); - } else { - SendmailAddress.sa.sa_family = AF_INET6; - addrlen = sizeof (struct sockaddr_in6); - } - continue; - } - perror("connect"); - exit(-1); - } - - if (raw) { - TtyBuf.sg_flags &= ~CRMOD; - (void) ioctl(0, TIOCSETP, &TtyBuf); - TtyBuf.sg_flags |= CRMOD; - } - - /* good connection, fork both sides */ - (void) printf("connection open\n"); - pid = fork(); - if (pid < 0) - { - perror("fork"); - exit(-1); - } - if (pid == 0) - { - /* child -- standard input to sendmail */ - int c; - - f = fdopen(s, "w"); - while ((c = fgetc(stdin)) >= 0) - { - if (!raw && c == '\n') - (void) fputc('\r', f); - (void) fputc(c, f); - if (c == '\n') - (void) fflush(f); - } - (void) shutdown(s, 1); - (void) sleep(10); - } - else - { - /* parent -- sendmail to standard output */ - f = fdopen(s, "r"); - while (fgets(buf, sizeof (buf), f) != NULL) - { - (void) fputs(buf, stdout); - (void) fflush(stdout); - } - (void) kill(pid, SIGTERM); - } - if (raw) - (void) ioctl(0, TIOCSETP, &TtyBuf); - return (0); -} diff --git a/usr/src/cmd/sendmail/aux/praliases.c b/usr/src/cmd/sendmail/aux/praliases.c deleted file mode 100644 index 8839334286..0000000000 --- a/usr/src/cmd/sendmail/aux/praliases.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1983 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include - -SM_IDSTR(copyright, -"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\ - Copyright (c) 1988, 1993\n\ - The Regents of the University of California. All rights reserved.\n") - -SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $") - -#include -#include -#include -#include -#ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -#endif /* EX_OK */ -#include - - -#ifndef NOT_SENDMAIL -# define NOT_SENDMAIL -#endif /* ! NOT_SENDMAIL */ -#include -#include -#include - -static void praliases __P((char *, int, char **)); - -uid_t RealUid; -gid_t RealGid; -char *RealUserName; -uid_t RunAsUid; -gid_t RunAsGid; -char *RunAsUserName; -int Verbose = 2; -bool DontInitGroups = false; -uid_t TrustedUid = 0; -BITMAP256 DontBlameSendmail; - -# define DELIMITERS " ,/" -# define PATH_SEPARATOR ':' - -int -main(argc, argv) - int argc; - char **argv; -{ - char *cfile; - char *filename = NULL; - SM_FILE_T *cfp; - int ch; - char afilebuf[MAXLINE]; - char buf[MAXLINE]; - struct passwd *pw; - static char rnamebuf[MAXNAME]; - extern char *optarg; - extern int optind; - - clrbitmap(DontBlameSendmail); - RunAsUid = RealUid = getuid(); - RunAsGid = RealGid = getgid(); - pw = getpwuid(RealUid); - if (pw != NULL) - { - if (strlen(pw->pw_name) > MAXNAME - 1) - pw->pw_name[MAXNAME] = 0; - sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); - } - else - (void) sm_snprintf(rnamebuf, sizeof rnamebuf, - "Unknown UID %d", (int) RealUid); - RunAsUserName = RealUserName = rnamebuf; - - cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); - while ((ch = getopt(argc, argv, "C:f:")) != -1) - { - switch ((char)ch) { - case 'C': - cfile = optarg; - break; - case 'f': - filename = optarg; - break; - case '?': - default: - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "usage: praliases [-C cffile] [-f aliasfile]" - " [key ...]\n"); - exit(EX_USAGE); - } - } - argc -= optind; - argv += optind; - - if (filename != NULL) - { - praliases(filename, argc, argv); - exit(EX_OK); - } - - if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, - NULL)) == NULL) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: %s: %s\n", cfile, - sm_errstring(errno)); - exit(EX_NOINPUT); - } - - while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) - { - register char *b, *p; - - b = strchr(buf, '\n'); - if (b != NULL) - *b = '\0'; - - b = buf; - switch (*b++) - { - case 'O': /* option -- see if alias file */ - if (sm_strncasecmp(b, " AliasFile", 10) == 0 && - !(isascii(b[10]) && isalnum(b[10]))) - { - /* new form -- find value */ - b = strchr(b, '='); - if (b == NULL) - continue; - while (isascii(*++b) && isspace(*b)) - continue; - } - else if (*b++ != 'A') - { - /* something else boring */ - continue; - } - - /* this is the A or AliasFile option -- save it */ - if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >= - sizeof afilebuf) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: AliasFile filename too long: %.30s\n", - b); - (void) sm_io_close(cfp, SM_TIME_DEFAULT); - exit(EX_CONFIG); - } - b = afilebuf; - - for (p = b; p != NULL; ) - { - while (isascii(*p) && isspace(*p)) - p++; - if (*p == '\0') - break; - b = p; - - p = strpbrk(p, DELIMITERS); - - /* find end of spec */ - if (p != NULL) - { - bool quoted = false; - - for (; *p != '\0'; p++) - { - /* - ** Don't break into a quoted - ** string. - */ - - if (*p == '"') - quoted = !quoted; - else if (*p == ',' && !quoted) - break; - } - - /* No more alias specs follow */ - if (*p == '\0') - { - /* chop trailing whitespace */ - while (isascii(*p) && - isspace(*p) && - p > b) - p--; - *p = '\0'; - p = NULL; - } - } - - if (p != NULL) - { - char *e = p - 1; - - /* chop trailing whitespace */ - while (isascii(*e) && - isspace(*e) && - e > b) - e--; - *++e = '\0'; - *p++ = '\0'; - } - praliases(b, argc, argv); - } - /* FALLTHROUGH */ - - default: - continue; - } - } - (void) sm_io_close(cfp, SM_TIME_DEFAULT); - exit(EX_OK); - /* NOTREACHED */ - return EX_OK; -} - -static void -praliases(filename, argc, argv) - char *filename; - int argc; - char **argv; -{ - int result; - char *colon; - char *db_name; - char *db_type; - SMDB_DATABASE *database = NULL; - SMDB_CURSOR *cursor = NULL; - SMDB_DBENT db_key, db_value; - SMDB_DBPARAMS params; - SMDB_USER_INFO user_info; - - colon = strchr(filename, PATH_SEPARATOR); - if (colon == NULL) - { - db_name = filename; - db_type = SMDB_TYPE_DEFAULT; - } - else - { - *colon = '\0'; - db_name = colon + 1; - db_type = filename; - } - - /* clean off arguments */ - for (;;) - { - while (isascii(*db_name) && isspace(*db_name)) - db_name++; - - if (*db_name != '-') - break; - while (*db_name != '\0' && - !(isascii(*db_name) && isspace(*db_name))) - db_name++; - } - - /* Skip non-file based DB types */ - if (db_type != NULL && *db_type != '\0') - { - if (db_type != SMDB_TYPE_DEFAULT && - strcmp(db_type, "hash") != 0 && - strcmp(db_type, "btree") != 0 && - strcmp(db_type, "dbm") != 0) - { - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: Skipping non-file based alias type %s\n", - db_type); - return; - } - } - - if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) - { - if (colon != NULL) - *colon = ':'; - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: illegal alias specification: %s\n", filename); - goto fatal; - } - - memset(¶ms, '\0', sizeof params); - params.smdbp_cache_size = 1024 * 1024; - - user_info.smdbu_id = RunAsUid; - user_info.smdbu_group_id = RunAsGid; - (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, - SMDB_MAX_USER_NAME_LEN); - - result = smdb_open_database(&database, db_name, O_RDONLY, 0, - SFF_ROOTOK, db_type, &user_info, ¶ms); - if (result != SMDBE_OK) - { - sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: %s: open: %s\n", - db_name, sm_errstring(result)); - goto fatal; - } - - if (argc == 0) - { - memset(&db_key, '\0', sizeof db_key); - memset(&db_value, '\0', sizeof db_value); - - result = database->smdb_cursor(database, &cursor, 0); - if (result != SMDBE_OK) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: %s: set cursor: %s\n", db_name, - sm_errstring(result)); - goto fatal; - } - - while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, - SMDB_CURSOR_GET_NEXT)) == - SMDBE_OK) - { -#if 0 - /* skip magic @:@ entry */ - if (db_key.size == 2 && - db_key.data[0] == '@' && - db_key.data[1] == '\0' && - db_value.size == 2 && - db_value.data[0] == '@' && - db_value.data[1] == '\0') - continue; -#endif /* 0 */ - - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "%.*s:%.*s\n", - (int) db_key.size, - (char *) db_key.data, - (int) db_value.size, - (char *) db_value.data); - } - - if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "praliases: %s: get value at cursor: %s\n", - db_name, sm_errstring(result)); - goto fatal; - } - } - else for (; *argv != NULL; ++argv) - { - int get_res; - - memset(&db_key, '\0', sizeof db_key); - memset(&db_value, '\0', sizeof db_value); - db_key.data = *argv; - db_key.size = strlen(*argv); - get_res = database->smdb_get(database, &db_key, &db_value, 0); - if (get_res == SMDBE_NOT_FOUND) - { - db_key.size++; - get_res = database->smdb_get(database, &db_key, - &db_value, 0); - } - if (get_res == SMDBE_OK) - { - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "%.*s:%.*s\n", - (int) db_key.size, - (char *) db_key.data, - (int) db_value.size, - (char *) db_value.data); - } - else - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "%s: No such key\n", - (char *)db_key.data); - } - - fatal: - if (cursor != NULL) - (void) cursor->smdbc_close(cursor); - if (database != NULL) - (void) database->smdb_close(database); - if (colon != NULL) - *colon = ':'; - return; -} diff --git a/usr/src/cmd/sendmail/aux/rfc2047.c b/usr/src/cmd/sendmail/aux/rfc2047.c deleted file mode 100644 index 8092a9a587..0000000000 --- a/usr/src/cmd/sendmail/aux/rfc2047.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * rfc2047.c -- decode RFC-2047 header format - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifndef lint -static char sccsi2[] = "%W% (Sun) %G%"; -#endif - -/* - * Copyright (c) 1997-1998 Richard Coleman - * All rights reserved. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and to distribute modified versions of this software for any - * purpose, provided that the above copyright notice and the following two - * paragraphs appear in all copies of this software. - * - * In no event shall Richard Coleman be liable to any party for direct, - * indirect, special, incidental, or consequential damages arising out of - * the use of this software and its documentation, even if Richard Coleman - * has been advised of the possibility of such damage. - * - * Richard Coleman specifically disclaims any warranties, including, but - * not limited to, the implied warranties of merchantability and fitness - * for a particular purpose. The software provided hereunder is on an "as - * is" basis, and Richard Coleman has no obligation to provide maintenance, - * support, updates, enhancements, or modifications. - */ - -/* - * Parts of this code were derived from metamail, which is ... - * - * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) - * - * Permission to use, copy, modify, and distribute this material - * for any purpose and without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies, and that the name of Bellcore not be - * used in advertising or publicity pertaining to this - * material without the specific, prior written permission - * of an authorized representative of Bellcore. BELLCORE - * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY - * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", - * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. - */ - -/* - * Copyright (c) 1998, by Sun Microsystems, Inc. - * All rights reserved. - */ - -#include - -typedef int bool; - -#define FALSE 0 -#define TRUE 1 - -static signed char hexindex[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static signed char index_64[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 -}; - -#define char64(c) (((unsigned char) (c) > 127) ? -1 : \ - index_64[(unsigned char) (c)]) - -static int -unqp(unsigned char byte1, unsigned char byte2) -{ - if (hexindex[byte1] == -1 || hexindex[byte2] == -1) - return (-1); - return (hexindex[byte1] << 4 | hexindex[byte2]); -} - -/* Check if character is linear whitespace */ -#define is_lws(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') - -/* - * Decode the string as a RFC-2047 header field - */ - -bool -decode_rfc2047(char *str, char *dst, char *charset) -{ - char *p, *q, *pp; - char *startofmime, *endofmime; - int c, quoted_printable; - bool encoding_found = FALSE; /* did we decode anything? */ - bool between_encodings = FALSE; /* are we between two encodings? */ - bool equals_pending = FALSE; /* is there a '=' pending? */ - int whitespace = 0; /* how much whitespace between encodings? */ - - if (str == NULL) - return (FALSE); - - /* - * Do a quick and dirty check for the '=' character. - * This should quickly eliminate many cases. - */ - if (!strchr(str, '=')) - return (FALSE); - - for (p = str, q = dst; *p; p++) { - /* - * If we had an '=' character pending from - * last iteration, then add it first. - */ - if (equals_pending) { - *q++ = '='; - equals_pending = FALSE; - between_encodings = FALSE; /* we added non-WS text */ - } - - if (*p != '=') { - /* count linear whitespace while between encodings */ - if (between_encodings && is_lws(*p)) - whitespace++; - else - between_encodings = FALSE; /* non-WS added */ - *q++ = *p; - continue; - } - - equals_pending = TRUE; /* we have a '=' pending */ - - /* Check for initial =? */ - if (*p == '=' && p[1] && p[1] == '?' && p[2]) { - startofmime = p + 2; - - /* Scan ahead for the next '?' character */ - for (pp = startofmime; *pp && *pp != '?'; pp++) - ; - - if (!*pp) - continue; - - strncpy(charset, startofmime, pp - startofmime); - charset[pp - startofmime] = '\0'; - - startofmime = pp + 1; - - /* Check for valid encoding type */ - if (*startofmime != 'B' && *startofmime != 'b' && - *startofmime != 'Q' && *startofmime != 'q') - continue; - - /* Is encoding quoted printable or base64? */ - quoted_printable = (*startofmime == 'Q' || - *startofmime == 'q'); - startofmime++; - - /* Check for next '?' character */ - if (*startofmime != '?') - continue; - startofmime++; - - /* - * Scan ahead for the ending ?= - * - * While doing this, we will also check if encoded - * word has any embedded linear whitespace. - */ - endofmime = NULL; - for (pp = startofmime; *pp && *(pp+1); pp++) { - if (is_lws(*pp)) - break; - else if (*pp == '?' && pp[1] == '=') { - endofmime = pp; - break; - } - } - if (is_lws(*pp) || endofmime == NULL) - continue; - - /* - * We've found an encoded word, so we can drop - * the '=' that was pending - */ - equals_pending = FALSE; - - /* - * If we are between two encoded words separated only - * by linear whitespace, then we ignore the whitespace. - * We will roll back the buffer the number of whitespace - * characters we've seen since last encoded word. - */ - if (between_encodings) - q -= whitespace; - - /* Now decode the text */ - if (quoted_printable) { - for (pp = startofmime; pp < endofmime; pp++) { - if (*pp == '=') { - c = unqp(pp[1], pp[2]); - if (c == -1) - continue; - if (c != 0) - *q++ = c; - pp += 2; - } else if (*pp == '_') - *q++ = ' '; - else - *q++ = *pp; - } - } else { - /* base64 */ - int c1, c2, c3, c4; - - pp = startofmime; - while (pp < endofmime) { - /* 6 + 2 bits */ - while ((pp < endofmime) && - ((c1 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime) - pp++; - while ((pp < endofmime) && - ((c2 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c1 != -1 && - c2 != -1) { - *q++ = (c1 << 2) | (c2 >> 4); - pp++; - } - /* 4 + 4 bits */ - while ((pp < endofmime) && - ((c3 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c2 != -1 && - c3 != -1) { - *q++ = ((c2 & 0xF) << 4) | - (c3 >> 2); - pp++; - } - /* 2 + 6 bits */ - while ((pp < endofmime) && - ((c4 = char64(*pp)) == -1)) { - pp++; - } - if (pp < endofmime && c3 != -1 && - c4 != -1) { - *q++ = ((c3 & 0x3) << 6) | (c4); - pp++; - } - } - } - - /* - * Now that we are done decoding this particular - * encoded word, advance string to trailing '='. - */ - p = endofmime + 1; - - encoding_found = TRUE; /* found (>= 1) encoded word */ - between_encodings = TRUE; /* just decoded something */ - whitespace = 0; /* re-initialize amount of whitespace */ - } - } - - /* If an equals was pending at end of string, add it now. */ - if (equals_pending) - *q++ = '='; - *q = '\0'; - - return (encoding_found); -} diff --git a/usr/src/cmd/sendmail/aux/smrsh.c b/usr/src/cmd/sendmail/aux/smrsh.c deleted file mode 100644 index 32d9afa8eb..0000000000 --- a/usr/src/cmd/sendmail/aux/smrsh.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1993 Eric P. Allman. All rights reserved. - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include - -SM_IDSTR(copyright, -"@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\ - Copyright (c) 1993\n\ - The Regents of the University of California. All rights reserved.\n") - -SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.65 2004/08/06 18:54:22 ca Exp $") - -/* -** SMRSH -- sendmail restricted shell -** -** This is a patch to get around the prog mailer bugs in most -** versions of sendmail. -** -** Use this in place of /bin/sh in the "prog" mailer definition -** in your sendmail.cf file. You then create CMDDIR (owned by -** root, mode 755) and put links to any programs you want -** available to prog mailers in that directory. This should -** include things like "vacation" and "procmail", but not "sed" -** or "sh". -** -** Leading pathnames are stripped from program names so that -** existing .forward files that reference things like -** "/usr/bin/vacation" will continue to work. -** -** The following characters are completely illegal: -** < > ^ & ` ( ) \n \r -** The following characters are sometimes illegal: -** | & -** This is more restrictive than strictly necessary. -** -** To use this, add FEATURE(`smrsh') to your .mc file. -** -** This can be used on any version of sendmail. -** -** In loving memory of RTM. 11/02/93. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef EX_OK -# undef EX_OK -#endif /* EX_OK */ -#include -#include -#include - -#include -#include - -/* directory in which all commands must reside */ -#ifndef CMDDIR -# ifdef SMRSH_CMDDIR -# define CMDDIR SMRSH_CMDDIR -# else /* SMRSH_CMDDIR */ -# define CMDDIR "/usr/adm/sm.bin" -# endif /* SMRSH_CMDDIR */ -#endif /* ! CMDDIR */ - -/* characters disallowed in the shell "-c" argument */ -#define SPECIALS "<|>^();&`$\r\n" - -/* default search path */ -#ifndef PATH -# ifdef SMRSH_PATH -# define PATH SMRSH_PATH -# else /* SMRSH_PATH */ -# define PATH "/bin:/usr/bin:/usr/ucb" -# endif /* SMRSH_PATH */ -#endif /* ! PATH */ - -char newcmdbuf[1000]; -char *prg, *par; - -static void addcmd __P((char *, bool, size_t)); - -/* -** ADDCMD -- add a string to newcmdbuf, check for overflow -** -** Parameters: -** s -- string to add -** cmd -- it's a command: prepend CMDDIR/ -** len -- length of string to add -** -** Side Effects: -** changes newcmdbuf or exits with a failure. -** -*/ - -static void -addcmd(s, cmd, len) - char *s; - bool cmd; - size_t len; -{ - if (s == NULL || *s == '\0') - return; - - /* enough space for s (len) and CMDDIR + "/" and '\0'? */ - if (sizeof newcmdbuf - strlen(newcmdbuf) <= - len + 1 + (cmd ? (strlen(CMDDIR) + 1) : 0)) - { - (void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: command too long: %s\n", prg, par); -#ifndef DEBUG - syslog(LOG_WARNING, "command too long: %.40s", par); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - if (cmd) - (void) sm_strlcat2(newcmdbuf, CMDDIR, "/", sizeof newcmdbuf); - (void) strncat(newcmdbuf, s, len); -} - -int -main(argc, argv) - int argc; - char **argv; -{ - register char *p; - register char *q; - register char *r; - register char *cmd; - int isexec; - int save_errno; - char *newenv[2]; - char pathbuf[1000]; - char specialbuf[32]; - struct stat st; - -#ifndef DEBUG -# ifndef LOG_MAIL - openlog("smrsh", 0); -# else /* ! LOG_MAIL */ - openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL); -# endif /* ! LOG_MAIL */ -#endif /* ! DEBUG */ - - (void) sm_strlcpyn(pathbuf, sizeof pathbuf, 2, "PATH=", PATH); - newenv[0] = pathbuf; - newenv[1] = NULL; - - /* - ** Do basic argv usage checking - */ - - prg = argv[0]; - - if (argc != 3 || strcmp(argv[1], "-c") != 0) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "Usage: %s -c command\n", prg); -#ifndef DEBUG - syslog(LOG_ERR, "usage"); -#endif /* ! DEBUG */ - exit(EX_USAGE); - } - - par = argv[2]; - - /* - ** Disallow special shell syntax. This is overly restrictive, - ** but it should shut down all attacks. - ** Be sure to include 8-bit versions, since many shells strip - ** the address to 7 bits before checking. - */ - - if (strlen(SPECIALS) * 2 >= sizeof specialbuf) - { -#ifndef DEBUG - syslog(LOG_ERR, "too many specials: %.40s", SPECIALS); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - (void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf); - for (p = specialbuf; *p != '\0'; p++) - *p |= '\200'; - (void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf); - - /* - ** Do a quick sanity check on command line length. - */ - - if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2)) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: command too long: %s\n", prg, par); -#ifndef DEBUG - syslog(LOG_WARNING, "command too long: %.40s", par); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - - q = par; - newcmdbuf[0] = '\0'; - isexec = false; - - while (*q != '\0') - { - /* - ** Strip off a leading pathname on the command name. For - ** example, change /usr/ucb/vacation to vacation. - */ - - /* strip leading spaces */ - while (*q != '\0' && isascii(*q) && isspace(*q)) - q++; - if (*q == '\0') - { - if (isexec) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: missing command to exec\n", - prg); -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid()); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - break; - } - - /* find the end of the command name */ - p = strpbrk(q, " \t"); - if (p == NULL) - cmd = &q[strlen(q)]; - else - { - *p = '\0'; - cmd = p; - } - /* search backwards for last / (allow for 0200 bit) */ - while (cmd > q) - { - if ((*--cmd & 0177) == '/') - { - cmd++; - break; - } - } - /* cmd now points at final component of path name */ - - /* allow a few shell builtins */ - if (strcmp(q, "exec") == 0 && p != NULL) - { - addcmd("exec ", false, strlen("exec ")); - - /* test _next_ arg */ - q = ++p; - isexec = true; - continue; - } - else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0) - { - addcmd(cmd, false, strlen(cmd)); - - /* test following chars */ - } - else - { - char cmdbuf[MAXPATHLEN]; - - /* - ** Check to see if the command name is legal. - */ - - if (sm_strlcpyn(cmdbuf, sizeof cmdbuf, 3, CMDDIR, - "/", cmd) >= sizeof cmdbuf) - { - /* too long */ - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: \"%s\" not available for sendmail programs (filename too long)\n", - prg, cmd); - if (p != NULL) - *p = ' '; -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (filename too long)", - (int) getuid(), cmd); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - -#ifdef DEBUG - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, - "Trying %s\n", cmdbuf); -#endif /* DEBUG */ - if (stat(cmdbuf, &st) < 0) - { - /* can't stat it */ - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: \"%s\" not available for sendmail programs (stat failed)\n", - prg, cmd); - if (p != NULL) - *p = ' '; -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (stat failed)", - (int) getuid(), cmd); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - if (!S_ISREG(st.st_mode) -#ifdef S_ISLNK - && !S_ISLNK(st.st_mode) -#endif /* S_ISLNK */ - ) - { - /* can't stat it */ - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: \"%s\" not available for sendmail programs (not a file)\n", - prg, cmd); - if (p != NULL) - *p = ' '; -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (not a file)", - (int) getuid(), cmd); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - if (access(cmdbuf, X_OK) < 0) - { - /* oops.... crack attack possiblity */ - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: \"%s\" not available for sendmail programs\n", - prg, cmd); - if (p != NULL) - *p = ' '; -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: attempt to use \"%s\"", - (int) getuid(), cmd); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - - /* - ** Create the actual shell input. - */ - - addcmd(cmd, true, strlen(cmd)); - } - isexec = false; - - if (p != NULL) - *p = ' '; - else - break; - - r = strpbrk(p, specialbuf); - if (r == NULL) - { - addcmd(p, false, strlen(p)); - break; - } -#if ALLOWSEMI - if (*r == ';') - { - addcmd(p, false, r - p + 1); - q = r + 1; - continue; - } -#endif /* ALLOWSEMI */ - if ((*r == '&' && *(r + 1) == '&') || - (*r == '|' && *(r + 1) == '|')) - { - addcmd(p, false, r - p + 2); - q = r + 2; - continue; - } - - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: cannot use %c in command\n", prg, *r); -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s", - (int) getuid(), *r, par); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - if (isexec) - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "%s: missing command to exec\n", prg); -#ifndef DEBUG - syslog(LOG_CRIT, "uid %d: missing command to exec", - (int) getuid()); -#endif /* ! DEBUG */ - exit(EX_UNAVAILABLE); - } - /* make sure we created something */ - if (newcmdbuf[0] == '\0') - { - (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, - "Usage: %s -c command\n", prg); -#ifndef DEBUG - syslog(LOG_ERR, "usage"); -#endif /* ! DEBUG */ - exit(EX_USAGE); - } - - /* - ** Now invoke the shell - */ - -#ifdef DEBUG - (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf); -#endif /* DEBUG */ - (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, - (char *)NULL, newenv); - save_errno = errno; -#ifndef DEBUG - syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno)); -#endif /* ! DEBUG */ - errno = save_errno; - sm_perror("/bin/sh"); - exit(EX_OSFILE); - /* NOTREACHED */ - return EX_OSFILE; -} diff --git a/usr/src/cmd/sendmail/aux/vacation.c b/usr/src/cmd/sendmail/aux/vacation.c deleted file mode 100644 index 5a0f93756d..0000000000 --- a/usr/src/cmd/sendmail/aux/vacation.c +++ /dev/null @@ -1,1158 +0,0 @@ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * Copyright (c) 2016 by Delphix. All rights reserved. - * - * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T - * All Rights Reserved - */ - -/* - * Vacation - * Copyright (c) 1983 Eric P. Allman - * Berkeley, California - * - * Copyright (c) 1983 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * VACATION -- return a message to the sender when on vacation. - * - * This program could be invoked as a message receiver - * when someone is on vacation. It returns a message - * specified by the user to whoever sent the mail, taking - * care not to return a message too often to prevent - * "I am on vacation" loops. - * - * For best operation, this program should run setuid to - * root or uucp or someone else that sendmail will believe - * a -f flag from. Otherwise, the user must be careful - * to include a header on their .vacation.msg file. - * - * Positional Parameters: - * the user to collect the vacation message from. - * - * Flag Parameters: - * -I initialize the database. - * -d turn on debugging. - * -tT set the timeout to T. messages arriving more - * often than T will be ignored to avoid loops. - * - * Side Effects: - * A message is sent back to the sender. - * - * Author: - * Eric Allman - * UCB/INGRES - */ - -#define MAXLINE 256 /* max size of a line */ - -#define ONEWEEK (60L*60L*24L*7L) -#define MsgFile "/.vacation.msg" -#define FilterFile "/.vacation.filter" -#define DbFileBase "/.vacation" -#define _PATH_TMP "/tmp/vacation.XXXXXX" - -typedef int bool; - -#define FALSE 0 -#define TRUE 1 - -static time_t Timeout = ONEWEEK; /* timeout between notices per user */ -static DBM *db; -static bool Debug = FALSE; -static bool ListMode = FALSE; -static bool AnswerAll = FALSE; /* default: answer if in To:/Cc: only */ -static char *Subject = NULL; /* subject in message header */ -static char *EncodedSubject = NULL; /* subject in message header */ -static char Charset[MAXLINE]; /* for use in reply message */ -static char *AliasList[MAXLINE]; /* list of aliases to allow */ -static int AliasCount = 0; -static char *myname; /* name of person "on vacation" */ -static char *homedir; /* home directory of said person */ - -extern time_t convtime(char *, char); -extern bool decode_rfc2047(char *, char *, char *); - -static bool ask(char *); -static bool junkmail(char *); -static bool filter_ok(char *, char *); -static bool knows(char *); -static bool sameword(char *, char *); -static char *getfrom(char **); -static char *newstr(char *); -static void AutoInstall(); -static void initialize(char *); -static void sendmessage(char *, char *, char *); -static void setknows(char *); -static void dumplist(); - -void usrerr(const char *, ...); - -int -main(argc, argv) - int argc; - char **argv; -{ - char *from; - char *p, *at, *c; - struct passwd *pw; - char *shortfrom; - char buf[MAXLINE]; - char *message_file = MsgFile; - char *db_file_base = DbFileBase; - char *filter_file = FilterFile; - char *sender; - bool sender_oob = FALSE; - bool initialize_only = FALSE; - - /* process arguments */ - while (--argc > 0 && (p = *++argv) != NULL && *p == '-') - { - switch (*++p) - { - case 'a': /* add this to list of acceptable aliases */ - AliasList[AliasCount++] = argv[1]; - if (argc > 0) { - argc--; argv++; - } - break; - - case 'd': /* debug */ - Debug = TRUE; - break; - - case 'e': /* alternate filter file */ - filter_file = argv[1]; - if (argc > 0) { - argc--; argv++; - } - break; - - case 'f': /* alternate database file name base */ - db_file_base = argv[1]; - if (argc > 0) { - argc--; argv++; - } - break; - - case 'I': /* initialize */ - initialize_only = TRUE; - break; - - case 'j': /* answer all mail, even if not in To/Cc */ - AnswerAll = TRUE; - break; - - case 'l': /* list all respondees */ - ListMode = TRUE; - break; - - case 'm': /* alternate message file */ - message_file = argv[1]; - if (argc > 0) { - argc--; argv++; - } - break; - - case 's': /* sender: use this instead of getfrom() */ - sender = argv[1]; - sender_oob = TRUE; - if (argc > 0) { - argc--; argv++; - } - break; - - case 't': /* set timeout */ - Timeout = convtime(++p, 'w'); - break; - - default: - usrerr("Unknown flag -%s", p); - exit(EX_USAGE); - } - } - - if (initialize_only) - { - initialize(db_file_base); - exit(EX_OK); - } - - /* verify recipient argument */ - if (argc == 0 && !ListMode) - AutoInstall(); - - if (argc != 1 && !ListMode) - { - usrerr("Usage:\tvacation username\n\tvacation -I\n" - "\tvacation -l"); - exit(EX_USAGE); - } - - myname = p; - Charset[0] = '\0'; - - /* find user's home directory */ - if (ListMode) - pw = getpwuid(getuid()); - else - pw = getpwnam(myname); - if (pw == NULL) - { - usrerr("user %s look up failed, name services outage ?", - myname); - exit(EX_TEMPFAIL); - } - homedir = newstr(pw->pw_dir); - - (void) snprintf(buf, sizeof (buf), "%s%s%s", homedir, - (db_file_base[0] == '/') ? "" : "/", db_file_base); - if (!(db = dbm_open(buf, O_RDWR, 0))) { - usrerr("%s: %s\n", buf, strerror(errno)); - exit(EX_DATAERR); - } - - if (ListMode) { - dumplist(); - exit(EX_OK); - } - - if (sender_oob) - { - at = strchr(sender, '@'); - if (at != NULL) - for (c = at + 1; *c; c++) - *c = (char)tolower((char)*c); - from = sender; - shortfrom = sender; - } - else - /* read message from standard input (just from line) */ - from = getfrom(&shortfrom); - - /* check if junk mail or this person is already informed */ - if (!junkmail(shortfrom) && filter_ok(shortfrom, filter_file) && - !knows(shortfrom)) - { - /* mark this person as knowing */ - setknows(shortfrom); - - /* send the message back */ - (void) strlcpy(buf, homedir, sizeof (buf)); - if (message_file[0] != '/') - (void) strlcat(buf, "/", sizeof (buf)); - (void) strlcat(buf, message_file, sizeof (buf)); - if (Debug) - printf("Sending %s to %s\n", buf, from); - else - { - sendmessage(buf, from, myname); - /*NOTREACHED*/ - } - } - while (fgets(buf, MAXLINE, stdin) != NULL) - continue; /* drain input */ - return (EX_OK); -} - -struct entry { - time_t when; - long when_size; - char *who; - long who_size; - struct entry *next; - struct entry *prev; -}; - -static void -dump_content(key_size, key_ptr, content_size, content_ptr) - long key_size, content_size; - char *key_ptr, *content_ptr; -{ - time_t then; - - if (content_size == sizeof (then)) { - bcopy(content_ptr, (char *)&then, sizeof (then)); - (void) printf("%-53.40*s: %s", (int)key_size, key_ptr, - ctime(&then)); - } else { - (void) fprintf(stderr, "content size error: %d\n", - (int)content_size); - } -} - -static void -dump_all_content(first) - struct entry *first; -{ - struct entry *which; - - for (which = first; which != NULL; which = which->next) { - dump_content(which->who_size, which->who, which->when_size, - (char *)&(which->when)); - } -} - -static void -dumplist() -{ - datum content, key; - struct entry *first = NULL, *last = NULL, *new_entry, *curr; - - for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) { - content = dbm_fetch(db, key); - new_entry = (struct entry *)malloc(sizeof (struct entry)); - if (new_entry == NULL) - perror("out of memory"); - new_entry->next = NULL; - new_entry->who = (char *)malloc(key.dsize); - if (new_entry->who == NULL) - perror("out of memory"); - new_entry->who_size = key.dsize; - (void) strlcpy(new_entry->who, key.dptr, key.dsize); - bcopy(content.dptr, (char *)&(new_entry->when), - sizeof (new_entry->when)); - new_entry->when_size = content.dsize; - if (first == NULL) { /* => so is last */ - new_entry->prev = NULL; - new_entry->next = NULL; - first = new_entry; - last = new_entry; - } else { - for (curr = first; curr != NULL && - new_entry->when > curr->when; curr = curr->next) - ; - if (curr == NULL) { - last->next = new_entry; - new_entry->prev = last; - new_entry->next = NULL; - last = new_entry; - } else { - new_entry->next = curr; - new_entry->prev = curr->prev; - if (curr->prev == NULL) - first = new_entry; - else - curr->prev->next = new_entry; - curr->prev = new_entry; - } - } - } - dump_all_content(first); - dbm_close(db); -} - -/* - * GETFROM -- read message from standard input and return sender - * - * Parameters: - * none. - * - * Returns: - * pointer to the sender address. - * - * Side Effects: - * Reads first line from standard input. - */ - -static char * -getfrom(shortp) -char **shortp; -{ - static char line[MAXLINE]; - char *p, *start, *at, *bang, *c; - char saveat; - - /* read the from line */ - if (fgets(line, sizeof (line), stdin) == NULL || - strncmp(line, "From ", 5) != NULL) - { - usrerr("No initial From line"); - exit(EX_PROTOCOL); - } - - /* find the end of the sender address and terminate it */ - start = &line[5]; - p = strchr(start, ' '); - if (p == NULL) - { - usrerr("Funny From line '%s'", line); - exit(EX_PROTOCOL); - } - *p = '\0'; - - /* - * Strip all but the rightmost UUCP host - * to prevent loops due to forwarding. - * Start searching leftward from the leftmost '@'. - * a!b!c!d yields a short name of c!d - * a!b!c!d@e yields a short name of c!d@e - * e@a!b!c yields the same short name - */ -#ifdef VDEBUG -printf("start='%s'\n", start); -#endif /* VDEBUG */ - *shortp = start; /* assume whole addr */ - if ((at = strchr(start, '@')) == NULL) /* leftmost '@' */ - at = p; /* if none, use end of addr */ - saveat = *at; - *at = '\0'; - if ((bang = strrchr(start, '!')) != NULL) { /* rightmost '!' */ - char *bang2; - *bang = '\0'; - /* 2nd rightmost '!' */ - if ((bang2 = strrchr(start, '!')) != NULL) - *shortp = bang2 + 1; /* move past ! */ - *bang = '!'; - } - *at = saveat; -#ifdef VDEBUG -printf("place='%s'\n", *shortp); -#endif /* VDEBUG */ - for (c = at + 1; *c; c++) - *c = (char)tolower((char)*c); - - /* return the sender address */ - return (start); -} - -/* - * JUNKMAIL -- read the header and tell us if this is junk/bulk mail. - * - * Parameters: - * from -- the Return-Path of the sender. We assume that - * anything from "*-REQUEST@*" is bulk mail. - * - * Returns: - * TRUE -- if this is junk or bulk mail (that is, if the - * sender shouldn't receive a response). - * FALSE -- if the sender deserves a response. - * - * Side Effects: - * May read the header from standard input. When this - * returns the position on stdin is undefined. - */ - -static bool -junkmail(from) - char *from; -{ - register char *p; - char buf[MAXLINE+1]; - bool inside, onlist; - - /* test for inhuman sender */ - p = strrchr(from, '@'); - if (p != NULL) - { - *p = '\0'; - if (sameword(&p[-8], "-REQUEST") || - sameword(&p[-10], "Postmaster") || - sameword(&p[-13], "MAILER-DAEMON")) - { - *p = '@'; - return (TRUE); - } - *p = '@'; - } - -#define Delims " \n\t:,:;()<>@!" - - /* read the header looking for "interesting" lines */ - inside = FALSE; - onlist = FALSE; - while (fgets(buf, MAXLINE, stdin) != NULL && buf[0] != '\n') - { - if (buf[0] != ' ' && buf[0] != '\t' && strchr(buf, ':') == NULL) - return (FALSE); /* no header found */ - - p = strtok(buf, Delims); - if (p == NULL) - continue; - - if (sameword(p, "To") || sameword(p, "Cc")) - { - inside = TRUE; - p = strtok((char *)NULL, Delims); - if (p == NULL) - continue; - - } else /* continuation line? */ - if (inside) - inside = (buf[0] == ' ' || buf[0] == '\t'); - - if (inside) { - int i; - - do { - if (sameword(p, myname)) - onlist = TRUE; /* I am on the list */ - - for (i = 0; i < AliasCount; i++) - if (sameword(p, AliasList[i])) - onlist = TRUE; /* alias on list */ - - } while (p = strtok((char *)NULL, Delims)); - continue; - } - - if (sameword(p, "Precedence")) - { - /* find the value of this field */ - p = strtok((char *)NULL, Delims); - if (p == NULL) - continue; - - /* see if it is "junk" or "bulk" */ - p[4] = '\0'; - if (sameword(p, "junk") || sameword(p, "bulk")) - return (TRUE); - } - - if (sameword(p, "Subject")) - { - char *decoded_subject; - - Subject = newstr(buf+9); - if (p = strrchr(Subject, '\n')) - *p = '\0'; - EncodedSubject = newstr(Subject); - decoded_subject = newstr(Subject); - if (decode_rfc2047(Subject, decoded_subject, Charset)) - Subject = decoded_subject; - else - Charset[0] = '\0'; - if (Debug) - printf("Subject=%s\n", Subject); - } - } - if (AnswerAll) - return (FALSE); - else - return (!onlist); -} - -/* - * FILTER_OK -- see if the Return-Path is in the filter file. - * Note that a non-existent filter file means everything - * is OK, but an empty file means nothing is OK. - * - * Parameters: - * from -- the Return-Path of the sender. - * - * Returns: - * TRUE -- if this is in the filter file - * (sender should receive a response). - * FALSE -- if the sender does not deserve a response. - */ - -static bool -filter_ok(from, filter_file) - char *from; - char *filter_file; -{ - char file[MAXLINE]; - char line[MAXLINE]; - char *match_start; - size_t line_len, from_len; - bool result = FALSE; - bool negated = FALSE; - FILE *f; - - from_len = strlen(from); - (void) strlcpy(file, homedir, sizeof (file)); - if (filter_file[0] != '/') - (void) strlcat(file, "/", sizeof (file)); - (void) strlcat(file, filter_file, sizeof (file)); - f = fopen(file, "r"); - if (f == NULL) { - /* - * If the file does not exist, then there is no filter to - * apply, so we simply return TRUE. - */ - if (Debug) - (void) printf("%s does not exist, filter ok.\n", - file); - return (TRUE); - } - while (fgets(line, MAXLINE, f)) { - line_len = strlen(line); - /* zero out trailing newline */ - if (line[line_len - 1] == '\n') - line[--line_len] = '\0'; - /* skip blank lines */ - if (line_len == 0) - continue; - /* skip comment lines */ - if (line[0] == '#') - continue; - if (line[0] == '!') { - negated = TRUE; - match_start = &line[1]; - line_len--; - } else { - negated = FALSE; - match_start = &line[0]; - } - if (strchr(line, '@') != NULL) { - /* @ => full address */ - if (strcasecmp(match_start, from) == 0) { - result = TRUE; - if (Debug) - (void) printf("filter match on %s\n", - line); - break; - } - } else { - /* no @ => domain */ - if (from_len <= line_len) - continue; - /* - * Make sure the last part of from is the domain line - * and that the character immediately preceding is an - * '@' or a '.', otherwise we could get false positives - * from e.g. twinsun.com for sun.com . - */ - if (strncasecmp(&from[from_len - line_len], - match_start, line_len) == 0 && - (from[from_len - line_len -1] == '@' || - from[from_len - line_len -1] == '.')) { - result = TRUE; - if (Debug) - (void) printf("filter match on %s\n", - line); - break; - } - } - } - (void) fclose(f); - if (Debug && !result) - (void) printf("no filter match\n"); - return (!negated && result); -} - -/* - * KNOWS -- predicate telling if user has already been informed. - * - * Parameters: - * user -- the user who sent this message. - * - * Returns: - * TRUE if 'user' has already been informed that the - * recipient is on vacation. - * FALSE otherwise. - * - * Side Effects: - * none. - */ - -static bool -knows(user) - char *user; -{ - datum key, data; - time_t now, then; - - (void) time(&now); - key.dptr = user; - key.dsize = strlen(user) + 1; - data = dbm_fetch(db, key); - if (data.dptr == NULL) - return (FALSE); - - bcopy(data.dptr, (char *)&then, sizeof (then)); - if (then + Timeout < now) - return (FALSE); - if (Debug) - printf("User %s already knows\n", user); - return (TRUE); -} - -/* - * SETKNOWS -- set that this user knows about the vacation. - * - * Parameters: - * user -- the user who should be marked. - * - * Returns: - * none. - * - * Side Effects: - * The dbm file is updated as appropriate. - */ - -static void -setknows(user) - char *user; -{ - datum key, data; - time_t now; - - key.dptr = user; - key.dsize = strlen(user) + 1; - (void) time(&now); - data.dptr = (char *)&now; - data.dsize = sizeof (now); - dbm_store(db, key, data, DBM_REPLACE); -} - -static bool -any8bitchars(line) - char *line; -{ - char *c; - - for (c = line; *c; c++) - if (*c & 0x80) - return (TRUE); - return (FALSE); -} - -/* - * SENDMESSAGE -- send a message to a particular user. - * - * Parameters: - * msgf -- filename containing the message. - * user -- user who should receive it. - * - * Returns: - * none. - * - * Side Effects: - * sends mail to 'user' using /usr/lib/sendmail. - */ - -static void -sendmessage(msgf, user, myname) - char *msgf; - char *user; - char *myname; -{ - FILE *f, *fpipe, *tmpf; - char line[MAXLINE]; - char *p, *tmpf_name; - int i, pipefd[2], tmpfd; - bool seen8bitchars = FALSE; - bool in_header = TRUE; - - /* find the message to send */ - f = fopen(msgf, "r"); - if (f == NULL) - { - f = fopen("/etc/mail/vacation.def", "r"); - if (f == NULL) { - usrerr("No message to send"); - exit(EX_OSFILE); - } - } - - if (pipe(pipefd) < 0) { - usrerr("pipe() failed"); - exit(EX_OSERR); - } - i = fork(); - if (i < 0) { - usrerr("fork() failed"); - exit(EX_OSERR); - } - if (i == 0) { - dup2(pipefd[0], 0); - close(pipefd[0]); - close(pipefd[1]); - fclose(f); - execl("/usr/lib/sendmail", "sendmail", "-eq", "-f", myname, - "--", user, NULL); - usrerr("can't exec /usr/lib/sendmail"); - exit(EX_OSERR); - } - close(pipefd[0]); - fpipe = fdopen(pipefd[1], "w"); - if (fpipe == NULL) { - usrerr("fdopen() failed"); - exit(EX_OSERR); - } - fprintf(fpipe, "To: %s\n", user); - fputs("Auto-Submitted: auto-replied\n", fpipe); - fputs("X-Mailer: vacation %I%\n", fpipe); - - /* - * We used to write directly to the pipe. But now we need to know - * what character set to use, and we need to examine the entire - * message to determine this. So write to a temp file first. - */ - tmpf_name = strdup(_PATH_TMP); - if (tmpf_name == NULL) { - usrerr("newstr: cannot alloc memory"); - exit(EX_OSERR); - } - tmpfd = -1; - tmpfd = mkstemp(tmpf_name); - if (tmpfd == -1) { - usrerr("can't open temp file %s", tmpf_name); - exit(EX_OSERR); - } - tmpf = fdopen(tmpfd, "w"); - if (tmpf == NULL) { - usrerr("can't open temp file %s", tmpf_name); - exit(EX_OSERR); - } - while (fgets(line, MAXLINE, f)) { - /* - * Check for a line with no ':' character. If it's just \n, - * we're at the end of the headers and all is fine. Or if - * it starts with white-space, then it's a continuation header. - * Otherwise, it's the start of the body, which means the - * header/body separator was skipped. So output it. - */ - if (in_header && line[0] != '\0' && strchr(line, ':') == NULL) { - if (line[0] == '\n') - in_header = FALSE; - else if (!isspace(line[0])) { - in_header = FALSE; - fputs("\n", tmpf); - } - } - p = strchr(line, '$'); - if (p && strncmp(p, "$SUBJECT", 8) == 0) { - *p = '\0'; - seen8bitchars |= any8bitchars(line); - fputs(line, tmpf); - if (Subject) { - if (in_header) - fputs(EncodedSubject, tmpf); - else { - seen8bitchars |= any8bitchars(Subject); - fputs(Subject, tmpf); - } - } - seen8bitchars |= any8bitchars(p+8); - fputs(p+8, tmpf); - continue; - } - seen8bitchars |= any8bitchars(line); - fputs(line, tmpf); - } - fclose(f); - fclose(tmpf); - - /* - * If we haven't seen a funky Subject with Charset, use the default. - * If we have and it's us-ascii, 8-bit chars in the message file will - * still result in iso-8859-1. - */ - if (Charset[0] == '\0') - (void) strlcpy(Charset, (seen8bitchars) ? "iso-8859-1" : - "us-ascii", sizeof (Charset)); - else if ((strcasecmp(Charset, "us-ascii") == 0) && seen8bitchars) - (void) strlcpy(Charset, "iso-8859-1", sizeof (Charset)); - if (Debug) - printf("Charset is %s\n", Charset); - fprintf(fpipe, "Content-Type: text/plain; charset=%s\n", Charset); - fputs("Mime-Version: 1.0\n", fpipe); - - /* - * Now read back in from the temp file and write to the pipe. - */ - tmpf = fopen(tmpf_name, "r"); - if (tmpf == NULL) { - usrerr("can't open temp file %s", tmpf_name); - exit(EX_OSERR); - } - while (fgets(line, MAXLINE, tmpf)) - fputs(line, fpipe); - fclose(fpipe); - fclose(tmpf); - (void) unlink(tmpf_name); - free(tmpf_name); -} - -/* - * INITIALIZE -- initialize the database before leaving for vacation - * - * Parameters: - * none. - * - * Returns: - * none. - * - * Side Effects: - * Initializes the files .vacation.{pag,dir} in the - * caller's home directory. - */ - -static void -initialize(db_file_base) - char *db_file_base; -{ - char *homedir; - char buf[MAXLINE]; - DBM *db; - - setgid(getgid()); - setuid(getuid()); - homedir = getenv("HOME"); - if (homedir == NULL) { - usrerr("No home!"); - exit(EX_NOUSER); - } - (void) snprintf(buf, sizeof (buf), "%s%s%s", homedir, - (db_file_base[0] == '/') ? "" : "/", db_file_base); - - if (!(db = dbm_open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0644))) { - usrerr("%s: %s\n", buf, strerror(errno)); - exit(EX_DATAERR); - } - dbm_close(db); -} - -/* - * USRERR -- print user error - * - * Parameters: - * f -- format. - * - * Returns: - * none. - * - * Side Effects: - * none. - */ - -/* PRINTFLIKE1 */ -void -usrerr(const char *f, ...) -{ - va_list alist; - - va_start(alist, f); - (void) fprintf(stderr, "vacation: "); - (void) vfprintf(stderr, f, alist); - (void) fprintf(stderr, "\n"); - va_end(alist); -} - -/* - * NEWSTR -- copy a string - * - * Parameters: - * s -- the string to copy. - * - * Returns: - * A copy of the string. - * - * Side Effects: - * none. - */ - -static char * -newstr(s) - char *s; -{ - char *p; - size_t s_sz = strlen(s); - - p = malloc(s_sz + 1); - if (p == NULL) - { - usrerr("newstr: cannot alloc memory"); - exit(EX_OSERR); - } - (void) strlcpy(p, s, s_sz + 1); - return (p); -} - -/* - * SAMEWORD -- return TRUE if the words are the same - * - * Ignores case. - * - * Parameters: - * a, b -- the words to compare. - * - * Returns: - * TRUE if a & b match exactly (modulo case) - * FALSE otherwise. - * - * Side Effects: - * none. - */ - -static bool -sameword(a, b) - register char *a, *b; -{ - char ca, cb; - - do - { - ca = *a++; - cb = *b++; - if (isascii(ca) && isupper(ca)) - ca = ca - 'A' + 'a'; - if (isascii(cb) && isupper(cb)) - cb = cb - 'A' + 'a'; - } while (ca != '\0' && ca == cb); - return (ca == cb); -} - -/* - * When invoked with no arguments, we fall into an automatic installation - * mode, stepping the user through a default installation. - */ - -static void -AutoInstall() -{ - char file[MAXLINE]; - char forward[MAXLINE]; - char cmd[MAXLINE]; - char line[MAXLINE]; - char *editor; - FILE *f; - struct passwd *pw; - extern mode_t umask(mode_t cmask); - - umask(022); - pw = getpwuid(getuid()); - if (pw == NULL) { - usrerr("User ID unknown"); - exit(EX_NOUSER); - } - myname = strdup(pw->pw_name); - if (myname == NULL) { - usrerr("Out of memory"); - exit(EX_OSERR); - } - homedir = getenv("HOME"); - if (homedir == NULL) { - usrerr("Home directory unknown"); - exit(EX_NOUSER); - } - - printf("This program can be used to answer your mail automatically\n"); - printf("when you go away on vacation.\n"); - (void) strlcpy(file, homedir, sizeof (file)); - (void) strlcat(file, MsgFile, sizeof (file)); - do { - f = fopen(file, "r"); - if (f) { - printf("You have a message file in %s.\n", file); - if (ask("Would you like to see it")) { - (void) snprintf(cmd, sizeof (cmd), - "/usr/bin/more %s", file); - system(cmd); - } - if (ask("Would you like to edit it")) - f = NULL; - } else { - printf("You need to create a message file" - " in %s first.\n", file); - f = fopen(file, "w"); - if (f == NULL) { - usrerr("Cannot open %s", file); - exit(EX_CANTCREAT); - } - fprintf(f, "Subject: away from my mail\n"); - fprintf(f, "\nI will not be reading my mail" - " for a while.\n"); - fprintf(f, "Your mail regarding \"$SUBJECT\" will" - " be read when I return.\n"); - fclose(f); - f = NULL; - } - if (f == NULL) { - editor = getenv("VISUAL"); - if (editor == NULL) - editor = getenv("EDITOR"); - if (editor == NULL) - editor = "/usr/bin/vi"; - (void) snprintf(cmd, sizeof (cmd), "%s %s", editor, - file); - printf("Please use your editor (%s)" - " to edit this file.\n", editor); - system(cmd); - } - } while (f == NULL); - fclose(f); - (void) strlcpy(forward, homedir, sizeof (forward)); - (void) strlcat(forward, "/.forward", sizeof (forward)); - f = fopen(forward, "r"); - if (f) { - printf("You have a .forward file" - " in your home directory containing:\n"); - while (fgets(line, MAXLINE, f)) - printf(" %s", line); - fclose(f); - if (!ask("Would you like to remove it and" - " disable the vacation feature")) - exit(EX_OK); - if (unlink(forward)) - perror("Error removing .forward file:"); - else - printf("Back to normal reception of mail.\n"); - exit(EX_OK); - } - - printf("To enable the vacation feature" - " a \".forward\" file is created.\n"); - if (!ask("Would you like to enable the vacation feature")) { - printf("OK, vacation feature NOT enabled.\n"); - exit(EX_OK); - } - f = fopen(forward, "w"); - if (f == NULL) { - perror("Error opening .forward file"); - exit(EX_CANTCREAT); - } - fprintf(f, "\\%s, \"|/usr/bin/vacation %s\"\n", myname, myname); - fclose(f); - printf("Vacation feature ENABLED." - " Please remember to turn it off when\n"); - printf("you get back from vacation. Bon voyage.\n"); - - initialize(DbFileBase); - exit(EX_OK); -} - - -/* - * Ask the user a question until we get a reasonable answer - */ - -static bool -ask(prompt) - char *prompt; -{ - char line[MAXLINE]; - char *res; - - for (;;) { - printf("%s? ", prompt); - fflush(stdout); - res = fgets(line, sizeof (line), stdin); - if (res == NULL) - return (FALSE); - if (res[0] == 'y' || res[0] == 'Y') - return (TRUE); - if (res[0] == 'n' || res[0] == 'N') - return (FALSE); - printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n"); - } -} diff --git a/usr/src/cmd/sendmail/util/Makefile b/usr/src/cmd/sendmail/util/Makefile new file mode 100644 index 0000000000..455879af02 --- /dev/null +++ b/usr/src/cmd/sendmail/util/Makefile @@ -0,0 +1,125 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# cmd/sendmail/aux/Makefile +# +include ../../Makefile.cmd +include ../Makefile.cmd + +PROG= mailstats mconnect vacation mailcompat praliases + +LIBPROG= mail.local smrsh + +USRSBINPROG= etrn makemap editmap + +LIBSMTPSMPROG= mailq + +# $(PROG) by default +CLOBBERFILES= $(LIBPROG) $(USRSBINPROG) $(LIBSMTPSMPROG) + +OBJS= $(PROG:%=%.o) + +.PARALLEL: $(OBJS) $(PROG) $(LIBPROG) $(USRSBINPROG) + +SRCS= $(PROG:%=%.c) + +editmap := LDLIBS += -lldap +mail.local := LDLIBS += -lsocket -lnsl -lmail -lldap +mailq := LDLIBS += -lsecdb +mailstats := LDLIBS += -lldap +makemap := LDLIBS += -lldap +mconnect := LDLIBS += -lsocket -lnsl +praliases := LDLIBS += -lldap +smrsh := LDLIBS += -lldap +vacation := LDLIBS += -lldap +$(ROOTLIBSMTPSM)/mailq := FILEMODE = 4555 + +INCPATH= -I../src -I../db -I../include + +ENVDEF= -DNOT_SENDMAIL +SUNENVDEF= -DSUN_EXTENSIONS -DUSE_VENDOR_CF_PATH +DBMDEF= -DNDBM -DNEWDB + +CPPFLAGS = $(INCPATH) $(ENVDEF) $(SUNENVDEF) $(DBMDEF) $(CPPFLAGS.sm) + +# Nearly every support application provides sleep(). This isn't incompatible +# with libc, but can be confined to the applications themselves. +LDFLAGS += $(MAPFILE.NGB:%=-M%) + +.KEEP_STATE: + +all: $(PROG) $(LIBSMTPSMPROG) $(LIBPROG) $(USRSBINPROG) + +convtime.o: ../src/convtime.c + $(COMPILE.c) ../src/convtime.c + $(POST_PROCESS_O) + +vacation: vacation.o convtime.o rfc2047.o ../libsm/libsm.a + $(LINK.c) vacation.o convtime.o rfc2047.o -o $@ $(LDLIBS) \ + ../libsm/libsm.a + $(POST_PROCESS) + +mail.local: mail.local.o ../libsmutil/libsmutil.a ../libsm/libsm.a + $(LINK.c) mail.local.o -o $@ $(LDLIBS) ../libsmutil/libsmutil.a \ + ../libsm/libsm.a + $(POST_PROCESS) + +smrsh: smrsh.o ../libsm/libsm.a + $(LINK.c) smrsh.o -o $@ $(LDLIBS) ../libsm/libsm.a + $(POST_PROCESS) + +makemap: makemap.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ + ../db/libdb.a ../libsm/libsm.a + $(LINK.c) makemap.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ + ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a + $(POST_PROCESS) + +editmap: editmap.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ + ../db/libdb.a ../libsm/libsm.a + $(LINK.c) editmap.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ + ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a + $(POST_PROCESS) + +praliases: praliases.o ../libsmutil/libsmutil.a ../libsmdb/libsmdb.a \ + ../libsm/libsm.a + $(LINK.c) praliases.o -o $@ $(LDLIBS) ../libsmdb/libsmdb.a \ + ../libsmutil/libsmutil.a ../db/libdb.a ../libsm/libsm.a + $(POST_PROCESS) + +mailstats: mailstats.o ../libsmutil/libsmutil.a ../libsm/libsm.a + $(LINK.c) mailstats.o -o $@ $(LDLIBS) ../libsmutil/libsmutil.a \ + ../libsm/libsm.a + $(POST_PROCESS) + +install: all $(ROOTPROG) $(ROOTLIB)/mail.local $(ROOTLIB)/smrsh \ + $(ROOTLIBSMTPSM)/mailq $(ROOTUSRSBIN)/makemap \ + $(ROOTUSRSBIN)/etrn $(ROOTUSRSBIN)/editmap + +clean: + $(RM) $(OBJS) *.o + +lint: lint_PROG + + +include ../../Makefile.targ diff --git a/usr/src/cmd/sendmail/util/editmap.c b/usr/src/cmd/sendmail/util/editmap.c new file mode 100644 index 0000000000..a86a24d456 --- /dev/null +++ b/usr/src/cmd/sendmail/util/editmap.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1992 Eric P. Allman. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include +#ifndef lint +SM_UNUSED(static char copyright[]) = +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ + Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* ! lint */ + +#ifndef lint +SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.25 2007/05/11 18:50:35 ca Exp $"; +#endif /* ! lint */ + + +#include +#ifndef ISC_UNIX +# include +#endif /* ! ISC_UNIX */ +#include +#include +#include +#ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +#endif /* EX_OK */ +#include +#include +#include +#include +#include + +uid_t RealUid; +gid_t RealGid; +char *RealUserName; +uid_t RunAsUid; +gid_t RunAsGid; +char *RunAsUserName; +int Verbose = 2; +bool DontInitGroups = false; +uid_t TrustedUid = 0; +BITMAP256 DontBlameSendmail; + +#define BUFSIZE 1024 +#define ISSEP(c) (isascii(c) && isspace(c)) + + +static void usage __P((char *)); + +static void +usage(progname) + char *progname; +{ + fprintf(stderr, + "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n", + progname); + exit(EX_USAGE); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + char *progname; + char *cfile; + bool verbose = false; + bool query = false; + bool update = false; + bool remove = false; + bool inclnull = false; + bool foldcase = true; + unsigned int nops = 0; + int exitstat; + int opt; + char *typename = NULL; + char *mapname = NULL; + char *keyname = NULL; + char *value = NULL; + int mode; + int smode; + int putflags = 0; + long sff = SFF_ROOTOK|SFF_REGONLY; + struct passwd *pw; + SMDB_DATABASE *database; + SMDB_DBENT db_key, db_val; + SMDB_DBPARAMS params; + SMDB_USER_INFO user_info; +#if HASFCHOWN + FILE *cfp; + char buf[MAXLINE]; +#endif /* HASFCHOWN */ + static char rnamebuf[MAXNAME]; /* holds RealUserName */ + extern char *optarg; + extern int optind; + + memset(¶ms, '\0', sizeof params); + params.smdbp_cache_size = 1024 * 1024; + + progname = strrchr(argv[0], '/'); + if (progname != NULL) + progname++; + else + progname = argv[0]; + cfile = _PATH_SENDMAILCF; + + clrbitmap(DontBlameSendmail); + RunAsUid = RealUid = getuid(); + RunAsGid = RealGid = getgid(); + pw = getpwuid(RealUid); + if (pw != NULL) + (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); + else + (void) sm_snprintf(rnamebuf, sizeof rnamebuf, + "Unknown UID %d", (int) RealUid); + RunAsUserName = RealUserName = rnamebuf; + user_info.smdbu_id = RunAsUid; + user_info.smdbu_group_id = RunAsGid; + (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, + SMDB_MAX_USER_NAME_LEN); + +#define OPTIONS "C:fquxvN" + while ((opt = getopt(argc, argv, OPTIONS)) != -1) + { + switch (opt) + { + case 'C': + cfile = optarg; + break; + + case 'f': + foldcase = false; + break; + + case 'q': + query = true; + nops++; + break; + + case 'u': + update = true; + nops++; + break; + + case 'x': + remove = true; + nops++; + break; + + case 'v': + verbose = true; + break; + + case 'N': + inclnull = true; + break; + + default: + usage(progname); + assert(0); /* NOTREACHED */ + } + } + + if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) + sff |= SFF_NOSLINK; + if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) + sff |= SFF_NOHLINK; + if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) + sff |= SFF_NOWLINK; + + argc -= optind; + argv += optind; + if ((nops != 1) || + (query && argc != 3) || + (remove && argc != 3) || + (update && argc <= 3)) + { + usage(progname); + assert(0); /* NOTREACHED */ + } + + typename = argv[0]; + mapname = argv[1]; + keyname = argv[2]; + if (update) + value = argv[3]; + + if (foldcase) + { + char *p; + + for (p = keyname; *p != '\0'; p++) + { + if (isascii(*p) && isupper(*p)) + *p = tolower(*p); + } + } + + +#if HASFCHOWN + /* Find TrustedUser value in sendmail.cf */ + if ((cfp = fopen(cfile, "r")) == NULL) + { + fprintf(stderr, "%s: %s: %s\n", progname, + cfile, sm_errstring(errno)); + exit(EX_NOINPUT); + } + while (fgets(buf, sizeof(buf), cfp) != NULL) + { + register char *b; + + if ((b = strchr(buf, '\n')) != NULL) + *b = '\0'; + + b = buf; + switch (*b++) + { + case 'O': /* option */ + if (strncasecmp(b, " TrustedUser", 12) == 0 && + !(isascii(b[12]) && isalnum(b[12]))) + { + b = strchr(b, '='); + if (b == NULL) + continue; + while (isascii(*++b) && isspace(*b)) + continue; + if (isascii(*b) && isdigit(*b)) + TrustedUid = atoi(b); + else + { + TrustedUid = 0; + pw = getpwnam(b); + if (pw == NULL) + fprintf(stderr, + "TrustedUser: unknown user %s\n", b); + else + TrustedUid = pw->pw_uid; + } + +# ifdef UID_MAX + if (TrustedUid > UID_MAX) + { + fprintf(stderr, + "TrustedUser: uid value (%ld) > UID_MAX (%ld)", + (long) TrustedUid, + (long) UID_MAX); + TrustedUid = 0; + } +# endif /* UID_MAX */ + break; + } + /* FALLTHROUGH */ + + default: + continue; + } + } + (void) fclose(cfp); +#endif /* HASFCHOWN */ + + if (query) + { + mode = O_RDONLY; + smode = S_IRUSR; + } + else + { + mode = O_RDWR | O_CREAT; + sff |= SFF_CREAT|SFF_NOTEXCL; + smode = S_IWUSR; + } + + params.smdbp_num_elements = 4096; + + errno = smdb_open_database(&database, mapname, mode, smode, sff, + typename, &user_info, ¶ms); + if (errno != SMDBE_OK) + { + char *hint; + + if (errno == SMDBE_UNSUPPORTED_DB_TYPE && + (hint = smdb_db_definition(typename)) != NULL) + fprintf(stderr, + "%s: Need to recompile with -D%s for %s support\n", + progname, hint, typename); + else + fprintf(stderr, + "%s: error opening type %s map %s: %s\n", + progname, typename, mapname, + sm_errstring(errno)); + exit(EX_CANTCREAT); + } + + (void) database->smdb_sync(database, 0); + + if (geteuid() == 0 && TrustedUid != 0) + { + errno = database->smdb_set_owner(database, TrustedUid, -1); + if (errno != SMDBE_OK) + { + fprintf(stderr, + "WARNING: ownership change on %s failed %s", + mapname, sm_errstring(errno)); + } + } + + exitstat = EX_OK; + if (query) + { + memset(&db_key, '\0', sizeof db_key); + memset(&db_val, '\0', sizeof db_val); + + db_key.data = keyname; + db_key.size = strlen(keyname); + if (inclnull) + db_key.size++; + + errno = database->smdb_get(database, &db_key, &db_val, 0); + if (errno != SMDBE_OK) + { + /* XXX - Need to distinguish between not found */ + fprintf(stderr, + "%s: couldn't find key %s in map %s\n", + progname, keyname, mapname); + exitstat = EX_UNAVAILABLE; + } + else + { + printf("%.*s\n", (int) db_val.size, + (char *) db_val.data); + } + } + else if (update) + { + memset(&db_key, '\0', sizeof db_key); + memset(&db_val, '\0', sizeof db_val); + + db_key.data = keyname; + db_key.size = strlen(keyname); + if (inclnull) + db_key.size++; + db_val.data = value; + db_val.size = strlen(value); + if (inclnull) + db_val.size++; + + errno = database->smdb_put(database, &db_key, &db_val, + putflags); + if (errno != SMDBE_OK) + { + fprintf(stderr, + "%s: error updating (%s, %s) in map %s: %s\n", + progname, keyname, value, mapname, + sm_errstring(errno)); + exitstat = EX_IOERR; + } + } + else if (remove) + { + memset(&db_key, '\0', sizeof db_key); + memset(&db_val, '\0', sizeof db_val); + + db_key.data = keyname; + db_key.size = strlen(keyname); + if (inclnull) + db_key.size++; + + errno = database->smdb_del(database, &db_key, 0); + + switch (errno) + { + case SMDBE_NOT_FOUND: + fprintf(stderr, + "%s: key %s doesn't exist in map %s\n", + progname, keyname, mapname); + /* Don't set exitstat */ + break; + case SMDBE_OK: + /* All's well */ + break; + default: + fprintf(stderr, + "%s: couldn't remove key %s in map %s (error)\n", + progname, keyname, mapname); + exitstat = EX_IOERR; + break; + } + } + else + { + assert(0); /* NOT REACHED */ + } + + /* + ** Now close the database. + */ + + errno = database->smdb_close(database); + if (errno != SMDBE_OK) + { + fprintf(stderr, "%s: close(%s): %s\n", + progname, mapname, sm_errstring(errno)); + exitstat = EX_IOERR; + } + smdb_free_database(database); + + exit(exitstat); + /* NOTREACHED */ + return exitstat; +} diff --git a/usr/src/cmd/sendmail/util/etrn.pl b/usr/src/cmd/sendmail/util/etrn.pl new file mode 100644 index 0000000000..fc067b1a6a --- /dev/null +++ b/usr/src/cmd/sendmail/util/etrn.pl @@ -0,0 +1,273 @@ +#!/usr/perl5/bin/perl -w +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1996-2000 by John T. Beck +# All rights reserved. +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +require 5.8.4; # minimal Perl version required +use strict; +use warnings; +use English; + +use Socket; +use Getopt::Std; +our ($opt_v, $opt_b); + +# system requirements: +# must have 'hostname' program. + +my $port = 'smtp'; +select(STDERR); + +chop(my $name = `hostname || uname -n`); + +my ($hostname) = (gethostbyname($name))[0]; + +my $usage = "Usage: $PROGRAM_NAME [-bv] host [args]"; +getopts('bv'); +my $verbose = $opt_v; +my $boot_check = $opt_b; +my $server = shift(@ARGV); +my @hosts = @ARGV; +die $usage unless $server; +my @cwfiles = (); +my $alarm_action = ""; + +if (!@hosts) { + push(@hosts, $hostname); + + open(CF, "){ + # look for a line starting with "Fw" + if (/^Fw.*$/) { + my $cwfile = $ARG; + chop($cwfile); + my $optional = /^Fw-o/; + # extract the file name + $cwfile =~ s,^Fw[^/]*,,; + + # strip the options after the filename + $cwfile =~ s/ [^ ]+$//; + + if (-r $cwfile) { + push (@cwfiles, $cwfile); + } else { + die "$cwfile is not readable" unless $optional; + } + } + # look for a line starting with "Cw" + if (/^Cw(.*)$/) { + my @cws = split (' ', $1); + while (@cws) { + my $thishost = shift(@cws); + push(@hosts, $thishost) + unless $thishost =~ "$hostname|localhost"; + } + } + } + close(CF); + + for my $cwfile (@cwfiles) { + if (open(CW, "<$cwfile")) { + while () { + next if /^\#/; + my $thishost = $ARG; + chop($thishost); + push(@hosts, $thishost) + unless $thishost =~ $hostname; + } + close(CW); + } else { + die "open $cwfile: $ERRNO"; + } + } + # Do this automatically if no client hosts are specified. + $boot_check = "yes"; +} + +my ($proto) = (getprotobyname('tcp'))[2]; +($port) = (getservbyname($port, 'tcp'))[2] + unless $port =~ /^\d+/; + +if ($boot_check) { + # first connect to localhost to verify that we can accept connections + print "verifying that localhost is accepting SMTP connections\n" + if ($verbose); + my $localhost_ok = 0; + ($name, my $laddr) = (gethostbyname('localhost'))[0, 4]; + (!defined($name)) && die "gethostbyname failed, unknown host $server"; + + # get a connection + my $sinl = sockaddr_in($port, $laddr); + my $save_errno = 0; + for (my $num_tries = 1; $num_tries < 5; $num_tries++) { + socket(S, &PF_INET, &SOCK_STREAM, $proto) + || die "socket: $ERRNO"; + if (connect(S, $sinl)) { + &alarm("sending 'quit' to $server"); + print S "quit\n"; + alarm(0); + $localhost_ok = 1; + close(S); + alarm(0); + last; + } + print STDERR "localhost connect failed ($num_tries)\n"; + $save_errno = $ERRNO; + sleep(1 << $num_tries); + close(S); + alarm(0); + } + if (! $localhost_ok) { + die "could not connect to localhost: $save_errno\n"; + } +} + +# look it up + +($name, my $thataddr) = (gethostbyname($server))[0, 4]; +(!defined($name)) && die "gethostbyname failed, unknown host $server"; + +# get a connection +my $sinr = sockaddr_in($port, $thataddr); +socket(S, &PF_INET, &SOCK_STREAM, $proto) + || die "socket: $ERRNO"; +print "server = $server\n" if (defined($verbose)); +&alarm("connect to $server"); +if (! connect(S, $sinr)) { + die "cannot connect to $server: $ERRNO\n"; +} +alarm(0); +select((select(S), $OUTPUT_AUTOFLUSH = 1)[0]); # don't buffer output to S + +# read the greeting +&alarm("greeting with $server"); +while () { + alarm(0); + print if $verbose; + if (/^(\d+)([- ])/) { + # SMTP's initial greeting response code is 220. + if ($1 != 220) { + &alarm("giving up after bad response from $server"); + &read_response($2, $verbose); + alarm(0); + print STDERR "$server: NOT 220 greeting: $ARG" + if ($verbose); + } + last if ($2 eq " "); + } else { + print STDERR "$server: NOT 220 greeting: $ARG" + if ($verbose); + close(S); + } + &alarm("greeting with $server"); +} +alarm(0); + +&alarm("sending ehlo to $server"); +&ps("ehlo $hostname"); +my $etrn_support = 0; +while () { + if (/^250([- ])ETRN(.+)$/) { + $etrn_support = 1; + } + print if $verbose; + last if /^\d+ /; +} +alarm(0); + +if ($etrn_support) { + print "ETRN supported\n" if ($verbose); + &alarm("sending etrn to $server"); + while (@hosts) { + $server = shift(@hosts); + &ps("etrn $server"); + while () { + print if $verbose; + last if /^\d+ /; + } + sleep(1); + } +} else { + print "\nETRN not supported\n\n" +} + +&alarm("sending 'quit' to $server"); +&ps("quit"); +while () { + print if $verbose; + last if /^\d+ /; +} +close(S); +alarm(0); + +select(STDOUT); +exit(0); + +# print to the server (also to stdout, if -v) +sub ps +{ + my ($p) = @_; + print ">>> $p\n" if $verbose; + print S "$p\n"; +} + +sub alarm +{ + ($alarm_action) = @_; + alarm(10); + $SIG{ALRM} = 'handle_alarm'; +} + +sub handle_alarm +{ + &giveup($alarm_action); +} + +sub giveup +{ + my $reason = @_; + (my $pk, my $file, my $line); + ($pk, $file, $line) = caller; + + print "Timed out during $reason\n" if $verbose; + exit(1); +} + +# read the rest of the current smtp daemon's response (and toss it away) +sub read_response +{ + (my $done, $verbose) = @_; + (my @resp); + print my $s if $verbose; + while (($done eq "-") && ($s = ) && ($s =~ /^\d+([- ])/)) { + print $s if $verbose; + $done = $1; + push(@resp, $s); + } + return @resp; +} diff --git a/usr/src/cmd/sendmail/util/mail.local.c b/usr/src/cmd/sendmail/util/mail.local.c new file mode 100644 index 0000000000..0d04d3c58c --- /dev/null +++ b/usr/src/cmd/sendmail/util/mail.local.c @@ -0,0 +1,1225 @@ +/* + * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level + * of the sendmail distribution. + */ + +/* + * Copyright 1994-2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef lint +static char sccsid[] = "@(#)mail.local.c 8.83 (Berkeley) 12/17/98"; +static char sccsi2[] = "%W% (Sun) %G%"; +#endif /* not lint */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +#include +#include + +#include +#include + +/* +** If you don't have flock, you could try using lockf instead. +*/ + +#ifdef LDA_USE_LOCKF +# define flock(a, b) lockf(a, b, 0) +# ifdef LOCK_EX +# undef LOCK_EX +# endif /* LOCK_EX */ +# define LOCK_EX F_LOCK +#endif /* LDA_USE_LOCKF */ + +#ifndef LOCK_EX +# include +#endif /* ! LOCK_EX */ + +#ifndef MAILER_DAEMON +# define MAILER_DAEMON "MAILER-DAEMON" +#endif + +typedef int bool; + +#define FALSE 0 +#define TRUE 1 + +bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */ +static int eval = EX_OK; /* sysexits.h error value. */ +static int lmtpmode = 0; +bool bouncequota = FALSE; /* permanent error when over quota */ + +#define _PATH_MAILDIR "/var/mail" +#define _PATH_LOCTMP "/tmp/local.XXXXXX" +#define _PATH_LOCHTMP "/tmp/lochd.XXXXXX" +#define FALSE 0 +#define TRUE 1 +#define MAXLINE 2048 + +static void deliver(int, int, char *, bool); +static void e_to_sys(int); +static void err(const char *fmt, ...); +static void notifybiff(char *); +static void store(char *, int); +static void usage(void); +static void vwarn(); +static void warn(const char *fmt, ...); +static void mailerr(const char *, const char *, ...); +static void sigterm_handler(); + +static char unix_from_line[MAXLINE]; +static int ulen; +static int content_length; +static int bfd, hfd; /* temp file */ +static uid_t src_uid, targ_uid, saved_uid; +static int sigterm_caught; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct passwd *pw; + int ch; + uid_t uid; + char *from; + struct group *grpptr; + void dolmtp(); + + openlog("mail.local", 0, LOG_MAIL); + + from = NULL; + pw = NULL; + sigterm_caught = FALSE; + + (void) sigset(SIGTERM, sigterm_handler); + + while ((ch = getopt(argc, argv, "7bdf:r:l")) != EOF) + switch (ch) { + case '7': /* Do not advertise 8BITMIME */ + EightBitMime = FALSE; + break; + + case 'b': /* bounce mail when over quota. */ + bouncequota = TRUE; + break; + + case 'd': /* Backward compatible. */ + break; + case 'f': + case 'r': /* Backward compatible. */ + if (from != NULL) { + warn("multiple -f options"); + usage(); + } + from = optarg; + break; + case 'l': + lmtpmode++; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + notifybiff(NULL); /* initialize biff structures */ + + /* + * We expect sendmail will invoke us with saved id 0 + * We then do setgid and setuid defore delivery + * setgid to mail group + */ + if ((grpptr = getgrnam("mail")) != NULL) + (void) setgid(grpptr->gr_gid); + saved_uid = geteuid(); + + if (lmtpmode) { + if (saved_uid != 0) { + warn("only super-user can use -l option"); + exit(EX_CANTCREAT); + } + dolmtp(bouncequota); + } + + if (!*argv) + usage(); + + /* + * If from not specified, use the name from getlogin() if the + * uid matches, otherwise, use the name from the password file + * corresponding to the uid. + */ + uid = getuid(); + if (!from && (!(from = getlogin()) || + !(pw = getpwnam(from)) || pw->pw_uid != uid)) + from = (pw = getpwuid(uid)) ? pw->pw_name : "???"; + src_uid = pw ? pw->pw_uid : uid; + + /* + * There is no way to distinguish the error status of one delivery + * from the rest of the deliveries. So, if we failed hard on one + * or more deliveries, but had no failures on any of the others, we + * return a hard failure. If we failed temporarily on one or more + * deliveries, we return a temporary failure regardless of the other + * failures. This results in the delivery being reattempted later + * at the expense of repeated failures and multiple deliveries. + */ + + for (store(from, 0); *argv; ++argv) + deliver(hfd, bfd, *argv, bouncequota); + return (eval); +} + +void +sigterm_handler() +{ + sigterm_caught = TRUE; + (void) sigignore(SIGTERM); +} + +char * +parseaddr(s) + char *s; +{ + char *p; + int len; + + if (*s++ != '<') + return NULL; + + p = s; + + /* at-domain-list */ + while (*p == '@') { + p++; + if (*p == '[') { + p++; + while (isascii(*p) && + (isalnum(*p) || *p == '.' || + *p == '-' || *p == ':')) + p++; + if (*p++ != ']') + return NULL; + } else { + while ((isascii(*p) && isalnum(*p)) || + strchr(".-_", *p)) + p++; + } + if (*p == ',' && p[1] == '@') + p++; + else if (*p == ':' && p[1] != '@') + p++; + else + return NULL; + } + + s = p; + + /* local-part */ + if (*p == '\"') { + p++; + while (*p && *p != '\"') { + if (*p == '\\') { + if (!*++p) + return NULL; + } + p++; + } + if (!*p++) + return NULL; + } else { + while (*p && *p != '@' && *p != '>') { + if (*p == '\\') { + if (!*++p) + return NULL; + } else { + if (*p <= ' ' || (*p & 128) || + strchr("<>()[]\\,;:\"", *p)) + return NULL; + } + p++; + } + } + + /* @domain */ + if (*p == '@') { + p++; + if (*p == '[') { + p++; + while (isascii(*p) && + (isalnum(*p) || *p == '.' || + *p == '-' || *p == ':')) + p++; + if (*p++ != ']') + return NULL; + } else { + while ((isascii(*p) && isalnum(*p)) || + strchr(".-_", *p)) + p++; + } + } + + if (*p++ != '>') + return NULL; + if (*p && *p != ' ') + return NULL; + len = p - s - 1; + + if (*s == '\0' || len <= 0) + { + s = MAILER_DAEMON; + len = strlen(s); + } + + p = malloc(len + 1); + if (p == NULL) { + printf("421 4.3.0 memory exhausted\r\n"); + exit(EX_TEMPFAIL); + } + + strncpy(p, s, len); + p[len] = '\0'; + return p; +} + +char * +process_recipient(addr) + char *addr; +{ + if (getpwnam(addr) == NULL) { + return "550 5.1.1 user unknown"; + } + + return NULL; +} + +#define RCPT_GROW 30 + +void +dolmtp(bouncequota) + bool bouncequota; +{ + char *return_path = NULL; + char **rcpt_addr = NULL; + int rcpt_num = 0; + int rcpt_alloc = 0; + bool gotlhlo = FALSE; + char myhostname[MAXHOSTNAMELEN]; + char buf[4096]; + char *err; + char *p; + int i; + + gethostname(myhostname, sizeof myhostname - 1); + + printf("220 %s LMTP ready\r\n", myhostname); + for (;;) { + if (sigterm_caught) { + for (; rcpt_num > 0; rcpt_num--) + printf("451 4.3.0 shutting down\r\n"); + exit(EX_OK); + } + fflush(stdout); + if (fgets(buf, sizeof(buf)-1, stdin) == NULL) { + exit(EX_OK); + } + p = buf + strlen(buf) - 1; + if (p >= buf && *p == '\n') + *p-- = '\0'; + if (p >= buf && *p == '\r') + *p-- = '\0'; + + switch (buf[0]) { + + case 'd': + case 'D': + if (strcasecmp(buf, "data") == 0) { + if (rcpt_num == 0) { + printf("503 5.5.1 No recipients\r\n"); + continue; + } + store(return_path, rcpt_num); + if (bfd == -1 || hfd == -1) + continue; + + for (i = 0; i < rcpt_num; i++) { + p = strchr(rcpt_addr[i], '+'); + if (p != NULL) + *p++ = '\0'; + deliver(hfd, bfd, rcpt_addr[i], + bouncequota); + } + close(bfd); + close(hfd); + goto rset; + } + goto syntaxerr; + /* NOTREACHED */ + break; + + case 'l': + case 'L': + if (strncasecmp(buf, "lhlo ", 5) == 0) + { + /* check for duplicate per RFC 1651 4.2 */ + if (gotlhlo) + { + printf("503 %s Duplicate LHLO\r\n", + myhostname); + continue; + } + gotlhlo = TRUE; + printf("250-%s\r\n", myhostname); + if (EightBitMime) + printf("250-8BITMIME\r\n"); + printf("250-ENHANCEDSTATUSCODES\r\n"); + printf("250 PIPELINING\r\n"); + continue; + } + goto syntaxerr; + /* NOTREACHED */ + break; + + case 'm': + case 'M': + if (strncasecmp(buf, "mail ", 5) == 0) { + if (return_path != NULL) { + printf("503 5.5.1 Nested MAIL command\r\n"); + continue; + } + if (strncasecmp(buf+5, "from:", 5) != 0 || + ((return_path = parseaddr(buf+10)) == NULL)) { + printf("501 5.5.4 Syntax error in parameters\r\n"); + continue; + } + printf("250 2.5.0 ok\r\n"); + continue; + } + goto syntaxerr; + + case 'n': + case 'N': + if (strcasecmp(buf, "noop") == 0) { + printf("250 2.0.0 ok\r\n"); + continue; + } + goto syntaxerr; + + case 'q': + case 'Q': + if (strcasecmp(buf, "quit") == 0) { + printf("221 2.0.0 bye\r\n"); + exit(EX_OK); + } + goto syntaxerr; + + case 'r': + case 'R': + if (strncasecmp(buf, "rcpt ", 5) == 0) { + if (return_path == NULL) { + printf("503 5.5.1 Need MAIL command\r\n"); + continue; + } + if (rcpt_num >= rcpt_alloc) { + rcpt_alloc += RCPT_GROW; + rcpt_addr = (char **) + realloc((char *)rcpt_addr, + rcpt_alloc * sizeof(char **)); + if (rcpt_addr == NULL) { + printf("421 4.3.0 memory exhausted\r\n"); + exit(EX_TEMPFAIL); + } + } + if (strncasecmp(buf+5, "to:", 3) != 0 || + ((rcpt_addr[rcpt_num] = parseaddr(buf+8)) == NULL)) { + printf("501 5.5.4 Syntax error in parameters\r\n"); + continue; + } + if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL) { + printf("%s\r\n", err); + continue; + } + rcpt_num++; + printf("250 2.1.5 ok\r\n"); + continue; + } + else if (strcasecmp(buf, "rset") == 0) { + printf("250 2.0.0 ok\r\n"); + + rset: + while (rcpt_num > 0) { + free(rcpt_addr[--rcpt_num]); + } + if (return_path != NULL) + free(return_path); + return_path = NULL; + continue; + } + goto syntaxerr; + + case 'v': + case 'V': + if (strncasecmp(buf, "vrfy ", 5) == 0) { + printf("252 2.3.3 try RCPT to attempt delivery\r\n"); + continue; + } + goto syntaxerr; + + default: + syntaxerr: + printf("500 5.5.2 Syntax error\r\n"); + continue; + } + } +} + +static void +store(from, lmtprcpts) + char *from; + int lmtprcpts; +{ + FILE *fp = NULL; + time_t tval; + bool fullline = TRUE; /* current line is terminated */ + bool prevfl; /* previous line was terminated */ + char line[MAXLINE]; + FILE *bfp, *hfp; + char *btn, *htn; + int in_header_section; + int newfd; + + bfd = -1; + hfd = -1; + btn = strdup(_PATH_LOCTMP); + if ((bfd = mkstemp(btn)) == -1 || (bfp = fdopen(bfd, "w+")) == NULL) { + if (bfd != -1) + (void) close(bfd); + if (lmtprcpts) { + printf("451 4.3.0 unable to open temporary file\r\n"); + return; + } else { + mailerr("451 4.3.0", "unable to open temporary file"); + exit(eval); + } + } + (void) unlink(btn); + free(btn); + + if (lmtpmode) { + printf("354 go ahead\r\n"); + fflush(stdout); + } + + htn = strdup(_PATH_LOCHTMP); + if ((hfd = mkstemp(htn)) == -1 || (hfp = fdopen(hfd, "w+")) == NULL) { + if (hfd != -1) + (void) close(hfd); + e_to_sys(errno); + err("unable to open temporary file"); + } + (void) unlink(htn); + free(htn); + + in_header_section = TRUE; + content_length = 0; + fp = hfp; + + line[0] = '\0'; + while (fgets(line, sizeof(line), stdin) != (char *)NULL) + { + size_t line_len = 0; + int peek; + + prevfl = fullline; /* preserve state of previous line */ + while (line[line_len] != '\n' && line_len < sizeof(line) - 2) + line_len++; + line_len++; + + /* Check for dot-stuffing */ + if (prevfl && lmtprcpts && line[0] == '.') + { + if (line[1] == '\n' || + (line[1] == '\r' && line[2] == '\n')) + goto lmtpdot; + memcpy(line, line + 1, line_len); + line_len--; + } + + /* Check to see if we have the full line from fgets() */ + fullline = FALSE; + if (line_len > 0) + { + if (line[line_len - 1] == '\n') + { + if (line_len >= 2 && + line[line_len - 2] == '\r') + { + line[line_len - 2] = '\n'; + line[line_len - 1] = '\0'; + line_len--; + } + fullline = TRUE; + } + else if (line[line_len - 1] == '\r') + { + /* Did we just miss the CRLF? */ + peek = fgetc(stdin); + if (peek == '\n') + { + line[line_len - 1] = '\n'; + fullline = TRUE; + } + else + (void) ungetc(peek, stdin); + } + } + else + fullline = TRUE; + + if (prevfl && line[0] == '\n' && in_header_section) { + in_header_section = FALSE; + if (fflush(fp) == EOF || ferror(fp)) { + if (lmtprcpts) { + while (lmtprcpts--) + printf("451 4.3.0 temporary file write error\r\n"); + fclose(fp); + return; + } else { + mailerr("451 4.3.0", + "temporary file write error"); + fclose(fp); + exit(eval); + } + } + fp = bfp; + continue; + } + + if (in_header_section) { + if (strncasecmp("Content-Length:", line, 15) == 0) { + continue; /* skip this header */ + } + } else + content_length += strlen(line); + (void) fwrite(line, sizeof(char), line_len, fp); + if (ferror(fp)) { + if (lmtprcpts) { + while (lmtprcpts--) + printf("451 4.3.0 temporary file write error\r\n"); + fclose(fp); + return; + } else { + mailerr("451 4.3.0", + "temporary file write error"); + fclose(fp); + exit(eval); + } + } + } + if (sigterm_caught) { + if (lmtprcpts) + while (lmtprcpts--) + printf("451 4.3.0 shutting down\r\n"); + else + mailerr("451 4.3.0", "shutting down"); + fclose(fp); + exit(eval); + } + + if (lmtprcpts) { + /* Got a premature EOF -- toss message and exit */ + exit(EX_OK); + } + + /* If message not newline terminated, need an extra. */ + if (!strchr(line, '\n')) { + (void) putc('\n', fp); + content_length++; + } + + lmtpdot: + + /* Output a newline; note, empty messages are allowed. */ + (void) putc('\n', fp); + + if (fflush(fp) == EOF || ferror(fp)) { + if (lmtprcpts) { + while (lmtprcpts--) { + printf("451 4.3.0 temporary file write error\r\n"); + } + fclose(fp); + return; + } else { + mailerr("451 4.3.0", "temporary file write error"); + fclose(fp); + exit(eval); + } + } + + if ((newfd = dup(bfd)) >= 0) { + fclose(bfp); + bfd = newfd; + } + if ((newfd = dup(hfd)) >= 0) { + fclose(hfp); + hfd = newfd; + } + (void) time(&tval); + (void) snprintf(unix_from_line, sizeof (unix_from_line), "From %s %s", + from, ctime(&tval)); + ulen = strlen(unix_from_line); +} + +static void +handle_error(err_num, bouncequota, path) + int err_num; + bool bouncequota; + char *path; +{ +#ifdef EDQUOT + if (err_num == EDQUOT && bouncequota) { + mailerr("552 5.2.2", "%s: %s", path, sm_errstring(err_num)); + } else +#endif /* EDQUOT */ + mailerr("450 4.2.0", "%s: %s", path, sm_errstring(err_num)); +} + +static void +deliver(hfd, bfd, name, bouncequota) + int hfd; + int bfd; + char *name; + bool bouncequota; +{ + struct stat fsb, sb; + int mbfd = -1, nr, nw = 0, off; + char biffmsg[100], buf[8*1024], path[MAXPATHLEN]; + off_t curoff, cursize; + int len; + struct passwd *pw = NULL; + + /* + * Disallow delivery to unknown names -- special mailboxes + * can be handled in the sendmail aliases file. + */ + if ((pw = getpwnam(name)) == NULL) { + eval = EX_TEMPFAIL; + mailerr("451 4.3.0", "cannot lookup name: %s", name); + return; + } + endpwent(); + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + return; + } + + /* mailbox may be NFS mounted, seteuid to user */ + targ_uid = pw->pw_uid; + (void) seteuid(targ_uid); + + if ((saved_uid != 0) && (src_uid != targ_uid)) { + /* + * If saved_uid == 0 (root), anything is OK; this is + * as it should be. But to prevent a random user from + * calling "mail.local foo" in an attempt to hijack + * foo's mail-box, make sure src_uid == targ_uid o/w. + */ + warn("%s: wrong owner (is %d, should be %d)", + name, src_uid, targ_uid); + eval = EX_CANTCREAT; + return; + } + + path[0] = '\0'; + (void) snprintf(path, sizeof (path), "%s/%s", _PATH_MAILDIR, name); + + /* + * If the mailbox is linked or a symlink, fail. There's an obvious + * race here, that the file was replaced with a symbolic link after + * the lstat returned, but before the open. We attempt to detect + * this by comparing the original stat information and information + * returned by an fstat of the file descriptor returned by the open. + * + * NB: this is a symptom of a larger problem, that the mail spooling + * directory is writeable by the wrong users. If that directory is + * writeable, system security is compromised for other reasons, and + * it cannot be fixed here. + * + * If we created the mailbox, set the owner/group. If that fails, + * just return. Another process may have already opened it, so we + * can't unlink it. Historically, binmail set the owner/group at + * each mail delivery. We no longer do this, assuming that if the + * ownership or permissions were changed there was a reason. + * + * XXX + * open(2) should support flock'ing the file. + */ +tryagain: + /* should check lock status, but... maillock return no value */ + maillock(name, 10); + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err0; + } + + if (lstat(path, &sb)) { + mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, + S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + if (mbfd != -1) + (void) fchmod(mbfd, 0660); + + + if (mbfd == -1) { + if (errno == EEXIST) { + mailunlock(); + goto tryagain; + } + } + } else if (sb.st_nlink != 1) { + mailerr("550 5.2.0", "%s: too many links", path); + goto err0; + } else if (!S_ISREG(sb.st_mode)) { + mailerr("550 5.2.0", "%s: irregular file", path); + goto err0; + } else { + mbfd = open(path, O_APPEND|O_WRONLY, 0); + if (mbfd != -1 && + (fstat(mbfd, &fsb) || fsb.st_nlink != 1 || + S_ISLNK(fsb.st_mode) || sb.st_dev != fsb.st_dev || + sb.st_ino != fsb.st_ino)) { + eval = EX_TEMPFAIL; + mailerr("550 5.2.0", + "%s: fstat: file changed after open", path); + goto err1; + } + } + + if (mbfd == -1) { + mailerr("450 4.2.0", "%s: %s", path, strerror(errno)); + goto err0; + } + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err0; + } + + /* Get the starting offset of the new message for biff. */ + curoff = lseek(mbfd, (off_t)0, SEEK_END); + (void) snprintf(biffmsg, sizeof (biffmsg), "%s@%ld\n", name, curoff); + + /* Copy the message into the file. */ + if (lseek(hfd, (off_t)0, SEEK_SET) == (off_t)-1) { + mailerr("450 4.2.0", "temporary file: %s", strerror(errno)); + goto err1; + } + /* Copy the message into the file. */ + if (lseek(bfd, (off_t)0, SEEK_SET) == (off_t)-1) { + mailerr("450 4.2.0", "temporary file: %s", strerror(errno)); + goto err1; + } + if ((write(mbfd, unix_from_line, ulen)) != ulen) { + handle_error(errno, bouncequota, path); + goto err2; + } + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err2; + } + + while ((nr = read(hfd, buf, sizeof (buf))) > 0) + for (off = 0; off < nr; nr -= nw, off += nw) + if ((nw = write(mbfd, buf + off, nr)) < 0) + { + handle_error(errno, bouncequota, path); + goto err2; + } + if (nr < 0) { + handle_error(errno, bouncequota, path); + goto err2; + } + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err2; + } + + (void) snprintf(buf, sizeof (buf), "Content-Length: %d\n\n", + content_length); + len = strlen(buf); + if (write(mbfd, buf, len) != len) { + handle_error(errno, bouncequota, path); + goto err2; + } + + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err2; + } + + while ((nr = read(bfd, buf, sizeof (buf))) > 0) { + for (off = 0; off < nr; nr -= nw, off += nw) + if ((nw = write(mbfd, buf + off, nr)) < 0) { + handle_error(errno, bouncequota, path); + goto err2; + } + if (sigterm_caught) { + mailerr("451 4.3.0", "shutting down"); + goto err2; + } + } + if (nr < 0) { + handle_error(errno, bouncequota, path); + goto err2; + } + + /* Flush to disk, don't wait for update. */ + if (fsync(mbfd)) { + handle_error(errno, bouncequota, path); +err2: if (mbfd >= 0) + (void)ftruncate(mbfd, curoff); +err1: (void)close(mbfd); +err0: mailunlock(); + (void)seteuid(saved_uid); + return; + } + + /* + ** Save the current size so if the close() fails below + ** we can make sure no other process has changed the mailbox + ** between the failed close and the re-open()/re-lock(). + ** If something else has changed the size, we shouldn't + ** try to truncate it as we may do more harm then good + ** (e.g., truncate a later message delivery). + */ + + if (fstat(mbfd, &sb) < 0) + cursize = 0; + else + cursize = sb.st_size; + + /* Close and check -- NFS doesn't write until the close. */ + if (close(mbfd)) + { + handle_error(errno, bouncequota, path); + mbfd = open(path, O_WRONLY, 0); + if (mbfd < 0 || + cursize == 0 + || flock(mbfd, LOCK_EX) < 0 || + fstat(mbfd, &sb) < 0 || + sb.st_size != cursize || + sb.st_nlink != 1 || + !S_ISREG(sb.st_mode) || + sb.st_dev != fsb.st_dev || + sb.st_ino != fsb.st_ino || + sb.st_uid != fsb.st_uid) + { + /* Don't use a bogus file */ + if (mbfd >= 0) + { + (void) close(mbfd); + mbfd = -1; + } + } + + /* Attempt to truncate back to pre-write size */ + goto err2; + } else + notifybiff(biffmsg); + + mailunlock(); + + (void)seteuid(saved_uid); + + if (lmtpmode) { + printf("250 2.1.5 %s OK\r\n", name); + } +} + +static void +notifybiff(msg) + char *msg; +{ + static struct sockaddr_in addr; + static int f = -1; + struct hostent *hp; + struct servent *sp; + int len; + + if (msg == NULL) { + /* Be silent if biff service not available. */ + if ((sp = getservbyname("biff", "udp")) == NULL) + return; + if ((hp = gethostbyname("localhost")) == NULL) { + warn("localhost: %s", strerror(errno)); + return; + } + addr.sin_family = hp->h_addrtype; + (void) memmove(&addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_port = sp->s_port; + return; + } + + if (addr.sin_family == 0) + return; /* did not initialize */ + + if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + warn("socket: %s", strerror(errno)); + return; + } + len = strlen(msg) + 1; + if (sendto(f, msg, len, 0, (struct sockaddr *)&addr, sizeof (addr)) + != len) + warn("sendto biff: %s", strerror(errno)); +} + +static void +usage() +{ + eval = EX_USAGE; + err("usage: mail.local [-l] [-f from] user ..."); +} + +static void +/*VARARGS2*/ +#ifdef __STDC__ +mailerr(const char *hdr, const char *fmt, ...) +#else +mailerr(hdr, fmt, va_alist) + const char *hdr; + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + if (lmtpmode) + { + if (hdr != NULL) + printf("%s ", hdr); + vprintf(fmt, ap); + printf("\r\n"); + } + else + { + e_to_sys(errno); + vwarn(fmt, ap); + } +} + +static void +/*VARARGS1*/ +#ifdef __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarn(fmt, ap); + va_end(ap); + + exit(eval); +} + +static void +/*VARARGS1*/ +#ifdef __STDC__ +warn(const char *fmt, ...) +#else +warn(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; + +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarn(fmt, ap); + va_end(ap); +} + +static void +vwarn(fmt, ap) + const char *fmt; + va_list ap; +{ + /* + * Log the message to stderr. + * + * Don't use LOG_PERROR as an openlog() flag to do this, + * it's not portable enough. + */ + if (eval != EX_USAGE) + (void) fprintf(stderr, "mail.local: "); + (void) vfprintf(stderr, fmt, ap); + (void) fprintf(stderr, "\n"); + + /* Log the message to syslog. */ + vsyslog(LOG_ERR, fmt, ap); +} + +/* + * e_to_sys -- + * Guess which errno's are temporary. Gag me. + */ +static void +e_to_sys(num) + int num; +{ + /* Temporary failures override hard errors. */ + if (eval == EX_TEMPFAIL) + return; + + switch (num) /* Hopefully temporary errors. */ + { +#ifdef EDQUOT + case EDQUOT: /* Disc quota exceeded */ + if (bouncequota) + { + eval = EX_UNAVAILABLE; + break; + } +#endif /* EDQUOT */ +#ifdef EAGAIN + /* FALLTHROUGH */ + case EAGAIN: /* Resource temporarily unavailable */ +#endif +#ifdef EBUSY + case EBUSY: /* Device busy */ +#endif +#ifdef EPROCLIM + case EPROCLIM: /* Too many processes */ +#endif +#ifdef EUSERS + case EUSERS: /* Too many users */ +#endif +#ifdef ECONNABORTED + case ECONNABORTED: /* Software caused connection abort */ +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: /* Connection refused */ +#endif +#ifdef ECONNRESET + case ECONNRESET: /* Connection reset by peer */ +#endif +#ifdef EDEADLK + case EDEADLK: /* Resource deadlock avoided */ +#endif +#ifdef EFBIG + case EFBIG: /* File too large */ +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: /* Host is down */ +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: /* No route to host */ +#endif +#ifdef EMFILE + case EMFILE: /* Too many open files */ +#endif +#ifdef ENETDOWN + case ENETDOWN: /* Network is down */ +#endif +#ifdef ENETRESET + case ENETRESET: /* Network dropped connection on reset */ +#endif +#ifdef ENETUNREACH + case ENETUNREACH: /* Network is unreachable */ +#endif +#ifdef ENFILE + case ENFILE: /* Too many open files in system */ +#endif +#ifdef ENOBUFS + case ENOBUFS: /* No buffer space available */ +#endif +#ifdef ENOMEM + case ENOMEM: /* Cannot allocate memory */ +#endif +#ifdef ENOSPC + case ENOSPC: /* No space left on device */ +#endif +#ifdef EROFS + case EROFS: /* Read-only file system */ +#endif +#ifdef ESTALE + case ESTALE: /* Stale NFS file handle */ +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: /* Connection timed out */ +#endif +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: /* Operation would block. */ +#endif + eval = EX_TEMPFAIL; + break; + default: + eval = EX_UNAVAILABLE; + break; + } +} diff --git a/usr/src/cmd/sendmail/util/mailcompat.c b/usr/src/cmd/sendmail/util/mailcompat.c new file mode 100644 index 0000000000..aefc3dcfe5 --- /dev/null +++ b/usr/src/cmd/sendmail/util/mailcompat.c @@ -0,0 +1,339 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 1983, 1984, 1986, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + */ + +/* + * Vacation + * Copyright (c) 1983 Eric P. Allman + * Berkeley, California + * + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "conf.h" + +/* + * MAILCOMPAT -- Deliver mail to a user's mailbox with the "From's" stuffed. + */ + +typedef int bool; + +#define FALSE 0 +#define TRUE 1 + +bool Debug = FALSE; +char *myname; /* person who is to have their mail filtered */ +char *homedir; /* home directory of said person */ +char *AliasList[MAXLINE]; /* list of aliases to allow */ +char *fromp; +char *fromuser; +int AliasCount = 0; + +static char *newstr(); + +int ask(char *); +int sendmessage(char *); +void AutoInstall(void); +void usrerr(const char *, ...); + +int +main(argc, argv) + int argc; + char **argv; +{ + register char *p; + struct passwd *pw; + extern char *getfrom(); + + /* process arguments */ + while (--argc > 0 && (p = *++argv) != NULL && *p == '-') + { + switch (*++p) + { + case 'd': /* debug */ + Debug = TRUE; + break; + default: + usrerr("Unknown flag -%s", p); + exit(EX_USAGE); + } + } + + /* verify recipient argument */ + if (argc != 1) + { + if (argc == 0) + AutoInstall(); + else + usrerr("Usage: mailcompat username (or) mailcompat -r"); + exit(EX_USAGE); + } + + myname = p; + /* find user's home directory */ + pw = getpwnam(myname); + if (pw == NULL) + { + usrerr("user: %s look up failed, name services outage ?", myname); + exit(EX_TEMPFAIL); + } + homedir = newstr(pw->pw_dir); + + /* read message from standard input (just from line) */ + fromuser = getfrom(&fromp); + return (sendmessage(fromuser)); +} + +/* +** sendmessage -- read message from standard input do the from stuffing +** and forward to /bin/mail, Being sure to delete any +** content-length headers (/bin/mail recalculates them). +** +** +** Parameters: +** none. +** +** +** Side Effects: +** Reads first line from standard input. +*/ + +#define L_HEADER "Content-Length:" +#define LL_HEADER 15 + +int +sendmessage(from) +char *from; +{ + static char line[MAXLINE]; + static char command[MAXLINE]; + bool in_body = FALSE; + FILE *mail_fp; + static char user_name[L_cuserid]; + + if (from == NULL) + from = cuserid(user_name); + + snprintf(command, sizeof (command), "/bin/mail -f %s -d %s", from, + myname); + mail_fp = popen(command, "w"); + + /* read the line */ + while (fgets(line, sizeof line, stdin) != NULL) + { + if (line[0] == (char)'\n') /* end of mail headers */ + in_body = TRUE; + if (in_body && (strncmp(line, "From ", 5) == 0)) + fprintf(mail_fp, ">"); + if (in_body || (strncasecmp(line, L_HEADER, LL_HEADER) != 0)) + fputs(line, mail_fp); + } + return (pclose(mail_fp)); +} + +char * +getfrom(shortp) +char **shortp; +{ + static char line[MAXLINE]; + register char *p, *start, *at, *bang; + char saveat; + + /* read the from line */ + if (fgets(line, sizeof line, stdin) == NULL || + strncmp(line, "From ", 5) != NULL) + { + usrerr("No initial From line"); + exit(EX_USAGE); + } + + /* find the end of the sender address and terminate it */ + start = &line[5]; + p = strchr(start, ' '); + if (p == NULL) + { + usrerr("Funny From line '%s'", line); + exit(EX_USAGE); + } + *p = '\0'; + + /* + * Strip all but the rightmost UUCP host + * to prevent loops due to forwarding. + * Start searching leftward from the leftmost '@'. + * a!b!c!d yields a short name of c!d + * a!b!c!d@e yields a short name of c!d@e + * e@a!b!c yields the same short name + */ +#ifdef VDEBUG +printf("start='%s'\n", start); +#endif /* VDEBUG */ + *shortp = start; /* assume whole addr */ + if ((at = strchr(start, '@')) == NULL) /* leftmost '@' */ + at = p; /* if none, use end of addr */ + saveat = *at; + *at = '\0'; + if ((bang = strrchr(start, '!')) != NULL) { /* rightmost '!' */ + char *bang2; + *bang = '\0'; + if ((bang2 = strrchr(start, '!')) != NULL) /* 2nd rightmost '!' */ + *shortp = bang2 + 1; /* move past ! */ + *bang = '!'; + } + *at = saveat; +#ifdef VDEBUG +printf("place='%s'\n", *shortp); +#endif /* VDEBUG */ + + /* return the sender address */ + return newstr(start); +} + +/* +** USRERR -- print user error +** +** Parameters: +** f -- format. +** +** Returns: +** none. +** +** Side Effects: +** none. +*/ + +void +usrerr(const char *f, ...) +{ + va_list alist; + + va_start(alist, f); + (void) fprintf(stderr, "mailcompat: "); + (void) vfprintf(stderr, f, alist); + (void) fprintf(stderr, "\n"); + va_end(alist); +} + +/* +** NEWSTR -- copy a string +** +** Parameters: +** s -- the string to copy. +** +** Returns: +** A copy of the string. +** +** Side Effects: +** none. +*/ + +char * +newstr(s) + char *s; +{ + char *p; + size_t psize = strlen(s) + 1; + + p = malloc(psize); + if (p == NULL) + { + usrerr("newstr: cannot alloc memory"); + exit(EX_OSERR); + } + strlcpy(p, s, psize); + return (p); +} + +/* + * When invoked with no arguments, we fall into an automatic installation + * mode, stepping the user through a default installation. + */ +void +AutoInstall() +{ + char forward[MAXLINE]; + char line[MAXLINE]; + static char user_name[L_cuserid]; + FILE *f; + + myname = cuserid(user_name); + homedir = getenv("HOME"); + if (homedir == NULL) { + usrerr("Home directory unknown"); + exit(EX_CONFIG); + } + + printf("This program can be used to store your mail in a format\n"); + printf("that you can read with SunOS 4.X based mail readers\n"); + (void) strlcpy(forward, homedir, sizeof (forward)); + (void) strlcat(forward, "/.forward", sizeof (forward)); + f = fopen(forward, "r"); + if (f) { + printf("You have a .forward file in your home directory"); + printf(" containing:\n"); + while (fgets(line, MAXLINE, f)) + printf(" %s", line); + fclose(f); + if (!ask("Would you like to remove it and disable the mailcompat feature")) + exit(0); + if (unlink(forward)) + perror("Error removing .forward file:"); + else + printf("Back to normal reception of mail.\n"); + exit(0); + } + + printf("To enable the mailcompat feature a \".forward\" "); + printf("file is created.\n"); + if (!ask("Would you like to enable the mailcompat feature")) { + printf("OK, mailcompat feature NOT enabled.\n"); + exit(0); + } + f = fopen(forward, "w"); + if (f == NULL) { + perror("Error opening .forward file"); + exit(EX_USAGE); + } + fprintf(f, "\"|/usr/bin/mailcompat %s\"\n", myname); + fclose(f); + printf("Mailcompat feature ENABLED."); + printf("Run mailcompat with no arguments to remove it\n"); +} + + +/* + * Ask the user a question until we get a reasonable answer + */ +int +ask(prompt) + char *prompt; +{ + char line[MAXLINE]; + + for (;;) { + printf("%s? ", prompt); + fflush(stdout); + fgets(line, sizeof (line), stdin); + if (line[0] == 'y' || line[0] == 'Y') + return (TRUE); + if (line[0] == 'n' || line[0] == 'N') + return (FALSE); + printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n"); + } + /* NOTREACHED */ +} diff --git a/usr/src/cmd/sendmail/util/mailq.c b/usr/src/cmd/sendmail/util/mailq.c new file mode 100644 index 0000000000..4fadd88ff0 --- /dev/null +++ b/usr/src/cmd/sendmail/util/mailq.c @@ -0,0 +1,62 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _PATH_SENDMAIL_BIN "/usr/lib/smtp/sendmail/sendmail" + +int +main(int argc, char *argv[], char *envp[]) +{ + struct passwd *pw = getpwuid(getuid()); + char **newargv; + int j; + + if (pw && chkauthattr(MAILQ_AUTH, pw->pw_name)) { + /* The extra 2 is 1 for the "-bp" + 1 for the terminator. */ + newargv = (char **)malloc((argc + 2) * sizeof (char *)); + if (newargv == NULL) + exit(EX_UNAVAILABLE); + newargv[0] = _PATH_SENDMAIL_BIN; + newargv[1] = "-bp"; + for (j = 1; j <= argc; j++) + newargv[j + 1] = argv[j]; + (void) execve(_PATH_SENDMAIL_BIN, newargv, envp); + perror("Cannot exec " _PATH_SENDMAIL_BIN); + exit(EX_OSERR); + } + (void) fputs("No authorization to run mailq; " + "see mailq(1) for details.\n", stderr); + return (EX_NOPERM); +} diff --git a/usr/src/cmd/sendmail/util/mailstats.c b/usr/src/cmd/sendmail/util/mailstats.c new file mode 100644 index 0000000000..6c5f9a18f8 --- /dev/null +++ b/usr/src/cmd/sendmail/util/mailstats.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1983 Eric P. Allman. All rights reserved. + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + * + */ + +#include + +SM_IDSTR(copyright, +"@(#) Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n") + +SM_IDSTR(id, "@(#)$Id: mailstats.c,v 8.100 2002/06/27 23:24:06 gshapiro Exp $") + +#include +#include +#include +#include +#include +#include +#ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +#endif /* EX_OK */ +#include + +#include +#include +#include +#include +#include + + +#define MNAMELEN 20 /* max length of mailer name */ + +int +main(argc, argv) + int argc; + char **argv; +{ + register int i; + int mno; + int save_errno; + int ch, fd; + char *sfile; + char *cfile; + SM_FILE_T *cfp; + bool mnames; + bool progmode; + bool trunc; + long frmsgs = 0, frbytes = 0, tomsgs = 0, tobytes = 0, rejmsgs = 0; + long dismsgs = 0; + long quarmsgs = 0; + time_t now; + char mtable[MAXMAILERS][MNAMELEN + 1]; + char sfilebuf[MAXPATHLEN]; + char buf[MAXLINE]; + struct statistics stats; + extern char *ctime(); + extern char *optarg; + extern int optind; + + cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); + sfile = NULL; + mnames = true; + progmode = false; + trunc = false; + while ((ch = getopt(argc, argv, "cC:f:opP")) != -1) + { + switch (ch) + { + case 'c': + cfile = getcfname(0, 0, SM_GET_SUBMIT_CF, NULL); + break; + + case 'C': + cfile = optarg; + break; + + case 'f': + sfile = optarg; + break; + + case 'o': + mnames = false; + break; + + case 'p': + trunc = true; + /* FALLTHROUGH */ + + case 'P': + progmode = true; + break; + + case '?': + default: + usage: + (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, + "usage: mailstats [-C cffile] [-c] [-P] [-f stfile] [-o] [-p]\n"); + exit(EX_USAGE); + } + } + argc -= optind; + argv += optind; + + if (argc != 0) + goto usage; + + if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, + NULL)) == NULL) + { + save_errno = errno; + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "mailstats: "); + errno = save_errno; + sm_perror(cfile); + exit(EX_NOINPUT); + } + + mno = 0; + (void) sm_strlcpy(mtable[mno++], "prog", MNAMELEN + 1); + (void) sm_strlcpy(mtable[mno++], "*file*", MNAMELEN + 1); + (void) sm_strlcpy(mtable[mno++], "*include*", MNAMELEN + 1); + + while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) + { + register char *b; + char *s; + register char *m; + + b = strchr(buf, '#'); + if (b == NULL) + b = strchr(buf, '\n'); + if (b == NULL) + b = &buf[strlen(buf)]; + while (isascii(*--b) && isspace(*b)) + continue; + *++b = '\0'; + + b = buf; + switch (*b++) + { + case 'M': /* mailer definition */ + break; + + case 'O': /* option -- see if .st file */ + if (sm_strncasecmp(b, " StatusFile", 11) == 0 && + !(isascii(b[11]) && isalnum(b[11]))) + { + /* new form -- find value */ + b = strchr(b, '='); + if (b == NULL) + continue; + while (isascii(*++b) && isspace(*b)) + continue; + } + else if (*b++ != 'S') + { + /* something else boring */ + continue; + } + + /* this is the S or StatusFile option -- save it */ + if (sm_strlcpy(sfilebuf, b, sizeof sfilebuf) >= + sizeof sfilebuf) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "StatusFile filename too long: %.30s...\n", + b); + exit(EX_CONFIG); + } + if (sfile == NULL) + sfile = sfilebuf; + /* FALLTHROUGH */ + + default: + continue; + } + + if (mno >= MAXMAILERS) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "Too many mailers defined, %d max.\n", + MAXMAILERS); + exit(EX_SOFTWARE); + } + m = mtable[mno]; + s = m + MNAMELEN; /* is [MNAMELEN + 1] */ + while (*b != ',' && !(isascii(*b) && isspace(*b)) && + *b != '\0' && m < s) + *m++ = *b++; + *m = '\0'; + for (i = 0; i < mno; i++) + { + if (strcmp(mtable[i], mtable[mno]) == 0) + break; + } + if (i == mno) + mno++; + } + (void) sm_io_close(cfp, SM_TIME_DEFAULT); + for (; mno < MAXMAILERS; mno++) + mtable[mno][0] = '\0'; + + if (sfile == NULL) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "mailstats: no statistics file located\n"); + exit(EX_OSFILE); + } + + fd = open(sfile, O_RDONLY, 0600); + if ((fd < 0) || (i = read(fd, &stats, sizeof stats)) < 0) + { + save_errno = errno; + (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, "mailstats: "); + errno = save_errno; + sm_perror(sfile); + exit(EX_NOINPUT); + } + if (i == 0) + { + (void) sleep(1); + if ((i = read(fd, &stats, sizeof stats)) < 0) + { + save_errno = errno; + (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, + "mailstats: "); + errno = save_errno; + sm_perror(sfile); + exit(EX_NOINPUT); + } + else if (i == 0) + { + memset((ARBPTR_T) &stats, '\0', sizeof stats); + (void) time(&stats.stat_itime); + } + } + if (i != 0) + { + if (stats.stat_magic != STAT_MAGIC) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "mailstats: incorrect magic number in %s\n", + sfile); + exit(EX_OSERR); + } + else if (stats.stat_version != STAT_VERSION) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "mailstats version (%d) incompatible with %s version (%d)\n", + STAT_VERSION, sfile, + stats.stat_version); + + exit(EX_OSERR); + } + else if (i != sizeof stats || stats.stat_size != sizeof(stats)) + { + (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, + "mailstats: file size changed.\n"); + exit(EX_OSERR); + } + } + + if (progmode) + { + (void) time(&now); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%ld %ld\n", + (long) stats.stat_itime, (long) now); + } + else + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Statistics from %s", + ctime(&stats.stat_itime)); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " M msgsfr bytes_from msgsto bytes_to msgsrej msgsdis"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, " msgsqur"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", + mnames ? " Mailer" : ""); + } + for (i = 0; i < MAXMAILERS; i++) + { + if (stats.stat_nf[i] || stats.stat_nt[i] || + stats.stat_nq[i] || + stats.stat_nr[i] || stats.stat_nd[i]) + { + char *format; + + if (progmode) + format = "%2d %8ld %10ld %8ld %10ld %6ld %6ld"; + else + format = "%2d %8ld %10ldK %8ld %10ldK %6ld %6ld"; + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + format, i, + stats.stat_nf[i], + stats.stat_bf[i], + stats.stat_nt[i], + stats.stat_bt[i], + stats.stat_nr[i], + stats.stat_nd[i]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " %6ld", stats.stat_nq[i]); + if (mnames) + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " %s", + mtable[i]); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); + frmsgs += stats.stat_nf[i]; + frbytes += stats.stat_bf[i]; + tomsgs += stats.stat_nt[i]; + tobytes += stats.stat_bt[i]; + rejmsgs += stats.stat_nr[i]; + dismsgs += stats.stat_nd[i]; + quarmsgs += stats.stat_nq[i]; + } + } + if (progmode) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " T %8ld %10ld %8ld %10ld %6ld %6ld", + frmsgs, frbytes, tomsgs, tobytes, rejmsgs, + dismsgs); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " %6ld", quarmsgs); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " C %8ld %8ld %6ld\n", + stats.stat_cf, stats.stat_ct, + stats.stat_cr); + (void) close(fd); + if (trunc) + { + fd = open(sfile, O_RDWR | O_TRUNC, 0600); + if (fd >= 0) + (void) close(fd); + } + } + else + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "============================================================="); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "========"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " T %8ld %10ldK %8ld %10ldK %6ld %6ld", + frmsgs, frbytes, tomsgs, tobytes, rejmsgs, + dismsgs); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " %6ld", quarmsgs); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\n"); + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + " C %8ld %10s %8ld %10s %6ld\n", + stats.stat_cf, "", stats.stat_ct, "", + stats.stat_cr); + } + exit(EX_OK); + /* NOTREACHED */ + return EX_OK; +} diff --git a/usr/src/cmd/sendmail/util/makemap.c b/usr/src/cmd/sendmail/util/makemap.c new file mode 100644 index 0000000000..3b4ab68ba5 --- /dev/null +++ b/usr/src/cmd/sendmail/util/makemap.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 1998-2002, 2004, 2008 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1992 Eric P. Allman. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include + +SM_IDSTR(copyright, +"@(#) Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\ + Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n") + +SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.179 2008/04/14 02:06:16 ca Exp $") + +#include +#ifndef ISC_UNIX +# include +#endif /* ! ISC_UNIX */ +#include +#include +#include +#ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +#endif /* EX_OK */ +#include +#include +#include +#include + +uid_t RealUid; +gid_t RealGid; +char *RealUserName; +uid_t RunAsUid; +gid_t RunAsGid; +char *RunAsUserName; +int Verbose = 2; +bool DontInitGroups = false; +uid_t TrustedUid = 0; +BITMAP256 DontBlameSendmail; + +#define BUFSIZE 1024 +#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep) + +static void usage __P((char *)); + +static void +usage(progname) + char *progname; +{ + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n", + progname); + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n", + (int) strlen(progname), ""); + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + " %*s [-u] [-v] type mapname\n", + (int) strlen(progname), ""); + exit(EX_USAGE); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + char *progname; + char *cfile; + bool inclnull = false; + bool notrunc = false; + bool allowreplace = false; + bool allowempty = false; + bool verbose = false; + bool foldcase = true; + bool unmake = false; + char sep = '\0'; + char comment = '#'; + int exitstat; + int opt; + char *typename = NULL; + char *mapname = NULL; + unsigned int lineno; + int st; + int mode; + int smode; + int putflags = 0; + long sff = SFF_ROOTOK|SFF_REGONLY; + struct passwd *pw; + SMDB_DATABASE *database; + SMDB_CURSOR *cursor; + SMDB_DBENT db_key, db_val; + SMDB_DBPARAMS params; + SMDB_USER_INFO user_info; + char ibuf[BUFSIZE]; +#if HASFCHOWN + SM_FILE_T *cfp; + char buf[MAXLINE]; +#endif /* HASFCHOWN */ + static char rnamebuf[MAXNAME]; /* holds RealUserName */ + extern char *optarg; + extern int optind; + + memset(¶ms, '\0', sizeof params); + params.smdbp_cache_size = 1024 * 1024; + + progname = strrchr(argv[0], '/'); + if (progname != NULL) + progname++; + else + progname = argv[0]; + cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); + + clrbitmap(DontBlameSendmail); + RunAsUid = RealUid = getuid(); + RunAsGid = RealGid = getgid(); + pw = getpwuid(RealUid); + if (pw != NULL) + (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf); + else + (void) sm_snprintf(rnamebuf, sizeof rnamebuf, + "Unknown UID %d", (int) RealUid); + RunAsUserName = RealUserName = rnamebuf; + user_info.smdbu_id = RunAsUid; + user_info.smdbu_group_id = RunAsGid; + (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, + SMDB_MAX_USER_NAME_LEN); + +#define OPTIONS "C:D:Nc:deflorst:uv" + while ((opt = getopt(argc, argv, OPTIONS)) != -1) + { + switch (opt) + { + case 'C': + cfile = optarg; + break; + + case 'N': + inclnull = true; + break; + + case 'c': + params.smdbp_cache_size = atol(optarg); + break; + + case 'd': + params.smdbp_allow_dup = true; + break; + + case 'e': + allowempty = true; + break; + + case 'f': + foldcase = false; + break; + + case 'D': + comment = *optarg; + break; + + case 'l': + smdb_print_available_types(); + exit(EX_OK); + break; + + case 'o': + notrunc = true; + break; + + case 'r': + allowreplace = true; + break; + + case 's': + setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail); + setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail); + setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail); + setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail); + break; + + case 't': + if (optarg == NULL || *optarg == '\0') + { + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "Invalid separator\n"); + break; + } + sep = *optarg; + break; + + case 'u': + unmake = true; + break; + + case 'v': + verbose = true; + break; + + default: + usage(progname); + /* NOTREACHED */ + } + } + + if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) + sff |= SFF_NOSLINK; + if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) + sff |= SFF_NOHLINK; + if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) + sff |= SFF_NOWLINK; + + argc -= optind; + argv += optind; + if (argc != 2) + { + usage(progname); + /* NOTREACHED */ + } + else + { + typename = argv[0]; + mapname = argv[1]; + } + +#if HASFCHOWN + /* Find TrustedUser value in sendmail.cf */ + if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, + NULL)) == NULL) + { + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s", + cfile, sm_errstring(errno)); + exit(EX_NOINPUT); + } + while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) + { + register char *b; + + if ((b = strchr(buf, '\n')) != NULL) + *b = '\0'; + + b = buf; + switch (*b++) + { + case 'O': /* option */ + if (strncasecmp(b, " TrustedUser", 12) == 0 && + !(isascii(b[12]) && isalnum(b[12]))) + { + b = strchr(b, '='); + if (b == NULL) + continue; + while (isascii(*++b) && isspace(*b)) + continue; + if (isascii(*b) && isdigit(*b)) + TrustedUid = atoi(b); + else + { + TrustedUid = 0; + pw = getpwnam(b); + if (pw == NULL) + (void) sm_io_fprintf(smioerr, + SM_TIME_DEFAULT, + "TrustedUser: unknown user %s\n", b); + else + TrustedUid = pw->pw_uid; + } + +# ifdef UID_MAX + if (TrustedUid > UID_MAX) + { + (void) sm_io_fprintf(smioerr, + SM_TIME_DEFAULT, + "TrustedUser: uid value (%ld) > UID_MAX (%ld)", + (long) TrustedUid, + (long) UID_MAX); + TrustedUid = 0; + } +# endif /* UID_MAX */ + break; + } + /* FALLTHROUGH */ + + default: + continue; + } + } + (void) sm_io_close(cfp, SM_TIME_DEFAULT); +#endif /* HASFCHOWN */ + + if (!params.smdbp_allow_dup && !allowreplace) + putflags = SMDBF_NO_OVERWRITE; + + if (unmake) + { + mode = O_RDONLY; + smode = S_IRUSR; + } + else + { + mode = O_RDWR; + if (!notrunc) + { + mode |= O_CREAT|O_TRUNC; + sff |= SFF_CREAT; + } + smode = S_IWUSR; + } + + params.smdbp_num_elements = 4096; + + errno = smdb_open_database(&database, mapname, mode, smode, sff, + typename, &user_info, ¶ms); + if (errno != SMDBE_OK) + { + char *hint; + + if (errno == SMDBE_UNSUPPORTED_DB_TYPE && + (hint = smdb_db_definition(typename)) != NULL) + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: Need to recompile with -D%s for %s support\n", + progname, hint, typename); + else + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: error opening type %s map %s: %s\n", + progname, typename, mapname, + sm_errstring(errno)); + exit(EX_CANTCREAT); + } + + (void) database->smdb_sync(database, 0); + + if (!unmake && geteuid() == 0 && TrustedUid != 0) + { + errno = database->smdb_set_owner(database, TrustedUid, -1); + if (errno != SMDBE_OK) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "WARNING: ownership change on %s failed %s", + mapname, sm_errstring(errno)); + } + } + + /* + ** Copy the data + */ + + exitstat = EX_OK; + if (unmake) + { + errno = database->smdb_cursor(database, &cursor, 0); + if (errno != SMDBE_OK) + { + + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: cannot make cursor for type %s map %s\n", + progname, typename, mapname); + exit(EX_SOFTWARE); + } + + memset(&db_key, '\0', sizeof db_key); + memset(&db_val, '\0', sizeof db_val); + + for (lineno = 0; ; lineno++) + { + errno = cursor->smdbc_get(cursor, &db_key, &db_val, + SMDB_CURSOR_GET_NEXT); + if (errno != SMDBE_OK) + break; + + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "%.*s%c%.*s\n", + (int) db_key.size, + (char *) db_key.data, + (sep != '\0') ? sep : '\t', + (int) db_val.size, + (char *)db_val.data); + + } + (void) cursor->smdbc_close(cursor); + } + else + { + lineno = 0; + while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf) + != NULL) + { + register char *p; + + lineno++; + + /* + ** Parse the line. + */ + + p = strchr(ibuf, '\n'); + if (p != NULL) + *p = '\0'; + else if (!sm_io_eof(smioin)) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: %s: line %u: line too long (%ld bytes max)\n", + progname, mapname, lineno, + (long) sizeof ibuf); + exitstat = EX_DATAERR; + continue; + } + + if (ibuf[0] == '\0' || ibuf[0] == comment) + continue; + if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0])) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: %s: line %u: syntax error (leading space)\n", + progname, mapname, lineno); + exitstat = EX_DATAERR; + continue; + } + + memset(&db_key, '\0', sizeof db_key); + memset(&db_val, '\0', sizeof db_val); + db_key.data = ibuf; + + for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++) + { + if (foldcase && isascii(*p) && isupper(*p)) + *p = tolower(*p); + } + db_key.size = p - ibuf; + if (inclnull) + db_key.size++; + + if (*p != '\0') + *p++ = '\0'; + while (*p != '\0' && ISSEP(*p)) + p++; + if (!allowempty && *p == '\0') + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: %s: line %u: no RHS for LHS %s\n", + progname, mapname, lineno, + (char *) db_key.data); + exitstat = EX_DATAERR; + continue; + } + + db_val.data = p; + db_val.size = strlen(p); + if (inclnull) + db_val.size++; + + /* + ** Do the database insert. + */ + + if (verbose) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "key=`%s', val=`%s'\n", + (char *) db_key.data, + (char *) db_val.data); + } + + errno = database->smdb_put(database, &db_key, &db_val, + putflags); + switch (errno) + { + case SMDBE_KEY_EXIST: + st = 1; + break; + + case 0: + st = 0; + break; + + default: + st = -1; + break; + } + + if (st < 0) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: %s: line %u: key %s: put error: %s\n", + progname, mapname, lineno, + (char *) db_key.data, + sm_errstring(errno)); + exitstat = EX_IOERR; + } + else if (st > 0) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: %s: line %u: key %s: duplicate key\n", + progname, mapname, + lineno, + (char *) db_key.data); + exitstat = EX_DATAERR; + } + } + } + + /* + ** Now close the database. + */ + + errno = database->smdb_close(database); + if (errno != SMDBE_OK) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: close(%s): %s\n", + progname, mapname, sm_errstring(errno)); + exitstat = EX_IOERR; + } + smdb_free_database(database); + + exit(exitstat); + + /* NOTREACHED */ + return exitstat; +} diff --git a/usr/src/cmd/sendmail/util/mconnect.c b/usr/src/cmd/sendmail/util/mconnect.c new file mode 100644 index 0000000000..3a4f1fa0e1 --- /dev/null +++ b/usr/src/cmd/sendmail/util/mconnect.c @@ -0,0 +1,240 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * mconnect.c - A program to test out SMTP connections. + * Usage: mconnect [host] + * ... SMTP dialog + * ^C or ^D or QUIT + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +union bigsockaddr +{ + struct sockaddr sa; /* general version */ + struct sockaddr_in sin; /* INET family */ + struct sockaddr_in6 sin6; /* INET/IPv6 */ +}; + +static struct sgttyb TtyBuf; +static int raw = 0; + +/* ARGSUSED */ +static void +finis(sig) + int sig; +{ + if (raw) + (void) ioctl(0, TIOCSETP, &TtyBuf); + exit(0); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + union bigsockaddr SendmailAddress; + register int s; + char *host = NULL; + int pid; + int on = 1; + struct servent *sp; + char buf[1000]; + register FILE *f; + register struct hostent *hp; + in_port_t port = 0; + int err; + char buf6[INET6_ADDRSTRLEN]; + int addr_num = 0; + int addrlen; + + (void) ioctl(0, TIOCGETP, &TtyBuf); + (void) signal(SIGINT, finis); + + while (--argc > 0) + { + register char *p; + + p = *++argv; + if (*p == '-') + { + switch (*++p) + { + case 'h': /* host */ + break; + + case 'p': /* port */ + port = htons(atoi(*++argv)); + argc--; + break; + + case 'r': /* raw connection */ + raw = 1; + break; + } + } else if (host == NULL) + host = p; + } + if (host == NULL) + host = "localhost"; + + bzero(&SendmailAddress, sizeof (SendmailAddress)); + hp = getipnodebyname(host, AF_INET6, AI_DEFAULT|AI_ALL, &err); + if (hp == NULL) + { + (void) fprintf(stderr, "mconnect: unknown host %s\r\n", host); + exit(0); + } + + if (port == 0) { + sp = getservbyname("smtp", "tcp"); + if (sp != NULL) + port = sp->s_port; + } + + for (;;) { + bcopy(hp->h_addr_list[addr_num], + &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&SendmailAddress.sin6.sin6_addr)) { + SendmailAddress.sa.sa_family = AF_INET; + SendmailAddress.sin.sin_port = port; + bcopy(&hp->h_addr_list[addr_num][IN6ADDRSZ - INADDRSZ], + &SendmailAddress.sin.sin_addr, INADDRSZ); + addrlen = sizeof (struct sockaddr_in); + } else { + SendmailAddress.sa.sa_family = AF_INET6; + SendmailAddress.sin6.sin6_port = port; + addrlen = sizeof (struct sockaddr_in6); + } + + s = socket(SendmailAddress.sa.sa_family, SOCK_STREAM, 0); + if (s < 0) + { + perror("socket"); + exit(-1); + } + (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, + sizeof (on)); + if (SendmailAddress.sa.sa_family == AF_INET) + (void) printf("connecting to host %s (%s), port %d\r\n", + host, inet_ntoa(SendmailAddress.sin.sin_addr), + ntohs(SendmailAddress.sin.sin_port)); + else + (void) printf("connecting to host %s (%s), port %d\r\n", + host, inet_ntop(AF_INET6, + SendmailAddress.sin6.sin6_addr.s6_addr, + buf6, sizeof (buf6)), + ntohs(SendmailAddress.sin6.sin6_port)); + if (connect(s, (struct sockaddr *)&SendmailAddress, + addrlen) >= 0) + break; + if (hp->h_addr_list[++addr_num] != NULL) { + (void) printf("connect failed (%s), next address ...\n", + strerror(errno)); + bcopy(hp->h_addr_list[addr_num], + &SendmailAddress.sin6.sin6_addr, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED( + &SendmailAddress.sin6.sin6_addr)) { + SendmailAddress.sa.sa_family = AF_INET; + bcopy(&hp->h_addr_list[addr_num] + [IN6ADDRSZ - INADDRSZ], + &SendmailAddress.sin.sin_addr, + INADDRSZ); + addrlen = sizeof (struct sockaddr_in); + } else { + SendmailAddress.sa.sa_family = AF_INET6; + addrlen = sizeof (struct sockaddr_in6); + } + continue; + } + perror("connect"); + exit(-1); + } + + if (raw) { + TtyBuf.sg_flags &= ~CRMOD; + (void) ioctl(0, TIOCSETP, &TtyBuf); + TtyBuf.sg_flags |= CRMOD; + } + + /* good connection, fork both sides */ + (void) printf("connection open\n"); + pid = fork(); + if (pid < 0) + { + perror("fork"); + exit(-1); + } + if (pid == 0) + { + /* child -- standard input to sendmail */ + int c; + + f = fdopen(s, "w"); + while ((c = fgetc(stdin)) >= 0) + { + if (!raw && c == '\n') + (void) fputc('\r', f); + (void) fputc(c, f); + if (c == '\n') + (void) fflush(f); + } + (void) shutdown(s, 1); + (void) sleep(10); + } + else + { + /* parent -- sendmail to standard output */ + f = fdopen(s, "r"); + while (fgets(buf, sizeof (buf), f) != NULL) + { + (void) fputs(buf, stdout); + (void) fflush(stdout); + } + (void) kill(pid, SIGTERM); + } + if (raw) + (void) ioctl(0, TIOCSETP, &TtyBuf); + return (0); +} diff --git a/usr/src/cmd/sendmail/util/praliases.c b/usr/src/cmd/sendmail/util/praliases.c new file mode 100644 index 0000000000..8839334286 --- /dev/null +++ b/usr/src/cmd/sendmail/util/praliases.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1983 Eric P. Allman. All rights reserved. + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include + +SM_IDSTR(copyright, +"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1983 Eric P. Allman. All rights reserved.\n\ + Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n") + +SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $") + +#include +#include +#include +#include +#ifdef EX_OK +# undef EX_OK /* unistd.h may have another use for this */ +#endif /* EX_OK */ +#include + + +#ifndef NOT_SENDMAIL +# define NOT_SENDMAIL +#endif /* ! NOT_SENDMAIL */ +#include +#include +#include + +static void praliases __P((char *, int, char **)); + +uid_t RealUid; +gid_t RealGid; +char *RealUserName; +uid_t RunAsUid; +gid_t RunAsGid; +char *RunAsUserName; +int Verbose = 2; +bool DontInitGroups = false; +uid_t TrustedUid = 0; +BITMAP256 DontBlameSendmail; + +# define DELIMITERS " ,/" +# define PATH_SEPARATOR ':' + +int +main(argc, argv) + int argc; + char **argv; +{ + char *cfile; + char *filename = NULL; + SM_FILE_T *cfp; + int ch; + char afilebuf[MAXLINE]; + char buf[MAXLINE]; + struct passwd *pw; + static char rnamebuf[MAXNAME]; + extern char *optarg; + extern int optind; + + clrbitmap(DontBlameSendmail); + RunAsUid = RealUid = getuid(); + RunAsGid = RealGid = getgid(); + pw = getpwuid(RealUid); + if (pw != NULL) + { + if (strlen(pw->pw_name) > MAXNAME - 1) + pw->pw_name[MAXNAME] = 0; + sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); + } + else + (void) sm_snprintf(rnamebuf, sizeof rnamebuf, + "Unknown UID %d", (int) RealUid); + RunAsUserName = RealUserName = rnamebuf; + + cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); + while ((ch = getopt(argc, argv, "C:f:")) != -1) + { + switch ((char)ch) { + case 'C': + cfile = optarg; + break; + case 'f': + filename = optarg; + break; + case '?': + default: + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "usage: praliases [-C cffile] [-f aliasfile]" + " [key ...]\n"); + exit(EX_USAGE); + } + } + argc -= optind; + argv += optind; + + if (filename != NULL) + { + praliases(filename, argc, argv); + exit(EX_OK); + } + + if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY, + NULL)) == NULL) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: %s: %s\n", cfile, + sm_errstring(errno)); + exit(EX_NOINPUT); + } + + while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) + { + register char *b, *p; + + b = strchr(buf, '\n'); + if (b != NULL) + *b = '\0'; + + b = buf; + switch (*b++) + { + case 'O': /* option -- see if alias file */ + if (sm_strncasecmp(b, " AliasFile", 10) == 0 && + !(isascii(b[10]) && isalnum(b[10]))) + { + /* new form -- find value */ + b = strchr(b, '='); + if (b == NULL) + continue; + while (isascii(*++b) && isspace(*b)) + continue; + } + else if (*b++ != 'A') + { + /* something else boring */ + continue; + } + + /* this is the A or AliasFile option -- save it */ + if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >= + sizeof afilebuf) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: AliasFile filename too long: %.30s\n", + b); + (void) sm_io_close(cfp, SM_TIME_DEFAULT); + exit(EX_CONFIG); + } + b = afilebuf; + + for (p = b; p != NULL; ) + { + while (isascii(*p) && isspace(*p)) + p++; + if (*p == '\0') + break; + b = p; + + p = strpbrk(p, DELIMITERS); + + /* find end of spec */ + if (p != NULL) + { + bool quoted = false; + + for (; *p != '\0'; p++) + { + /* + ** Don't break into a quoted + ** string. + */ + + if (*p == '"') + quoted = !quoted; + else if (*p == ',' && !quoted) + break; + } + + /* No more alias specs follow */ + if (*p == '\0') + { + /* chop trailing whitespace */ + while (isascii(*p) && + isspace(*p) && + p > b) + p--; + *p = '\0'; + p = NULL; + } + } + + if (p != NULL) + { + char *e = p - 1; + + /* chop trailing whitespace */ + while (isascii(*e) && + isspace(*e) && + e > b) + e--; + *++e = '\0'; + *p++ = '\0'; + } + praliases(b, argc, argv); + } + /* FALLTHROUGH */ + + default: + continue; + } + } + (void) sm_io_close(cfp, SM_TIME_DEFAULT); + exit(EX_OK); + /* NOTREACHED */ + return EX_OK; +} + +static void +praliases(filename, argc, argv) + char *filename; + int argc; + char **argv; +{ + int result; + char *colon; + char *db_name; + char *db_type; + SMDB_DATABASE *database = NULL; + SMDB_CURSOR *cursor = NULL; + SMDB_DBENT db_key, db_value; + SMDB_DBPARAMS params; + SMDB_USER_INFO user_info; + + colon = strchr(filename, PATH_SEPARATOR); + if (colon == NULL) + { + db_name = filename; + db_type = SMDB_TYPE_DEFAULT; + } + else + { + *colon = '\0'; + db_name = colon + 1; + db_type = filename; + } + + /* clean off arguments */ + for (;;) + { + while (isascii(*db_name) && isspace(*db_name)) + db_name++; + + if (*db_name != '-') + break; + while (*db_name != '\0' && + !(isascii(*db_name) && isspace(*db_name))) + db_name++; + } + + /* Skip non-file based DB types */ + if (db_type != NULL && *db_type != '\0') + { + if (db_type != SMDB_TYPE_DEFAULT && + strcmp(db_type, "hash") != 0 && + strcmp(db_type, "btree") != 0 && + strcmp(db_type, "dbm") != 0) + { + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: Skipping non-file based alias type %s\n", + db_type); + return; + } + } + + if (*db_name == '\0' || (db_type != NULL && *db_type == '\0')) + { + if (colon != NULL) + *colon = ':'; + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: illegal alias specification: %s\n", filename); + goto fatal; + } + + memset(¶ms, '\0', sizeof params); + params.smdbp_cache_size = 1024 * 1024; + + user_info.smdbu_id = RunAsUid; + user_info.smdbu_group_id = RunAsGid; + (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName, + SMDB_MAX_USER_NAME_LEN); + + result = smdb_open_database(&database, db_name, O_RDONLY, 0, + SFF_ROOTOK, db_type, &user_info, ¶ms); + if (result != SMDBE_OK) + { + sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: %s: open: %s\n", + db_name, sm_errstring(result)); + goto fatal; + } + + if (argc == 0) + { + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + + result = database->smdb_cursor(database, &cursor, 0); + if (result != SMDBE_OK) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: %s: set cursor: %s\n", db_name, + sm_errstring(result)); + goto fatal; + } + + while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, + SMDB_CURSOR_GET_NEXT)) == + SMDBE_OK) + { +#if 0 + /* skip magic @:@ entry */ + if (db_key.size == 2 && + db_key.data[0] == '@' && + db_key.data[1] == '\0' && + db_value.size == 2 && + db_value.data[0] == '@' && + db_value.data[1] == '\0') + continue; +#endif /* 0 */ + + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "%.*s:%.*s\n", + (int) db_key.size, + (char *) db_key.data, + (int) db_value.size, + (char *) db_value.data); + } + + if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "praliases: %s: get value at cursor: %s\n", + db_name, sm_errstring(result)); + goto fatal; + } + } + else for (; *argv != NULL; ++argv) + { + int get_res; + + memset(&db_key, '\0', sizeof db_key); + memset(&db_value, '\0', sizeof db_value); + db_key.data = *argv; + db_key.size = strlen(*argv); + get_res = database->smdb_get(database, &db_key, &db_value, 0); + if (get_res == SMDBE_NOT_FOUND) + { + db_key.size++; + get_res = database->smdb_get(database, &db_key, + &db_value, 0); + } + if (get_res == SMDBE_OK) + { + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "%.*s:%.*s\n", + (int) db_key.size, + (char *) db_key.data, + (int) db_value.size, + (char *) db_value.data); + } + else + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "%s: No such key\n", + (char *)db_key.data); + } + + fatal: + if (cursor != NULL) + (void) cursor->smdbc_close(cursor); + if (database != NULL) + (void) database->smdb_close(database); + if (colon != NULL) + *colon = ':'; + return; +} diff --git a/usr/src/cmd/sendmail/util/rfc2047.c b/usr/src/cmd/sendmail/util/rfc2047.c new file mode 100644 index 0000000000..8092a9a587 --- /dev/null +++ b/usr/src/cmd/sendmail/util/rfc2047.c @@ -0,0 +1,289 @@ +/* + * rfc2047.c -- decode RFC-2047 header format + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef lint +static char sccsi2[] = "%W% (Sun) %G%"; +#endif + +/* + * Copyright (c) 1997-1998 Richard Coleman + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following two + * paragraphs appear in all copies of this software. + * + * In no event shall Richard Coleman be liable to any party for direct, + * indirect, special, incidental, or consequential damages arising out of + * the use of this software and its documentation, even if Richard Coleman + * has been advised of the possibility of such damage. + * + * Richard Coleman specifically disclaims any warranties, including, but + * not limited to, the implied warranties of merchantability and fitness + * for a particular purpose. The software provided hereunder is on an "as + * is" basis, and Richard Coleman has no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + */ + +/* + * Parts of this code were derived from metamail, which is ... + * + * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) + * + * Permission to use, copy, modify, and distribute this material + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies, and that the name of Bellcore not be + * used in advertising or publicity pertaining to this + * material without the specific, prior written permission + * of an authorized representative of Bellcore. BELLCORE + * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY + * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", + * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. + */ + +/* + * Copyright (c) 1998, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#include + +typedef int bool; + +#define FALSE 0 +#define TRUE 1 + +static signed char hexindex[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static signed char index_64[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 +}; + +#define char64(c) (((unsigned char) (c) > 127) ? -1 : \ + index_64[(unsigned char) (c)]) + +static int +unqp(unsigned char byte1, unsigned char byte2) +{ + if (hexindex[byte1] == -1 || hexindex[byte2] == -1) + return (-1); + return (hexindex[byte1] << 4 | hexindex[byte2]); +} + +/* Check if character is linear whitespace */ +#define is_lws(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') + +/* + * Decode the string as a RFC-2047 header field + */ + +bool +decode_rfc2047(char *str, char *dst, char *charset) +{ + char *p, *q, *pp; + char *startofmime, *endofmime; + int c, quoted_printable; + bool encoding_found = FALSE; /* did we decode anything? */ + bool between_encodings = FALSE; /* are we between two encodings? */ + bool equals_pending = FALSE; /* is there a '=' pending? */ + int whitespace = 0; /* how much whitespace between encodings? */ + + if (str == NULL) + return (FALSE); + + /* + * Do a quick and dirty check for the '=' character. + * This should quickly eliminate many cases. + */ + if (!strchr(str, '=')) + return (FALSE); + + for (p = str, q = dst; *p; p++) { + /* + * If we had an '=' character pending from + * last iteration, then add it first. + */ + if (equals_pending) { + *q++ = '='; + equals_pending = FALSE; + between_encodings = FALSE; /* we added non-WS text */ + } + + if (*p != '=') { + /* count linear whitespace while between encodings */ + if (between_encodings && is_lws(*p)) + whitespace++; + else + between_encodings = FALSE; /* non-WS added */ + *q++ = *p; + continue; + } + + equals_pending = TRUE; /* we have a '=' pending */ + + /* Check for initial =? */ + if (*p == '=' && p[1] && p[1] == '?' && p[2]) { + startofmime = p + 2; + + /* Scan ahead for the next '?' character */ + for (pp = startofmime; *pp && *pp != '?'; pp++) + ; + + if (!*pp) + continue; + + strncpy(charset, startofmime, pp - startofmime); + charset[pp - startofmime] = '\0'; + + startofmime = pp + 1; + + /* Check for valid encoding type */ + if (*startofmime != 'B' && *startofmime != 'b' && + *startofmime != 'Q' && *startofmime != 'q') + continue; + + /* Is encoding quoted printable or base64? */ + quoted_printable = (*startofmime == 'Q' || + *startofmime == 'q'); + startofmime++; + + /* Check for next '?' character */ + if (*startofmime != '?') + continue; + startofmime++; + + /* + * Scan ahead for the ending ?= + * + * While doing this, we will also check if encoded + * word has any embedded linear whitespace. + */ + endofmime = NULL; + for (pp = startofmime; *pp && *(pp+1); pp++) { + if (is_lws(*pp)) + break; + else if (*pp == '?' && pp[1] == '=') { + endofmime = pp; + break; + } + } + if (is_lws(*pp) || endofmime == NULL) + continue; + + /* + * We've found an encoded word, so we can drop + * the '=' that was pending + */ + equals_pending = FALSE; + + /* + * If we are between two encoded words separated only + * by linear whitespace, then we ignore the whitespace. + * We will roll back the buffer the number of whitespace + * characters we've seen since last encoded word. + */ + if (between_encodings) + q -= whitespace; + + /* Now decode the text */ + if (quoted_printable) { + for (pp = startofmime; pp < endofmime; pp++) { + if (*pp == '=') { + c = unqp(pp[1], pp[2]); + if (c == -1) + continue; + if (c != 0) + *q++ = c; + pp += 2; + } else if (*pp == '_') + *q++ = ' '; + else + *q++ = *pp; + } + } else { + /* base64 */ + int c1, c2, c3, c4; + + pp = startofmime; + while (pp < endofmime) { + /* 6 + 2 bits */ + while ((pp < endofmime) && + ((c1 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime) + pp++; + while ((pp < endofmime) && + ((c2 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c1 != -1 && + c2 != -1) { + *q++ = (c1 << 2) | (c2 >> 4); + pp++; + } + /* 4 + 4 bits */ + while ((pp < endofmime) && + ((c3 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c2 != -1 && + c3 != -1) { + *q++ = ((c2 & 0xF) << 4) | + (c3 >> 2); + pp++; + } + /* 2 + 6 bits */ + while ((pp < endofmime) && + ((c4 = char64(*pp)) == -1)) { + pp++; + } + if (pp < endofmime && c3 != -1 && + c4 != -1) { + *q++ = ((c3 & 0x3) << 6) | (c4); + pp++; + } + } + } + + /* + * Now that we are done decoding this particular + * encoded word, advance string to trailing '='. + */ + p = endofmime + 1; + + encoding_found = TRUE; /* found (>= 1) encoded word */ + between_encodings = TRUE; /* just decoded something */ + whitespace = 0; /* re-initialize amount of whitespace */ + } + } + + /* If an equals was pending at end of string, add it now. */ + if (equals_pending) + *q++ = '='; + *q = '\0'; + + return (encoding_found); +} diff --git a/usr/src/cmd/sendmail/util/smrsh.c b/usr/src/cmd/sendmail/util/smrsh.c new file mode 100644 index 0000000000..32d9afa8eb --- /dev/null +++ b/usr/src/cmd/sendmail/util/smrsh.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. + * All rights reserved. + * Copyright (c) 1993 Eric P. Allman. All rights reserved. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include + +SM_IDSTR(copyright, +"@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\ + All rights reserved.\n\ + Copyright (c) 1993 Eric P. Allman. All rights reserved.\n\ + Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n") + +SM_IDSTR(id, "@(#)$Id: smrsh.c,v 8.65 2004/08/06 18:54:22 ca Exp $") + +/* +** SMRSH -- sendmail restricted shell +** +** This is a patch to get around the prog mailer bugs in most +** versions of sendmail. +** +** Use this in place of /bin/sh in the "prog" mailer definition +** in your sendmail.cf file. You then create CMDDIR (owned by +** root, mode 755) and put links to any programs you want +** available to prog mailers in that directory. This should +** include things like "vacation" and "procmail", but not "sed" +** or "sh". +** +** Leading pathnames are stripped from program names so that +** existing .forward files that reference things like +** "/usr/bin/vacation" will continue to work. +** +** The following characters are completely illegal: +** < > ^ & ` ( ) \n \r +** The following characters are sometimes illegal: +** | & +** This is more restrictive than strictly necessary. +** +** To use this, add FEATURE(`smrsh') to your .mc file. +** +** This can be used on any version of sendmail. +** +** In loving memory of RTM. 11/02/93. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef EX_OK +# undef EX_OK +#endif /* EX_OK */ +#include +#include +#include + +#include +#include + +/* directory in which all commands must reside */ +#ifndef CMDDIR +# ifdef SMRSH_CMDDIR +# define CMDDIR SMRSH_CMDDIR +# else /* SMRSH_CMDDIR */ +# define CMDDIR "/usr/adm/sm.bin" +# endif /* SMRSH_CMDDIR */ +#endif /* ! CMDDIR */ + +/* characters disallowed in the shell "-c" argument */ +#define SPECIALS "<|>^();&`$\r\n" + +/* default search path */ +#ifndef PATH +# ifdef SMRSH_PATH +# define PATH SMRSH_PATH +# else /* SMRSH_PATH */ +# define PATH "/bin:/usr/bin:/usr/ucb" +# endif /* SMRSH_PATH */ +#endif /* ! PATH */ + +char newcmdbuf[1000]; +char *prg, *par; + +static void addcmd __P((char *, bool, size_t)); + +/* +** ADDCMD -- add a string to newcmdbuf, check for overflow +** +** Parameters: +** s -- string to add +** cmd -- it's a command: prepend CMDDIR/ +** len -- length of string to add +** +** Side Effects: +** changes newcmdbuf or exits with a failure. +** +*/ + +static void +addcmd(s, cmd, len) + char *s; + bool cmd; + size_t len; +{ + if (s == NULL || *s == '\0') + return; + + /* enough space for s (len) and CMDDIR + "/" and '\0'? */ + if (sizeof newcmdbuf - strlen(newcmdbuf) <= + len + 1 + (cmd ? (strlen(CMDDIR) + 1) : 0)) + { + (void)sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: command too long: %s\n", prg, par); +#ifndef DEBUG + syslog(LOG_WARNING, "command too long: %.40s", par); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + if (cmd) + (void) sm_strlcat2(newcmdbuf, CMDDIR, "/", sizeof newcmdbuf); + (void) strncat(newcmdbuf, s, len); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + register char *p; + register char *q; + register char *r; + register char *cmd; + int isexec; + int save_errno; + char *newenv[2]; + char pathbuf[1000]; + char specialbuf[32]; + struct stat st; + +#ifndef DEBUG +# ifndef LOG_MAIL + openlog("smrsh", 0); +# else /* ! LOG_MAIL */ + openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL); +# endif /* ! LOG_MAIL */ +#endif /* ! DEBUG */ + + (void) sm_strlcpyn(pathbuf, sizeof pathbuf, 2, "PATH=", PATH); + newenv[0] = pathbuf; + newenv[1] = NULL; + + /* + ** Do basic argv usage checking + */ + + prg = argv[0]; + + if (argc != 3 || strcmp(argv[1], "-c") != 0) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "Usage: %s -c command\n", prg); +#ifndef DEBUG + syslog(LOG_ERR, "usage"); +#endif /* ! DEBUG */ + exit(EX_USAGE); + } + + par = argv[2]; + + /* + ** Disallow special shell syntax. This is overly restrictive, + ** but it should shut down all attacks. + ** Be sure to include 8-bit versions, since many shells strip + ** the address to 7 bits before checking. + */ + + if (strlen(SPECIALS) * 2 >= sizeof specialbuf) + { +#ifndef DEBUG + syslog(LOG_ERR, "too many specials: %.40s", SPECIALS); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + (void) sm_strlcpy(specialbuf, SPECIALS, sizeof specialbuf); + for (p = specialbuf; *p != '\0'; p++) + *p |= '\200'; + (void) sm_strlcat(specialbuf, SPECIALS, sizeof specialbuf); + + /* + ** Do a quick sanity check on command line length. + */ + + if (strlen(par) > (sizeof newcmdbuf - sizeof CMDDIR - 2)) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: command too long: %s\n", prg, par); +#ifndef DEBUG + syslog(LOG_WARNING, "command too long: %.40s", par); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + + q = par; + newcmdbuf[0] = '\0'; + isexec = false; + + while (*q != '\0') + { + /* + ** Strip off a leading pathname on the command name. For + ** example, change /usr/ucb/vacation to vacation. + */ + + /* strip leading spaces */ + while (*q != '\0' && isascii(*q) && isspace(*q)) + q++; + if (*q == '\0') + { + if (isexec) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: missing command to exec\n", + prg); +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: missing command to exec", (int) getuid()); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + break; + } + + /* find the end of the command name */ + p = strpbrk(q, " \t"); + if (p == NULL) + cmd = &q[strlen(q)]; + else + { + *p = '\0'; + cmd = p; + } + /* search backwards for last / (allow for 0200 bit) */ + while (cmd > q) + { + if ((*--cmd & 0177) == '/') + { + cmd++; + break; + } + } + /* cmd now points at final component of path name */ + + /* allow a few shell builtins */ + if (strcmp(q, "exec") == 0 && p != NULL) + { + addcmd("exec ", false, strlen("exec ")); + + /* test _next_ arg */ + q = ++p; + isexec = true; + continue; + } + else if (strcmp(q, "exit") == 0 || strcmp(q, "echo") == 0) + { + addcmd(cmd, false, strlen(cmd)); + + /* test following chars */ + } + else + { + char cmdbuf[MAXPATHLEN]; + + /* + ** Check to see if the command name is legal. + */ + + if (sm_strlcpyn(cmdbuf, sizeof cmdbuf, 3, CMDDIR, + "/", cmd) >= sizeof cmdbuf) + { + /* too long */ + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: \"%s\" not available for sendmail programs (filename too long)\n", + prg, cmd); + if (p != NULL) + *p = ' '; +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (filename too long)", + (int) getuid(), cmd); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + +#ifdef DEBUG + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, + "Trying %s\n", cmdbuf); +#endif /* DEBUG */ + if (stat(cmdbuf, &st) < 0) + { + /* can't stat it */ + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: \"%s\" not available for sendmail programs (stat failed)\n", + prg, cmd); + if (p != NULL) + *p = ' '; +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (stat failed)", + (int) getuid(), cmd); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + if (!S_ISREG(st.st_mode) +#ifdef S_ISLNK + && !S_ISLNK(st.st_mode) +#endif /* S_ISLNK */ + ) + { + /* can't stat it */ + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: \"%s\" not available for sendmail programs (not a file)\n", + prg, cmd); + if (p != NULL) + *p = ' '; +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: attempt to use \"%s\" (not a file)", + (int) getuid(), cmd); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + if (access(cmdbuf, X_OK) < 0) + { + /* oops.... crack attack possiblity */ + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: \"%s\" not available for sendmail programs\n", + prg, cmd); + if (p != NULL) + *p = ' '; +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: attempt to use \"%s\"", + (int) getuid(), cmd); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + + /* + ** Create the actual shell input. + */ + + addcmd(cmd, true, strlen(cmd)); + } + isexec = false; + + if (p != NULL) + *p = ' '; + else + break; + + r = strpbrk(p, specialbuf); + if (r == NULL) + { + addcmd(p, false, strlen(p)); + break; + } +#if ALLOWSEMI + if (*r == ';') + { + addcmd(p, false, r - p + 1); + q = r + 1; + continue; + } +#endif /* ALLOWSEMI */ + if ((*r == '&' && *(r + 1) == '&') || + (*r == '|' && *(r + 1) == '|')) + { + addcmd(p, false, r - p + 2); + q = r + 2; + continue; + } + + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: cannot use %c in command\n", prg, *r); +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s", + (int) getuid(), *r, par); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + if (isexec) + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "%s: missing command to exec\n", prg); +#ifndef DEBUG + syslog(LOG_CRIT, "uid %d: missing command to exec", + (int) getuid()); +#endif /* ! DEBUG */ + exit(EX_UNAVAILABLE); + } + /* make sure we created something */ + if (newcmdbuf[0] == '\0') + { + (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, + "Usage: %s -c command\n", prg); +#ifndef DEBUG + syslog(LOG_ERR, "usage"); +#endif /* ! DEBUG */ + exit(EX_USAGE); + } + + /* + ** Now invoke the shell + */ + +#ifdef DEBUG + (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s\n", newcmdbuf); +#endif /* DEBUG */ + (void) execle("/bin/sh", "/bin/sh", "-c", newcmdbuf, + (char *)NULL, newenv); + save_errno = errno; +#ifndef DEBUG + syslog(LOG_CRIT, "Cannot exec /bin/sh: %s", sm_errstring(errno)); +#endif /* ! DEBUG */ + errno = save_errno; + sm_perror("/bin/sh"); + exit(EX_OSFILE); + /* NOTREACHED */ + return EX_OSFILE; +} diff --git a/usr/src/cmd/sendmail/util/vacation.c b/usr/src/cmd/sendmail/util/vacation.c new file mode 100644 index 0000000000..5a0f93756d --- /dev/null +++ b/usr/src/cmd/sendmail/util/vacation.c @@ -0,0 +1,1158 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright (c) 2016 by Delphix. All rights reserved. + * + * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T + * All Rights Reserved + */ + +/* + * Vacation + * Copyright (c) 1983 Eric P. Allman + * Berkeley, California + * + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * VACATION -- return a message to the sender when on vacation. + * + * This program could be invoked as a message receiver + * when someone is on vacation. It returns a message + * specified by the user to whoever sent the mail, taking + * care not to return a message too often to prevent + * "I am on vacation" loops. + * + * For best operation, this program should run setuid to + * root or uucp or someone else that sendmail will believe + * a -f flag from. Otherwise, the user must be careful + * to include a header on their .vacation.msg file. + * + * Positional Parameters: + * the user to collect the vacation message from. + * + * Flag Parameters: + * -I initialize the database. + * -d turn on debugging. + * -tT set the timeout to T. messages arriving more + * often than T will be ignored to avoid loops. + * + * Side Effects: + * A message is sent back to the sender. + * + * Author: + * Eric Allman + * UCB/INGRES + */ + +#define MAXLINE 256 /* max size of a line */ + +#define ONEWEEK (60L*60L*24L*7L) +#define MsgFile "/.vacation.msg" +#define FilterFile "/.vacation.filter" +#define DbFileBase "/.vacation" +#define _PATH_TMP "/tmp/vacation.XXXXXX" + +typedef int bool; + +#define FALSE 0 +#define TRUE 1 + +static time_t Timeout = ONEWEEK; /* timeout between notices per user */ +static DBM *db; +static bool Debug = FALSE; +static bool ListMode = FALSE; +static bool AnswerAll = FALSE; /* default: answer if in To:/Cc: only */ +static char *Subject = NULL; /* subject in message header */ +static char *EncodedSubject = NULL; /* subject in message header */ +static char Charset[MAXLINE]; /* for use in reply message */ +static char *AliasList[MAXLINE]; /* list of aliases to allow */ +static int AliasCount = 0; +static char *myname; /* name of person "on vacation" */ +static char *homedir; /* home directory of said person */ + +extern time_t convtime(char *, char); +extern bool decode_rfc2047(char *, char *, char *); + +static bool ask(char *); +static bool junkmail(char *); +static bool filter_ok(char *, char *); +static bool knows(char *); +static bool sameword(char *, char *); +static char *getfrom(char **); +static char *newstr(char *); +static void AutoInstall(); +static void initialize(char *); +static void sendmessage(char *, char *, char *); +static void setknows(char *); +static void dumplist(); + +void usrerr(const char *, ...); + +int +main(argc, argv) + int argc; + char **argv; +{ + char *from; + char *p, *at, *c; + struct passwd *pw; + char *shortfrom; + char buf[MAXLINE]; + char *message_file = MsgFile; + char *db_file_base = DbFileBase; + char *filter_file = FilterFile; + char *sender; + bool sender_oob = FALSE; + bool initialize_only = FALSE; + + /* process arguments */ + while (--argc > 0 && (p = *++argv) != NULL && *p == '-') + { + switch (*++p) + { + case 'a': /* add this to list of acceptable aliases */ + AliasList[AliasCount++] = argv[1]; + if (argc > 0) { + argc--; argv++; + } + break; + + case 'd': /* debug */ + Debug = TRUE; + break; + + case 'e': /* alternate filter file */ + filter_file = argv[1]; + if (argc > 0) { + argc--; argv++; + } + break; + + case 'f': /* alternate database file name base */ + db_file_base = argv[1]; + if (argc > 0) { + argc--; argv++; + } + break; + + case 'I': /* initialize */ + initialize_only = TRUE; + break; + + case 'j': /* answer all mail, even if not in To/Cc */ + AnswerAll = TRUE; + break; + + case 'l': /* list all respondees */ + ListMode = TRUE; + break; + + case 'm': /* alternate message file */ + message_file = argv[1]; + if (argc > 0) { + argc--; argv++; + } + break; + + case 's': /* sender: use this instead of getfrom() */ + sender = argv[1]; + sender_oob = TRUE; + if (argc > 0) { + argc--; argv++; + } + break; + + case 't': /* set timeout */ + Timeout = convtime(++p, 'w'); + break; + + default: + usrerr("Unknown flag -%s", p); + exit(EX_USAGE); + } + } + + if (initialize_only) + { + initialize(db_file_base); + exit(EX_OK); + } + + /* verify recipient argument */ + if (argc == 0 && !ListMode) + AutoInstall(); + + if (argc != 1 && !ListMode) + { + usrerr("Usage:\tvacation username\n\tvacation -I\n" + "\tvacation -l"); + exit(EX_USAGE); + } + + myname = p; + Charset[0] = '\0'; + + /* find user's home directory */ + if (ListMode) + pw = getpwuid(getuid()); + else + pw = getpwnam(myname); + if (pw == NULL) + { + usrerr("user %s look up failed, name services outage ?", + myname); + exit(EX_TEMPFAIL); + } + homedir = newstr(pw->pw_dir); + + (void) snprintf(buf, sizeof (buf), "%s%s%s", homedir, + (db_file_base[0] == '/') ? "" : "/", db_file_base); + if (!(db = dbm_open(buf, O_RDWR, 0))) { + usrerr("%s: %s\n", buf, strerror(errno)); + exit(EX_DATAERR); + } + + if (ListMode) { + dumplist(); + exit(EX_OK); + } + + if (sender_oob) + { + at = strchr(sender, '@'); + if (at != NULL) + for (c = at + 1; *c; c++) + *c = (char)tolower((char)*c); + from = sender; + shortfrom = sender; + } + else + /* read message from standard input (just from line) */ + from = getfrom(&shortfrom); + + /* check if junk mail or this person is already informed */ + if (!junkmail(shortfrom) && filter_ok(shortfrom, filter_file) && + !knows(shortfrom)) + { + /* mark this person as knowing */ + setknows(shortfrom); + + /* send the message back */ + (void) strlcpy(buf, homedir, sizeof (buf)); + if (message_file[0] != '/') + (void) strlcat(buf, "/", sizeof (buf)); + (void) strlcat(buf, message_file, sizeof (buf)); + if (Debug) + printf("Sending %s to %s\n", buf, from); + else + { + sendmessage(buf, from, myname); + /*NOTREACHED*/ + } + } + while (fgets(buf, MAXLINE, stdin) != NULL) + continue; /* drain input */ + return (EX_OK); +} + +struct entry { + time_t when; + long when_size; + char *who; + long who_size; + struct entry *next; + struct entry *prev; +}; + +static void +dump_content(key_size, key_ptr, content_size, content_ptr) + long key_size, content_size; + char *key_ptr, *content_ptr; +{ + time_t then; + + if (content_size == sizeof (then)) { + bcopy(content_ptr, (char *)&then, sizeof (then)); + (void) printf("%-53.40*s: %s", (int)key_size, key_ptr, + ctime(&then)); + } else { + (void) fprintf(stderr, "content size error: %d\n", + (int)content_size); + } +} + +static void +dump_all_content(first) + struct entry *first; +{ + struct entry *which; + + for (which = first; which != NULL; which = which->next) { + dump_content(which->who_size, which->who, which->when_size, + (char *)&(which->when)); + } +} + +static void +dumplist() +{ + datum content, key; + struct entry *first = NULL, *last = NULL, *new_entry, *curr; + + for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db)) { + content = dbm_fetch(db, key); + new_entry = (struct entry *)malloc(sizeof (struct entry)); + if (new_entry == NULL) + perror("out of memory"); + new_entry->next = NULL; + new_entry->who = (char *)malloc(key.dsize); + if (new_entry->who == NULL) + perror("out of memory"); + new_entry->who_size = key.dsize; + (void) strlcpy(new_entry->who, key.dptr, key.dsize); + bcopy(content.dptr, (char *)&(new_entry->when), + sizeof (new_entry->when)); + new_entry->when_size = content.dsize; + if (first == NULL) { /* => so is last */ + new_entry->prev = NULL; + new_entry->next = NULL; + first = new_entry; + last = new_entry; + } else { + for (curr = first; curr != NULL && + new_entry->when > curr->when; curr = curr->next) + ; + if (curr == NULL) { + last->next = new_entry; + new_entry->prev = last; + new_entry->next = NULL; + last = new_entry; + } else { + new_entry->next = curr; + new_entry->prev = curr->prev; + if (curr->prev == NULL) + first = new_entry; + else + curr->prev->next = new_entry; + curr->prev = new_entry; + } + } + } + dump_all_content(first); + dbm_close(db); +} + +/* + * GETFROM -- read message from standard input and return sender + * + * Parameters: + * none. + * + * Returns: + * pointer to the sender address. + * + * Side Effects: + * Reads first line from standard input. + */ + +static char * +getfrom(shortp) +char **shortp; +{ + static char line[MAXLINE]; + char *p, *start, *at, *bang, *c; + char saveat; + + /* read the from line */ + if (fgets(line, sizeof (line), stdin) == NULL || + strncmp(line, "From ", 5) != NULL) + { + usrerr("No initial From line"); + exit(EX_PROTOCOL); + } + + /* find the end of the sender address and terminate it */ + start = &line[5]; + p = strchr(start, ' '); + if (p == NULL) + { + usrerr("Funny From line '%s'", line); + exit(EX_PROTOCOL); + } + *p = '\0'; + + /* + * Strip all but the rightmost UUCP host + * to prevent loops due to forwarding. + * Start searching leftward from the leftmost '@'. + * a!b!c!d yields a short name of c!d + * a!b!c!d@e yields a short name of c!d@e + * e@a!b!c yields the same short name + */ +#ifdef VDEBUG +printf("start='%s'\n", start); +#endif /* VDEBUG */ + *shortp = start; /* assume whole addr */ + if ((at = strchr(start, '@')) == NULL) /* leftmost '@' */ + at = p; /* if none, use end of addr */ + saveat = *at; + *at = '\0'; + if ((bang = strrchr(start, '!')) != NULL) { /* rightmost '!' */ + char *bang2; + *bang = '\0'; + /* 2nd rightmost '!' */ + if ((bang2 = strrchr(start, '!')) != NULL) + *shortp = bang2 + 1; /* move past ! */ + *bang = '!'; + } + *at = saveat; +#ifdef VDEBUG +printf("place='%s'\n", *shortp); +#endif /* VDEBUG */ + for (c = at + 1; *c; c++) + *c = (char)tolower((char)*c); + + /* return the sender address */ + return (start); +} + +/* + * JUNKMAIL -- read the header and tell us if this is junk/bulk mail. + * + * Parameters: + * from -- the Return-Path of the sender. We assume that + * anything from "*-REQUEST@*" is bulk mail. + * + * Returns: + * TRUE -- if this is junk or bulk mail (that is, if the + * sender shouldn't receive a response). + * FALSE -- if the sender deserves a response. + * + * Side Effects: + * May read the header from standard input. When this + * returns the position on stdin is undefined. + */ + +static bool +junkmail(from) + char *from; +{ + register char *p; + char buf[MAXLINE+1]; + bool inside, onlist; + + /* test for inhuman sender */ + p = strrchr(from, '@'); + if (p != NULL) + { + *p = '\0'; + if (sameword(&p[-8], "-REQUEST") || + sameword(&p[-10], "Postmaster") || + sameword(&p[-13], "MAILER-DAEMON")) + { + *p = '@'; + return (TRUE); + } + *p = '@'; + } + +#define Delims " \n\t:,:;()<>@!" + + /* read the header looking for "interesting" lines */ + inside = FALSE; + onlist = FALSE; + while (fgets(buf, MAXLINE, stdin) != NULL && buf[0] != '\n') + { + if (buf[0] != ' ' && buf[0] != '\t' && strchr(buf, ':') == NULL) + return (FALSE); /* no header found */ + + p = strtok(buf, Delims); + if (p == NULL) + continue; + + if (sameword(p, "To") || sameword(p, "Cc")) + { + inside = TRUE; + p = strtok((char *)NULL, Delims); + if (p == NULL) + continue; + + } else /* continuation line? */ + if (inside) + inside = (buf[0] == ' ' || buf[0] == '\t'); + + if (inside) { + int i; + + do { + if (sameword(p, myname)) + onlist = TRUE; /* I am on the list */ + + for (i = 0; i < AliasCount; i++) + if (sameword(p, AliasList[i])) + onlist = TRUE; /* alias on list */ + + } while (p = strtok((char *)NULL, Delims)); + continue; + } + + if (sameword(p, "Precedence")) + { + /* find the value of this field */ + p = strtok((char *)NULL, Delims); + if (p == NULL) + continue; + + /* see if it is "junk" or "bulk" */ + p[4] = '\0'; + if (sameword(p, "junk") || sameword(p, "bulk")) + return (TRUE); + } + + if (sameword(p, "Subject")) + { + char *decoded_subject; + + Subject = newstr(buf+9); + if (p = strrchr(Subject, '\n')) + *p = '\0'; + EncodedSubject = newstr(Subject); + decoded_subject = newstr(Subject); + if (decode_rfc2047(Subject, decoded_subject, Charset)) + Subject = decoded_subject; + else + Charset[0] = '\0'; + if (Debug) + printf("Subject=%s\n", Subject); + } + } + if (AnswerAll) + return (FALSE); + else + return (!onlist); +} + +/* + * FILTER_OK -- see if the Return-Path is in the filter file. + * Note that a non-existent filter file means everything + * is OK, but an empty file means nothing is OK. + * + * Parameters: + * from -- the Return-Path of the sender. + * + * Returns: + * TRUE -- if this is in the filter file + * (sender should receive a response). + * FALSE -- if the sender does not deserve a response. + */ + +static bool +filter_ok(from, filter_file) + char *from; + char *filter_file; +{ + char file[MAXLINE]; + char line[MAXLINE]; + char *match_start; + size_t line_len, from_len; + bool result = FALSE; + bool negated = FALSE; + FILE *f; + + from_len = strlen(from); + (void) strlcpy(file, homedir, sizeof (file)); + if (filter_file[0] != '/') + (void) strlcat(file, "/", sizeof (file)); + (void) strlcat(file, filter_file, sizeof (file)); + f = fopen(file, "r"); + if (f == NULL) { + /* + * If the file does not exist, then there is no filter to + * apply, so we simply return TRUE. + */ + if (Debug) + (void) printf("%s does not exist, filter ok.\n", + file); + return (TRUE); + } + while (fgets(line, MAXLINE, f)) { + line_len = strlen(line); + /* zero out trailing newline */ + if (line[line_len - 1] == '\n') + line[--line_len] = '\0'; + /* skip blank lines */ + if (line_len == 0) + continue; + /* skip comment lines */ + if (line[0] == '#') + continue; + if (line[0] == '!') { + negated = TRUE; + match_start = &line[1]; + line_len--; + } else { + negated = FALSE; + match_start = &line[0]; + } + if (strchr(line, '@') != NULL) { + /* @ => full address */ + if (strcasecmp(match_start, from) == 0) { + result = TRUE; + if (Debug) + (void) printf("filter match on %s\n", + line); + break; + } + } else { + /* no @ => domain */ + if (from_len <= line_len) + continue; + /* + * Make sure the last part of from is the domain line + * and that the character immediately preceding is an + * '@' or a '.', otherwise we could get false positives + * from e.g. twinsun.com for sun.com . + */ + if (strncasecmp(&from[from_len - line_len], + match_start, line_len) == 0 && + (from[from_len - line_len -1] == '@' || + from[from_len - line_len -1] == '.')) { + result = TRUE; + if (Debug) + (void) printf("filter match on %s\n", + line); + break; + } + } + } + (void) fclose(f); + if (Debug && !result) + (void) printf("no filter match\n"); + return (!negated && result); +} + +/* + * KNOWS -- predicate telling if user has already been informed. + * + * Parameters: + * user -- the user who sent this message. + * + * Returns: + * TRUE if 'user' has already been informed that the + * recipient is on vacation. + * FALSE otherwise. + * + * Side Effects: + * none. + */ + +static bool +knows(user) + char *user; +{ + datum key, data; + time_t now, then; + + (void) time(&now); + key.dptr = user; + key.dsize = strlen(user) + 1; + data = dbm_fetch(db, key); + if (data.dptr == NULL) + return (FALSE); + + bcopy(data.dptr, (char *)&then, sizeof (then)); + if (then + Timeout < now) + return (FALSE); + if (Debug) + printf("User %s already knows\n", user); + return (TRUE); +} + +/* + * SETKNOWS -- set that this user knows about the vacation. + * + * Parameters: + * user -- the user who should be marked. + * + * Returns: + * none. + * + * Side Effects: + * The dbm file is updated as appropriate. + */ + +static void +setknows(user) + char *user; +{ + datum key, data; + time_t now; + + key.dptr = user; + key.dsize = strlen(user) + 1; + (void) time(&now); + data.dptr = (char *)&now; + data.dsize = sizeof (now); + dbm_store(db, key, data, DBM_REPLACE); +} + +static bool +any8bitchars(line) + char *line; +{ + char *c; + + for (c = line; *c; c++) + if (*c & 0x80) + return (TRUE); + return (FALSE); +} + +/* + * SENDMESSAGE -- send a message to a particular user. + * + * Parameters: + * msgf -- filename containing the message. + * user -- user who should receive it. + * + * Returns: + * none. + * + * Side Effects: + * sends mail to 'user' using /usr/lib/sendmail. + */ + +static void +sendmessage(msgf, user, myname) + char *msgf; + char *user; + char *myname; +{ + FILE *f, *fpipe, *tmpf; + char line[MAXLINE]; + char *p, *tmpf_name; + int i, pipefd[2], tmpfd; + bool seen8bitchars = FALSE; + bool in_header = TRUE; + + /* find the message to send */ + f = fopen(msgf, "r"); + if (f == NULL) + { + f = fopen("/etc/mail/vacation.def", "r"); + if (f == NULL) { + usrerr("No message to send"); + exit(EX_OSFILE); + } + } + + if (pipe(pipefd) < 0) { + usrerr("pipe() failed"); + exit(EX_OSERR); + } + i = fork(); + if (i < 0) { + usrerr("fork() failed"); + exit(EX_OSERR); + } + if (i == 0) { + dup2(pipefd[0], 0); + close(pipefd[0]); + close(pipefd[1]); + fclose(f); + execl("/usr/lib/sendmail", "sendmail", "-eq", "-f", myname, + "--", user, NULL); + usrerr("can't exec /usr/lib/sendmail"); + exit(EX_OSERR); + } + close(pipefd[0]); + fpipe = fdopen(pipefd[1], "w"); + if (fpipe == NULL) { + usrerr("fdopen() failed"); + exit(EX_OSERR); + } + fprintf(fpipe, "To: %s\n", user); + fputs("Auto-Submitted: auto-replied\n", fpipe); + fputs("X-Mailer: vacation %I%\n", fpipe); + + /* + * We used to write directly to the pipe. But now we need to know + * what character set to use, and we need to examine the entire + * message to determine this. So write to a temp file first. + */ + tmpf_name = strdup(_PATH_TMP); + if (tmpf_name == NULL) { + usrerr("newstr: cannot alloc memory"); + exit(EX_OSERR); + } + tmpfd = -1; + tmpfd = mkstemp(tmpf_name); + if (tmpfd == -1) { + usrerr("can't open temp file %s", tmpf_name); + exit(EX_OSERR); + } + tmpf = fdopen(tmpfd, "w"); + if (tmpf == NULL) { + usrerr("can't open temp file %s", tmpf_name); + exit(EX_OSERR); + } + while (fgets(line, MAXLINE, f)) { + /* + * Check for a line with no ':' character. If it's just \n, + * we're at the end of the headers and all is fine. Or if + * it starts with white-space, then it's a continuation header. + * Otherwise, it's the start of the body, which means the + * header/body separator was skipped. So output it. + */ + if (in_header && line[0] != '\0' && strchr(line, ':') == NULL) { + if (line[0] == '\n') + in_header = FALSE; + else if (!isspace(line[0])) { + in_header = FALSE; + fputs("\n", tmpf); + } + } + p = strchr(line, '$'); + if (p && strncmp(p, "$SUBJECT", 8) == 0) { + *p = '\0'; + seen8bitchars |= any8bitchars(line); + fputs(line, tmpf); + if (Subject) { + if (in_header) + fputs(EncodedSubject, tmpf); + else { + seen8bitchars |= any8bitchars(Subject); + fputs(Subject, tmpf); + } + } + seen8bitchars |= any8bitchars(p+8); + fputs(p+8, tmpf); + continue; + } + seen8bitchars |= any8bitchars(line); + fputs(line, tmpf); + } + fclose(f); + fclose(tmpf); + + /* + * If we haven't seen a funky Subject with Charset, use the default. + * If we have and it's us-ascii, 8-bit chars in the message file will + * still result in iso-8859-1. + */ + if (Charset[0] == '\0') + (void) strlcpy(Charset, (seen8bitchars) ? "iso-8859-1" : + "us-ascii", sizeof (Charset)); + else if ((strcasecmp(Charset, "us-ascii") == 0) && seen8bitchars) + (void) strlcpy(Charset, "iso-8859-1", sizeof (Charset)); + if (Debug) + printf("Charset is %s\n", Charset); + fprintf(fpipe, "Content-Type: text/plain; charset=%s\n", Charset); + fputs("Mime-Version: 1.0\n", fpipe); + + /* + * Now read back in from the temp file and write to the pipe. + */ + tmpf = fopen(tmpf_name, "r"); + if (tmpf == NULL) { + usrerr("can't open temp file %s", tmpf_name); + exit(EX_OSERR); + } + while (fgets(line, MAXLINE, tmpf)) + fputs(line, fpipe); + fclose(fpipe); + fclose(tmpf); + (void) unlink(tmpf_name); + free(tmpf_name); +} + +/* + * INITIALIZE -- initialize the database before leaving for vacation + * + * Parameters: + * none. + * + * Returns: + * none. + * + * Side Effects: + * Initializes the files .vacation.{pag,dir} in the + * caller's home directory. + */ + +static void +initialize(db_file_base) + char *db_file_base; +{ + char *homedir; + char buf[MAXLINE]; + DBM *db; + + setgid(getgid()); + setuid(getuid()); + homedir = getenv("HOME"); + if (homedir == NULL) { + usrerr("No home!"); + exit(EX_NOUSER); + } + (void) snprintf(buf, sizeof (buf), "%s%s%s", homedir, + (db_file_base[0] == '/') ? "" : "/", db_file_base); + + if (!(db = dbm_open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0644))) { + usrerr("%s: %s\n", buf, strerror(errno)); + exit(EX_DATAERR); + } + dbm_close(db); +} + +/* + * USRERR -- print user error + * + * Parameters: + * f -- format. + * + * Returns: + * none. + * + * Side Effects: + * none. + */ + +/* PRINTFLIKE1 */ +void +usrerr(const char *f, ...) +{ + va_list alist; + + va_start(alist, f); + (void) fprintf(stderr, "vacation: "); + (void) vfprintf(stderr, f, alist); + (void) fprintf(stderr, "\n"); + va_end(alist); +} + +/* + * NEWSTR -- copy a string + * + * Parameters: + * s -- the string to copy. + * + * Returns: + * A copy of the string. + * + * Side Effects: + * none. + */ + +static char * +newstr(s) + char *s; +{ + char *p; + size_t s_sz = strlen(s); + + p = malloc(s_sz + 1); + if (p == NULL) + { + usrerr("newstr: cannot alloc memory"); + exit(EX_OSERR); + } + (void) strlcpy(p, s, s_sz + 1); + return (p); +} + +/* + * SAMEWORD -- return TRUE if the words are the same + * + * Ignores case. + * + * Parameters: + * a, b -- the words to compare. + * + * Returns: + * TRUE if a & b match exactly (modulo case) + * FALSE otherwise. + * + * Side Effects: + * none. + */ + +static bool +sameword(a, b) + register char *a, *b; +{ + char ca, cb; + + do + { + ca = *a++; + cb = *b++; + if (isascii(ca) && isupper(ca)) + ca = ca - 'A' + 'a'; + if (isascii(cb) && isupper(cb)) + cb = cb - 'A' + 'a'; + } while (ca != '\0' && ca == cb); + return (ca == cb); +} + +/* + * When invoked with no arguments, we fall into an automatic installation + * mode, stepping the user through a default installation. + */ + +static void +AutoInstall() +{ + char file[MAXLINE]; + char forward[MAXLINE]; + char cmd[MAXLINE]; + char line[MAXLINE]; + char *editor; + FILE *f; + struct passwd *pw; + extern mode_t umask(mode_t cmask); + + umask(022); + pw = getpwuid(getuid()); + if (pw == NULL) { + usrerr("User ID unknown"); + exit(EX_NOUSER); + } + myname = strdup(pw->pw_name); + if (myname == NULL) { + usrerr("Out of memory"); + exit(EX_OSERR); + } + homedir = getenv("HOME"); + if (homedir == NULL) { + usrerr("Home directory unknown"); + exit(EX_NOUSER); + } + + printf("This program can be used to answer your mail automatically\n"); + printf("when you go away on vacation.\n"); + (void) strlcpy(file, homedir, sizeof (file)); + (void) strlcat(file, MsgFile, sizeof (file)); + do { + f = fopen(file, "r"); + if (f) { + printf("You have a message file in %s.\n", file); + if (ask("Would you like to see it")) { + (void) snprintf(cmd, sizeof (cmd), + "/usr/bin/more %s", file); + system(cmd); + } + if (ask("Would you like to edit it")) + f = NULL; + } else { + printf("You need to create a message file" + " in %s first.\n", file); + f = fopen(file, "w"); + if (f == NULL) { + usrerr("Cannot open %s", file); + exit(EX_CANTCREAT); + } + fprintf(f, "Subject: away from my mail\n"); + fprintf(f, "\nI will not be reading my mail" + " for a while.\n"); + fprintf(f, "Your mail regarding \"$SUBJECT\" will" + " be read when I return.\n"); + fclose(f); + f = NULL; + } + if (f == NULL) { + editor = getenv("VISUAL"); + if (editor == NULL) + editor = getenv("EDITOR"); + if (editor == NULL) + editor = "/usr/bin/vi"; + (void) snprintf(cmd, sizeof (cmd), "%s %s", editor, + file); + printf("Please use your editor (%s)" + " to edit this file.\n", editor); + system(cmd); + } + } while (f == NULL); + fclose(f); + (void) strlcpy(forward, homedir, sizeof (forward)); + (void) strlcat(forward, "/.forward", sizeof (forward)); + f = fopen(forward, "r"); + if (f) { + printf("You have a .forward file" + " in your home directory containing:\n"); + while (fgets(line, MAXLINE, f)) + printf(" %s", line); + fclose(f); + if (!ask("Would you like to remove it and" + " disable the vacation feature")) + exit(EX_OK); + if (unlink(forward)) + perror("Error removing .forward file:"); + else + printf("Back to normal reception of mail.\n"); + exit(EX_OK); + } + + printf("To enable the vacation feature" + " a \".forward\" file is created.\n"); + if (!ask("Would you like to enable the vacation feature")) { + printf("OK, vacation feature NOT enabled.\n"); + exit(EX_OK); + } + f = fopen(forward, "w"); + if (f == NULL) { + perror("Error opening .forward file"); + exit(EX_CANTCREAT); + } + fprintf(f, "\\%s, \"|/usr/bin/vacation %s\"\n", myname, myname); + fclose(f); + printf("Vacation feature ENABLED." + " Please remember to turn it off when\n"); + printf("you get back from vacation. Bon voyage.\n"); + + initialize(DbFileBase); + exit(EX_OK); +} + + +/* + * Ask the user a question until we get a reasonable answer + */ + +static bool +ask(prompt) + char *prompt; +{ + char line[MAXLINE]; + char *res; + + for (;;) { + printf("%s? ", prompt); + fflush(stdout); + res = fgets(line, sizeof (line), stdin); + if (res == NULL) + return (FALSE); + if (res[0] == 'y' || res[0] == 'Y') + return (TRUE); + if (res[0] == 'n' || res[0] == 'N') + return (FALSE); + printf("Please reply \"yes\" or \"no\" (\'y\' or \'n\')\n"); + } +} -- cgit v1.2.3