]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tools/smtp-orig.c
Update
[bacula/bacula] / bacula / src / tools / smtp-orig.c
1 /*
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"  
8  ISM Kolemanov, Ivan: 
9  > hi all, 
10  > 
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. 
15  > 
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. 
18  > 
19  > 10x in advance 
20  > Ivan Kolemanov 
21  
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 
26  the jail. 
27  
28         Wietse 
29  */
30 /*++ 
31  /* NAME 
32  /* smtp 1 
33  /* SUMMARY 
34  /* simple smtp client 
35  /* SYNOPSIS 
36  /* smtp [options] recipient(s)... 
37  /* DESCRIPTION 
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. 
43  /* 
44  /* Options: 
45  /* .TP 
46  /* -c carbon-copy 
47  /* Specifies one Cc: address to send one copy of the message to. 
48  /* .TP 
49  /* -e errors-to 
50  /* Specifies the Errors-To: address. This is where delivery 
51  /* problems should be reported. 
52  /* .TP 
53  /* -f from 
54  /* Sets the From: address. Default is "daemon", which is 
55  /* probably wrong. 
56  /* .TP 
57  /* -m mailhost 
58  /* Specifies where the mail should be posted. By default, the 
59  /* mail is posted to the smtp daemon on \fIlocalhost\fR. 
60  /* .TP 
61  /* -M 
62  /* Use MIME-style translation to quoted-printable (base 16). 
63  /* .TP 
64  /* -r reply-to 
65  /* Sets the Reply-To: address. 
66  /* .TP 
67  /* -s subject 
68  /* Specifies the message subject. 
69  /* .TP 
70  /* -v 
71  /* Turn on verbose logging to stdout. 
72  /* DIAGNOSTICS 
73  /* Non-zero exit status in case of problems. Errors are reported 
74  /* to the syslogd, with facility daemon. 
75  /* AUTHOR(S) 
76  /* W.Z. Venema 
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 
80  /* CREATION DATE 
81  /* Wed Dec 1 14:51:13 MET 1993 
82  /* LAST UPDATE 
83  /* Fri Aug 11 12:29:23 MET DST 1995 
84  /*--*/ 
85  
86 /* System libraries */ 
87  
88 #include <sys/types.h> 
89  #include <sys/socket.h> 
90  #include <netinet/in.h> 
91  #include <syslog.h> 
92  #include <stdio.h> 
93  #include <netdb.h> 
94  #include <string.h> 
95  #include <ctype.h> 
96  #include <pwd.h> 
97  
98 #ifdef __STDC__ 
99  #include <stdarg.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); } 
103  #else 
104  #include <varargs.h> 
105  #define VARARGS(func,arg,type) func(va_alist) \ 
106                                  va_dcl 
107  #define VASTART(ap,name,type) { type name; \ 
108                                  va_start(ap); \ 
109                                  name = va_arg(ap, type) 
110  #define VAEND(ap) va_end(ap); } 
111  #endif /* __STDC__ */ 
112  
113 extern int optind; 
114  extern char *optarg; 
115  
116 /* Local stuff */ 
117  
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; 
126  
127 static FILE *sfp; 
128  static FILE *rfp; 
129  
130 #define dprintf if (verbose) printf 
131  #define dvprintf if (verbose) vprintf 
132  
133 void toqp(); 
134  
135 /* usage - explain and bail out */ 
136  
137 void usage() 
138  { 
139      syslog(LOG_ERR, 
140             "usage: smtp [-c cc] [-e errors-to] [-f from] [-m mailhost] [-M] [-r reply-to] [-s subject] [-v] recipents..\n"); 
141      exit(1); 
142  } 
143  
144 /* get_response - examine message from server */ 
145  
146 void get_response() 
147  { 
148      char buf[BUFSIZ]; 
149  
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); 
155              exit(1); 
156          } 
157          if (buf[4] != '-') 
158              break; 
159      } 
160  } 
161  
162 /* chat - say something to server and check the response */ 
163  
164 void VARARGS(chat, fmt, char *) 
165  { 
166      va_list ap; 
167  
168     /* Format the message. */ 
169  
170     VASTART(ap, fmt, char *); 
171      vfprintf(sfp, fmt, ap); 
172      VAEND(ap); 
173  
174     VASTART(ap, fmt, char *); 
175      dvprintf(fmt, ap); 
176      VAEND(ap); 
177  
178     /* Send message to server and parse its response. */ 
179  
180     fflush(sfp); 
181      get_response(); 
182  } 
183  
184 main(argc, argv) 
185  int argc; 
186  char **argv; 
187  { 
188      char buf[BUFSIZ]; 
189      char my_name[BUFSIZ]; 
190      struct sockaddr_in sin; 
191      struct hostent *hp; 
192      struct servent *sp; 
193      int c; 
194      int s; 
195      int r; 
196      int i; 
197      struct passwd *pwd; 
198  
199     openlog(argv[0], LOG_PID, LOG_DAEMON); 
200  
201     /* Go away when something gets stuck. */ 
202  
203     alarm(60); 
204  
205     /* Parse JCL. */ 
206  
207     while ((c = getopt(argc, argv, "c:e:f:m:Mr:s:v")) != EOF) { 
208          switch (c) { 
209          case 'c': /* carbon copy */ 
210              cc_addr = optarg; 
211              break; 
212          case 'e': /* errors-to */ 
213              err_addr = optarg; 
214              break; 
215          case 'f': /* originator */ 
216              from_addr = optarg; 
217              break; 
218          case 'm': /* mailhost */ 
219              mailhost = optarg; 
220              break; 
221          case 'M': /* MIME quoted printable */ 
222              mime_style = 1; 
223              break; 
224          case 'r': /* reply-to */ 
225              reply_addr = optarg; 
226              break; 
227          case 's': /* subject */ 
228              subject = optarg; 
229              break; 
230          case 'v': /* log protocol */ 
231              verbose = 1; 
232              break; 
233          default: 
234              usage(); 
235              /* NOTREACHED */ 
236          } 
237      } 
238      if (argc == optind) 
239          usage(); 
240  
241     /* Find out my own host name for HELO; if possible, get the FQDN. */ 
242  
243     if (gethostname(my_name, sizeof(my_name) - 1) < 0) { 
244          syslog(LOG_ERR, "gethostname: %m"); 
245          exit(1); 
246      } 
247      if ((hp = gethostbyname(my_name)) == 0) { 
248          syslog(LOG_ERR, "%s: unknown host\n", my_name); 
249          exit(1); 
250      } 
251      strncpy(my_name, hp->h_name, sizeof(my_name) - 1); 
252  
253     /* Connect to smtp daemon on mailhost. */ 
254  
255     if ((hp = gethostbyname(mailhost)) == 0) { 
256          syslog(LOG_ERR, "%s: unknown host\n", mailhost); 
257          exit(1); 
258      } 
259      if (hp->h_addrtype != AF_INET) { 
260          syslog(LOG_ERR, "unknown address family: %d", hp->h_addrtype); 
261          exit(1); 
262      } 
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; 
268      } else { 
269          syslog(LOG_ERR, "smtp/tcp: unknown service"); 
270          exit(1); 
271      } 
272      if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
273          syslog(LOG_ERR, "socket: %m"); 
274          exit(1); 
275      } 
276      if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) { 
277          syslog(LOG_ERR, "connect: %m"); 
278          exit(1); 
279      } 
280      if ((r = dup(s)) < 0) { 
281          syslog(LOG_ERR, "dup: %m"); 
282          exit(1); 
283      } 
284      if ((sfp = fdopen(s, "w")) == 0) { 
285          syslog(LOG_ERR, "fdopen: %m"); 
286          exit(1); 
287      } 
288      if ((rfp = fdopen(r, "r")) == 0) { 
289          syslog(LOG_ERR, "fdopen: %m"); 
290          exit(1); 
291      } 
292      /* Speak SMTP. */ 
293  
294     get_response(); /* banner */ 
295  
296     chat("HELO %s\r\n", my_name); 
297  
298     chat("MAIL FROM: <%s>\r\n", from_addr); 
299  
300     for (i = optind; i < argc; i++) 
301          chat("RCPT TO: <%s>\r\n", argv[i]); 
302      if (cc_addr) 
303          chat("RCPT TO: <%s>\r\n", cc_addr); 
304  
305     chat("DATA\r\n"); 
306  
307     /* Do message header. */ 
308  
309     fprintf(sfp, "From: %s\r\n", from_addr); 
310  
311     if (subject) 
312          fprintf(sfp, "Subject: %s\r\n", subject); 
313  
314     if (err_addr) 
315          fprintf(sfp, "Errors-To: %s\r\n", err_addr); 
316  
317     if (reply_addr) 
318          fprintf(sfp, "Reply-To: %s\r\n", reply_addr); 
319  
320     if ((pwd = getpwuid(getuid())) == 0) { 
321          fprintf(sfp, "Sender: userid-%d%s\r\n", getuid(), my_name); 
322      } else { 
323          fprintf(sfp, "Sender: %s%s\r\n", pwd->pw_name, my_name); 
324      } 
325  
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"); 
330  
331     if (cc_addr) 
332          fprintf(sfp, "Cc: %s\r\n", cc_addr); 
333  
334     if (mime_style) { 
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"); 
338      } 
339      fprintf(sfp, "\r\n"); 
340  
341     /* Do message body. */ 
342  
343     if (mime_style) { /* MIME quoted-printable */ 
344          toqp(stdin, sfp); 
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); 
352              } 
353          } 
354      } 
355      chat(".\r\n"); 
356      chat("QUIT\r\n"); 
357      exit(0); 
358  } 
359  
360  /* 
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. 
363    */ 
364  
365 static char basis_hex[] = "0123456789ABCDEF"; 
366  
367 /* toqp - transform to MIME-style quoted printable */ 
368  
369 void toqp(infile, outfile) 
370  FILE *infile, 
371         *outfile; 
372  { 
373      int c, 
374              ct = 0, 
375              prevc = 255; 
376  
377     while ((c = getc(infile)) != EOF) { 
378          if ((c < 32 && (c != '\n' && c != '\t')) 
379              || (c == '=') 
380              || (c >= 127) 
381  
382         /* 
383           * Following line is to avoid single periods alone on lines, which 
384           * messes up some dumb smtp implementations, sigh... 
385           */ 
386              || (ct == 0 && c == '.')) { 
387              putc('=', outfile); 
388              putc(basis_hex[c >> 4], outfile); 
389              putc(basis_hex[c & 0xF], outfile); 
390              ct += 3; 
391              prevc = 'A'; /* close enough */ 
392          } else if (c == '\n') { 
393              if (prevc == ' ' || prevc == '\t') { 
394                  putc('=', outfile); /* soft & hard lines */ 
395                  putc(c, outfile); 
396              } 
397              putc(c, outfile); 
398              ct = 0; 
399              prevc = c; 
400          } else { 
401              if (c == 'F' && prevc == '\n') { 
402  
403                 /* 
404                   * HORRIBLE but clever hack suggested by MTR for 
405                   * sendmail-avoidance 
406                   */ 
407                  c = getc(infile); 
408                  if (c == 'r') { 
409                      c = getc(infile); 
410                      if (c == 'o') { 
411                          c = getc(infile); 
412                          if (c == 'm') { 
413                              c = getc(infile); 
414                              if (c == ' ') { 
415                                  /* This is the case we are looking for */ 
416                                  fputs("=46rom", outfile); 
417                                  ct += 6; 
418                              } else { 
419                                  fputs("From", outfile); 
420                                  ct += 4; 
421                              } 
422                          } else { 
423                              fputs("Fro", outfile); 
424                              ct += 3; 
425                          } 
426                      } else { 
427                          fputs("Fr", outfile); 
428                          ct += 2; 
429                      } 
430                  } else { 
431                      putc('F', outfile); 
432                      ++ct; 
433                  } 
434                  ungetc(c, infile); 
435                  prevc = 'x'; /* close enough -- printable */ 
436              } else { /* END horrible hack */ 
437                  putc(c, outfile); 
438                  ++ct; 
439                  prevc = c; 
440              } 
441          } 
442          if (ct > 72) { 
443              putc('=', outfile); 
444              putc('\r', outfile); /* XXX */ 
445              putc('\n', outfile); 
446              ct = 0; 
447              prevc = '\n'; 
448          } 
449      } 
450      if (ct) { 
451          putc('=', outfile); 
452          putc('\r', outfile); /* XXX */ 
453          putc('\n', outfile); 
454      } 
455  }