/[anubis]/anubis/testsuite/mta.c
ViewVC logotype

Diff of /anubis/testsuite/mta.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by polak, Wed Feb 19 17:39:25 2003 UTC revision 1.4 by gray, Tue May 27 19:52:21 2003 UTC
# Line 63  Line 63 
63  #include <string.h>  #include <string.h>
64  #include <stdarg.h>  #include <stdarg.h>
65  #include <ctype.h>  #include <ctype.h>
66    #include <fcntl.h>
67    
68  #include <pwd.h>  #include <pwd.h>
69  #include <sys/stat.h>  #include <sys/stat.h>
# Line 70  Line 71 
71  #include <sys/socket.h>  #include <sys/socket.h>
72  #include <netinet/in.h>  #include <netinet/in.h>
73    
74    #if defined(HAVE_LIBGCRYPT) && defined(HAVE_LIBGNUTLS) && defined(HAVE_GNUTLS_GNUTLS_H)
75    # define HAVE_GNUTLS
76    #endif
77    #if defined(USE_GNUTLS) && defined(HAVE_GNUTLS)
78    # include <gnutls/gnutls.h>
79    # define HAVE_TLS
80    #endif /* USE_GNUTLS and HAVE_GNUTLS */
81    
82  FILE *diag = NULL;       /* diagnostic output */  FILE *diag = NULL;       /* diagnostic output */
83  int port = 0;            /* Port number (for smtp mode) */  int port = 0;            /* Port number (for smtp mode) */
84    
85    #ifdef HAVE_TLS
86    char *tls_cert;          /* TLS sertificate */
87    char *tls_key;           /* TLS key */
88    char *tls_cafile;
89    
90    #define enable_tls() (tls_cafile != NULL || (tls_cert != NULL && tls_key != NULL))
91    
92    #define DH_BITS 768
93    
94    gnutls_dh_params dh_params;
95    static gnutls_certificate_server_credentials x509_cred;
96    #endif
97    
98  char *progname;  char *progname;
99    
100  int mta_daemon(int, char **);  int mta_daemon(int, char **);
# Line 80  int mta_stdio(int, char **); Line 102  int mta_stdio(int, char **);
102  void error(const char *, ...);  void error(const char *, ...);
103  void smtp_reply(int, char *, ...);  void smtp_reply(int, char *, ...);
104    
105    #define R_CONT     0x8000
106    #define R_CODEMASK 0xfff
107    
108  int  int
109  main (int argc, char **argv)  main (int argc, char **argv)
110  {  {
# Line 94  main (int argc, char **argv) Line 119  main (int argc, char **argv)
119          else          else
120                  progname++;                  progname++;
121                                    
122          while ((c = getopt(argc, argv, "ab:d:p:")) != EOF) {          while ((c = getopt(argc, argv, "ac:C:b:d:k:p:")) != EOF) {
123                  switch (c) {                  switch (c) {
124                  case 'a':                  case 'a':
125                          append = 1;                          append = 1;
# Line 116  main (int argc, char **argv) Line 141  main (int argc, char **argv)
141                          }                          }
142                          break;                          break;
143    
144    #ifdef HAVE_TLS
145                    case 'c':
146                            tls_cert = optarg;
147                            break;
148                    case 'C':
149                            tls_cafile = optarg;
150                            break;
151                    case 'k':
152                            tls_key = optarg;
153                            break;
154    #endif
155                            
156                  case 'd':                  case 'd':
157                          diag_name = optarg;                          diag_name = optarg;
158                          break;                          break;
# Line 149  main (int argc, char **argv) Line 186  main (int argc, char **argv)
186                  error("use either -bs or -bd");                  error("use either -bs or -bd");
187                  exit(1);                  exit(1);
188          }          }
189    
190    #ifdef HAVE_TLS
191            tls_init();
192    #endif
193          status = mta_mode(argc, argv);          status = mta_mode(argc, argv);
194    
195          if (diag)          if (diag)
# Line 169  error(const char *fmt, ...) Line 210  error(const char *fmt, ...)
210          va_end(ap);          va_end(ap);
211  }  }
212    
213  static FILE *in, *out;  static void *in, *out;
214    
215    static const char *
216    _def_strerror(int rc)
217    {
218            return strerror(rc);
219    }
220    
221    static int
222    _def_write(void *sd, char *data, size_t size, size_t *nbytes)
223    {
224            int n = write((int)sd, data, size);
225            if (n != size)
226                    return errno;
227            if (nbytes)
228                    *nbytes = n;
229            return 0;
230    }
231    
232    static int
233    _def_read(void *sd, char *data, size_t size, size_t *nbytes)
234    {
235            int n = read((int)sd, data, size);
236            if (n != size)
237                    return errno;
238            if (nbytes)
239                    *nbytes = n;
240            return 0;
241    }
242    
243    static int
244    _def_close(void *sd)
245    {
246            return close((int)sd);
247    }
248    
249    int (*_mta_read)(void *, char *, size_t, size_t *) = _def_read;
250    int (*_mta_write)(void *, char *, size_t, size_t *) = _def_write;
251    int (*_mta_close)(void *) = _def_close;
252    const char *(*_mta_strerror)(int) = _def_strerror;
253    
254    #ifdef HAVE_TLS
255    
256    static void
257    _tls_cleanup_x509()
258    {
259            if (x509_cred)
260                    gnutls_certificate_free_credentials(x509_cred);
261    }
262    
263    static void
264    generate_dh_params(void)
265    {
266            gnutls_datum prime, generator;
267    
268            gnutls_dh_params_init(&dh_params);
269            gnutls_dh_params_generate(&prime, &generator, DH_BITS);
270            gnutls_dh_params_set(dh_params, prime, generator, DH_BITS);
271    
272            free(prime.data);
273            free(generator.data);
274            return;
275    }
276    
277    void
278    tls_init()
279    {
280            if (!enable_tls())
281                    return;
282            gnutls_global_init();
283            atexit(gnutls_global_deinit);
284            gnutls_certificate_allocate_credentials(&x509_cred);
285            atexit(_tls_cleanup_x509);
286            if (tls_cafile) {
287                    int rc = gnutls_certificate_set_x509_trust_file(x509_cred,
288    
289                                                                    tls_cafile,
290                                                                GNUTLS_X509_FMT_PEM);
291                    if (rc < 0) {
292                            gnutls_perror(rc);
293                            return;
294                    }
295            }
296            if (tls_cert && tls_key)
297                    gnutls_certificate_set_x509_key_file(x509_cred,
298                                                         tls_cert, tls_key,
299                                                         GNUTLS_X509_FMT_PEM);
300    
301            generate_dh_params();
302            gnutls_certificate_set_dh_params(x509_cred, dh_params);
303    }
304    
305    static ssize_t
306    _tls_fd_pull(gnutls_transport_ptr fd, void *buf, size_t size)
307    {
308            int rc;
309            do {
310                    rc = read(fd, buf, size);
311            } while (rc == -1 && errno == EAGAIN);
312            return rc;
313    }
314    
315    static ssize_t
316    _tls_fd_push(gnutls_transport_ptr fd, const void *buf, size_t size)
317    {
318            int rc;
319            do {
320                    rc = write(fd, buf, size);
321            } while (rc == -1 && errno == EAGAIN);
322            return rc;
323    }
324    
325    static const char *
326    _tls_strerror(int rc)
327    {
328            return gnutls_strerror(rc);
329    }
330    
331    static int
332    _tls_write(void *sd, char *data, size_t size, size_t *nbytes)
333    {
334            int rc;
335            
336            do
337                    rc = gnutls_record_send(sd, data, size);
338            while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
339            if (rc >= 0) {
340                    if (nbytes)
341                            *nbytes = rc;
342                    return 0;
343            }
344            return rc;
345    }
346    
347    static int
348    _tls_read(void *sd, char *data, size_t size, size_t *nbytes)
349    {
350            int rc = gnutls_record_recv(sd, data, size);
351            if (rc >= 0) {
352                    if (nbytes)
353                            *nbytes = rc;
354                    return 0;
355            }
356            return rc;
357    }
358    
359    static int
360    _tls_close(void *sd)
361    {
362            if (sd) {
363                    gnutls_bye(sd, GNUTLS_SHUT_RDWR);
364                    gnutls_deinit(sd);
365            }
366            return 0;
367    }
368    
369    static gnutls_session
370    tls_session_init(void)
371    {
372            gnutls_session session = 0;
373            int rc;
374            
375            gnutls_init(&session, GNUTLS_SERVER);
376            gnutls_set_default_priority(session);  
377            gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
378            gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUEST);
379            gnutls_dh_set_prime_bits(session, DH_BITS);
380    
381            gnutls_transport_set_pull_function(session, _tls_fd_pull);
382            gnutls_transport_set_push_function(session, _tls_fd_push);
383    
384            gnutls_transport_set_ptr2(session, (int)in, (int)out);
385            rc = gnutls_handshake(session);
386            if (rc < 0) {
387                    gnutls_deinit(session);
388                    gnutls_perror(rc);
389                    return 0;
390            }
391    
392            return (gnutls_session)session;
393    }
394    
395    void
396    smtp_starttls()
397    {
398            gnutls_session session;
399    
400            smtp_reply(220, "Ready to start TLS");
401            
402            session = tls_session_init();
403            if (session) {
404                    in = out = session;
405                    _mta_read = _tls_read;
406                    _mta_write = _tls_write;
407                    _mta_close = _tls_close;
408                    _mta_strerror = _tls_strerror;
409                    reset_capa("STARTTLS");
410            } else
411                    smtp_reply(530, "TLS negotiation failed");
412    }
413    
414    #endif
415    
416  void  void
417  smtp_reply(int code, char *fmt, ...)  smtp_reply(int code, char *fmt, ...)
418  {  {
419          va_list ap;          va_list ap;
420            int cont = code & R_CONT ? '-' : ' ';
421            static char obuf[512];
422            int n, rc;
423            
424          va_start(ap, fmt);          va_start(ap, fmt);
425          fprintf(out, "%d ", code);          n = snprintf(obuf, sizeof obuf, "%d%c", code & R_CODEMASK, cont);
426          vfprintf(out, fmt, ap);          n += vsnprintf(obuf + n, sizeof obuf - n, fmt, ap);
427          va_end(ap);          va_end(ap);
428          fprintf(out, "\r\n");          n += snprintf(obuf + n, sizeof obuf - n, "\r\n");
429            rc = _mta_write(out, obuf, n, NULL);
430            if (rc) {
431                    fprintf(stderr, "Write failed: %s", _mta_strerror(rc));
432                    abort();
433            }
434    }
435    
436    int
437    get_input_line(char *buf, size_t bufsize)
438    {
439            int i, rc;
440            
441            for (i = 0; i < bufsize-1; i++) {
442                    size_t n;
443                    rc = _mta_read(in, buf + i, 1, &n);
444                    if (rc) {
445                            fprintf(stderr, "Read failed: %s", _mta_strerror(rc));
446                            abort();
447                    }
448                    if (n == 0)
449                            break;
450                    if (buf[i] == '\n')
451                            break;
452            }
453            buf[++i] = 0;
454            return i;
455  }  }
456    
457  #define STATE_INIT   0  #define STATE_INIT   0
# Line 198  smtp_reply(int code, char *fmt, ...) Line 469  smtp_reply(int code, char *fmt, ...)
469  #define KW_DATA      4    #define KW_DATA      4  
470  #define KW_HELP      5  #define KW_HELP      5
471  #define KW_QUIT      6  #define KW_QUIT      6
472    #define KW_STARTTLS  7
473    
474  int  int
475  smtp_kw (const char *name)  smtp_kw (const char *name)
# Line 213  smtp_kw (const char *name) Line 485  smtp_kw (const char *name)
485                  { "data", KW_DATA },                  { "data", KW_DATA },
486                  { "help", KW_HELP },                  { "help", KW_HELP },
487                  { "quit", KW_QUIT },                  { "quit", KW_QUIT },
488                    { "help", KW_HELP },
489                    { "starttls", KW_STARTTLS },
490                  { NULL },                  { NULL },
491          };          };
492          int i;          int i;
# Line 271  argcv_free(int argc, char **argv) Line 545  argcv_free(int argc, char **argv)
545    return 1;    return 1;
546  }  }
547    
548    char *mta_capa[] = {
549    #if defined(HAVE_TLS)
550            "STARTTLS",
551    #endif
552            NULL
553    };
554    
555    void
556    reset_capa(char *name)
557    {
558            int i;
559            for (i = 0; mta_capa[i]; i++)
560                    if (strcmp(mta_capa[i], name) == 0) {
561                            mta_capa[i] = NULL;
562                            break;
563                    }
564    }
565    
566    void
567    smtp_ehlo(int extended)
568    {
569            int i;
570    
571            if (!extended) {
572                    smtp_reply(250,  "pleased to meet you");
573                    return;
574            }
575            
576            smtp_reply(R_CONT|250,  "pleased to meet you");
577            for (i = 0; mta_capa[i]; i++)
578                    smtp_reply(R_CONT|250, "%s", mta_capa[i]);
579            smtp_reply(250, "HELP");
580    }
581    
582    void
583    smtp_help()
584    {
585            smtp_reply(502, "HELP not implemented");
586    }
587    
588  void  void
589  smtp()  smtp()
590  {  {
591          int state;          int state;
592          char buf[128];          char buf[128];
     
         SETVBUF(in, NULL, _IOLBF, 0);  
         SETVBUF(out, NULL, _IOLBF, 0);  
593                                    
594          smtp_reply(220, "localhost bitbucket ready");          smtp_reply(220, "localhost bitbucket ready");
595          for (state = STATE_INIT; state != STATE_QUIT; ) {          for (state = STATE_INIT; state != STATE_QUIT; ) {
# Line 286  smtp() Line 597  smtp()
597                  char **argv;                  char **argv;
598                  int kw, len;                  int kw, len;
599                
600                  if (fgets(buf, sizeof buf, stdin) == NULL)                  if (get_input_line(buf, sizeof buf) <= 0)
601                          exit (1);                          exit (1);
602                                    
603                  len = strlen (buf);                  len = strlen (buf);
# Line 305  smtp() Line 616  smtp()
616                          state = STATE_QUIT;                          state = STATE_QUIT;
617                          argcv_free(argc, argv);                          argcv_free(argc, argv);
618                          continue;                          continue;
619                    } else if (kw == KW_HELP) {
620                            smtp_help();
621                            continue;
622                  }                  }
623                
624                  switch (state) {                  switch (state) {
# Line 313  smtp() Line 627  smtp()
627                          case KW_EHLO:                          case KW_EHLO:
628                          case KW_HELO:                          case KW_HELO:
629                                  if (argc == 2) {                                  if (argc == 2) {
630                                          smtp_reply(250,                                          smtp_ehlo(kw == KW_EHLO);
                                                    "pleased to meet you");  
631                                          state = STATE_EHLO;                                          state = STATE_EHLO;
632                                  } else                                  } else
633                                          smtp_reply(501,                                          smtp_reply(501,
# Line 330  smtp() Line 643  smtp()
643                        
644                  case STATE_EHLO:                  case STATE_EHLO:
645                          switch (kw) {                          switch (kw) {
646                            case KW_EHLO:
647                                    if (argc == 2) {
648                                            smtp_ehlo(1);
649                                    } else
650                                            smtp_reply(501,
651                                        "%s requires domain address", argv[0]);
652                                    break;
653                                    
654                          case KW_MAIL:                          case KW_MAIL:
655                                  if (argc == 3                                  if (argc == 3
656                                      && strcasecmp(argv[1], "from:") == 0) {                                      && strcasecmp(argv[1], "from:") == 0) {
# Line 339  smtp() Line 660  smtp()
660                                          smtp_reply(501, "Syntax error");                                          smtp_reply(501, "Syntax error");
661                                  break;                                  break;
662    
663    #if defined(HAVE_TLS)
664                            case KW_STARTTLS:
665                                    smtp_starttls();
666                                    break;
667    #endif  
668                          default:                          default:
669                                  smtp_reply(503, "Need MAIL command");                                  smtp_reply(503, "Need MAIL command");
670                          }                          }
# Line 459  mta_daemon(int argc, char **argv) Line 785  mta_daemon(int argc, char **argv)
785                          return 1;                          return 1;
786                  }                  }
787    
788                  in = fdopen(fd, "r");                  in = out = (void *)fd;
                 out = fdopen (fd, "w");  
789                  smtp();                  smtp();
790                  break;                  break;
791          }          }
# Line 471  mta_daemon(int argc, char **argv) Line 796  mta_daemon(int argc, char **argv)
796  int  int
797  mta_stdio(int argc, char **argv)  mta_stdio(int argc, char **argv)
798  {  {
799          in = stdin;          in = (void *) fileno(stdin);
800          out = stdout;          out = (void *) fileno(stdout);
801          smtp();          smtp();
802          return 0;          return 0;
803  }  }

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26