1c2aa98e2SPeter Wemm /* 23299c2f1SGregory Neil Shapiro * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 5c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 6c2aa98e2SPeter Wemm * 7c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 8c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 9c2aa98e2SPeter Wemm * the sendmail distribution. 10c2aa98e2SPeter Wemm * 11c2aa98e2SPeter Wemm */ 12c2aa98e2SPeter Wemm 13c2aa98e2SPeter Wemm #ifndef lint 14c2aa98e2SPeter Wemm static char copyright[] = 153299c2f1SGregory Neil Shapiro "@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\ 163299c2f1SGregory Neil Shapiro All rights reserved.\n\ 173299c2f1SGregory Neil Shapiro Copyright (c) 1988, 1993\n\ 18c2aa98e2SPeter Wemm The Regents of the University of California. All rights reserved.\n"; 193299c2f1SGregory Neil Shapiro #endif /* ! lint */ 20c2aa98e2SPeter Wemm 21c2aa98e2SPeter Wemm #ifndef lint 223299c2f1SGregory Neil Shapiro static char id[] = "@(#)$Id: rmail.c,v 8.39.4.5 2000/07/18 05:55:29 gshapiro Exp $"; 233299c2f1SGregory Neil Shapiro #endif /* ! lint */ 243299c2f1SGregory Neil Shapiro 253299c2f1SGregory Neil Shapiro /* $FreeBSD$ */ 26c2aa98e2SPeter Wemm 27c2aa98e2SPeter Wemm /* 28c2aa98e2SPeter Wemm * RMAIL -- UUCP mail server. 29c2aa98e2SPeter Wemm * 30c2aa98e2SPeter Wemm * This program reads the >From ... remote from ... lines that UUCP is so 31c2aa98e2SPeter Wemm * fond of and turns them into something reasonable. It then execs sendmail 32c2aa98e2SPeter Wemm * with various options built from these lines. 33c2aa98e2SPeter Wemm * 34c2aa98e2SPeter Wemm * The expected syntax is: 35c2aa98e2SPeter Wemm * 36c2aa98e2SPeter Wemm * <user> := [-a-z0-9]+ 37c2aa98e2SPeter Wemm * <date> := ctime format 38c2aa98e2SPeter Wemm * <site> := [-a-z0-9!]+ 39c2aa98e2SPeter Wemm * <blank line> := "^\n$" 40c2aa98e2SPeter Wemm * <from> := "From" <space> <user> <space> <date> 41c2aa98e2SPeter Wemm * [<space> "remote from" <space> <site>] 42c2aa98e2SPeter Wemm * <forward> := ">" <from> 43c2aa98e2SPeter Wemm * msg := <from> <forward>* <blank-line> <body> 44c2aa98e2SPeter Wemm * 45c2aa98e2SPeter Wemm * The output of rmail(8) compresses the <forward> lines into a single 46c2aa98e2SPeter Wemm * from path. 47c2aa98e2SPeter Wemm * 48c2aa98e2SPeter Wemm * The err(3) routine is included here deliberately to make this code 49c2aa98e2SPeter Wemm * a bit more portable. 50c2aa98e2SPeter Wemm */ 513299c2f1SGregory Neil Shapiro 523299c2f1SGregory Neil Shapiro #include <sys/types.h> 53c2aa98e2SPeter Wemm #include <sys/param.h> 54c2aa98e2SPeter Wemm #include <sys/stat.h> 55c2aa98e2SPeter Wemm #include <sys/wait.h> 56c2aa98e2SPeter Wemm 57c2aa98e2SPeter Wemm #include <ctype.h> 58c2aa98e2SPeter Wemm #include <fcntl.h> 59c2aa98e2SPeter Wemm #ifdef BSD4_4 60c2aa98e2SPeter Wemm # define FORK vfork 61c2aa98e2SPeter Wemm # include <paths.h> 623299c2f1SGregory Neil Shapiro #else /* BSD4_4 */ 63c2aa98e2SPeter Wemm # define FORK fork 64c2aa98e2SPeter Wemm # ifndef _PATH_SENDMAIL 65c2aa98e2SPeter Wemm # define _PATH_SENDMAIL "/usr/lib/sendmail" 663299c2f1SGregory Neil Shapiro # endif /* ! _PATH_SENDMAIL */ 673299c2f1SGregory Neil Shapiro #endif /* BSD4_4 */ 68c2aa98e2SPeter Wemm #include <stdio.h> 69c2aa98e2SPeter Wemm #include <stdlib.h> 70c2aa98e2SPeter Wemm #include <string.h> 71c2aa98e2SPeter Wemm #include <unistd.h> 72c2aa98e2SPeter Wemm #ifdef EX_OK 73c2aa98e2SPeter Wemm # undef EX_OK /* unistd.h may have another use for this */ 743299c2f1SGregory Neil Shapiro #endif /* EX_OK */ 75c2aa98e2SPeter Wemm #include <sysexits.h> 76c2aa98e2SPeter Wemm 77c2aa98e2SPeter Wemm #ifndef MAX 78c2aa98e2SPeter Wemm # define MAX(a, b) ((a) < (b) ? (b) : (a)) 793299c2f1SGregory Neil Shapiro #endif /* ! MAX */ 80c2aa98e2SPeter Wemm 81c2aa98e2SPeter Wemm #ifndef __P 82c2aa98e2SPeter Wemm # ifdef __STDC__ 83c2aa98e2SPeter Wemm # define __P(protos) protos 843299c2f1SGregory Neil Shapiro # else /* __STDC__ */ 85c2aa98e2SPeter Wemm # define __P(protos) () 86c2aa98e2SPeter Wemm # define const 873299c2f1SGregory Neil Shapiro # endif /* __STDC__ */ 883299c2f1SGregory Neil Shapiro #endif /* ! __P */ 89c2aa98e2SPeter Wemm 903299c2f1SGregory Neil Shapiro #ifndef STDIN_FILENO 913299c2f1SGregory Neil Shapiro # define STDIN_FILENO 0 923299c2f1SGregory Neil Shapiro #endif /* ! STDIN_FILENO */ 933299c2f1SGregory Neil Shapiro 943299c2f1SGregory Neil Shapiro #if defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 95c2aa98e2SPeter Wemm # define HASSNPRINTF 1 963299c2f1SGregory Neil Shapiro #endif /* defined(BSD4_4) || defined(linux) || SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) || _AIX4 >= 40300 */ 97c2aa98e2SPeter Wemm 98c2aa98e2SPeter Wemm #if defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) 99c2aa98e2SPeter Wemm # define memmove(d, s, l) (bcopy((s), (d), (l))) 1003299c2f1SGregory Neil Shapiro #endif /* defined(sun) && !defined(BSD) && !defined(SOLARIS) && !defined(__svr4__) && !defined(__SVR4) */ 101c2aa98e2SPeter Wemm 102c2aa98e2SPeter Wemm #if !HASSNPRINTF 103c2aa98e2SPeter Wemm extern int snprintf __P((char *, size_t, const char *, ...)); 104c2aa98e2SPeter Wemm #endif /* !HASSNPRINTF */ 105c2aa98e2SPeter Wemm 1063299c2f1SGregory Neil Shapiro #if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) 1073299c2f1SGregory Neil Shapiro # ifndef HASSTRERROR 1083299c2f1SGregory Neil Shapiro # define HASSTRERROR 1 1093299c2f1SGregory Neil Shapiro # endif /* ! HASSTRERROR */ 1103299c2f1SGregory Neil Shapiro #endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || 1113299c2f1SGregory Neil Shapiro defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */ 112c2aa98e2SPeter Wemm 1133299c2f1SGregory Neil Shapiro #if defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__) 1143299c2f1SGregory Neil Shapiro # undef WIFEXITED 1153299c2f1SGregory Neil Shapiro # undef WEXITSTATUS 1163299c2f1SGregory Neil Shapiro # define WIFEXITED(st) (((st) & 0377) == 0) 1173299c2f1SGregory Neil Shapiro # define WEXITSTATUS(st) (((st) >> 8) & 0377) 1183299c2f1SGregory Neil Shapiro #endif /* defined(SUNOS403) || defined(NeXT) || (defined(MACH) && defined(i386) && !defined(__GNU__)) || defined(oldBSD43) || defined(MORE_BSD) || defined(umipsbsd) || defined(ALTOS_SYSTEM_V) || defined(RISCOS) || defined(_AUX_SOURCE) || defined(UMAXV) || defined(titan) || defined(UNIXWARE) || defined(sony_news) || defined(luna) || defined(nec_ews_svr4) || defined(_nec_ews_svr4) || defined(__MAXION__) */ 1193299c2f1SGregory Neil Shapiro 1203299c2f1SGregory Neil Shapiro 1213299c2f1SGregory Neil Shapiro #include "sendmail/errstring.h" 1223299c2f1SGregory Neil Shapiro 1233299c2f1SGregory Neil Shapiro static void err __P((int, const char *, ...)); 1243299c2f1SGregory Neil Shapiro static void usage __P((void)); 1253299c2f1SGregory Neil Shapiro static char *xalloc __P((int)); 126c2aa98e2SPeter Wemm 127c2aa98e2SPeter Wemm #define newstr(s) strcpy(xalloc(strlen(s) + 1), s) 128c2aa98e2SPeter Wemm 1293299c2f1SGregory Neil Shapiro static char * 130c2aa98e2SPeter Wemm xalloc(sz) 131c2aa98e2SPeter Wemm register int sz; 132c2aa98e2SPeter Wemm { 133c2aa98e2SPeter Wemm register char *p; 134c2aa98e2SPeter Wemm 135c2aa98e2SPeter Wemm /* some systems can't handle size zero mallocs */ 136c2aa98e2SPeter Wemm if (sz <= 0) 137c2aa98e2SPeter Wemm sz = 1; 138c2aa98e2SPeter Wemm 139c2aa98e2SPeter Wemm p = malloc((unsigned) sz); 140c2aa98e2SPeter Wemm if (p == NULL) 141c2aa98e2SPeter Wemm err(EX_TEMPFAIL, "out of memory"); 142c2aa98e2SPeter Wemm return (p); 143c2aa98e2SPeter Wemm } 144c2aa98e2SPeter Wemm 145c2aa98e2SPeter Wemm int 146c2aa98e2SPeter Wemm main(argc, argv) 147c2aa98e2SPeter Wemm int argc; 148c2aa98e2SPeter Wemm char *argv[]; 149c2aa98e2SPeter Wemm { 1503299c2f1SGregory Neil Shapiro int ch, debug, i, pdes[2], pid, status; 15176b7bf71SPeter Wemm size_t fplen = 0, fptlen = 0, len; 152c2aa98e2SPeter Wemm off_t offset; 1533299c2f1SGregory Neil Shapiro FILE *fp; 15476b7bf71SPeter Wemm char *addrp = NULL, *domain, *p, *t; 155c2aa98e2SPeter Wemm char *from_path, *from_sys, *from_user; 156c2aa98e2SPeter Wemm char *args[100], buf[2048], lbuf[2048]; 1573299c2f1SGregory Neil Shapiro struct stat sb; 1583299c2f1SGregory Neil Shapiro extern char *optarg; 1593299c2f1SGregory Neil Shapiro extern int optind; 160c2aa98e2SPeter Wemm 161c2aa98e2SPeter Wemm debug = 0; 162c2aa98e2SPeter Wemm domain = "UUCP"; /* Default "domain". */ 163b2ee1660SPeter Wemm while ((ch = getopt(argc, argv, "D:T")) != -1) 1643299c2f1SGregory Neil Shapiro { 1653299c2f1SGregory Neil Shapiro switch (ch) 1663299c2f1SGregory Neil Shapiro { 167c2aa98e2SPeter Wemm case 'T': 168c2aa98e2SPeter Wemm debug = 1; 169c2aa98e2SPeter Wemm break; 1703299c2f1SGregory Neil Shapiro 171c2aa98e2SPeter Wemm case 'D': 172c2aa98e2SPeter Wemm domain = optarg; 173c2aa98e2SPeter Wemm break; 1743299c2f1SGregory Neil Shapiro 175c2aa98e2SPeter Wemm case '?': 176c2aa98e2SPeter Wemm default: 177c2aa98e2SPeter Wemm usage(); 178c2aa98e2SPeter Wemm } 1793299c2f1SGregory Neil Shapiro } 1803299c2f1SGregory Neil Shapiro 181c2aa98e2SPeter Wemm argc -= optind; 182c2aa98e2SPeter Wemm argv += optind; 183c2aa98e2SPeter Wemm 184c2aa98e2SPeter Wemm if (argc < 1) 185c2aa98e2SPeter Wemm usage(); 186c2aa98e2SPeter Wemm 187c2aa98e2SPeter Wemm from_path = from_sys = from_user = NULL; 1883299c2f1SGregory Neil Shapiro for (offset = 0; ; ) 1893299c2f1SGregory Neil Shapiro { 190c2aa98e2SPeter Wemm /* Get and nul-terminate the line. */ 191c2aa98e2SPeter Wemm if (fgets(lbuf, sizeof(lbuf), stdin) == NULL) 192c2aa98e2SPeter Wemm exit(EX_DATAERR); 193c2aa98e2SPeter Wemm if ((p = strchr(lbuf, '\n')) == NULL) 194c2aa98e2SPeter Wemm err(EX_DATAERR, "line too long"); 195c2aa98e2SPeter Wemm *p = '\0'; 196c2aa98e2SPeter Wemm 197c2aa98e2SPeter Wemm /* Parse lines until reach a non-"From" line. */ 198c2aa98e2SPeter Wemm if (!strncmp(lbuf, "From ", 5)) 199c2aa98e2SPeter Wemm addrp = lbuf + 5; 200c2aa98e2SPeter Wemm else if (!strncmp(lbuf, ">From ", 6)) 201c2aa98e2SPeter Wemm addrp = lbuf + 6; 202c2aa98e2SPeter Wemm else if (offset == 0) 203c2aa98e2SPeter Wemm err(EX_DATAERR, 204c2aa98e2SPeter Wemm "missing or empty From line: %s", lbuf); 2053299c2f1SGregory Neil Shapiro else 2063299c2f1SGregory Neil Shapiro { 207c2aa98e2SPeter Wemm *p = '\n'; 208c2aa98e2SPeter Wemm break; 209c2aa98e2SPeter Wemm } 210c2aa98e2SPeter Wemm 2113299c2f1SGregory Neil Shapiro if (addrp == NULL || *addrp == '\0') 212c2aa98e2SPeter Wemm err(EX_DATAERR, "corrupted From line: %s", lbuf); 213c2aa98e2SPeter Wemm 214c2aa98e2SPeter Wemm /* Use the "remote from" if it exists. */ 215c2aa98e2SPeter Wemm for (p = addrp; (p = strchr(p + 1, 'r')) != NULL; ) 2163299c2f1SGregory Neil Shapiro { 2173299c2f1SGregory Neil Shapiro if (!strncmp(p, "remote from ", 12)) 2183299c2f1SGregory Neil Shapiro { 2193299c2f1SGregory Neil Shapiro for (t = p += 12; *t != '\0'; ++t) 2203299c2f1SGregory Neil Shapiro { 2213299c2f1SGregory Neil Shapiro if (isascii(*t) && isspace(*t)) 2223299c2f1SGregory Neil Shapiro break; 2233299c2f1SGregory Neil Shapiro } 224c2aa98e2SPeter Wemm *t = '\0'; 225c2aa98e2SPeter Wemm if (debug) 2263299c2f1SGregory Neil Shapiro fprintf(stderr, "remote from: %s\n", p); 227c2aa98e2SPeter Wemm break; 228c2aa98e2SPeter Wemm } 2293299c2f1SGregory Neil Shapiro } 230c2aa98e2SPeter Wemm 231c2aa98e2SPeter Wemm /* Else use the string up to the last bang. */ 2323299c2f1SGregory Neil Shapiro if (p == NULL) 2333299c2f1SGregory Neil Shapiro { 234c2aa98e2SPeter Wemm if (*addrp == '!') 2353299c2f1SGregory Neil Shapiro err(EX_DATAERR, "bang starts address: %s", 2363299c2f1SGregory Neil Shapiro addrp); 2373299c2f1SGregory Neil Shapiro else if ((t = strrchr(addrp, '!')) != NULL) 2383299c2f1SGregory Neil Shapiro { 239c2aa98e2SPeter Wemm *t = '\0'; 240c2aa98e2SPeter Wemm p = addrp; 241c2aa98e2SPeter Wemm addrp = t + 1; 242c2aa98e2SPeter Wemm if (*addrp == '\0') 243c2aa98e2SPeter Wemm err(EX_DATAERR, 244c2aa98e2SPeter Wemm "corrupted From line: %s", lbuf); 245c2aa98e2SPeter Wemm if (debug) 2463299c2f1SGregory Neil Shapiro fprintf(stderr, "bang: %s\n", p); 247c2aa98e2SPeter Wemm } 248c2aa98e2SPeter Wemm } 2493299c2f1SGregory Neil Shapiro 250c2aa98e2SPeter Wemm /* 'p' now points to any system string from this line. */ 2513299c2f1SGregory Neil Shapiro if (p != NULL) 2523299c2f1SGregory Neil Shapiro { 253c2aa98e2SPeter Wemm /* Nul terminate it as necessary. */ 2543299c2f1SGregory Neil Shapiro for (t = p; *t != '\0'; ++t) 2553299c2f1SGregory Neil Shapiro { 2563299c2f1SGregory Neil Shapiro if (isascii(*t) && isspace(*t)) 2573299c2f1SGregory Neil Shapiro break; 2583299c2f1SGregory Neil Shapiro } 259c2aa98e2SPeter Wemm *t = '\0'; 260c2aa98e2SPeter Wemm 261c2aa98e2SPeter Wemm /* If the first system, copy to the from_sys string. */ 2623299c2f1SGregory Neil Shapiro if (from_sys == NULL) 2633299c2f1SGregory Neil Shapiro { 264c2aa98e2SPeter Wemm from_sys = newstr(p); 265c2aa98e2SPeter Wemm if (debug) 2663299c2f1SGregory Neil Shapiro fprintf(stderr, "from_sys: %s\n", 2673299c2f1SGregory Neil Shapiro from_sys); 268c2aa98e2SPeter Wemm } 269c2aa98e2SPeter Wemm 270c2aa98e2SPeter Wemm /* Concatenate to the path string. */ 271c2aa98e2SPeter Wemm len = t - p; 2723299c2f1SGregory Neil Shapiro if (from_path == NULL) 2733299c2f1SGregory Neil Shapiro { 274c2aa98e2SPeter Wemm fplen = 0; 275c2aa98e2SPeter Wemm if ((from_path = malloc(fptlen = 256)) == NULL) 276c2aa98e2SPeter Wemm err(EX_TEMPFAIL, NULL); 277c2aa98e2SPeter Wemm } 2783299c2f1SGregory Neil Shapiro if (fplen + len + 2 > fptlen) 2793299c2f1SGregory Neil Shapiro { 280c2aa98e2SPeter Wemm fptlen += MAX(fplen + len + 2, 256); 2813299c2f1SGregory Neil Shapiro if ((from_path = realloc(from_path, 2823299c2f1SGregory Neil Shapiro fptlen)) == NULL) 283c2aa98e2SPeter Wemm err(EX_TEMPFAIL, NULL); 284c2aa98e2SPeter Wemm } 285c2aa98e2SPeter Wemm memmove(from_path + fplen, p, len); 286c2aa98e2SPeter Wemm fplen += len; 287c2aa98e2SPeter Wemm from_path[fplen++] = '!'; 288c2aa98e2SPeter Wemm from_path[fplen] = '\0'; 289c2aa98e2SPeter Wemm } 290c2aa98e2SPeter Wemm 291c2aa98e2SPeter Wemm /* Save off from user's address; the last one wins. */ 2923299c2f1SGregory Neil Shapiro for (p = addrp; *p != '\0'; ++p) 2933299c2f1SGregory Neil Shapiro { 2943299c2f1SGregory Neil Shapiro if (isascii(*p) && isspace(*p)) 2953299c2f1SGregory Neil Shapiro break; 2963299c2f1SGregory Neil Shapiro } 297c2aa98e2SPeter Wemm *p = '\0'; 298c2aa98e2SPeter Wemm if (*addrp == '\0') 299c2aa98e2SPeter Wemm addrp = "<>"; 300c2aa98e2SPeter Wemm if (from_user != NULL) 301c2aa98e2SPeter Wemm free(from_user); 302c2aa98e2SPeter Wemm from_user = newstr(addrp); 303c2aa98e2SPeter Wemm 3043299c2f1SGregory Neil Shapiro if (debug) 3053299c2f1SGregory Neil Shapiro { 306c2aa98e2SPeter Wemm if (from_path != NULL) 3073299c2f1SGregory Neil Shapiro fprintf(stderr, "from_path: %s\n", from_path); 3083299c2f1SGregory Neil Shapiro fprintf(stderr, "from_user: %s\n", from_user); 309c2aa98e2SPeter Wemm } 310c2aa98e2SPeter Wemm 311c2aa98e2SPeter Wemm if (offset != -1) 312c2aa98e2SPeter Wemm offset = (off_t)ftell(stdin); 313c2aa98e2SPeter Wemm } 314c2aa98e2SPeter Wemm 315c2aa98e2SPeter Wemm i = 0; 316c2aa98e2SPeter Wemm args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */ 317c2aa98e2SPeter Wemm args[i++] = "-oee"; /* No errors, just status. */ 318829be59cSPeter Wemm #ifdef QUEUE_ONLY 319c2aa98e2SPeter Wemm args[i++] = "-odq"; /* Queue it, don't try to deliver. */ 320829be59cSPeter Wemm #else 321829be59cSPeter Wemm args[i++] = "-odi"; /* Deliver in foreground. */ 322829be59cSPeter Wemm #endif 323c2aa98e2SPeter Wemm args[i++] = "-oi"; /* Ignore '.' on a line by itself. */ 324c2aa98e2SPeter Wemm 325c2aa98e2SPeter Wemm /* set from system and protocol used */ 326c2aa98e2SPeter Wemm if (from_sys == NULL) 3273299c2f1SGregory Neil Shapiro snprintf(buf, sizeof(buf), "-p%s", domain); 328c2aa98e2SPeter Wemm else if (strchr(from_sys, '.') == NULL) 3293299c2f1SGregory Neil Shapiro snprintf(buf, sizeof(buf), "-p%s:%s.%s", 330c2aa98e2SPeter Wemm domain, from_sys, domain); 331c2aa98e2SPeter Wemm else 3323299c2f1SGregory Neil Shapiro snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys); 333c2aa98e2SPeter Wemm args[i++] = newstr(buf); 334c2aa98e2SPeter Wemm 335c2aa98e2SPeter Wemm /* Set name of ``from'' person. */ 3363299c2f1SGregory Neil Shapiro snprintf(buf, sizeof(buf), "-f%s%s", 337c2aa98e2SPeter Wemm from_path ? from_path : "", from_user); 338c2aa98e2SPeter Wemm args[i++] = newstr(buf); 339c2aa98e2SPeter Wemm 340c2aa98e2SPeter Wemm /* 3413299c2f1SGregory Neil Shapiro ** Don't copy arguments beginning with - as they will be 3423299c2f1SGregory Neil Shapiro ** passed to sendmail and could be interpreted as flags. 3433299c2f1SGregory Neil Shapiro ** To prevent confusion of sendmail wrap < and > around 3443299c2f1SGregory Neil Shapiro ** the address (helps to pass addrs like @gw1,@gw2:aa@bb) 345c2aa98e2SPeter Wemm */ 3463299c2f1SGregory Neil Shapiro 3473299c2f1SGregory Neil Shapiro while (*argv) 3483299c2f1SGregory Neil Shapiro { 349c2aa98e2SPeter Wemm if (**argv == '-') 350c2aa98e2SPeter Wemm err(EX_USAGE, "dash precedes argument: %s", *argv); 3513299c2f1SGregory Neil Shapiro 352c2aa98e2SPeter Wemm if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL) 353c2aa98e2SPeter Wemm args[i++] = *argv; 3543299c2f1SGregory Neil Shapiro else 3553299c2f1SGregory Neil Shapiro { 3563299c2f1SGregory Neil Shapiro len = strlen(*argv) + 3; 3573299c2f1SGregory Neil Shapiro if ((args[i] = malloc(len)) == NULL) 358c2aa98e2SPeter Wemm err(EX_TEMPFAIL, "Cannot malloc"); 3593299c2f1SGregory Neil Shapiro snprintf(args[i++], len, "<%s>", *argv); 360c2aa98e2SPeter Wemm } 361c2aa98e2SPeter Wemm argv++; 362c2aa98e2SPeter Wemm } 363c2aa98e2SPeter Wemm args[i] = 0; 364c2aa98e2SPeter Wemm 3653299c2f1SGregory Neil Shapiro if (debug) 3663299c2f1SGregory Neil Shapiro { 3673299c2f1SGregory Neil Shapiro fprintf(stderr, "Sendmail arguments:\n"); 368c2aa98e2SPeter Wemm for (i = 0; args[i]; i++) 3693299c2f1SGregory Neil Shapiro fprintf(stderr, "\t%s\n", args[i]); 370c2aa98e2SPeter Wemm } 371c2aa98e2SPeter Wemm 372c2aa98e2SPeter Wemm /* 3733299c2f1SGregory Neil Shapiro ** If called with a regular file as standard input, seek to the right 3743299c2f1SGregory Neil Shapiro ** position in the file and just exec sendmail. Could probably skip 3753299c2f1SGregory Neil Shapiro ** skip the stat, but it's not unreasonable to believe that a failed 3763299c2f1SGregory Neil Shapiro ** seek will cause future reads to fail. 377c2aa98e2SPeter Wemm */ 3783299c2f1SGregory Neil Shapiro 3793299c2f1SGregory Neil Shapiro if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) 3803299c2f1SGregory Neil Shapiro { 381c2aa98e2SPeter Wemm if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset) 382c2aa98e2SPeter Wemm err(EX_TEMPFAIL, "stdin seek"); 3833299c2f1SGregory Neil Shapiro (void) execv(_PATH_SENDMAIL, args); 384c2aa98e2SPeter Wemm err(EX_OSERR, "%s", _PATH_SENDMAIL); 385c2aa98e2SPeter Wemm } 386c2aa98e2SPeter Wemm 387c2aa98e2SPeter Wemm if (pipe(pdes) < 0) 388c2aa98e2SPeter Wemm err(EX_OSERR, NULL); 389c2aa98e2SPeter Wemm 3903299c2f1SGregory Neil Shapiro switch (pid = FORK()) 3913299c2f1SGregory Neil Shapiro { 392c2aa98e2SPeter Wemm case -1: /* Err. */ 393c2aa98e2SPeter Wemm err(EX_OSERR, NULL); 3943299c2f1SGregory Neil Shapiro /* NOTREACHED */ 3953299c2f1SGregory Neil Shapiro 396c2aa98e2SPeter Wemm case 0: /* Child. */ 3973299c2f1SGregory Neil Shapiro if (pdes[0] != STDIN_FILENO) 3983299c2f1SGregory Neil Shapiro { 399c2aa98e2SPeter Wemm (void) dup2(pdes[0], STDIN_FILENO); 400c2aa98e2SPeter Wemm (void) close(pdes[0]); 401c2aa98e2SPeter Wemm } 402c2aa98e2SPeter Wemm (void) close(pdes[1]); 4033299c2f1SGregory Neil Shapiro (void) execv(_PATH_SENDMAIL, args); 404c2aa98e2SPeter Wemm _exit(127); 405c2aa98e2SPeter Wemm /* NOTREACHED */ 406c2aa98e2SPeter Wemm } 407c2aa98e2SPeter Wemm 408c2aa98e2SPeter Wemm if ((fp = fdopen(pdes[1], "w")) == NULL) 409c2aa98e2SPeter Wemm err(EX_OSERR, NULL); 410c2aa98e2SPeter Wemm (void) close(pdes[0]); 411c2aa98e2SPeter Wemm 412c2aa98e2SPeter Wemm /* Copy the file down the pipe. */ 4133299c2f1SGregory Neil Shapiro do 4143299c2f1SGregory Neil Shapiro { 415c2aa98e2SPeter Wemm (void) fprintf(fp, "%s", lbuf); 416c2aa98e2SPeter Wemm } while (fgets(lbuf, sizeof(lbuf), stdin) != NULL); 417c2aa98e2SPeter Wemm 418c2aa98e2SPeter Wemm if (ferror(stdin)) 4193299c2f1SGregory Neil Shapiro err(EX_TEMPFAIL, "stdin: %s", errstring(errno)); 420c2aa98e2SPeter Wemm 421c2aa98e2SPeter Wemm if (fclose(fp)) 422c2aa98e2SPeter Wemm err(EX_OSERR, NULL); 423c2aa98e2SPeter Wemm 424c2aa98e2SPeter Wemm if ((waitpid(pid, &status, 0)) == -1) 425c2aa98e2SPeter Wemm err(EX_OSERR, "%s", _PATH_SENDMAIL); 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm if (!WIFEXITED(status)) 4283299c2f1SGregory Neil Shapiro err(EX_OSERR, "%s: did not terminate normally", _PATH_SENDMAIL); 429c2aa98e2SPeter Wemm 430c2aa98e2SPeter Wemm if (WEXITSTATUS(status)) 431c2aa98e2SPeter Wemm err(status, "%s: terminated with %d (non-zero) status", 432c2aa98e2SPeter Wemm _PATH_SENDMAIL, WEXITSTATUS(status)); 433c2aa98e2SPeter Wemm exit(EX_OK); 4343299c2f1SGregory Neil Shapiro /* NOTREACHED */ 4353299c2f1SGregory Neil Shapiro return EX_OK; 436c2aa98e2SPeter Wemm } 437c2aa98e2SPeter Wemm 4383299c2f1SGregory Neil Shapiro static void 439c2aa98e2SPeter Wemm usage() 440c2aa98e2SPeter Wemm { 441c2aa98e2SPeter Wemm (void) fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n"); 442c2aa98e2SPeter Wemm exit(EX_USAGE); 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm 445c2aa98e2SPeter Wemm #ifdef __STDC__ 446c2aa98e2SPeter Wemm # include <stdarg.h> 4473299c2f1SGregory Neil Shapiro #else /* __STDC__ */ 448c2aa98e2SPeter Wemm # include <varargs.h> 4493299c2f1SGregory Neil Shapiro #endif /* __STDC__ */ 450c2aa98e2SPeter Wemm 4513299c2f1SGregory Neil Shapiro static void 452c2aa98e2SPeter Wemm #ifdef __STDC__ 453c2aa98e2SPeter Wemm err(int eval, const char *fmt, ...) 4543299c2f1SGregory Neil Shapiro #else /* __STDC__ */ 455c2aa98e2SPeter Wemm err(eval, fmt, va_alist) 456c2aa98e2SPeter Wemm int eval; 457c2aa98e2SPeter Wemm const char *fmt; 458c2aa98e2SPeter Wemm va_dcl 4593299c2f1SGregory Neil Shapiro #endif /* __STDC__ */ 460c2aa98e2SPeter Wemm { 461c2aa98e2SPeter Wemm va_list ap; 4623299c2f1SGregory Neil Shapiro #ifdef __STDC__ 463c2aa98e2SPeter Wemm va_start(ap, fmt); 4643299c2f1SGregory Neil Shapiro #else /* __STDC__ */ 465c2aa98e2SPeter Wemm va_start(ap); 4663299c2f1SGregory Neil Shapiro #endif /* __STDC__ */ 467c2aa98e2SPeter Wemm (void) fprintf(stderr, "rmail: "); 468c2aa98e2SPeter Wemm (void) vfprintf(stderr, fmt, ap); 469c2aa98e2SPeter Wemm va_end(ap); 470c2aa98e2SPeter Wemm (void) fprintf(stderr, "\n"); 471c2aa98e2SPeter Wemm exit(eval); 472c2aa98e2SPeter Wemm } 473