* Copyright (c) 1983, 1995 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char copyright
[] =
"@(#) Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)main.c 8.122 (Berkeley) %G%";
** SENDMAIL -- Post mail to a set of destinations.
** This is the basic mail router. All user mail programs should
** call this routine to actually deliver mail. Sendmail in
** turn calls a bunch of mail servers that do the real work of
** Sendmail is driven by tables read in from /usr/lib/sendmail.cf
** (read by readcf.c). Some more static configuration info,
** including some code that you may want to tailor for your
** installation, is in conf.c. You may also want to touch
** daemon.c (if you have some other IPC mechanism), acct.c
** (to change your accounting), names.c (to adjust the name
** /usr/lib/sendmail [flags] addr ...
** See the associated documentation for details.
** Eric Allman, UCB/INGRES (until 10/81)
** Britton-Lee, Inc., purveyors of fine
** database computers (from 11/81)
** Now back at UCB at the Mammoth project.
** The support of the INGRES Project and Britton-Lee is
** gratefully acknowledged. Britton-Lee in
** particular had absolutely nothing to gain from
** my involvement in this project.
int NextMailer
; /* "free" index into Mailer struct */
char *FullName
; /* sender's full name */
ENVELOPE BlankEnvelope
; /* a "blank" envelope */
ENVELOPE MainEnvelope
; /* the envelope around the basic letter */
ADDRESS NullAddress
= /* a null address */
char *CommandLineArgs
; /* command line args for pid file */
bool Warn_Q_option
= FALSE
; /* warn about Q option use */
char **SaveArgv
; /* argument vector for re-execing */
** Pointers for setproctitle.
** This allows "ps" listings to give more useful information.
char **Argv
= NULL
; /* pointer to argument vector */
char *LastArgv
= NULL
; /* end of argv */
ERROR
%%%% Cannot have daemon mode without SMTP
%%%% ERROR
#define MAXCONFIGLEVEL 6 /* highest config version level known */
bool queuemode
= FALSE
; /* process queue requests */
bool warn_C_flag
= FALSE
;
static bool reenter
= FALSE
;
char jbuf
[MAXHOSTNAMELEN
]; /* holds MyHostName */
static char rnamebuf
[MAXNAME
]; /* holds RealUserName */
extern time_t convtime();
extern struct hostent
*myhostname();
extern char *getauthinfo();
extern char *getcfname();
extern void initmacros
__P((ENVELOPE
*));
** Check to see if we reentered.
** This would normally happen if e_putheader or e_putbody
** were NULL when invoked.
syserr("main: reentered!");
extern ADDRESS
*recipient();
/* do machine-dependent initializations */
/* arrange to dump state on user-1 signal */
setsignal(SIGUSR1
, sigusr1
);
/* in 4.4BSD, the table can be huge; impose a reasonable limit */
DtableSize
= getdtsize();
** Be sure we have enough file descriptors.
** But also be sure that 0, 1, & 2 are open.
i
= open("/dev/null", O_RDWR
, 0);
if (fstat(STDIN_FILENO
, &stb
) < 0 && errno
!= EOPNOTSUPP
)
(void) dup2(i
, STDIN_FILENO
);
if (fstat(STDOUT_FILENO
, &stb
) < 0 && errno
!= EOPNOTSUPP
)
(void) dup2(i
, STDOUT_FILENO
);
if (fstat(STDERR_FILENO
, &stb
) < 0 && errno
!= EOPNOTSUPP
)
(void) dup2(i
, STDERR_FILENO
);
if (i
!= STDIN_FILENO
&& i
!= STDOUT_FILENO
&& i
!= STDERR_FILENO
)
if (i
!= STDIN_FILENO
&& i
!= STDOUT_FILENO
&& i
!= STDERR_FILENO
)
openlog("sendmail", LOG_PID
, LOG_MAIL
);
openlog("sendmail", LOG_PID
);
tTsetup(tTdvect
, sizeof tTdvect
, "0-99.1");
/* set up the blank envelope */
BlankEnvelope
.e_puthdr
= putheader
;
BlankEnvelope
.e_putbody
= putbody
;
BlankEnvelope
.e_xfp
= NULL
;
STRUCTCOPY(NullAddress
, BlankEnvelope
.e_from
);
STRUCTCOPY(BlankEnvelope
, MainEnvelope
);
** Set default values for variables.
** These cannot be in initialized data space.
setdefaults(&BlankEnvelope
);
pw
= sm_getpwuid(RealUid
);
(void) strcpy(rnamebuf
, pw
->pw_name
);
(void) sprintf(rnamebuf
, "Unknown UID %d", RealUid
);
/* save command line arguments */
for (av
= argv
; *av
!= NULL
; )
SaveArgv
= (char **) xalloc(sizeof (char *) * (argc
+ 1));
CommandLineArgs
= xalloc(i
);
for (av
= argv
, i
= 0; *av
!= NULL
; )
SaveArgv
[i
++] = newstr(*av
);
/* Handle any non-getoptable constructions. */
** Do a quick prescan of the argument list.
#if defined(__osf__) || defined(_AIX3)
# define OPTIONS "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:x"
# define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:"
# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:mnO:o:p:q:r:sTtvX:"
# define OPTIONS "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:"
while ((j
= getopt(argc
, argv
, OPTIONS
)) != EOF
)
setbuf(stdout
, (char *) NULL
);
extern char *CompileOptions
[];
printf("Version %s\nCompiled with:\t", Version
);
if (ll
+ strlen(*av
) > 63)
extern char *OsCompileOptions
[];
printf("OS Defines:\t", Version
);
if (ll
+ strlen(*av
) > 63)
printf("Unix path:\t %s\n", _PATH_UNIX
);
printf("Config file:\t %s\n", getcfname());
printf("Proc Id file:\t %s\n", PidFile
);
** Move the environment so setproctitle can use the space at
for (i
= 0; envp
[i
] != NULL
; i
++)
environ
= (char **) xalloc(sizeof (char *) * i
);
for (i
= 0; envp
[i
] != NULL
; i
++)
environ
[i
] = newstr(envp
[i
]);
/* and prime the child environment */
setuserenv("AGENT", "sendmail");
** Save start and extent of argv for setproctitle.
LastArgv
= envp
[i
- 1] + strlen(envp
[i
- 1]);
LastArgv
= argv
[argc
- 1] + strlen(argv
[argc
- 1]);
if (setsignal(SIGINT
, SIG_IGN
) != SIG_IGN
)
(void) setsignal(SIGINT
, intsig
);
(void) setsignal(SIGTERM
, intsig
);
(void) setsignal(SIGPIPE
, SIG_IGN
);
FullName
= getenv("NAME");
_res
.options
|= RES_DEBUG
;
/* initialize some macros, etc. */
init_vendor_macros(CurEnv
);
define('v', Version
, CurEnv
);
hp
= myhostname(jbuf
, sizeof jbuf
);
printf("canonical name: %s\n", jbuf
);
define('w', newstr(jbuf
), CurEnv
); /* must be new string */
define('j', newstr(jbuf
), CurEnv
);
define('m', newstr(&p
[1]), CurEnv
);
while (p
!= NULL
&& strchr(&p
[1], '.') != NULL
)
if (uname(&utsname
) >= 0)
printf("uname failed (%s)\n", errstring(errno
));
printf(" UUCP nodename: %s\n", p
);
for (av
= hp
->h_aliases
; av
!= NULL
&& *av
!= NULL
; av
++)
printf("\ta.k.a.: %s\n", *av
);
if (hp
->h_addrtype
== AF_INET
&& hp
->h_length
== INADDRSZ
)
for (i
= 0; hp
->h_addr_list
[i
] != NULL
; i
++)
inet_ntoa(*((struct in_addr
*) hp
->h_addr_list
[i
])));
printf("\ta.k.a.: %s\n", ipbuf
);
/* probe interfaces and locate any additional names */
define('b', arpadate((char *) NULL
), CurEnv
);
** Find our real host name for future logging.
p
= getauthinfo(STDIN_FILENO
);
if (strcmp(p
, "newaliases") == 0)
else if (strcmp(p
, "mailq") == 0)
else if (strcmp(p
, "smtpd") == 0)
while ((j
= getopt(argc
, argv
, OPTIONS
)) != EOF
)
case 'b': /* operations mode */
usrerr("Permission denied");
(void) unsetenv("HOSTALIASES");
usrerr("Daemon mode not implemented");
usrerr("I don't speak SMTP");
usrerr("Frozen configurations unsupported");
usrerr("Invalid operation mode %c", j
);
case 'B': /* body type */
if (strcasecmp(optarg
, "7bit") == 0 ||
strcasecmp(optarg
, "8bitmime") == 0)
CurEnv
->e_bodytype
= newstr(optarg
);
usrerr("Illegal body type %s", optarg
);
case 'C': /* select configuration file (already done) */
case 'd': /* debugging -- already done */
case 'f': /* from address */
case 'r': /* obsolete -f flag */
usrerr("More than one \"from\" person");
from
= newstr(denlstring(optarg
, TRUE
, TRUE
));
if (strcmp(RealUserName
, from
) != 0)
case 'F': /* set full name */
FullName
= newstr(optarg
);
case 'h': /* hop count */
CurEnv
->e_hopcount
= strtol(optarg
, &ep
, 10);
usrerr("Bad hop count (%s)", optarg
);
case 'n': /* don't alias */
case 'o': /* set option */
setoption(*optarg
, optarg
+ 1, FALSE
, TRUE
, CurEnv
);
case 'O': /* set option (long form) */
setoption(' ', optarg
, FALSE
, TRUE
, CurEnv
);
case 'p': /* set protocol */
ep
= xalloc(strlen(p
) + 1);
cleanstrcpy(ep
, p
, MAXNAME
);
ep
= xalloc(strlen(optarg
) + 1);
cleanstrcpy(ep
, optarg
, MAXNAME
);
case 'q': /* run queue files at intervals */
(void) unsetenv("HOSTALIASES");
QueueLimitId
= newstr(&optarg
[1]);
QueueLimitRecipient
= newstr(&optarg
[1]);
QueueLimitSender
= newstr(&optarg
[1]);
QueueIntvl
= convtime(optarg
, 'm');
usrerr("I don't know about queues");
case 't': /* read recipients from message */
case 'X': /* traffic log file */
TrafficLogFile
= fopen(optarg
, "a");
if (TrafficLogFile
== NULL
)
syserr("cannot open %s", optarg
);
setvbuf(TrafficLogFile
, NULL
, _IOLBF
, 0);
setlinebuf(TrafficLogFile
);
/* compatibility flags */
case 'c': /* connect to non-local mailers */
case 'i': /* don't let dot stop me */
case 'm': /* send to me too */
case 'T': /* set timeout interval */
case 'v': /* give blow-by-blow description */
setoption(j
, "T", FALSE
, TRUE
, CurEnv
);
case 'e': /* error message disposition */
case 'M': /* define macro */
setoption(j
, optarg
, FALSE
, TRUE
, CurEnv
);
case 's': /* save From lines in headers */
setoption('f', "T", FALSE
, TRUE
, CurEnv
);
case 'I': /* initialize alias DBM file */
# if defined(__osf__) || defined(_AIX3)
case 'x': /* random flag that OSF/1 & AIX mailx passes */
case 'J': /* ignore flags for Japanese code conversion
impremented on Sony NEWS */
** Do basic initialization.
** Read system control file.
** Extract special fields for local use.
checkfd012("before readcf");
vendor_pre_defaults(CurEnv
);
readcf(getcfname(), safecf
, CurEnv
);
vendor_post_defaults(CurEnv
);
/* set up the $=m class now, after .cf has a chance to redefine $m */
expand("\201m", jbuf
, sizeof jbuf
, CurEnv
);
printf("SYSTEM IDENTITY (after readcf):");
printf("\n\t (short domain name) $w = ");
xputs(macvalue('w', CurEnv
));
printf("\n\t(canonical domain name) $j = ");
xputs(macvalue('j', CurEnv
));
printf("\n\t (subdomain name) $m = ");
xputs(macvalue('m', CurEnv
));
printf("\n\t (node name) $k = ");
xputs(macvalue('k', CurEnv
));
** Initialize name server if it is going to be used.
if (!bitset(RES_INIT
, _res
.options
))
** Initialize name server if it is going to be used.
if (UseNameServer
&& !bitset(RES_INIT
, _res
.options
))
** Process authorization warnings from command line.
auth_warning(CurEnv
, "Processed by %s with -C %s",
if (warn_f_flag
!= '\0' && !wordinclass(RealUserName
, 't'))
auth_warning(CurEnv
, "%s set sender to %s using -%c",
RealUserName
, from
, warn_f_flag
);
auth_warning(CurEnv
, "Processed from queue %s", QueueDir
);
/* supress error printing if errors mailed back or whatever */
if (CurEnv
->e_errormode
!= EM_PRINT
)
/* Enforce use of local time (null string overrides this) */
if (TimeZoneSpec
== NULL
)
else if (TimeZoneSpec
[0] != '\0')
setuserenv("TZ", TimeZoneSpec
);
if (ConfigLevel
> MAXCONFIGLEVEL
)
syserr("Warning: .cf version level (%d) exceeds program functionality (%d)",
ConfigLevel
, MAXCONFIGLEVEL
);
BlankEnvelope
.e_flags
|= EF_METOO
;
/* remove things that don't make sense in daemon mode */
/* arrange to restart on hangup signal */
setsignal(SIGHUP
, sighup
);
/* arrange to exit cleanly on hangup signal */
setsignal(SIGHUP
, intsig
);
/* full names can't have newlines */
if (FullName
!= NULL
&& strchr(FullName
, '\n') != NULL
)
FullName
= newstr(denlstring(FullName
, TRUE
, TRUE
));
/* do heuristic mode adjustment */
/* turn off noconnect option */
setoption('c', "F", TRUE
, FALSE
, CurEnv
);
/* turn on interactive delivery */
setoption('d', "", TRUE
, FALSE
, CurEnv
);
/* our name for SMTP codes */
expand("\201j", jbuf
, sizeof jbuf
, CurEnv
);
if (strchr(jbuf
, '.') == NULL
)
message("WARNING: local host name (%s) is not qualified; fix $j in config file",
/* make certain that this name is part of the $=w class */
setclass('w', MyHostName
);
/* the indices of built-in mailers */
st
= stab("local", ST_MAILER
, ST_FIND
);
syserr("No local mailer defined");
LocalMailer
= st
->s_mailer
;
st
= stab("prog", ST_MAILER
, ST_FIND
);
syserr("No prog mailer defined");
ProgMailer
= st
->s_mailer
;
clrbitn(M_MUSER
, ProgMailer
->m_flags
);
st
= stab("*file*", ST_MAILER
, ST_FIND
);
syserr("No *file* mailer defined");
FileMailer
= st
->s_mailer
;
clrbitn(M_MUSER
, FileMailer
->m_flags
);
st
= stab("*include*", ST_MAILER
, ST_FIND
);
syserr("No *include* mailer defined");
InclMailer
= st
->s_mailer
;
/* heuristic tweaking of local mailer for back compat */
setbitn(M_ALIASABLE
, LocalMailer
->m_flags
);
setbitn(M_HASPWENT
, LocalMailer
->m_flags
);
setbitn(M_TRYRULESET5
, LocalMailer
->m_flags
);
setbitn(M_CHECKINCLUDE
, LocalMailer
->m_flags
);
setbitn(M_CHECKPROG
, LocalMailer
->m_flags
);
setbitn(M_CHECKFILE
, LocalMailer
->m_flags
);
setbitn(M_CHECKUDB
, LocalMailer
->m_flags
);
setbitn(M_RUNASRCPT
, ProgMailer
->m_flags
);
setbitn(M_RUNASRCPT
, FileMailer
->m_flags
);
/* propogate some envariables into children */
setuserenv("SYSTYPE", NULL
);
/* MIME Content-Types that cannot be transfer encoded */
setclass('n', "multipart/signed");
/* MIME Content-Transfer-Encodings that can be encoded */
/* operate in queue directory */
if (OpMode
!= MD_TEST
&& chdir(QueueDir
) < 0)
syserr("cannot chdir(%s)", QueueDir
);
if (queuemode
&& RealUid
!= 0 && bitset(PRIV_RESTRICTQRUN
, PrivacyFlags
))
/* check to see if we own the queue directory */
if (stat(".", &stbuf
) < 0)
syserr("main: cannot stat %s", QueueDir
);
if (stbuf
.st_uid
!= RealUid
)
/* nope, really a botch */
usrerr("You do not have permission to process the queue");
/* if we've had errors so far, exit now */
if (ExitStat
!= EX_OK
&& OpMode
!= MD_TEST
)
checkfd012("before main() initmaps");
** Do operation-mode-dependent initialization.
usrerr("No queue to print");
/* initialize alias database */
/* don't open alias database -- done in srvrsmtp */
/* open the alias database */
/* print configuration table (or at least part of it) */
for (i
= 0; i
< MAXMAILERS
; i
++)
** Switch to the main envelope.
CurEnv
= newenvelope(&MainEnvelope
, CurEnv
);
MainEnvelope
.e_flags
= BlankEnvelope
.e_flags
;
** If test mode, read addresses from stdin and process.
if (isatty(fileno(stdin
)))
printf("ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)\n");
printf("Enter <ruleset> <address>\n");
extern void testmodeline
__P((char *, ENVELOPE
*));
if (fgets(buf
, sizeof buf
, stdin
) == NULL
)
testmodeline(buf
, CurEnv
);
** If collecting stuff from the queue, go start doing that.
if (queuemode
&& OpMode
!= MD_DAEMON
&& QueueIntvl
== 0)
** If a daemon, wait for a request.
** getrequests will always return in a child.
** If we should also be processing the queue, start
** doing it in background.
** We check for any errors that might have happened
if (OpMode
== MD_DAEMON
|| QueueIntvl
!= 0)
/* put us in background */
syserr("daemon: cannot fork");
/* disconnect from our controlling tty */
strcat(dtype
, "+queueing@");
strcat(dtype
, pintvl(QueueIntvl
, TRUE
));
strcat(dtype
, "+debugging");
syslog(LOG_INFO
, "starting daemon (%s): %s", Version
, dtype
+ 1);
/* at this point we are in a child: reset state */
(void) newenvelope(CurEnv
, CurEnv
);
** Get authentication data
p
= getauthinfo(fileno(InChannel
));
** If running SMTP protocol, start collecting and executing
** commands. This will never return.
if (OpMode
== MD_SMTP
|| OpMode
== MD_DAEMON
)
CurEnv
->e_sendmode
= SM_VERIFY
;
CurEnv
->e_errormode
= EM_QUIET
;
/* interactive -- all errors are global */
CurEnv
->e_flags
|= EF_GLOBALERRS
|EF_LOGSENDER
;
** Do basic system initialization and set the sender
setsender(from
, CurEnv
, NULL
, FALSE
);
if (macvalue('s', CurEnv
) == NULL
)
define('s', RealHostName
, CurEnv
);
if (*av
== NULL
&& !GrabTo
)
CurEnv
->e_flags
|= EF_GLOBALERRS
;
usrerr("Recipient names must be specified");
/* collect body for UUCP return */
collect(InChannel
, FALSE
, FALSE
, NULL
, CurEnv
);
** Scan argv and deliver the message to everyone.
/* if we have had errors sofar, arrange a meaningful exit stat */
if (Errors
> 0 && ExitStat
== EX_OK
)
if (OpMode
!= MD_VERIFY
|| GrabTo
)
CurEnv
->e_flags
|= EF_GLOBALERRS
;
collect(InChannel
, FALSE
, FALSE
, NULL
, CurEnv
);
printf("From person = \"%s\"\n", CurEnv
->e_from
.q_paddr
);
** Actually send everything.
** If verifying, just ack.
CurEnv
->e_from
.q_flags
|= QDONTSEND
;
printf("main: QDONTSEND ");
printaddr(&CurEnv
->e_from
, FALSE
);
sendall(CurEnv
, SM_DEFAULT
);
** Don't send return error message if in VERIFY mode.
** FINIS -- Clean up and exit.
extern void printenvflags();
printf("\n====finis: stat %d e_id=%s e_flags=",
CurEnv
->e_id
== NULL
? "NOQUEUE" : CurEnv
->e_id
);
/* clean up temp files */
/* flush any cached connections */
/* clean up extended load average stuff */
syslog(LOG_DEBUG
, "finis, pid=%d", getpid());
if (ExitStat
== EX_TEMPFAIL
|| CurEnv
->e_errormode
== EM_BERKNET
)
/* reset uid for process accounting */
** INTSIG -- clean up on interrupt
** This just arranges to exit. It pessimises in that it
** Unlocks the current job.
/* reset uid for process accounting */
** INITMACROS -- initialize the macro system
** This just involves defining some macros that are actually
** used internally as metasymbols to be themselves.
** initializes several macros to be themselves.
struct metamac MetaMacros
[] =
/* LHS pattern matching characters */
'*', MATCHZANY
, '+', MATCHANY
, '-', MATCHONE
,
'=', MATCHCLASS
, '~', MATCHNCLASS
,
/* these are RHS metasymbols */
'#', CANONNET
, '@', CANONHOST
, ':', CANONUSER
,
'{', MATCHLOOKUP
, '}', MATCHELOOKUP
,
/* the conditional operations */
'?', CONDIF
, '|', CONDELSE
, '.', CONDFI
,
/* the hostname lookup characters */
'[', HOSTBEGIN
, ']', HOSTEND
,
'(', LOOKUPBEGIN
, ')', LOOKUPEND
,
/* miscellaneous control characters */
register struct metamac
*m
;
for (m
= MetaMacros
; m
->metaname
!= '\0'; m
++)
define(m
->metaname
, newstr(buf
), e
);
for (c
= '0'; c
<= '9'; c
++)
define(c
, newstr(buf
), e
);
/* set defaults for some macros sendmail will use later */
define('e', "\201j Sendmail \201v ready at \201b", e
);
define('l', "From \201g \201d", e
);
define('n', "MAILER-DAEMON", e
);
define('q', "<\201g>", e
);
** DISCONNECT -- remove our connection with any foreground process
** droplev -- how "deeply" we should drop the line.
** 0 -- ignore signals, mail back errors, make sure
** output goes to stdout.
** 1 -- also, make stdout go to transcript.
** 2 -- also, disconnect from controlling terminal
** (only for daemon mode).
** e -- the current envelope.
** Trys to insure that we are immune to vagaries of
printf("disconnect: In %d Out %d, e=%x\n",
fileno(InChannel
), fileno(OutChannel
), e
);
/* be sure we don't get nasty signals */
(void) setsignal(SIGINT
, SIG_IGN
);
(void) setsignal(SIGQUIT
, SIG_IGN
);
/* we can't communicate with our caller, so.... */
CurEnv
->e_errormode
= EM_MAIL
;
/* all input from /dev/null */
(void) fclose(InChannel
);
(void) freopen("/dev/null", "r", stdin
);
/* output to the transcript */
if (OutChannel
!= stdout
)
(void) fclose(OutChannel
);
fd
= open("/dev/null", O_WRONLY
, 0666);
/* drop our controlling TTY completely if possible */
checkfd012("disconnect");
syslog(LOG_DEBUG
, "in background, pid=%d", getpid());
while ((ap
= *++argv
) != NULL
)
/* Return if "--" or not an option of any form. */
if (ap
[0] != '-' || ap
[1] == '-')
/* skip over options that do have a value */
op
= strchr(OPTIONS
, ap
[1]);
if (op
!= NULL
&& *++op
== ':' && ap
[2] == '\0' &&
ap
[1] != 'E' && ap
[1] != 'J' &&
argv
[1] != NULL
&& argv
[1][0] != '-')
/* If -C doesn't have an argument, use sendmail.cf. */
#define __DEFPATH "sendmail.cf"
if (ap
[1] == 'C' && ap
[2] == '\0')
*argv
= xalloc(sizeof(__DEFPATH
) + 2);
(void)strcpy(&argv
[0][2], __DEFPATH
);
/* If -q doesn't have an argument, run it once. */
if (ap
[1] == 'q' && ap
[2] == '\0')
/* if -d doesn't have an argument, use 0-99.1 */
if (ap
[1] == 'd' && ap
[2] == '\0')
/* if -E doesn't have an argument, use -EC */
if (ap
[1] == 'E' && ap
[2] == '\0')
/* if -J doesn't have an argument, use -JJ */
if (ap
[1] == 'J' && ap
[2] == '\0')
** AUTH_WARNING -- specify authorization warning
** e -- the current envelope.
** msg -- the text of the message.
** args -- arguments to the message.
auth_warning(register ENVELOPE
*e
, const char *msg
, ...)
auth_warning(e
, msg
, va_alist
)
if (bitset(PRIV_AUTHWARNINGS
, PrivacyFlags
))
extern struct hostent
*myhostname();
(void) myhostname(hostbuf
, sizeof hostbuf
);
(void) sprintf(buf
, "%s: ", hostbuf
);
addheader("X-Authentication-Warning", buf
, &e
->e_header
);
syslog(LOG_INFO
, "%s: Authentication-Warning: %s",
e
->e_id
== NULL
? "[NOQUEUE]" : e
->e_id
, buf
);
** SETUSERENV -- set an environment in the propogated environment
** envar -- the name of the environment variable.
** value -- the value to which it should be set. If
** null, this is extracted from the incoming
** environment. If that is not set, the call
** to setuserenv is ignored.
char **evp
= UserEnviron
;
p
= (char *) xalloc(strlen(value
) + i
+ 2);
while (*evp
!= NULL
&& strncmp(*evp
, p
, i
) != 0)
else if (evp
< &UserEnviron
[MAXUSERENVIRON
])
/* make sure it is in our environment as well */
syserr("setuserenv: putenv(%s) failed", p
);
** DUMPSTATE -- dump state
register char *j
= macvalue('j', CurEnv
);
syslog(LOG_DEBUG
, "--- dumping state on %s: $j = %s ---",
j
== NULL
? "<NULL>" : j
);
if (!wordinclass(j
, 'w'))
syslog(LOG_DEBUG
, "*** $j not in $=w ***");
syslog(LOG_DEBUG
, "--- open file descriptors: ---");
syslog(LOG_DEBUG
, "--- connection cache: ---");
if (RewriteRules
[89] != NULL
)
stat
= rewrite(pv
, 89, 0, CurEnv
);
syslog(LOG_DEBUG
, "--- ruleset 89 returns stat %d, pv: ---",
for (pvp
= pv
; *pvp
!= NULL
; pvp
++)
syslog(LOG_DEBUG
, "%s", *pvp
);
syslog(LOG_DEBUG
, "--- end of state dump ---");
dumpstate("user signal");
syslog(LOG_INFO
, "restarting %s on signal", SaveArgv
[0]);
execv(SaveArgv
[0], (ARGV_T
) SaveArgv
);
syslog(LOG_ALERT
, "could not exec %s: %m", SaveArgv
[0]);
** TESTMODELINE -- process a test mode input line
** line -- the input line.
** e -- the current environment.
extern bool invalidaddr();
extern char *crackaddr();
case '.': /* config-style settings */
mid
= macid(&line
[2], &delimptr
);
define(mid
, newstr(delimptr
), e
);
setclass(line
[2], &line
[3]);
case 'S': /* dump rule set */
s
= stab(&line
[2], ST_RULESET
, ST_FIND
);
if (rs
< 0 || rs
> MAXRWSETS
)
if ((rw
= RewriteRules
[rs
]) == NULL
)
} while (rw
= rw
->r_next
);
printf("Unknown config command %s", line
);
case '-': /* set command-line-like opts */
printf("Unknown \"-\" command %s", line
);
mid
= macid(&line
[1], NULL
);
case '/': /* miscellaneous commands */
while (--p
>= line
&& isascii(*p
) && isspace(*p
))
p
= strpbrk(line
, " \t");
while (isascii(*p
) && isspace(*p
))
if (strcasecmp(&line
[1], "mx") == 0)
char *mxhosts
[MAXMXHOSTS
+ 1];
nmx
= getmxrr(p
, mxhosts
, FALSE
, &rcode
);
printf("getmxrr(%s) returns %d value(s):\n", p
, nmx
);
for (i
= 0; i
< nmx
; i
++)
printf("\t%s\n", mxhosts
[i
]);
printf("No MX code compiled in\n");
else if (strcasecmp(&line
[1], "try") == 0)
printf("Cracked address = ");
if (parseaddr(p
, &a
, RF_COPYNONE
, '\0', NULL
, e
) == NULL
)
printf("Cannot parse\n");
else if (a
.q_host
!= NULL
&& a
.q_host
[0] != '\0')
printf("mailer %s, host %s, user %s\n",
a
.q_mailer
->m_name
, a
.q_host
, a
.q_user
);
printf("mailer %s, user %s\n",
a
.q_mailer
->m_name
, a
.q_user
);
printf("Unknown test command %s\n", line
);
for (p
= line
; isascii(*p
) && isspace(*p
); p
++)
while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
if (invalidaddr(p
+ 1, NULL
))
pvp
= prescan(++p
, ',', pvpbuf
, sizeof pvpbuf
,
stat
= rewrite(pvp
, atoi(p
), 0, e
);
printf("== Ruleset %s status %d\n",
while (*p
!= '\0' && *p
++ != ',')
} while (*(p
= delimptr
) != '\0');