2 Subject: Re: send mail from chrooted Apache
3 From: Wietse Venema (wietseporcupine.org)
4 Date: Tue Jun 06 2000 - 07:43:31 CDT
5 Next message: Wietse Venema: "Re: -"
6 Previous message: Brad Knowles: "Re: performance issues"
7 In reply to: ISM Kolemanov, Ivan: "send mail from chrooted Apache"
11 > I've just prepared Apache Web Server in chroot env.
12 > but now I have a problem, I can't send mails from the web server
13 > I mean that on the web server I have some formulars,
14 > which my clients are using to send me mail.
16 > I guess that there is any solution for that, but up to now I didn't find it.
17 > If anybody knows it please respond.
22 This is a quick-and-dirty stand-alone SMTP client from long ago.
23 Works OK for lines up to BUFSIZ characters, nothing to worry about
24 security-wise. You could probably do the same in PERL, but I wrote
25 this for a web server that allowed no programming languages inside
36 /* smtp [options] recipient(s)...
38 /* \fIsmtp\fP is a minimal smtp client that takes an email
39 /* message body and passes it on to an smtp daemon (default
40 /* the smtp daemon on the local host). Since it is
41 /* completely self-supporting, the smtp client is especially
42 /* suitable for use in restricted environments.
47 /* Specifies one Cc: address to send one copy of the message to.
50 /* Specifies the Errors-To: address. This is where delivery
51 /* problems should be reported.
54 /* Sets the From: address. Default is "daemon", which is
58 /* Specifies where the mail should be posted. By default, the
59 /* mail is posted to the smtp daemon on \fIlocalhost\fR.
62 /* Use MIME-style translation to quoted-printable (base 16).
65 /* Sets the Reply-To: address.
68 /* Specifies the message subject.
71 /* Turn on verbose logging to stdout.
73 /* Non-zero exit status in case of problems. Errors are reported
74 /* to the syslogd, with facility daemon.
77 /* Eindhoven University of Technology
78 /* Department of Mathematics and Computer Science
79 /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
81 /* Wed Dec 1 14:51:13 MET 1993
83 /* Fri Aug 11 12:29:23 MET DST 1995
86 /* System libraries */
88 #include <sys/types.h>
89 #include <sys/socket.h>
90 #include <netinet/in.h>
100 #define VARARGS(func,arg,type) func(type arg, ...)
101 #define VASTART(ap,name,type) { va_start(ap, name)
102 #define VAEND(ap) va_end(ap); }
105 #define VARARGS(func,arg,type) func(va_alist) \
107 #define VASTART(ap,name,type) { type name; \
109 name = va_arg(ap, type)
110 #define VAEND(ap) va_end(ap); }
111 #endif /* __STDC__ */
118 static char *cc_addr = 0;
119 static char *err_addr = 0;
120 static char *from_addr = "daemon";
121 static char *mailhost = "localhost";
122 static char *reply_addr = 0;
123 static char *subject = 0;
124 static int mime_style = 0;
125 static int verbose = 0;
130 #define dprintf if (verbose) printf
131 #define dvprintf if (verbose) vprintf
135 /* usage - explain and bail out */
140 "usage: smtp [-c cc] [-e errors-to] [-f from] [-m mailhost] [-M] [-r reply-to] [-s subject] [-v] recipents..\n");
144 /* get_response - examine message from server */
150 while (fgets(buf, sizeof(buf), rfp)) {
151 buf[strlen(buf) - 1] = 0;
152 dprintf(">>>> %s\n", buf);
153 if (!isdigit(buf[0]) || buf[0] > '3') {
154 syslog(LOG_ERR, "unexpected reply: %s", buf);
162 /* chat - say something to server and check the response */
164 void VARARGS(chat, fmt, char *)
168 /* Format the message. */
170 VASTART(ap, fmt, char *);
171 vfprintf(sfp, fmt, ap);
174 VASTART(ap, fmt, char *);
178 /* Send message to server and parse its response. */
189 char my_name[BUFSIZ];
190 struct sockaddr_in sin;
199 openlog(argv[0], LOG_PID, LOG_DAEMON);
201 /* Go away when something gets stuck. */
207 while ((c = getopt(argc, argv, "c:e:f:m:Mr:s:v")) != EOF) {
209 case 'c': /* carbon copy */
212 case 'e': /* errors-to */
215 case 'f': /* originator */
218 case 'm': /* mailhost */
221 case 'M': /* MIME quoted printable */
224 case 'r': /* reply-to */
227 case 's': /* subject */
230 case 'v': /* log protocol */
241 /* Find out my own host name for HELO; if possible, get the FQDN. */
243 if (gethostname(my_name, sizeof(my_name) - 1) < 0) {
244 syslog(LOG_ERR, "gethostname: %m");
247 if ((hp = gethostbyname(my_name)) == 0) {
248 syslog(LOG_ERR, "%s: unknown host\n", my_name);
251 strncpy(my_name, hp->h_name, sizeof(my_name) - 1);
253 /* Connect to smtp daemon on mailhost. */
255 if ((hp = gethostbyname(mailhost)) == 0) {
256 syslog(LOG_ERR, "%s: unknown host\n", mailhost);
259 if (hp->h_addrtype != AF_INET) {
260 syslog(LOG_ERR, "unknown address family: %d", hp->h_addrtype);
263 memset((char *) &sin, 0, sizeof(sin));
264 memcpy((char *) &sin.sin_addr, hp->h_addr, hp->h_length);
265 sin.sin_family = hp->h_addrtype;
266 if ((sp = getservbyname("smtp", "tcp")) != 0) {
267 sin.sin_port = sp->s_port;
269 syslog(LOG_ERR, "smtp/tcp: unknown service");
272 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
273 syslog(LOG_ERR, "socket: %m");
276 if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
277 syslog(LOG_ERR, "connect: %m");
280 if ((r = dup(s)) < 0) {
281 syslog(LOG_ERR, "dup: %m");
284 if ((sfp = fdopen(s, "w")) == 0) {
285 syslog(LOG_ERR, "fdopen: %m");
288 if ((rfp = fdopen(r, "r")) == 0) {
289 syslog(LOG_ERR, "fdopen: %m");
294 get_response(); /* banner */
296 chat("HELO %s\r\n", my_name);
298 chat("MAIL FROM: <%s>\r\n", from_addr);
300 for (i = optind; i < argc; i++)
301 chat("RCPT TO: <%s>\r\n", argv[i]);
303 chat("RCPT TO: <%s>\r\n", cc_addr);
307 /* Do message header. */
309 fprintf(sfp, "From: %s\r\n", from_addr);
312 fprintf(sfp, "Subject: %s\r\n", subject);
315 fprintf(sfp, "Errors-To: %s\r\n", err_addr);
318 fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
320 if ((pwd = getpwuid(getuid())) == 0) {
321 fprintf(sfp, "Sender: userid-%d%s\r\n", getuid(), my_name);
323 fprintf(sfp, "Sender: %s%s\r\n", pwd->pw_name, my_name);
326 fprintf(sfp, "To: %s", argv[optind]);
327 for (i = optind + 1; i < argc; i++)
328 fprintf(sfp, ", %s", argv[i]);
329 fprintf(sfp, "\r\n");
332 fprintf(sfp, "Cc: %s\r\n", cc_addr);
335 fprintf(sfp, "Mime-Version: 1.0\r\n");
336 fprintf(sfp, "Content-Type: text/plain; charset=ISO-8859-1\r\n");
337 fprintf(sfp, "Content-Transfer-Encoding: quoted-printable\r\n");
339 fprintf(sfp, "\r\n");
341 /* Do message body. */
343 if (mime_style) { /* MIME quoted-printable */
345 } else { /* traditional... */
346 while (fgets(buf, sizeof(buf), stdin)) {
347 buf[strlen(buf) - 1] = 0;
348 if (strcmp(buf, ".") == 0) { /* quote lone dots */
349 fprintf(sfp, "..\r\n");
350 } else { /* pass thru mode */
351 fprintf(sfp, "%s\r\n", buf);
361 * Following code was lifted from the metamail version 2.7 source code
362 * (codes.c) and modified to emit \r\n at line boundaries.
365 static char basis_hex[] = "0123456789ABCDEF";
367 /* toqp - transform to MIME-style quoted printable */
369 void toqp(infile, outfile)
377 while ((c = getc(infile)) != EOF) {
378 if ((c < 32 && (c != '\n' && c != '\t'))
383 * Following line is to avoid single periods alone on lines, which
384 * messes up some dumb smtp implementations, sigh...
386 || (ct == 0 && c == '.')) {
388 putc(basis_hex[c >> 4], outfile);
389 putc(basis_hex[c & 0xF], outfile);
391 prevc = 'A'; /* close enough */
392 } else if (c == '\n') {
393 if (prevc == ' ' || prevc == '\t') {
394 putc('=', outfile); /* soft & hard lines */
401 if (c == 'F' && prevc == '\n') {
404 * HORRIBLE but clever hack suggested by MTR for
415 /* This is the case we are looking for */
416 fputs("=46rom", outfile);
419 fputs("From", outfile);
423 fputs("Fro", outfile);
427 fputs("Fr", outfile);
435 prevc = 'x'; /* close enough -- printable */
436 } else { /* END horrible hack */
444 putc('\r', outfile); /* XXX */
452 putc('\r', outfile); /* XXX */