+++ /dev/null
-/*
-Subject: Re: send mail from chrooted Apache
- From: Wietse Venema (wietseporcupine.org)
- Date: Tue Jun 06 2000 - 07:43:31 CDT
-Next message: Wietse Venema: "Re: -"
-Previous message: Brad Knowles: "Re: performance issues"
-In reply to: ISM Kolemanov, Ivan: "send mail from chrooted Apache"
- ISM Kolemanov, Ivan:
- > hi all,
- >
- > I've just prepared Apache Web Server in chroot env.
- > but now I have a problem, I can't send mails from the web server
- > I mean that on the web server I have some formulars,
- > which my clients are using to send me mail.
- >
- > I guess that there is any solution for that, but up to now I didn't find it.
- > If anybody knows it please respond.
- >
- > 10x in advance
- > Ivan Kolemanov
-
-This is a quick-and-dirty stand-alone SMTP client from long ago.
- Works OK for lines up to BUFSIZ characters, nothing to worry about
- security-wise. You could probably do the same in PERL, but I wrote
- this for a web server that allowed no programming languages inside
- the jail.
-
- Wietse
- */
-/*++
- /* NAME
- /* smtp 1
- /* SUMMARY
- /* simple smtp client
- /* SYNOPSIS
- /* smtp [options] recipient(s)...
- /* DESCRIPTION
- /* \fIsmtp\fP is a minimal smtp client that takes an email
- /* message body and passes it on to an smtp daemon (default
- /* the smtp daemon on the local host). Since it is
- /* completely self-supporting, the smtp client is especially
- /* suitable for use in restricted environments.
- /*
- /* Options:
- /* .TP
- /* -c carbon-copy
- /* Specifies one Cc: address to send one copy of the message to.
- /* .TP
- /* -e errors-to
- /* Specifies the Errors-To: address. This is where delivery
- /* problems should be reported.
- /* .TP
- /* -f from
- /* Sets the From: address. Default is "daemon", which is
- /* probably wrong.
- /* .TP
- /* -m mailhost
- /* Specifies where the mail should be posted. By default, the
- /* mail is posted to the smtp daemon on \fIlocalhost\fR.
- /* .TP
- /* -M
- /* Use MIME-style translation to quoted-printable (base 16).
- /* .TP
- /* -r reply-to
- /* Sets the Reply-To: address.
- /* .TP
- /* -s subject
- /* Specifies the message subject.
- /* .TP
- /* -v
- /* Turn on verbose logging to stdout.
- /* DIAGNOSTICS
- /* Non-zero exit status in case of problems. Errors are reported
- /* to the syslogd, with facility daemon.
- /* AUTHOR(S)
- /* W.Z. Venema
- /* Eindhoven University of Technology
- /* Department of Mathematics and Computer Science
- /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- /* CREATION DATE
- /* Wed Dec 1 14:51:13 MET 1993
- /* LAST UPDATE
- /* Fri Aug 11 12:29:23 MET DST 1995
- /*--*/
-
-/* System libraries */
-
-#include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <syslog.h>
- #include <stdio.h>
- #include <netdb.h>
- #include <string.h>
- #include <ctype.h>
- #include <pwd.h>
-
-#ifdef __STDC__
- #include <stdarg.h>
- #define VARARGS(func,arg,type) func(type arg, ...)
- #define VASTART(ap,name,type) { va_start(ap, name)
- #define VAEND(ap) va_end(ap); }
- #else
- #include <varargs.h>
- #define VARARGS(func,arg,type) func(va_alist) \
- va_dcl
- #define VASTART(ap,name,type) { type name; \
- va_start(ap); \
- name = va_arg(ap, type)
- #define VAEND(ap) va_end(ap); }
- #endif /* __STDC__ */
-
-extern int optind;
- extern char *optarg;
-
-/* Local stuff */
-
-static char *cc_addr = 0;
- static char *err_addr = 0;
- static char *from_addr = "daemon";
- static char *mailhost = "localhost";
- static char *reply_addr = 0;
- static char *subject = 0;
- static int mime_style = 0;
- static int verbose = 0;
-
-static FILE *sfp;
- static FILE *rfp;
-
-#define dprintf if (verbose) printf
- #define dvprintf if (verbose) vprintf
-
-void toqp();
-
-/* usage - explain and bail out */
-
-void usage()
- {
- syslog(LOG_ERR,
- "usage: smtp [-c cc] [-e errors-to] [-f from] [-m mailhost] [-M] [-r reply-to] [-s subject] [-v] recipents..\n");
- exit(1);
- }
-
-/* get_response - examine message from server */
-
-void get_response()
- {
- char buf[BUFSIZ];
-
- while (fgets(buf, sizeof(buf), rfp)) {
- buf[strlen(buf) - 1] = 0;
- dprintf(">>>> %s\n", buf);
- if (!isdigit(buf[0]) || buf[0] > '3') {
- syslog(LOG_ERR, "unexpected reply: %s", buf);
- exit(1);
- }
- if (buf[4] != '-')
- break;
- }
- }
-
-/* chat - say something to server and check the response */
-
-void VARARGS(chat, fmt, char *)
- {
- va_list ap;
-
- /* Format the message. */
-
- VASTART(ap, fmt, char *);
- vfprintf(sfp, fmt, ap);
- VAEND(ap);
-
- VASTART(ap, fmt, char *);
- dvprintf(fmt, ap);
- VAEND(ap);
-
- /* Send message to server and parse its response. */
-
- fflush(sfp);
- get_response();
- }
-
-main(argc, argv)
- int argc;
- char **argv;
- {
- char buf[BUFSIZ];
- char my_name[BUFSIZ];
- struct sockaddr_in sin;
- struct hostent *hp;
- struct servent *sp;
- int c;
- int s;
- int r;
- int i;
- struct passwd *pwd;
-
- openlog(argv[0], LOG_PID, LOG_DAEMON);
-
- /* Go away when something gets stuck. */
-
- alarm(60);
-
- /* Parse JCL. */
-
- while ((c = getopt(argc, argv, "c:e:f:m:Mr:s:v")) != EOF) {
- switch (c) {
- case 'c': /* carbon copy */
- cc_addr = optarg;
- break;
- case 'e': /* errors-to */
- err_addr = optarg;
- break;
- case 'f': /* originator */
- from_addr = optarg;
- break;
- case 'm': /* mailhost */
- mailhost = optarg;
- break;
- case 'M': /* MIME quoted printable */
- mime_style = 1;
- break;
- case 'r': /* reply-to */
- reply_addr = optarg;
- break;
- case 's': /* subject */
- subject = optarg;
- break;
- case 'v': /* log protocol */
- verbose = 1;
- break;
- default:
- usage();
- /* NOTREACHED */
- }
- }
- if (argc == optind)
- usage();
-
- /* Find out my own host name for HELO; if possible, get the FQDN. */
-
- if (gethostname(my_name, sizeof(my_name) - 1) < 0) {
- syslog(LOG_ERR, "gethostname: %m");
- exit(1);
- }
- if ((hp = gethostbyname(my_name)) == 0) {
- syslog(LOG_ERR, "%s: unknown host\n", my_name);
- exit(1);
- }
- strncpy(my_name, hp->h_name, sizeof(my_name) - 1);
-
- /* Connect to smtp daemon on mailhost. */
-
- if ((hp = gethostbyname(mailhost)) == 0) {
- syslog(LOG_ERR, "%s: unknown host\n", mailhost);
- exit(1);
- }
- if (hp->h_addrtype != AF_INET) {
- syslog(LOG_ERR, "unknown address family: %d", hp->h_addrtype);
- exit(1);
- }
- memset((char *) &sin, 0, sizeof(sin));
- memcpy((char *) &sin.sin_addr, hp->h_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- if ((sp = getservbyname("smtp", "tcp")) != 0) {
- sin.sin_port = sp->s_port;
- } else {
- syslog(LOG_ERR, "smtp/tcp: unknown service");
- exit(1);
- }
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(LOG_ERR, "socket: %m");
- exit(1);
- }
- if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
- syslog(LOG_ERR, "connect: %m");
- exit(1);
- }
- if ((r = dup(s)) < 0) {
- syslog(LOG_ERR, "dup: %m");
- exit(1);
- }
- if ((sfp = fdopen(s, "w")) == 0) {
- syslog(LOG_ERR, "fdopen: %m");
- exit(1);
- }
- if ((rfp = fdopen(r, "r")) == 0) {
- syslog(LOG_ERR, "fdopen: %m");
- exit(1);
- }
- /* Speak SMTP. */
-
- get_response(); /* banner */
-
- chat("HELO %s\r\n", my_name);
-
- chat("MAIL FROM: <%s>\r\n", from_addr);
-
- for (i = optind; i < argc; i++)
- chat("RCPT TO: <%s>\r\n", argv[i]);
- if (cc_addr)
- chat("RCPT TO: <%s>\r\n", cc_addr);
-
- chat("DATA\r\n");
-
- /* Do message header. */
-
- fprintf(sfp, "From: %s\r\n", from_addr);
-
- if (subject)
- fprintf(sfp, "Subject: %s\r\n", subject);
-
- if (err_addr)
- fprintf(sfp, "Errors-To: %s\r\n", err_addr);
-
- if (reply_addr)
- fprintf(sfp, "Reply-To: %s\r\n", reply_addr);
-
- if ((pwd = getpwuid(getuid())) == 0) {
- fprintf(sfp, "Sender: userid-%d%s\r\n", getuid(), my_name);
- } else {
- fprintf(sfp, "Sender: %s%s\r\n", pwd->pw_name, my_name);
- }
-
- fprintf(sfp, "To: %s", argv[optind]);
- for (i = optind + 1; i < argc; i++)
- fprintf(sfp, ", %s", argv[i]);
- fprintf(sfp, "\r\n");
-
- if (cc_addr)
- fprintf(sfp, "Cc: %s\r\n", cc_addr);
-
- if (mime_style) {
- fprintf(sfp, "Mime-Version: 1.0\r\n");
- fprintf(sfp, "Content-Type: text/plain; charset=ISO-8859-1\r\n");
- fprintf(sfp, "Content-Transfer-Encoding: quoted-printable\r\n");
- }
- fprintf(sfp, "\r\n");
-
- /* Do message body. */
-
- if (mime_style) { /* MIME quoted-printable */
- toqp(stdin, sfp);
- } else { /* traditional... */
- while (fgets(buf, sizeof(buf), stdin)) {
- buf[strlen(buf) - 1] = 0;
- if (strcmp(buf, ".") == 0) { /* quote lone dots */
- fprintf(sfp, "..\r\n");
- } else { /* pass thru mode */
- fprintf(sfp, "%s\r\n", buf);
- }
- }
- }
- chat(".\r\n");
- chat("QUIT\r\n");
- exit(0);
- }
-
- /*
- * Following code was lifted from the metamail version 2.7 source code
- * (codes.c) and modified to emit \r\n at line boundaries.
- */
-
-static char basis_hex[] = "0123456789ABCDEF";
-
-/* toqp - transform to MIME-style quoted printable */
-
-void toqp(infile, outfile)
- FILE *infile,
- *outfile;
- {
- int c,
- ct = 0,
- prevc = 255;
-
- while ((c = getc(infile)) != EOF) {
- if ((c < 32 && (c != '\n' && c != '\t'))
- || (c == '=')
- || (c >= 127)
-
- /*
- * Following line is to avoid single periods alone on lines, which
- * messes up some dumb smtp implementations, sigh...
- */
- || (ct == 0 && c == '.')) {
- putc('=', outfile);
- putc(basis_hex[c >> 4], outfile);
- putc(basis_hex[c & 0xF], outfile);
- ct += 3;
- prevc = 'A'; /* close enough */
- } else if (c == '\n') {
- if (prevc == ' ' || prevc == '\t') {
- putc('=', outfile); /* soft & hard lines */
- putc(c, outfile);
- }
- putc(c, outfile);
- ct = 0;
- prevc = c;
- } else {
- if (c == 'F' && prevc == '\n') {
-
- /*
- * HORRIBLE but clever hack suggested by MTR for
- * sendmail-avoidance
- */
- c = getc(infile);
- if (c == 'r') {
- c = getc(infile);
- if (c == 'o') {
- c = getc(infile);
- if (c == 'm') {
- c = getc(infile);
- if (c == ' ') {
- /* This is the case we are looking for */
- fputs("=46rom", outfile);
- ct += 6;
- } else {
- fputs("From", outfile);
- ct += 4;
- }
- } else {
- fputs("Fro", outfile);
- ct += 3;
- }
- } else {
- fputs("Fr", outfile);
- ct += 2;
- }
- } else {
- putc('F', outfile);
- ++ct;
- }
- ungetc(c, infile);
- prevc = 'x'; /* close enough -- printable */
- } else { /* END horrible hack */
- putc(c, outfile);
- ++ct;
- prevc = c;
- }
- }
- if (ct > 72) {
- putc('=', outfile);
- putc('\r', outfile); /* XXX */
- putc('\n', outfile);
- ct = 0;
- prevc = '\n';
- }
- }
- if (ct) {
- putc('=', outfile);
- putc('\r', outfile); /* XXX */
- putc('\n', outfile);
- }
- }