diff options
author | peter <peter@FreeBSD.org> | 2008-08-28 02:25:51 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2008-08-28 02:25:51 +0000 |
commit | ea50d71feb02a78d4d5fa746a26ca7ddc6e8cb19 (patch) | |
tree | daf40952cf309641cc6c7d987989fd2abce2d758 /contrib/sendmail/mail.local | |
parent | a2b986fa722f9860a6c56bb5cc724b7e2937d1b7 (diff) | |
download | FreeBSD-src-ea50d71feb02a78d4d5fa746a26ca7ddc6e8cb19.zip FreeBSD-src-ea50d71feb02a78d4d5fa746a26ca7ddc6e8cb19.tar.gz |
Stage 1 of sendmail dist tree flattening. contrib/sendmail/contrib
prevents doing this in one pass.
Diffstat (limited to 'contrib/sendmail/mail.local')
-rw-r--r-- | contrib/sendmail/mail.local/Makefile | 19 | ||||
-rw-r--r-- | contrib/sendmail/mail.local/Makefile.m4 | 36 | ||||
-rw-r--r-- | contrib/sendmail/mail.local/README | 64 | ||||
-rw-r--r-- | contrib/sendmail/mail.local/mail.local.8 | 152 | ||||
-rw-r--r-- | contrib/sendmail/mail.local/mail.local.c | 1924 |
5 files changed, 0 insertions, 2195 deletions
diff --git a/contrib/sendmail/mail.local/Makefile b/contrib/sendmail/mail.local/Makefile deleted file mode 100644 index b560a30..0000000 --- a/contrib/sendmail/mail.local/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# $Id: Makefile,v 8.5 1999/10/05 16:39:32 ca Exp $ - -SHELL= /bin/sh -BUILD= ./Build -OPTIONS= $(CONFIG) $(FLAGS) - -all: FRC - $(SHELL) $(BUILD) $(OPTIONS) $@ -clean: FRC - $(SHELL) $(BUILD) $(OPTIONS) $@ -install: FRC - $(SHELL) $(BUILD) $(OPTIONS) $@ -force-install: FRC - $(SHELL) $(BUILD) $(OPTIONS) $@ - -fresh: FRC - $(SHELL) $(BUILD) $(OPTIONS) -c - -FRC: diff --git a/contrib/sendmail/mail.local/Makefile.m4 b/contrib/sendmail/mail.local/Makefile.m4 deleted file mode 100644 index 4f1e763..0000000 --- a/contrib/sendmail/mail.local/Makefile.m4 +++ /dev/null @@ -1,36 +0,0 @@ -dnl $Id: Makefile.m4,v 8.52 2006/06/28 21:08:02 ca Exp $ -include(confBUILDTOOLSDIR`/M4/switch.m4') - -define(`confREQUIRE_LIBSM', `true') -define(`confREQUIRE_SM_OS_H', `true') -# sendmail dir -SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail') -PREPENDDEF(`confENVDEF', `confMAPDEF') -PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ') - -bldPRODUCT_START(`executable', `mail.local') -define(`bldINSTALL_DIR', `E') -define(`bldNO_INSTALL', `true') -define(`bldSOURCES', `mail.local.c ') -bldPUSH_SMLIB(`sm') -APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL') -bldPRODUCT_END - -bldPRODUCT_START(`manpage', `mail.local') -define(`bldSOURCES', `mail.local.8') -bldPRODUCT_END - -divert(bldTARGETS_SECTION) -install: - @echo "NOTE: This version of mail.local is not suited for some operating" - @echo " systems such as HP-UX and Solaris. Please consult the" - @echo " README file in the mail.local directory. You can force" - @echo " the install using 'Build force-install'." - -force-install: install-mail.local ifdef(`confNO_MAN_BUILD',, `install-docs') - -install-mail.local: mail.local - ${INSTALL} -c -o ${UBINOWN} -g ${UBINGRP} -m ${UBINMODE} mail.local ${DESTDIR}${EBINDIR} -divert - -bldFINISH diff --git a/contrib/sendmail/mail.local/README b/contrib/sendmail/mail.local/README deleted file mode 100644 index 2ab9dbc..0000000 --- a/contrib/sendmail/mail.local/README +++ /dev/null @@ -1,64 +0,0 @@ -This directory contains the source files for mail.local. - -This is not intended to be used on *stock* System V derived systems such as -Solaris or HP-UX, since they use a totally different approach to mailboxes -(essentially, they have a set-group-ID program rather than set-user-ID, and -they rely on the ability to "give away" files to do their work). - -If you choose to run *this* mail.local on these systems then you may also -need to replace the existing MUAs, as well as IMAP and POP servers, with -ones that are compatible with the BSD interface. You have been warned! - -For systems with maillock() support, compile with -DMAILLOCK and link with --lmail to use the maillock() routines. This can be accomplished in your -site.config.m4 file with: - - APPENDDEF(`conf_mail_local_ENVDEF', `-DMAILLOCK') - APPENDDEF(`conf_mail_local_LIBS', `-lmail') - -Defining CONTENTLENGTH (-DCONTENTLENGTH) will build a mail.local which -outputs a Content-Length: header. Solaris 2.3 and later will automatically -include Content-Length: support. This can be accomplished in your -site.config.m4 file with: - - APPENDDEF(`conf_mail_local_ENVDEF', `-DCONTENTLENGTH') - -Defining MAILGID to a 'gid' (-DMAILGID=6) will cause mailboxes to be -written group writable and with group 'gid'. This can be accomplished in -your site.config.m4 file with: - - APPENDDEF(`conf_mail_local_ENVDEF', `-DMAILGID=6') - -mail.local will not be installed set-user-ID root. To use it as local -delivery agent without LMTP mode, use: - - MODIFY_MAILER_FLAGS(`LOCAL', `+S') - -in the .mc file. - -Defining HASHSPOOL (-DHASHSPOOL) will build a mail.local which supports -delivering to subdirectories of the mail spool, based on a hash of the -username (i.e., a hash depth of 2 and a username of "user" will result in -/var/spool/mail/u/s/user). If the hash depth is greater than the length -of the username, "_" will be used. The necessary subdirectories must -exist; mail.local will not create them. Use the "-H" option to set the -hash type and depth (like "-H u2" for a username hash two levels deep). - -The HASHSPOOL option also adds two other options: "-p path" to specify -an alternate mail spool path (i.e., "-p /local/mail") and "-n" to specify -that mail.local should not strip the @domain part of recipient addresses -in LMTP mode. - -In addition to HASHSPOOL, defining HASHSPOOLMD5 and linking against -libcrypto from OpenSSL like: - - APPENDDEF(`conf_mail_local_ENVDEF', `-DHASHSPOOL -DHASHSPOOLMD5') - APPENDDEF(`conf_mail_local_LIBS', `-lcrypto') - -will offer an alternate hash, using a base64 encoding (changing / to _) -of an MD5 hash of the username. This results in a more balanced -subdirectory tree. The subdirectories will be named with A-Z, a-z, 0-9, -+, and _. The hash type is "m", so use "-H m3" to get a three level MD5 -based hash. - -$Revision: 8.11 $, Last updated $Date: 2003/10/20 20:19:13 $ diff --git a/contrib/sendmail/mail.local/mail.local.8 b/contrib/sendmail/mail.local/mail.local.8 deleted file mode 100644 index 0181f16..0000000 --- a/contrib/sendmail/mail.local/mail.local.8 +++ /dev/null @@ -1,152 +0,0 @@ -.\" Copyright (c) 1998-2001, 2003 Sendmail, Inc. and its suppliers. -.\" All rights reserved. -.\" Copyright (c) 1990, 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. -.\" -.\" -.\" $Id: mail.local.8,v 8.25 2003/10/20 20:26:51 ca Exp $ -.\" -.TH MAIL.LOCAL 8 "$Date: 2003/10/20 20:26:51 $" -.SH NAME -mail.local -\- store mail in a mailbox -.SH SYNOPSIS -.B mail.local -.RB [ \-7 "] [" \-b "] [" \-d "] [" \-D -.IR mbdb ] -.RB [ \-l "] [" \-f -\fIfrom\fR|\fB\-r\fR -.IR from ] -.RB [ \-h -\fIfilename\fR ] -.I "user ..." -.SH DESCRIPTION -.B Mail.local -reads the standard input up to an end-of-file and appends it to each -.I user's -.B mail -file. The -.I user -must be a valid user name. -.PP -The options are as follows: -.TP 1i -.B \-7 -Do not advertise 8BITMIME support in LMTP mode. -.TP -.B \-b -Return a permanent error instead of a temporary error -if a mailbox exceeds quota. -.TP -.B \-d -Specify this is a delivery (for backward compatibility). -This option has no effect. -.TP -.BI \-D " mbdb" -Specify the name of the mailbox database -which is used to look up local recipient names. -This option defaults to "pw", which means use getpwnam(). -.TP -.BI \-f " from" -Specify the sender's name. -.TP -.B \-l -Turn on LMTP mode. -.TP -.BI \-r " from" -Specify the sender's name (for backward compatibility). -Same as \-f. -.TP -.BI \-h " filename" -Store incoming mail in \fIfilename\fR in the user's home directory instead -of a system mail spool directory. -.PP -The next options are only available if -.B mail.local -has been compiled with -DHASHSPOOL. -.TP -.BI \-H " hashtypehashdepth" -Select hashed mail directories. -Valid hash types are -.B u -for user name and -.B m -for MD5 (requires compilation with -DHASHSPOOLMD5). -Example: -.BI \-H " u2" -selects user name hashing with a hash depth of 2. -Note: there must be no space between the hash type and the depth. -.TP -.BI \-p " path" -Specify an alternate mail spool path. -.TP -.BI \-n -Specify that the domain part of recipient addresses in LMTP mode -should not be stripped. -.PP -Individual mail messages in the mailbox are delimited by an empty -line followed by a line beginning with the string ``From ''. -A line containing the string ``From '', the sender's name and a time stamp -is prepended to each delivered mail message. -A blank line is appended to each message. -A greater-than character (``>'') is prepended to any line in the message -which could be mistaken for a ``From '' delimiter line -(that is, -a line beginning with the five characters -``From '' following a blank line). -.PP -The mail files are exclusively locked with -flock(2) -while mail is appended, -and a -.B user.lock -file also is created while the mailbox is locked -for compatibility with older MUAs. -.PP -If the ``biff'' service is returned by -getservbyname(3), -the biff server is notified of delivered mail. -.PP -The -.B mail.local -utility exits 0 on success, and >0 if an error occurs. -.SH ENVIRONMENT -.IP TZ -Used to set the appropriate time zone on the timestamp. -.SH FILES -.PD 0.2v -.TP 2.2i -/tmp/local.XXXXXX -temporary files -.TP -/var/mail/user -user's default mailbox directory -.TP -/var/mail/user.lock -lock file for a user's default mailbox -.PD -.SH SEE ALSO -mail(1), -xsend(1), -flock(2), -getservbyname(3), -comsat(8), -sendmail(8) -.SH WARNING -.B mail.local -escapes only "^From " lines that follow an empty line. -If all lines starting with "From " should be escaped, -use the 'E' flag for the local mailer in the -sendmail.cf file. -.SH HISTORY -A superset of -.B mail.local -(handling mailbox reading as well as mail delivery) -appeared in -Version 7 AT&T UNIX -as the program -.BR mail . diff --git a/contrib/sendmail/mail.local/mail.local.c b/contrib/sendmail/mail.local/mail.local.c deleted file mode 100644 index 492e115..0000000 --- a/contrib/sendmail/mail.local/mail.local.c +++ /dev/null @@ -1,1924 +0,0 @@ -/* - * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. - * 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. - * - */ - -#include <sm/gen.h> - -SM_IDSTR(copyright, -"@(#) Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.\n\ - All rights reserved.\n\ - Copyright (c) 1990, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n") - -SM_IDSTR(id, "@(#)$Id: mail.local.c,v 8.254 2006/10/12 22:23:45 ca Exp $") - -#include <stdlib.h> -#include <sm/errstring.h> -#include <sm/io.h> -#include <sm/limits.h> -# include <unistd.h> -# ifdef EX_OK -# undef EX_OK /* unistd.h may have another use for this */ -# endif /* EX_OK */ -# define LOCKFILE_PMODE 0 -#include <sm/mbdb.h> -#include <sm/sysexits.h> - -#ifndef HASHSPOOL -# define HASHSPOOL 0 -#endif /* ! HASHSPOOL */ -#ifndef HASHSPOOLMD5 -# define HASHSPOOLMD5 0 -#endif /* ! HASHSPOOLMD5 */ - -/* -** This is not intended to work on System V derived systems -** such as Solaris or HP-UX, since they use a totally different -** approach to mailboxes (essentially, they have a set-group-ID program -** rather than set-user-ID, and they rely on the ability to "give away" -** files to do their work). IT IS NOT A BUG that this doesn't -** work on such architectures. -*/ - - -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <time.h> -#include <stdlib.h> -# include <sys/socket.h> -# include <sys/file.h> -# include <netinet/in.h> -# include <arpa/nameser.h> -# include <netdb.h> -# include <pwd.h> - -#include <sm/string.h> -#include <syslog.h> -#include <ctype.h> - -#include <sm/conf.h> -#include <sendmail/pathnames.h> - -#if HASHSPOOL -# define HASH_NONE 0 -# define HASH_USER 1 -# if HASHSPOOLMD5 -# define HASH_MD5 2 -# include <openssl/md5.h> -# endif /* HASHSPOOLMD5 */ -#endif /* HASHSPOOL */ - - -#ifndef LOCKTO_RM -# define LOCKTO_RM 300 /* timeout for stale lockfile removal */ -#endif /* ! LOCKTO_RM */ -#ifndef LOCKTO_GLOB -# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */ -#endif /* ! LOCKTO_GLOB */ - -/* define a realloc() which works for NULL pointers */ -#define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size)) - -/* -** 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 <sys/file.h> -#endif /* ! LOCK_EX */ - -/* -** If you don't have setreuid, and you have saved uids, and you have -** a seteuid() call that doesn't try to emulate using setuid(), then -** you can try defining LDA_USE_SETEUID. -*/ - -#ifdef LDA_USE_SETEUID -# define setreuid(r, e) seteuid(e) -#endif /* LDA_USE_SETEUID */ - -#ifdef LDA_CONTENTLENGTH -# define CONTENTLENGTH 1 -#endif /* LDA_CONTENTLENGTH */ - -#ifndef INADDRSZ -# define INADDRSZ 4 /* size of an IPv4 address in bytes */ -#endif /* ! INADDRSZ */ - -#ifdef MAILLOCK -# include <maillock.h> -#endif /* MAILLOCK */ - -#ifndef MAILER_DAEMON -# define MAILER_DAEMON "MAILER-DAEMON" -#endif /* ! MAILER_DAEMON */ - -#ifdef CONTENTLENGTH -char ContentHdr[40] = "Content-Length: "; -off_t HeaderLength; -off_t BodyLength; -#endif /* CONTENTLENGTH */ - -bool EightBitMime = true; /* advertise 8BITMIME in LMTP */ -char ErrBuf[10240]; /* error buffer */ -int ExitVal = EX_OK; /* sysexits.h error value. */ -bool HoldErrs = false; /* Hold errors in ErrBuf */ -bool LMTPMode = false; -bool BounceQuota = false; /* permanent error when over quota */ -bool CloseMBDB = false; -char *HomeMailFile = NULL; /* store mail in homedir */ - -#if HASHSPOOL -int HashType = HASH_NONE; -int HashDepth = 0; -bool StripRcptDomain = true; -#else /* HASHSPOOL */ -# define StripRcptDomain true -#endif /* HASHSPOOL */ -char SpoolPath[MAXPATHLEN]; - -char *parseaddr __P((char *, bool)); -char *process_recipient __P((char *)); -void dolmtp __P((void)); -void deliver __P((int, char *)); -int e_to_sys __P((int)); -void notifybiff __P((char *)); -int store __P((char *, bool *)); -void usage __P((void)); -int lockmbox __P((char *)); -void unlockmbox __P((void)); -void mailerr __P((const char *, const char *, ...)); -void flush_error __P((void)); -#if HASHSPOOL -const char *hashname __P((char *)); -#endif /* HASHSPOOL */ - - -static void sm_exit __P((int)); - -static void -sm_exit(status) - int status; -{ - if (CloseMBDB) - { - sm_mbdb_terminate(); - CloseMBDB = false; /* not really necessary, but ... */ - } - exit(status); -} - -int -main(argc, argv) - int argc; - char *argv[]; -{ - struct passwd *pw; - int ch, fd; - uid_t uid; - char *from; - char *mbdbname = "pw"; - int err; - extern char *optarg; - extern int optind; - - - /* make sure we have some open file descriptors */ - for (fd = 10; fd < 30; fd++) - (void) close(fd); - - /* use a reasonable umask */ - (void) umask(0077); - -# ifdef LOG_MAIL - openlog("mail.local", 0, LOG_MAIL); -# else /* LOG_MAIL */ - openlog("mail.local", 0); -# endif /* LOG_MAIL */ - - from = NULL; - - /* XXX can this be converted to a compile time check? */ - if (sm_strlcpy(SpoolPath, _PATH_MAILDIR, sizeof(SpoolPath)) >= - sizeof(SpoolPath)) - { - mailerr("421", "Configuration error: _PATH_MAILDIR too large"); - sm_exit(EX_CONFIG); - } -#if HASHSPOOL - while ((ch = getopt(argc, argv, "7bdD:f:h:r:lH:p:n")) != -1) -#else /* HASHSPOOL */ - while ((ch = getopt(argc, argv, "7bdD:f:h:r:l")) != -1) -#endif /* HASHSPOOL */ - { - 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 'D': /* mailbox database type */ - mbdbname = optarg; - break; - - case 'f': - case 'r': /* Backward compatible. */ - if (from != NULL) - { - mailerr(NULL, "Multiple -f options"); - usage(); - } - from = optarg; - break; - - case 'h': - if (optarg != NULL || *optarg != '\0') - HomeMailFile = optarg; - else - { - mailerr(NULL, "-h: missing filename"); - usage(); - } - break; - - case 'l': - LMTPMode = true; - break; - - -#if HASHSPOOL - case 'H': - if (optarg == NULL || *optarg == '\0') - { - mailerr(NULL, "-H: missing hashinfo"); - usage(); - } - switch(optarg[0]) - { - case 'u': - HashType = HASH_USER; - break; - -# if HASHSPOOLMD5 - case 'm': - HashType = HASH_MD5; - break; -# endif /* HASHSPOOLMD5 */ - - default: - mailerr(NULL, "-H: unknown hash type"); - usage(); - } - if (optarg[1] == '\0') - { - mailerr(NULL, "-H: invalid hash depth"); - usage(); - } - HashDepth = atoi(&optarg[1]); - if ((HashDepth <= 0) || ((HashDepth * 2) >= MAXPATHLEN)) - { - mailerr(NULL, "-H: invalid hash depth"); - usage(); - } - break; - - case 'p': - if (optarg == NULL || *optarg == '\0') - { - mailerr(NULL, "-p: missing spool path"); - usage(); - } - if (sm_strlcpy(SpoolPath, optarg, sizeof(SpoolPath)) >= - sizeof(SpoolPath)) - { - mailerr(NULL, "-p: invalid spool path"); - usage(); - } - break; - - case 'n': - StripRcptDomain = false; - break; -#endif /* HASHSPOOL */ - - case '?': - default: - usage(); - } - } - argc -= optind; - argv += optind; - - /* initialize biff structures */ - notifybiff(NULL); - - err = sm_mbdb_initialize(mbdbname); - if (err != EX_OK) - { - char *errcode = "521"; - - if (err == EX_TEMPFAIL) - errcode = "421"; - - mailerr(errcode, "Can not open mailbox database %s: %s", - mbdbname, sm_strexit(err)); - sm_exit(err); - } - CloseMBDB = true; - - if (LMTPMode) - { - if (argc > 0) - { - mailerr("421", "Users should not be specified in command line if LMTP required"); - sm_exit(EX_TEMPFAIL); - } - - dolmtp(); - /* NOTREACHED */ - sm_exit(EX_OK); - } - - /* Non-LMTP from here on out */ - if (*argv == '\0') - 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 == NULL && ((from = getlogin()) == NULL || - (pw = getpwnam(from)) == NULL || - pw->pw_uid != uid)) - from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???"; - - /* - ** 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. - */ - - HoldErrs = true; - fd = store(from, NULL); - HoldErrs = false; - if (fd < 0) - { - flush_error(); - sm_exit(ExitVal); - } - for (; *argv != NULL; ++argv) - deliver(fd, *argv); - sm_exit(ExitVal); - /* NOTREACHED */ - return ExitVal; -} - -char * -parseaddr(s, rcpt) - char *s; - bool rcpt; -{ - char *p; - int l; - - if (*s++ != '<') - return NULL; - - p = s; - - /* at-domain-list */ - while (*p == '@') - { - p++; - while (*p != ',' && *p != ':' && *p != '\0') - p++; - if (*p == '\0') - return NULL; - - /* Skip over , or : */ - p++; - } - - s = p; - - /* local-part */ - while (*p != '\0' && *p != '@' && *p != '>') - { - if (*p == '\\') - { - if (*++p == '\0') - return NULL; - } - else if (*p == '\"') - { - p++; - while (*p != '\0' && *p != '\"') - { - if (*p == '\\') - { - if (*++p == '\0') - return NULL; - } - p++; - } - if (*p == '\0' || *(p + 1) == '\0') - return NULL; - } - /* +detail ? */ - if (*p == '+' && rcpt) - *p = '\0'; - p++; - } - - /* @domain */ - if (*p == '@') - { - if (rcpt) - *p++ = '\0'; - while (*p != '\0' && *p != '>') - p++; - } - - if (*p != '>') - return NULL; - else - *p = '\0'; - p++; - - if (*p != '\0' && *p != ' ') - return NULL; - - if (*s == '\0') - s = MAILER_DAEMON; - - l = strlen(s) + 1; - if (l < 0) - return NULL; - p = malloc(l); - if (p == NULL) - { - mailerr("421 4.3.0", "Memory exhausted"); - sm_exit(EX_TEMPFAIL); - } - - (void) sm_strlcpy(p, s, l); - return p; -} - -char * -process_recipient(addr) - char *addr; -{ - SM_MBDB_T user; - - switch (sm_mbdb_lookup(addr, &user)) - { - case EX_OK: - return NULL; - - case EX_NOUSER: - return "550 5.1.1 User unknown"; - - case EX_TEMPFAIL: - return "451 4.3.0 User database failure; retry later"; - - default: - return "550 5.3.0 User database failure"; - } -} - -#define RCPT_GROW 30 - -void -dolmtp() -{ - char *return_path = NULL; - char **rcpt_addr = NULL; - int rcpt_num = 0; - int rcpt_alloc = 0; - bool gotlhlo = false; - char *err; - int msgfd; - char *p; - int i; - char myhostname[1024]; - char buf[4096]; - - memset(myhostname, '\0', sizeof myhostname); - (void) gethostname(myhostname, sizeof myhostname - 1); - if (myhostname[0] == '\0') - sm_strlcpy(myhostname, "localhost", sizeof myhostname); - - printf("220 %s LMTP ready\r\n", myhostname); - for (;;) - { - (void) fflush(stdout); - if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) - sm_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 (sm_strcasecmp(buf, "data") == 0) - { - bool inbody = false; - - if (rcpt_num == 0) - { - mailerr("503 5.5.1", "No recipients"); - continue; - } - HoldErrs = true; - msgfd = store(return_path, &inbody); - HoldErrs = false; - if (msgfd < 0 && !inbody) - { - flush_error(); - continue; - } - - for (i = 0; i < rcpt_num; i++) - { - if (msgfd < 0) - { - /* print error for rcpt */ - flush_error(); - continue; - } - p = strchr(rcpt_addr[i], '+'); - if (p != NULL) - *p = '\0'; - deliver(msgfd, rcpt_addr[i]); - } - if (msgfd >= 0) - (void) close(msgfd); - goto rset; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'l': - case 'L': - if (sm_strncasecmp(buf, "lhlo ", 5) == 0) - { - /* check for duplicate per RFC 1651 4.2 */ - if (gotlhlo) - { - mailerr("503", "%s Duplicate LHLO", - 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 (sm_strncasecmp(buf, "mail ", 5) == 0) - { - if (return_path != NULL) - { - mailerr("503 5.5.1", - "Nested MAIL command"); - continue; - } - if (sm_strncasecmp(buf + 5, "from:", 5) != 0 || - ((return_path = parseaddr(buf + 10, - false)) == NULL)) - { - mailerr("501 5.5.4", - "Syntax error in parameters"); - continue; - } - printf("250 2.5.0 Ok\r\n"); - continue; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'n': - case 'N': - if (sm_strcasecmp(buf, "noop") == 0) - { - printf("250 2.0.0 Ok\r\n"); - continue; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'q': - case 'Q': - if (sm_strcasecmp(buf, "quit") == 0) - { - printf("221 2.0.0 Bye\r\n"); - sm_exit(EX_OK); - } - goto syntaxerr; - /* NOTREACHED */ - break; - - case 'r': - case 'R': - if (sm_strncasecmp(buf, "rcpt ", 5) == 0) - { - if (return_path == NULL) - { - mailerr("503 5.5.1", - "Need MAIL command"); - 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) - { - mailerr("421 4.3.0", - "Memory exhausted"); - sm_exit(EX_TEMPFAIL); - } - } - if (sm_strncasecmp(buf + 5, "to:", 3) != 0 || - ((rcpt_addr[rcpt_num] = parseaddr(buf + 8, - StripRcptDomain)) == NULL)) - { - mailerr("501 5.5.4", - "Syntax error in parameters"); - continue; - } - err = process_recipient(rcpt_addr[rcpt_num]); - if (err != NULL) - { - mailerr(NULL, "%s", err); - continue; - } - rcpt_num++; - printf("250 2.1.5 Ok\r\n"); - continue; - } - else if (sm_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; - /* NOTREACHED */ - break; - - case 'v': - case 'V': - if (sm_strncasecmp(buf, "vrfy ", 5) == 0) - { - printf("252 2.3.3 Try RCPT to attempt delivery\r\n"); - continue; - } - goto syntaxerr; - /* NOTREACHED */ - break; - - default: - syntaxerr: - mailerr("500 5.5.2", "Syntax error"); - continue; - /* NOTREACHED */ - break; - } - } -} - -int -store(from, inbody) - char *from; - bool *inbody; -{ - FILE *fp = NULL; - time_t tval; - bool eline; /* previous line was empty */ - bool fullline = true; /* current line is terminated */ - bool prevfl; /* previous line was terminated */ - char line[2048]; - int fd; - char tmpbuf[sizeof _PATH_LOCTMP + 1]; - - if (inbody != NULL) - *inbody = false; - - (void) umask(0077); - (void) sm_strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf); - if ((fd = mkstemp(tmpbuf)) < 0 || (fp = fdopen(fd, "w+")) == NULL) - { - if (fd >= 0) - (void) close(fd); - mailerr("451 4.3.0", "Unable to open temporary file"); - return -1; - } - (void) unlink(tmpbuf); - - if (LMTPMode) - { - printf("354 Go ahead\r\n"); - (void) fflush(stdout); - } - if (inbody != NULL) - *inbody = true; - - (void) time(&tval); - (void) fprintf(fp, "From %s %s", from, ctime(&tval)); - -#ifdef CONTENTLENGTH - HeaderLength = 0; - BodyLength = -1; -#endif /* CONTENTLENGTH */ - - line[0] = '\0'; - eline = true; - 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 && LMTPMode && 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; - -#ifdef CONTENTLENGTH - if (prevfl && line[0] == '\n' && HeaderLength == 0) - { - eline = false; - if (fp != NULL) - HeaderLength = ftell(fp); - if (HeaderLength <= 0) - { - /* - ** shouldn't happen, unless ftell() is - ** badly broken - */ - - HeaderLength = -1; - } - } -#else /* CONTENTLENGTH */ - if (prevfl && line[0] == '\n') - eline = true; -#endif /* CONTENTLENGTH */ - else - { - if (eline && line[0] == 'F' && - fp != NULL && - !memcmp(line, "From ", 5)) - (void) putc('>', fp); - eline = false; -#ifdef CONTENTLENGTH - /* discard existing "Content-Length:" headers */ - if (prevfl && HeaderLength == 0 && - (line[0] == 'C' || line[0] == 'c') && - sm_strncasecmp(line, ContentHdr, 15) == 0) - { - /* - ** be paranoid: clear the line - ** so no "wrong matches" may occur later - */ - line[0] = '\0'; - continue; - } -#endif /* CONTENTLENGTH */ - - } - if (fp != NULL) - { - (void) fwrite(line, sizeof(char), line_len, fp); - if (ferror(fp)) - { - mailerr("451 4.3.0", - "Temporary file write error"); - (void) fclose(fp); - fp = NULL; - continue; - } - } - } - - /* check if an error occurred */ - if (fp == NULL) - return -1; - - if (LMTPMode) - { - /* Got a premature EOF -- toss message and exit */ - sm_exit(EX_OK); - } - - /* If message not newline terminated, need an extra. */ - if (fp != NULL && strchr(line, '\n') == NULL) - (void) putc('\n', fp); - - lmtpdot: - -#ifdef CONTENTLENGTH - if (fp != NULL) - BodyLength = ftell(fp); - if (HeaderLength == 0 && BodyLength > 0) /* empty body */ - { - HeaderLength = BodyLength; - BodyLength = 0; - } - else - BodyLength = BodyLength - HeaderLength - 1 ; - - if (HeaderLength > 0 && BodyLength >= 0) - { - (void) sm_snprintf(line, sizeof line, "%lld\n", - (LONGLONG_T) BodyLength); - (void) sm_strlcpy(&ContentHdr[16], line, - sizeof(ContentHdr) - 16); - } - else - BodyLength = -1; /* Something is wrong here */ -#endif /* CONTENTLENGTH */ - - /* Output a newline; note, empty messages are allowed. */ - if (fp != NULL) - (void) putc('\n', fp); - - if (fp == NULL || fflush(fp) == EOF || ferror(fp) != 0) - { - mailerr("451 4.3.0", "Temporary file write error"); - if (fp != NULL) - (void) fclose(fp); - return -1; - } - return fd; -} - -void -deliver(fd, name) - int fd; - char *name; -{ - struct stat fsb; - struct stat sb; - char path[MAXPATHLEN]; - int mbfd = -1, nr = 0, nw, off; - int exitval; - char *p; - char *errcode; - off_t curoff, cursize; -#ifdef CONTENTLENGTH - off_t headerbytes; - int readamount; -#endif /* CONTENTLENGTH */ - char biffmsg[100], buf[8 * 1024]; - SM_MBDB_T user; - - /* - ** Disallow delivery to unknown names -- special mailboxes can be - ** handled in the sendmail aliases file. - */ - - exitval = sm_mbdb_lookup(name, &user); - switch (exitval) - { - case EX_OK: - break; - - case EX_NOUSER: - exitval = EX_UNAVAILABLE; - mailerr("550 5.1.1", "%s: User unknown", name); - break; - - case EX_TEMPFAIL: - mailerr("451 4.3.0", "%s: User database failure; retry later", - name); - break; - - default: - exitval = EX_UNAVAILABLE; - mailerr("550 5.3.0", "%s: User database failure", name); - break; - } - - if (exitval != EX_OK) - { - if (ExitVal != EX_TEMPFAIL) - ExitVal = exitval; - return; - } - - endpwent(); - - /* - ** Keep name reasonably short to avoid buffer overruns. - ** This isn't necessary on BSD because of the proper - ** definition of snprintf(), but it can cause problems - ** on other systems. - ** Also, clear out any bogus characters. - */ - -#if !HASHSPOOL - if (strlen(name) > 40) - name[40] = '\0'; - for (p = name; *p != '\0'; p++) - { - if (!isascii(*p)) - *p &= 0x7f; - else if (!isprint(*p)) - *p = '.'; - } -#endif /* !HASHSPOOL */ - - - if (HomeMailFile == NULL) - { - if (sm_strlcpyn(path, sizeof(path), -#if HASHSPOOL - 4, -#else /* HASHSPOOL */ - 3, -#endif /* HASHSPOOL */ - SpoolPath, "/", -#if HASHSPOOL - hashname(name), -#endif /* HASHSPOOL */ - name) >= sizeof(path)) - { - exitval = EX_UNAVAILABLE; - mailerr("550 5.1.1", "%s: Invalid mailbox path", name); - return; - } - } - else if (*user.mbdb_homedir == '\0') - { - exitval = EX_UNAVAILABLE; - mailerr("550 5.1.1", "%s: User missing home directory", name); - return; - } - else if (sm_snprintf(path, sizeof(path), "%s/%s", - user.mbdb_homedir, HomeMailFile) >= sizeof(path)) - { - exitval = EX_UNAVAILABLE; - mailerr("550 5.1.1", "%s: Invalid mailbox path", name); - return; - } - - - /* - ** 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: -#ifdef MAILLOCK - p = name; -#else /* MAILLOCK */ - p = path; -#endif /* MAILLOCK */ - if ((off = lockmbox(p)) != 0) - { - if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL) - { - ExitVal = EX_TEMPFAIL; - errcode = "451 4.3.0"; - } - else - errcode = "551 5.3.0"; - - mailerr(errcode, "lockmailbox %s failed; error code %d %s", - p, off, errno > 0 ? sm_errstring(errno) : ""); - return; - } - - if (lstat(path, &sb) < 0) - { - int save_errno; - int mode = S_IRUSR|S_IWUSR; - gid_t gid = user.mbdb_gid; - -#ifdef MAILGID - (void) umask(0007); - gid = MAILGID; - mode |= S_IRGRP|S_IWGRP; -#endif /* MAILGID */ - - mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY, - mode); - save_errno = errno; - - if (lstat(path, &sb) < 0) - { - ExitVal = EX_CANTCREAT; - mailerr("550 5.2.0", - "%s: lstat: file changed after open", path); - goto err1; - } - if (mbfd < 0) - { - if (save_errno == EEXIST) - goto tryagain; - - /* open failed, don't try again */ - mailerr("450 4.2.0", "%s: %s", path, - sm_errstring(save_errno)); - goto err0; - } - else if (fchown(mbfd, user.mbdb_uid, gid) < 0) - { - mailerr("451 4.3.0", "chown %u.%u: %s", - user.mbdb_uid, gid, name); - goto err1; - } - else - { - /* - ** open() was successful, now close it so can - ** be opened as the right owner again. - ** Paranoia: reset mbdf since the file descriptor - ** is no longer valid; better safe than sorry. - */ - - sb.st_uid = user.mbdb_uid; - (void) close(mbfd); - mbfd = -1; - } - } - 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 if (sb.st_uid != user.mbdb_uid) - { - ExitVal = EX_CANTCREAT; - mailerr("550 5.2.0", "%s: wrong ownership (%d)", - path, (int) sb.st_uid); - goto err0; - } - - /* change UID for quota checks */ - if (setreuid(0, user.mbdb_uid) < 0) - { - mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)", - (int) user.mbdb_uid, sm_errstring(errno), - (int) getuid(), (int) geteuid()); - goto err1; - } -#ifdef DEBUG - fprintf(stderr, "new euid = %d\n", (int) geteuid()); -#endif /* DEBUG */ - mbfd = open(path, O_APPEND|O_WRONLY, 0); - if (mbfd < 0) - { - mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); - goto err0; - } - else if (fstat(mbfd, &fsb) < 0 || - fsb.st_nlink != 1 || - sb.st_nlink != 1 || - !S_ISREG(fsb.st_mode) || - sb.st_dev != fsb.st_dev || - sb.st_ino != fsb.st_ino || -# if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ - sb.st_gen != fsb.st_gen || -# endif /* HAS_ST_GEN && 0 */ - sb.st_uid != fsb.st_uid) - { - ExitVal = EX_TEMPFAIL; - mailerr("550 5.2.0", "%s: fstat: file changed after open", - path); - goto err1; - } - -#if 0 - /* - ** This code could be reused if we decide to add a - ** per-user quota field to the sm_mbdb interface. - */ - - /* - ** Fail if the user has a quota specified, and delivery of this - ** message would exceed that quota. We bounce such failures using - ** EX_UNAVAILABLE, unless there were internal problems, since - ** storing immense messages for later retries can cause queueing - ** issues. - */ - - if (ui.quota > 0) - { - struct stat dsb; - - if (fstat(fd, &dsb) < 0) - { - ExitVal = EX_TEMPFAIL; - mailerr("451 4.3.0", - "%s: fstat: can't stat temporary storage: %s", - ui.mailspool, sm_errstring(errno)); - goto err1; - } - - if (dsb.st_size + sb.st_size + 1 > ui.quota) - { - ExitVal = EX_UNAVAILABLE; - mailerr("551 5.2.2", - "%s: Mailbox full or quota exceeded", - ui.mailspool); - goto err1; - } - } -#endif /* 0 */ - - /* Wait until we can get a lock on the file. */ - if (flock(mbfd, LOCK_EX) < 0) - { - mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); - goto err1; - } - - /* Get the starting offset of the new message */ - curoff = lseek(mbfd, (off_t) 0, SEEK_END); - (void) sm_snprintf(biffmsg, sizeof(biffmsg), "%s@%lld\n", - name, (LONGLONG_T) curoff); - - /* Copy the message into the file. */ - if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1) - { - mailerr("450 4.2.0", "Temporary file: %s", - sm_errstring(errno)); - goto err1; - } -#ifdef DEBUG - fprintf(stderr, "before writing: euid = %d\n", (int) geteuid()); -#endif /* DEBUG */ -#ifdef CONTENTLENGTH - headerbytes = (BodyLength >= 0) ? HeaderLength : -1 ; - for (;;) - { - if (headerbytes == 0) - { - (void) sm_snprintf(buf, sizeof buf, "%s", ContentHdr); - nr = strlen(buf); - headerbytes = -1; - readamount = 0; - } - else if (headerbytes > sizeof(buf) || headerbytes < 0) - readamount = sizeof(buf); - else - readamount = headerbytes; - if (readamount != 0) - nr = read(fd, buf, readamount); - if (nr <= 0) - break; - if (headerbytes > 0) - headerbytes -= nr ; - -#else /* CONTENTLENGTH */ - while ((nr = read(fd, buf, sizeof(buf))) > 0) - { -#endif /* CONTENTLENGTH */ - for (off = 0; off < nr; off += nw) - { - if ((nw = write(mbfd, buf + off, nr - off)) < 0) - { - errcode = "450 4.2.0"; -#ifdef EDQUOT - if (errno == EDQUOT && BounceQuota) - errcode = "552 5.2.2"; -#endif /* EDQUOT */ - mailerr(errcode, "%s: %s", - path, sm_errstring(errno)); - goto err3; - } - } - } - if (nr < 0) - { - mailerr("450 4.2.0", "Temporary file: %s", - sm_errstring(errno)); - goto err3; - } - - /* Flush to disk, don't wait for update. */ - if (fsync(mbfd) < 0) - { - mailerr("450 4.2.0", "%s: %s", path, sm_errstring(errno)); -err3: -#ifdef DEBUG - fprintf(stderr, "reset euid = %d\n", (int) geteuid()); -#endif /* DEBUG */ - if (mbfd >= 0) - (void) ftruncate(mbfd, curoff); -err1: if (mbfd >= 0) - (void) close(mbfd); -err0: (void) setreuid(0, 0); - unlockmbox(); - 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)) - { - errcode = "450 4.2.0"; -#ifdef EDQUOT - if (errno == EDQUOT && BounceQuota) - errcode = "552 5.2.2"; -#endif /* EDQUOT */ - mailerr(errcode, "%s: %s", path, sm_errstring(errno)); - 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 || -# if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */ - sb.st_gen != fsb.st_gen || -# endif /* HAS_ST_GEN && 0 */ - 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 err3; - } - else - notifybiff(biffmsg); - - if (setreuid(0, 0) < 0) - { - mailerr("450 4.2.0", "setreuid(0, 0): %s", - sm_errstring(errno)); - goto err0; - } -#ifdef DEBUG - fprintf(stderr, "reset euid = %d\n", (int) geteuid()); -#endif /* DEBUG */ - unlockmbox(); - if (LMTPMode) - printf("250 2.1.5 %s Ok\r\n", name); -} - -/* -** user.lock files are necessary for compatibility with other -** systems, e.g., when the mail spool file is NFS exported. -** Alas, mailbox locking is more than just a local matter. -** EPA 11/94. -*/ - -bool Locked = false; - -#ifdef MAILLOCK -int -lockmbox(name) - char *name; -{ - int r = 0; - - if (Locked) - return 0; - if ((r = maillock(name, 15)) == L_SUCCESS) - { - Locked = true; - return 0; - } - switch (r) - { - case L_TMPLOCK: /* Can't create tmp file */ - case L_TMPWRITE: /* Can't write pid into lockfile */ - case L_MAXTRYS: /* Failed after retrycnt attempts */ - errno = 0; - r = EX_TEMPFAIL; - break; - case L_ERROR: /* Check errno for reason */ - r = errno; - break; - default: /* other permanent errors */ - errno = 0; - r = EX_UNAVAILABLE; - break; - } - return r; -} - -void -unlockmbox() -{ - if (Locked) - mailunlock(); - Locked = false; -} -#else /* MAILLOCK */ - -char LockName[MAXPATHLEN]; - -int -lockmbox(path) - char *path; -{ - int statfailed = 0; - time_t start; - - if (Locked) - return 0; - if (strlen(path) + 6 > sizeof LockName) - return EX_SOFTWARE; - (void) sm_snprintf(LockName, sizeof LockName, "%s.lock", path); - (void) time(&start); - for (; ; sleep(5)) - { - int fd; - struct stat st; - time_t now; - - /* global timeout */ - (void) time(&now); - if (now > start + LOCKTO_GLOB) - { - errno = 0; - return EX_TEMPFAIL; - } - fd = open(LockName, O_WRONLY|O_EXCL|O_CREAT, LOCKFILE_PMODE); - if (fd >= 0) - { - /* defeat lock checking programs which test pid */ - (void) write(fd, "0", 2); - Locked = true; - (void) close(fd); - return 0; - } - if (stat(LockName, &st) < 0) - { - if (statfailed++ > 5) - { - errno = 0; - return EX_TEMPFAIL; - } - continue; - } - statfailed = 0; - (void) time(&now); - if (now < st.st_ctime + LOCKTO_RM) - continue; - - /* try to remove stale lockfile */ - if (unlink(LockName) < 0) - return errno; - } -} - -void -unlockmbox() -{ - if (!Locked) - return; - (void) unlink(LockName); - Locked = false; -} -#endif /* MAILLOCK */ - -void -notifybiff(msg) - char *msg; -{ - static bool initialized = false; - static int f = -1; - struct hostent *hp; - struct servent *sp; - int len; - static struct sockaddr_in addr; - - if (!initialized) - { - initialized = true; - - /* Be silent if biff service not available. */ - if ((sp = getservbyname("biff", "udp")) == NULL || - (hp = gethostbyname("localhost")) == NULL || - hp->h_length != INADDRSZ) - return; - - addr.sin_family = hp->h_addrtype; - memcpy(&addr.sin_addr, hp->h_addr, INADDRSZ); - addr.sin_port = sp->s_port; - } - - /* No message, just return */ - if (msg == NULL) - return; - - /* Couldn't initialize addr struct */ - if (addr.sin_family == AF_UNSPEC) - return; - - if (f < 0 && (f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - return; - len = strlen(msg) + 1; - (void) sendto(f, msg, len, 0, (struct sockaddr *) &addr, sizeof(addr)); -} - -void -usage() -{ - ExitVal = EX_USAGE; - mailerr(NULL, "usage: mail.local [-7] [-b] [-d] [-l] [-f from|-r from] [-h filename] user ..."); - sm_exit(ExitVal); -} - -void -/*VARARGS2*/ -#ifdef __STDC__ -mailerr(const char *hdr, const char *fmt, ...) -#else /* __STDC__ */ -mailerr(hdr, fmt, va_alist) - const char *hdr; - const char *fmt; - va_dcl -#endif /* __STDC__ */ -{ - size_t len = 0; - SM_VA_LOCAL_DECL - - (void) e_to_sys(errno); - - SM_VA_START(ap, fmt); - - if (LMTPMode && hdr != NULL) - { - sm_snprintf(ErrBuf, sizeof ErrBuf, "%s ", hdr); - len = strlen(ErrBuf); - } - (void) sm_vsnprintf(&ErrBuf[len], sizeof ErrBuf - len, fmt, ap); - SM_VA_END(ap); - - if (!HoldErrs) - flush_error(); - - /* Log the message to syslog. */ - if (!LMTPMode) - syslog(LOG_ERR, "%s", ErrBuf); -} - -void -flush_error() -{ - if (LMTPMode) - printf("%s\r\n", ErrBuf); - else - { - if (ExitVal != EX_USAGE) - (void) fprintf(stderr, "mail.local: "); - fprintf(stderr, "%s\n", ErrBuf); - } -} - -#if HASHSPOOL -const char * -hashname(name) - char *name; -{ - static char p[MAXPATHLEN]; - int i; - int len; - char *str; -# if HASHSPOOLMD5 - char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_"; - MD5_CTX ctx; - unsigned char md5[18]; -# if MAXPATHLEN <= 24 - ERROR _MAXPATHLEN <= 24 -# endif /* MAXPATHLEN <= 24 */ - char b64[24]; - MD5_LONG bits; - int j; -# endif /* HASHSPOOLMD5 */ - - if (HashType == HASH_NONE || HashDepth * 2 >= MAXPATHLEN) - { - p[0] = '\0'; - return p; - } - - switch(HashType) - { - case HASH_USER: - str = name; - break; - -# if HASHSPOOLMD5 - case HASH_MD5: - MD5_Init(&ctx); - MD5_Update(&ctx, name, strlen(name)); - MD5_Final(md5, &ctx); - md5[16] = 0; - md5[17] = 0; - - for (i = 0; i < 6; i++) - { - bits = (unsigned) md5[(3 * i)] << 16; - bits |= (unsigned) md5[(3 * i) + 1] << 8; - bits |= (unsigned) md5[(3 * i) + 2]; - - for (j = 3; j >= 0; j--) - { - b64[(4 * i) + j] = Base64[(bits & 0x3f)]; - bits >>= 6; - } - } - b64[22] = '\0'; - str = b64; - break; -# endif /* HASHSPOOLMD5 */ - } - - len = strlen(str); - for (i = 0; i < HashDepth; i++) - { - if (i < len) - p[i * 2] = str[i]; - else - p[i * 2] = '_'; - p[(i * 2) + 1] = '/'; - } - p[HashDepth * 2] = '\0'; - return p; -} -#endif /* HASHSPOOL */ - -/* - * e_to_sys -- - * Guess which errno's are temporary. Gag me. - */ - -int -e_to_sys(num) - int num; -{ - /* Temporary failures override hard errors. */ - if (ExitVal == EX_TEMPFAIL) - return ExitVal; - - switch (num) /* Hopefully temporary errors. */ - { -#ifdef EDQUOT - case EDQUOT: /* Disc quota exceeded */ - if (BounceQuota) - { - ExitVal = EX_UNAVAILABLE; - break; - } - /* FALLTHROUGH */ -#endif /* EDQUOT */ -#ifdef EAGAIN - case EAGAIN: /* Resource temporarily unavailable */ -#endif /* EAGAIN */ -#ifdef EBUSY - case EBUSY: /* Device busy */ -#endif /* EBUSY */ -#ifdef EPROCLIM - case EPROCLIM: /* Too many processes */ -#endif /* EPROCLIM */ -#ifdef EUSERS - case EUSERS: /* Too many users */ -#endif /* EUSERS */ -#ifdef ECONNABORTED - case ECONNABORTED: /* Software caused connection abort */ -#endif /* ECONNABORTED */ -#ifdef ECONNREFUSED - case ECONNREFUSED: /* Connection refused */ -#endif /* ECONNREFUSED */ -#ifdef ECONNRESET - case ECONNRESET: /* Connection reset by peer */ -#endif /* ECONNRESET */ -#ifdef EDEADLK - case EDEADLK: /* Resource deadlock avoided */ -#endif /* EDEADLK */ -#ifdef EFBIG - case EFBIG: /* File too large */ -#endif /* EFBIG */ -#ifdef EHOSTDOWN - case EHOSTDOWN: /* Host is down */ -#endif /* EHOSTDOWN */ -#ifdef EHOSTUNREACH - case EHOSTUNREACH: /* No route to host */ -#endif /* EHOSTUNREACH */ -#ifdef EMFILE - case EMFILE: /* Too many open files */ -#endif /* EMFILE */ -#ifdef ENETDOWN - case ENETDOWN: /* Network is down */ -#endif /* ENETDOWN */ -#ifdef ENETRESET - case ENETRESET: /* Network dropped connection on reset */ -#endif /* ENETRESET */ -#ifdef ENETUNREACH - case ENETUNREACH: /* Network is unreachable */ -#endif /* ENETUNREACH */ -#ifdef ENFILE - case ENFILE: /* Too many open files in system */ -#endif /* ENFILE */ -#ifdef ENOBUFS - case ENOBUFS: /* No buffer space available */ -#endif /* ENOBUFS */ -#ifdef ENOMEM - case ENOMEM: /* Cannot allocate memory */ -#endif /* ENOMEM */ -#ifdef ENOSPC - case ENOSPC: /* No space left on device */ -#endif /* ENOSPC */ -#ifdef EROFS - case EROFS: /* Read-only file system */ -#endif /* EROFS */ -#ifdef ESTALE - case ESTALE: /* Stale NFS file handle */ -#endif /* ESTALE */ -#ifdef ETIMEDOUT - case ETIMEDOUT: /* Connection timed out */ -#endif /* ETIMEDOUT */ -#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK - case EWOULDBLOCK: /* Operation would block. */ -#endif /* defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN && EWOULDBLOCK != EDEADLK */ - ExitVal = EX_TEMPFAIL; - break; - - default: - ExitVal = EX_UNAVAILABLE; - break; - } - return ExitVal; -} - -#if defined(ultrix) || defined(_CRAY) -/* - * Copyright (c) 1987, 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 - * are met: - * 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 - * SUCH DAMAGE. - */ - -# if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; -# endif /* defined(LIBC_SCCS) && !defined(lint) */ - -# include <sys/types.h> -# include <sys/stat.h> -# include <fcntl.h> -# include <errno.h> -# include <stdio.h> -# include <ctype.h> - -static int _gettemp(); - -mkstemp(path) - char *path; -{ - int fd; - - return (_gettemp(path, &fd) ? fd : -1); -} - -static -_gettemp(path, doopen) - char *path; - register int *doopen; -{ - extern int errno; - register char *start, *trv; - struct stat sbuf; - unsigned int pid; - - pid = getpid(); - for (trv = path; *trv; ++trv); /* extra X's get set to 0's */ - while (*--trv == 'X') - { - *trv = (pid % 10) + '0'; - pid /= 10; - } - - /* - * check the target directory; if you have six X's and it - * doesn't exist this runs for a *very* long time. - */ - for (start = trv + 1;; --trv) - { - if (trv <= path) - break; - if (*trv == '/') - { - *trv = '\0'; - if (stat(path, &sbuf) < 0) - return(0); - if (!S_ISDIR(sbuf.st_mode)) - { - errno = ENOTDIR; - return(0); - } - *trv = '/'; - break; - } - } - - for (;;) - { - if (doopen) - { - if ((*doopen = open(path, O_CREAT|O_EXCL|O_RDWR, - 0600)) >= 0) - return(1); - if (errno != EEXIST) - return(0); - } - else if (stat(path, &sbuf) < 0) - return(errno == ENOENT ? 1 : 0); - - /* tricky little algorithm for backward compatibility */ - for (trv = start;;) - { - if (!*trv) - return(0); - if (*trv == 'z') - *trv++ = 'a'; - else - { - if (isascii(*trv) && isdigit(*trv)) - *trv = 'a'; - else - ++*trv; - break; - } - } - } - /* NOTREACHED */ -} -#endif /* defined(ultrix) || defined(_CRAY) */ |