sendmail.c (5070B)
1 #include "sgetopt.h" 2 #include "substdio.h" 3 #include "subfd.h" 4 #include "alloc.h" 5 #include "auto_qmail.h" 6 #include "exit.h" 7 #include "env.h" 8 #include "noreturn.h" 9 #include "str.h" 10 11 void _noreturn_ nomem() 12 { 13 substdio_putsflush(subfderr,"sendmail: fatal: out of memory\n"); 14 _exit(111); 15 } 16 17 void _noreturn_ die_usage() 18 { 19 substdio_putsflush(subfderr,"sendmail: usage: sendmail [ -t ] [ -fsender ] [ -Fname ] [ -bp ] [ -bs ] [ arg ... ]\n"); 20 _exit(100); 21 } 22 23 void _noreturn_ die_exptcps() 24 { 25 substdio_putsflush(subfderr,"sendmail: usage: sendmail [ -t ] [ -fsender ] [ -Fname ] [ -bp ] [ -bs ] [ arg ... ]\n"); 26 substdio_putsflush(subfderr,"This sendmail is qmail-sendmail from Nightmare Mail. It is not capable of running a\n"); 27 substdio_putsflush(subfderr,"TCP service by itself. Try running bin/qmail-smtpd (or bin/nmail-smtpd if you have\n"); 28 substdio_putsflush(subfderr,"UCSPI-TLS) from port 25 in inetd or in a UCSPI TCP nowait server.\n"); 29 substdio_putsflush(subfderr,"'Backgrounding' should be achieved by running your inetd or UCSPI TCP server from a\n"); 30 substdio_putsflush(subfderr,"supervisory engine like systemd, initware, runit, or S6.\n"); 31 _exit(100); 32 } 33 34 char *smtpdarg[] = { "bin/qmail-smtpd", 0 }; 35 void _noreturn_ smtpd() 36 { 37 if (!env_get("PROTO")) { 38 if (!env_put("RELAYCLIENT=")) nomem(); 39 if (!env_put("DATABYTES=0")) nomem(); 40 if (!env_put("PROTO=TCP")) nomem(); 41 if (!env_put("TCPLOCALIP=127.0.0.1")) nomem(); 42 if (!env_put("TCPLOCALHOST=localhost")) nomem(); 43 if (!env_put("TCPREMOTEIP=127.0.0.1")) nomem(); 44 if (!env_put("TCPREMOTEHOST=localhost")) nomem(); 45 if (!env_put("TCPREMOTEINFO=sendmail-bs")) nomem(); 46 } 47 execv(*smtpdarg,smtpdarg); 48 substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-smtpd\n"); 49 _exit(111); 50 } 51 52 char *qreadarg[] = { "bin/qmail-qread", 0 }; 53 void _noreturn_ mailq() 54 { 55 execv(*qreadarg,qreadarg); 56 substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-qread\n"); 57 _exit(111); 58 } 59 60 void do_sender(s) 61 const char *s; 62 { 63 char *x; 64 unsigned int n; 65 unsigned int a; 66 unsigned int i; 67 68 env_unset("QMAILNAME"); 69 env_unset("MAILNAME"); 70 env_unset("NAME"); 71 env_unset("QMAILHOST"); 72 env_unset("MAILHOST"); 73 74 n = str_len(s); 75 a = str_rchr(s, '@'); 76 if (a == n) 77 { 78 env_put2("QMAILUSER", s); 79 return; 80 } 81 env_put2("QMAILHOST", s + a + 1); 82 83 x = (char *) alloc((a + 1) * sizeof(char)); 84 if (!x) nomem(); 85 for (i = 0; i < a; i++) 86 x[i] = s[i]; 87 x[i] = 0; 88 env_put2("QMAILUSER", x); 89 alloc_free(x); 90 } 91 92 int flagh; 93 char *sender; 94 95 int main(int argc, char **argv) 96 { 97 int opt; 98 char **qiargv; 99 char **arg; 100 int i; 101 102 if (chdir(auto_qmail) == -1) { 103 substdio_putsflush(subfderr,"sendmail: fatal: unable to switch to qmail home directory\n"); 104 return 111; 105 } 106 107 flagh = 0; 108 sender = 0; 109 while ((opt = getopt(argc,argv,"vimte:f:p:o:B:F:EJxb:")) != opteof) 110 switch(opt) { 111 case 'B': break; 112 case 't': flagh = 1; break; 113 case 'f': sender = optarg; break; 114 case 'F': if (!env_put2("MAILNAME",optarg)) nomem(); break; 115 case 'p': break; /* could generate a Received line from optarg */ 116 case 'v': break; /* we don't even bother with best effort verbosity. */ 117 case 'i': break; /* qmsendmail is already transparent to leading dots. */ 118 case 'x': break; /* SVR4 stupidity */ 119 case 'm': break; /* twisted-paper-path blindness, incompetent design */ 120 case 'e': break; /* qmail has only one error mode */ 121 case 'o': 122 switch(optarg[0]) { 123 case 'd': break; /* qmail has only one delivery mode */ 124 case 'e': break; /* qmail only has one error mode */ 125 case 'i': break; /* qmail does not ignore dots */ 126 case 'm': break; /* qmail always sends to me too if in an EXPN. */ 127 } 128 break; 129 case 'E': case 'J': /* Sony NEWS-OS */ 130 while (argv[optind][optpos]) ++optpos; /* skip optional argument */ 131 break; 132 case 'b': 133 switch(optarg[0]) { 134 case 'm': break; 135 case 'd': die_exptcps(); /* explain TCP servers to the user */ 136 case 'D': die_exptcps(); /* who is probably echt confused */ 137 case 'p': mailq(); 138 case 's': smtpd(); 139 default: die_usage(); 140 } 141 break; 142 default: 143 die_usage(); 144 } 145 argc -= optind; 146 argv += optind; 147 148 if (str_equal(optprogname,"mailq")) 149 mailq(); 150 151 if (str_equal(optprogname,"newaliases")) { 152 substdio_putsflush(subfderr,"sendmail: fatal: please use fastforward/newaliases instead\n"); 153 return 100; 154 } 155 156 qiargv = (char **) alloc((argc + 10) * sizeof(char *)); 157 if (!qiargv) nomem(); 158 /* This is arcane: qiargv is... a pointer to 10+argc pointers to char arrays. 159 * This kind of arcana confuses dragons. We don't work in nuances. */ 160 arg = qiargv; 161 *arg++ = "bin/qmail-inject"; 162 *arg++ = (flagh ? "-H" : "-a"); 163 if (sender) { 164 *arg++ = "-f"; 165 *arg++ = sender; 166 do_sender(sender); 167 } 168 *arg++ = "--"; 169 for (i = 0;i < argc;++i) *arg++ = argv[i]; 170 *arg = 0; 171 172 execv(*qiargv,qiargv); 173 substdio_putsflush(subfderr,"sendmail: fatal: unable to run qmail-inject\n"); 174 return 111; 175 }