* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
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.3 (Berkeley) 7/13/93";
#include <arpa/nameser.h>
** 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 *UserEnviron
[MAXUSERENVIRON
+ 1];
/* saved user environment */
char RealUserName
[256]; /* the actual user id on this host */
** Pointers for setproctitle.
** This allows "ps" listings to give more useful information.
** These must be kept out of BSS for frozen configuration files
char **Argv
= NULL
; /* pointer to argument vector */
char *LastArgv
= NULL
; /* end of argv */
# endif /* SETPROCTITLE */
ERROR
%%%% Cannot have daemon mode without SMTP
%%%% ERROR
#define MAXCONFIGLEVEL 4 /* highest config version level known */
bool queuemode
= FALSE
; /* process queue requests */
static bool reenter
= FALSE
;
char jbuf
[MAXHOSTNAMELEN
]; /* holds MyHostName */
extern time_t convtime();
extern putheader(), putbody();
extern char **myhostname();
extern char *getauthinfo();
** Check to see if we reentered.
** This would normally happen if e_putheader or e_putbody
** were NULL when invoked.
syserr("main: reentered!");
/* enforce use of kernel-supplied time zone information */
/* 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
);
if (fstat(STDIN_FILENO
, &stb
) < 0)
(void) dup2(i
, STDIN_FILENO
);
if (fstat(STDOUT_FILENO
, &stb
) < 0)
(void) dup2(i
, STDOUT_FILENO
);
if (fstat(STDERR_FILENO
, &stb
) < 0)
(void) dup2(i
, STDERR_FILENO
);
if (i
!= STDIN_FILENO
&& i
!= STDOUT_FILENO
&& i
!= STDERR_FILENO
)
openlog("sendmail", LOG_PID
, LOG_MAIL
);
openlog("sendmail", LOG_PID
);
/* set up the blank envelope */
BlankEnvelope
.e_puthdr
= putheader
;
BlankEnvelope
.e_putbody
= putbody
;
BlankEnvelope
.e_xfp
= NULL
;
STRUCTCOPY(NullAddress
, BlankEnvelope
.e_from
);
STRUCTCOPY(NullAddress
, MainEnvelope
.e_from
);
** Set default values for variables.
** These cannot be in initialized data space.
setdefaults(&BlankEnvelope
);
(void) strcpy(RealUserName
, pw
->pw_name
);
(void) sprintf(RealUserName
, "Unknown UID %d", RealUid
);
/* our real uid will have to be root -- we will trash this later */
/* Handle any non-getoptable constructions. */
** Do a quick prescan of the argument list.
** We do this to find out if we can potentially thaw the
** configuration file. If not, we do the thaw now so that
** the argument processing applies to this run rather than
** to the run that froze the configuration.
#if defined(__osf__) || defined(_AIX3)
#define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:x"
#define OPTIONS "B:b:C:cd:e:F:f:h:Iimno:p:q:r:sTtvX:"
while ((j
= getopt(argc
, argv
, OPTIONS
)) != EOF
)
if (optarg
[0] == 'z' && optarg
[1] == '\0')
tTsetup(tTdvect
, sizeof tTdvect
, "0-99.1");
setbuf(stdout
, (char *) NULL
);
printf("Version %s\n", Version
);
readconfig
= !thaw(FreezeFile
, argv0
);
** Move the environment so setproctitle can use the space at
for (i
= j
= 0; j
< MAXUSERENVIRON
&& (p
= envp
[i
]) != NULL
; i
++)
if (strncmp(p
, "FS=", 3) == 0 || strncmp(p
, "LD_", 3) == 0)
UserEnviron
[j
++] = newstr(p
);
** Save start and extent of argv for setproctitle.
LastArgv
= envp
[i
- 1] + strlen(envp
[i
- 1]);
LastArgv
= argv
[argc
- 1] + strlen(argv
[argc
- 1]);
# endif /* SETPROCTITLE */
if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
(void) signal(SIGINT
, intsig
);
if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
(void) signal(SIGHUP
, intsig
);
(void) signal(SIGTERM
, intsig
);
(void) signal(SIGPIPE
, SIG_IGN
);
FullName
= getenv("NAME");
_res
.options
|= RES_DEBUG
;
/* initialize some macros, etc. */
define('v', Version
, CurEnv
);
av
= myhostname(jbuf
, sizeof jbuf
);
printf("canonical name: %s\n", jbuf
);
if (uname(&utsname
) >= 0)
printf("UUCP nodename: %s\n", p
);
while (av
!= NULL
&& *av
!= NULL
)
printf("\ta.k.a.: %s\n", *av
);
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 */
CurEnv
->e_bodytype
= newstr(optarg
);
case 'C': /* select configuration file (already done) */
"Processed by %s with -C %s",
case 'd': /* debugging -- redo in case frozen */
tTsetup(tTdvect
, sizeof tTdvect
, "0-99.1");
setbuf(stdout
, (char *) NULL
);
case 'f': /* from address */
case 'r': /* obsolete -f flag */
usrerr("More than one \"from\" person");
if (strcmp(RealUserName
, from
) != 0)
"%s set sender to %s using -%c",
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 'p': /* set protocol */
define('r', newstr(optarg
), CurEnv
);
if (q
!= NULL
&& *q
!= '\0')
define('s', newstr(q
), CurEnv
);
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
, BUFSIZ
);
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 */
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 */
** Do basic initialization.
** Read system control file.
** Extract special fields for local use.
if (OpMode
== MD_FREEZE
|| readconfig
)
readcf(ConfFile
, safecf
, CurEnv
);
/* Enforce use of local time (null string overrides this) */
if (TimeZoneSpec
== NULL
)
else if (TimeZoneSpec
[0] != '\0')
p
= xalloc(strlen(TimeZoneSpec
) + 4);
(void) strcat(p
, TimeZoneSpec
);
if (ConfigLevel
> MAXCONFIGLEVEL
)
syserr("Warning: .cf version level (%d) exceeds program functionality (%d)",
ConfigLevel
, MAXCONFIGLEVEL
);
if (queuemode
&& RealUid
!= 0)
/* check to see if we own the queue directory */
if (stat(QueueDir
, &stbuf
) < 0)
syserr("main: cannot stat %s", QueueDir
);
if (stbuf
.st_uid
!= RealUid
)
/* nope, really a botch */
usrerr("Permission denied");
/* this is critical to avoid forgeries of the frozen config */
/* freeze the configuration */
/* remove things that don't make sense in daemon mode */
"%s owned process doing -bs",
/* 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
, &jbuf
[sizeof jbuf
- 1], CurEnv
);
/* 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
;
st
= stab("*file*", ST_MAILER
, ST_FIND
);
syserr("No *file* mailer defined");
FileMailer
= st
->s_mailer
;
st
= stab("*include*", ST_MAILER
, ST_FIND
);
syserr("No *include* mailer defined");
InclMailer
= st
->s_mailer
;
/* operate in queue directory */
syserr("cannot chdir(%s)", QueueDir
);
/* if we've had errors so far, exit now */
if (ExitStat
!= EX_OK
&& OpMode
!= MD_TEST
)
** 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
++)
register struct mailer
*m
= Mailer
[i
];
printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=", i
, m
->m_name
,
m
->m_mailer
, m
->m_se_rwset
, m
->m_sh_rwset
,
m
->m_re_rwset
, m
->m_rh_rwset
, m
->m_maxsize
);
for (j
= '\0'; j
<= '\177'; j
++)
if (bitnset(j
, m
->m_flags
))
** 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 bool invalidaddr();
if (fgets(buf
, sizeof buf
, stdin
) == NULL
)
for (p
= buf
; isascii(*p
) && isspace(*p
); p
++)
while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
pvp
= prescan(++p
, ',', pvpbuf
, &delimptr
);
stat
= rewrite(pvp
, atoi(p
), CurEnv
);
printf("== Ruleset %s status %d\n",
while (*p
!= '\0' && *p
++ != ',')
} while (*(p
= delimptr
) != '\0');
** 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 */
disconnect(TRUE
, CurEnv
);
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.
** Do basic system initialization and set the sender
/* make sendmail immune from process group signals */
# ifdef _POSIX_JOB_CONTROL
(void) setpgid(0, getpid());
(void) setpgrp(0, getpid());
setsender(from
, CurEnv
, NULL
, FALSE
);
if (macvalue('s', CurEnv
) == NULL
)
define('s', RealHostName
, CurEnv
);
if (*av
== NULL
&& !GrabTo
)
usrerr("Recipient names must be specified");
/* collect body for UUCP return */
collect(FALSE
, FALSE
, CurEnv
);
CurEnv
->e_sendmode
= SM_VERIFY
;
CurEnv
->e_errormode
= EM_QUIET
;
** 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
)
collect(FALSE
, FALSE
, CurEnv
);
markstats(CurEnv
, (ADDRESS
*) NULL
);
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.
printf("\n====finis: stat %d e_flags %o\n", ExitStat
, CurEnv
->e_flags
);
/* 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
)
/* 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
,
/* 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
), CurEnv
);
for (c
= '0'; c
<= '9'; c
++)
define(c
, newstr(buf
), CurEnv
);
** FREEZE -- freeze BSS & allocated memory
** This will be used to efficiently load the configuration file.
** freezefile -- the name of the file to freeze to.
** Writes BSS and malloc'ed memory to freezefile
char frzpad
[BUFSIZ
]; /* insure we are on a BUFSIZ boundary */
time_t frzstamp
; /* timestamp on this freeze */
char *frzbrk
; /* the current break */
char *frzedata
; /* address of edata */
char *frzend
; /* address of end */
char frzver
[252]; /* sendmail version */
#if defined(__hpux) || defined(__alpha)
/* try to open the freeze file */
f
= creat(freezefile
, FileMode
);
syserr("Cannot freeze %s", freezefile
);
/* build the freeze header */
fhdr
.frzinfo
.frzstamp
= curtime();
fhdr
.frzinfo
.frzbrk
= sbrk(0);
fhdr
.frzinfo
.frzedata
= &edata
;
fhdr
.frzinfo
.frzend
= &end
;
(void) strcpy(fhdr
.frzinfo
.frzver
, Version
);
/* write out the freeze header */
if (write(f
, (char *) &fhdr
, sizeof fhdr
) != sizeof fhdr
||
write(f
, (char *) &edata
, (int) (fhdr
.frzinfo
.frzbrk
- &edata
)) !=
(int) (fhdr
.frzinfo
.frzbrk
- &edata
))
syserr("Cannot freeze %s", freezefile
);
** THAW -- read in the frozen configuration file.
** freezefile -- the name of the file to thaw from.
** binfile -- the name of the sendmail binary (ok to guess).
** TRUE if it successfully read the freeze file.
** reads freezefile in to BSS area.
thaw(freezefile
, binfile
)
extern char **myhostname();
/* open the freeze file */
if (fstat(f
, &fst
) < 0 || stat(ConfFile
, &sst
) < 0 ||
fst
.st_mtime
< sst
.st_mtime
)
syslog(LOG_WARNING
, "Freeze file older than config file");
if (strchr(binfile
, '/') != NULL
&& stat(binfile
, &sst
) == 0 &&
fst
.st_mtime
< sst
.st_mtime
)
syslog(LOG_WARNING
, "Freeze file older than binary file");
if (read(f
, (char *) &fhdr
, sizeof fhdr
) < sizeof fhdr
)
syslog(LOG_WARNING
, "Cannot read frozen config file");
if (fhdr
.frzinfo
.frzedata
!= &edata
||
fhdr
.frzinfo
.frzend
!= &end
||
strcmp(fhdr
.frzinfo
.frzver
, Version
) != 0)
fprintf(stderr
, "Wrong version of frozen config file\n");
syslog(LOG_WARNING
, "Wrong version of frozen config file");
/* arrange to have enough space */
if (brk(fhdr
.frzinfo
.frzbrk
) == (BRK_TYPE
) -1)
syserr("Cannot break to %x", fhdr
.frzinfo
.frzbrk
);
/* now read in the freeze file */
if (read(f
, (char *) &edata
, (int) (fhdr
.frzinfo
.frzbrk
- &edata
)) !=
(int) (fhdr
.frzinfo
.frzbrk
- &edata
))
syserr("Cannot read frozen config file");
/* oops! we have trashed memory..... */
(void) write(2, "Cannot read freeze file\n", 24);
/* verify that the host name was correct on the freeze */
(void) myhostname(hbuf
, sizeof hbuf
);
p
= macvalue('w', CurEnv
);
if (strcmp(hbuf
, macvalue('w', CurEnv
)) == 0)
syslog(LOG_WARNING
, "Hostname changed since freeze (%s => %s)",
# endif /* FROZENCONFIG */
** DISCONNECT -- remove our connection with any foreground process
** fulldrop -- if set, we should also drop the controlling
** TTY if possible -- this should only be done when
** setting up the daemon since otherwise UUCP can
** leave us trying to open a dialin, and we will
** 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) signal(SIGHUP
, SIG_IGN
);
(void) signal(SIGINT
, SIG_IGN
);
(void) signal(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 */
fd
= open("/dev/tty", 2);
(void) ioctl(fd
, (int) TIOCNOTTY
, (char *) 0);
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] == '-')
/* If -C doesn't have an argument, use sendmail.cf. */
#define __DEFPATH "sendmail.cf"
if (ap
[1] == 'C' && ap
[2] == '\0' &&
(argv
[1] == NULL
|| argv
[1][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' &&
(argv
[1] == NULL
|| argv
[1][0] == '-'))
/* if -d doesn't have an argument, use 0-99.1 */
if (ap
[1] == 'd' && ap
[2] == '\0' &&
(argv
[1] == NULL
|| !isdigit(argv
[1][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 char **myhostname();
(void) myhostname(hostbuf
, sizeof hostbuf
);
(void) sprintf(buf
, "%s: ", hostbuf
);
addheader("X-Authentication-Warning", buf
, e
);