/* * Copyright (c) 1995-1999 Hannah Schroeter * * 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, * either in a separate file included with the distribution, or * copied into the source files. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND HIS 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 AUTHOR OR HIS 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. */ #include #include #include #include #include #include #include #include #include #include #include /* From .../sendmail/src/sysexits.h */ #define EX_OK 0 #define EX_USAGE 64 #define EX_OSERR 71 #define EX_CANTCREAT 73 #define EX_IOERR 74 #define EX_TEMPFAIL 75 #ifdef USE_FLOCK #undef USE_FLOCK #define USE_FLOCK 1 #undef USE_LOCKFILES #else #undef USE_LOCKFILES #define USE_LOCKFILES 1 #endif extern int errno; #if USE_LOCKFILES int lock (char *filename) { int fd; fd = open (filename, O_CREAT | O_EXCL, 0000); if (fd >= 0) { close (fd); return 0; } if (errno != EEXIST) { perror("open (lockfile)"); exit(EX_OSERR); } return -1; } void lockwait (char *filename) { while (lock (filename)) sleep (2); } void unlock (char *filename) { unlink (filename); } #endif /* #if USE_LOCKFILES */ void usage (char *av0) { fprintf (stderr, "usage: %s -f from host user ...\n", av0); exit (EX_USAGE); } int main (int argc, char **argv) { argv[0] = "bsmtp"; argv[argc]=0; if (initgroups ("@DAEMONUSER@", @DAEMONGID@) < 0) { fprintf (stderr, "initgroups\n"); exit (EX_OSERR); } if (setgid (@DAEMONGID@) < 0) { perror ("setgid"); exit (EX_OSERR); } if (setuid (@DAEMONUID@) < 0) { perror ("setuid"); exit (EX_OSERR); } if (argc < 5) usage (argv[0]); if (strcmp (argv[1], "-f")) usage (argv[0]); { char *from, *host; #if USE_LOCKFILES char lockfilename [MAXHOSTNAMELEN+1+5]; #endif FILE *file; #if USE_FLOCK int fd; /* for applying the advisory lock */ #endif size_t from_len; from = argv[2]; /* remove redundant pairs of <> */ from_len = strlen(from); while (from[0] == '<' && from[from_len - 1] == '>') { from[from_len - 1] = '\0'; from++; from_len -= 2; } host = argv[3]; argc -= 4; argv += 4; umask (0007); chdir ("@QUEUEDIR@"); #if USE_LOCKFILES sprintf (lockfilename, "%s.lock", host); lockwait (lockfilename); #endif file = fopen (host, "a+"); /* + for locking */ if (!file) { fprintf (stderr, "can't open file %s\n", host); exit (EX_CANTCREAT); } #if USE_FLOCK fd = fileno (file); lockredo: if (flock(fd, LOCK_EX) < 0) { switch (errno) { case EBADF: fprintf (stderr, "Panic: flock returns EBADF\n"); exit (EX_OSERR); /* NOTREACHED */ case EINVAL: fprintf (stderr, "Panic: flock returns EINVAL\n"); fprintf (stderr, "Was @QUEUEDIR@/%s not a plain file?\n", host); exit (EX_OSERR); /* NOTREACHED */ case EINTR: goto lockredo; default: perror("Panic: flock"); exit(EX_OSERR); } } #endif fseek (file, 0, SEEK_END); fprintf (file, "MAIL FROM:<%s>\n", from); while (argc) { fprintf (file, "RCPT TO:<%s>\n", argv[0]); argv++; argc--; } fprintf (file, "DATA\n"); { char buffer[1024]; size_t len; len = fread (buffer, 1, 1024, stdin); while (len > 0) { if (fwrite (buffer, 1, len, file) != len) { fprintf (stderr, "Can't write file %s\n", host); exit (EX_IOERR); /* no unlock, so file can be repaired XXX */ } len = fread (buffer, 1, 1024, stdin); } /* XXX check for errors, if len == 0 */ } fprintf (file, ".\n"); fclose (file); #if USE_LOCKFILES unlock (lockfilename); #endif } return (EX_OK); }