"Fossies" - the Fresh Open Source Software Archive

Member "libspf2-1.2.10/src/spfd/spfd.c" (28 Jan 2012, 20538 Bytes) of package /linux/privat/libspf2-1.2.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spfd.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * This program is free software; you can redistribute it and/or modify
    3  * it under the terms of either:
    4  * 
    5  *   a) The GNU Lesser General Public License as published by the Free
    6  *      Software Foundation; either version 2.1, or (at your option) any
    7  *      later version,
    8  * 
    9  *   OR
   10  * 
   11  *   b) The two-clause BSD license.
   12  *
   13  * These licenses can be found with the distribution in the file LICENSES
   14  *
   15  *
   16  *
   17  * This program is really a badly smashed together copy of spfquery.c and
   18  * the public domain "helloserver" example daemon.
   19  *
   20  * The original helloserver code contained the following copyright notice:
   21  *
   22  * HELLOSERVER.C - a 'Hello World' TCP/IP based server daemon
   23  *
   24  * Implements a skeleton of a single process iterative server
   25  * daemon.
   26  *
   27  * Wherever possible the code adheres to POSIX.
   28  *
   29  * David Gillies <daggillies@yahoo.com> Sep 2003
   30  *
   31  * Placed in the public domain. Unrestricted use or modification
   32  * of this code is permitted without attribution to the author.
   33  */
   34 
   35 
   36 #ifdef __GNUC__
   37 #define _GNU_SOURCE /* for strsignal() */
   38 #endif
   39 
   40 #ifdef HAVE_CONFIG_H
   41 # include "config.h"
   42 #endif
   43 
   44 #ifdef STDC_HEADERS
   45 # include <stdio.h>
   46 # include <stdlib.h>       /* malloc / free */
   47 # include <stddef.h>
   48 # include <stdarg.h>
   49 #endif
   50 
   51 #ifdef HAVE_SYS_TYPES_H
   52 #include <sys/types.h>    /* types (u_char .. etc..) */
   53 #endif
   54 
   55 #ifdef HAVE_INTTYPES_H
   56 #include <inttypes.h>
   57 #endif
   58 
   59 #ifdef HAVE_STRING_H
   60 # include <string.h>       /* strstr / strdup */
   61 #else
   62 # ifdef HAVE_STRINGS_H
   63 #  include <strings.h>       /* strstr / strdup */
   64 # endif
   65 #endif
   66 
   67 #ifdef HAVE_SYS_SOCKET_H
   68 # include <sys/socket.h>   /* inet_ functions / structs */
   69 #endif
   70 #ifdef HAVE_NETINET_IN_H
   71 # include <netinet/in.h>   /* inet_ functions / structs */
   72 #endif
   73 #ifdef HAVE_ARPA_INET_H
   74 # include <arpa/inet.h>    /* in_addr struct */
   75 #endif
   76 
   77 #ifdef HAVE_ARPA_NAMESER_H
   78 # include <arpa/nameser.h> /* DNS HEADER struct */
   79 #endif
   80 
   81 #include <sys/types.h>
   82 
   83 #ifdef HAVE_PWD_H
   84 #include <pwd.h>
   85 #endif
   86 
   87 #ifdef HAVE_GRP_H
   88 #include <grp.h>
   89 #endif
   90 
   91 #ifdef HAVE_GETOPT_LONG_ONLY
   92 #define _GNU_SOURCE
   93 #include <getopt.h>
   94 #else
   95 #include "libreplace/getopt.h"
   96 #endif
   97 
   98 #include <unistd.h>
   99 #include <netdb.h>
  100 #include <fcntl.h>
  101 #include <time.h>
  102 #include <signal.h>
  103 #include <syslog.h>
  104 #include <errno.h>
  105 #include <sys/types.h>
  106 #include <sys/stat.h>
  107 #include <sys/socket.h>
  108 #include <sys/un.h>
  109 #include <netinet/in.h>
  110 #include <ctype.h>
  111 #include <sys/wait.h>
  112 
  113 #include <pthread.h>
  114 
  115 #include "spf.h"
  116 #include "spf_dns.h"
  117 #include "spf_dns_null.h"
  118 #include "spf_dns_resolv.h"
  119 #include "spf_dns_test.h"
  120 #include "spf_dns_cache.h"
  121 
  122 
  123 #define TRUE 1
  124 #define FALSE 0
  125 
  126 #define bool int
  127 
  128 #define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
  129 #define FREE_REQUEST(x) FREE((x), SPF_request_free)
  130 #define FREE_RESPONSE(x) FREE((x), SPF_response_free)
  131 #define FREE_STRING(x) FREE((x), free)
  132 
  133 typedef
  134 struct _config_t {
  135     int      tcpport;
  136     int      udpport;
  137     char    *path;
  138 #ifdef HAVE_PWD_H
  139     uid_t    pathuser;
  140 #endif
  141 #ifdef HAVE_GRP_H
  142     gid_t    pathgroup;
  143 #endif
  144     int      pathmode;
  145 #ifdef HAVE_PWD_H
  146     uid_t    setuser;
  147 #endif
  148 #ifdef HAVE_GRP_H
  149     gid_t    setgroup;
  150 #endif
  151 
  152     int      debug;
  153     bool     sec_mx;
  154     char    *fallback;
  155 
  156     char    *rec_dom;
  157     bool     sanitize;
  158     int      max_lookup;
  159     char    *localpolicy;
  160     bool     use_trusted;
  161     char    *explanation;
  162 } config_t;
  163 
  164 typedef
  165 struct _request_t {
  166     int      sock;
  167     union {
  168         struct sockaddr_in  in;
  169         struct sockaddr_un  un;
  170     } addr;
  171     socklen_t    addrlen;
  172     char        *data;
  173     int          datalen;
  174 
  175     char        *ip;
  176     char        *helo;
  177     char        *sender;
  178     char        *rcpt_to;
  179 
  180     SPF_errcode_t    spf_err;
  181     SPF_request_t   *spf_request;
  182     SPF_response_t  *spf_response;
  183 
  184     char         fmt[4096];
  185     int          fmtlen;
  186 } request_t;
  187 
  188 typedef
  189 struct _state_t {
  190     int sock_udp;
  191     int sock_tcp;
  192     int sock_unix;
  193 } state_t;
  194 
  195 static SPF_server_t *spf_server;
  196 static config_t      spfd_config;
  197 static state_t       spfd_state;
  198 
  199 static void
  200 response_print_errors(const char *context,
  201                 SPF_response_t *spf_response, SPF_errcode_t err)
  202 {
  203     SPF_error_t *spf_error;
  204     int          i;
  205 
  206     if (context != NULL)
  207         printf("Context: %s\n", context);
  208     if (err != SPF_E_SUCCESS)
  209         printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
  210 
  211     if (spf_response != NULL) {
  212         for (i = 0; i < SPF_response_messages(spf_response); i++) {
  213             spf_error = SPF_response_message(spf_response, i);
  214             printf( "%s: %s%s\n",
  215                     SPF_error_errorp(spf_error) ? "Error" : "Warning",
  216                     ((SPF_error_errorp(spf_error) && (!err))
  217                             ? "[UNRETURNED] "
  218                             : ""),
  219                     SPF_error_message(spf_error) );
  220         }
  221     }
  222     else {
  223         printf("Error: libspf2 gave a NULL spf_response");
  224     }
  225 }
  226 
  227 static void
  228 response_print(const char *context, SPF_response_t *spf_response)
  229 {
  230     printf("--vv--\n");
  231     printf("Context: %s\n", context);
  232     if (spf_response == NULL) {
  233         printf("NULL RESPONSE!\n");
  234     }
  235     else {
  236         printf("Response result: %s\n",
  237                     SPF_strresult(SPF_response_result(spf_response)));
  238         printf("Response reason: %s\n",
  239                     SPF_strreason(SPF_response_reason(spf_response)));
  240         printf("Response err: %s\n",
  241                     SPF_strerror(SPF_response_errcode(spf_response)));
  242         response_print_errors(NULL, spf_response,
  243                         SPF_response_errcode(spf_response));
  244     }
  245     printf("--^^--\n");
  246 }
  247 
  248 static const char *
  249 request_check(request_t *req)
  250 {
  251     const char  *msg = NULL;
  252     if (!req->ip)
  253         msg = "No IP address given";
  254     else if (!req->sender)
  255         msg = "No sender address given";
  256     else
  257         return NULL;
  258     snprintf(req->fmt, 4095,
  259         "result=unknown\n"
  260         "reason=%s\n",
  261         msg);
  262     return msg;
  263 }
  264 
  265 static void
  266 request_query(request_t *req)
  267 {
  268     SPF_request_t   *spf_request = NULL;
  269     SPF_response_t  *spf_response = NULL;
  270     SPF_response_t  *spf_response_2mx = NULL;
  271     SPF_errcode_t    err;
  272     char            *p, *p_end;
  273 
  274 #define UNLESS(x) err = (x); if (err)
  275 // #define FAIL(x) do { response_print_errors((x), spf_response, err); goto fail; } while(0)
  276 #define FAIL(x) do { goto fail; } while(0)
  277 #define WARN(x, r) response_print_errors((x), (r), err)
  278 
  279     spf_request = SPF_request_new(spf_server);
  280 
  281     if (strchr(req->ip, ':')) {
  282         UNLESS(SPF_request_set_ipv6_str(spf_request, req->ip)) {
  283             FAIL("Setting IPv6 address");
  284         }
  285     }
  286     else {
  287         UNLESS(SPF_request_set_ipv4_str(spf_request, req->ip)) {
  288             FAIL("Setting IPv4 address");
  289         }
  290     }
  291 
  292     if (req->helo) {
  293         UNLESS(SPF_request_set_helo_dom(spf_request, req->helo)) {
  294             FAIL("Failed to set HELO domain");
  295         }
  296         /* XXX Set some flag saying to query on helo */
  297     }
  298 
  299     if (req->sender) {
  300         UNLESS(SPF_request_set_env_from(spf_request, req->sender)) {
  301             FAIL("Failed to set envelope-from address");
  302         }
  303         /* XXX Set some flag saying to query on sender */
  304     }
  305 
  306     /* XXX If flag not set, FAIL() */
  307 
  308     UNLESS(SPF_request_query_mailfrom(spf_request, &spf_response)) {
  309         FAIL("Failed to query based on mail-from address");
  310     }
  311 
  312     if (spfd_config.sec_mx) {
  313         if (req->rcpt_to && *req->rcpt_to) {
  314             p = req->rcpt_to;
  315             p_end = p + strcspn(p, " ,;");
  316             while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
  317                 if (*p_end)
  318                     *p_end = '\0';
  319                 else
  320                     p_end = NULL;   /* Note this is last rcpt */
  321                 UNLESS(SPF_request_query_rcptto(spf_request,
  322                                 &spf_response_2mx, p)) {
  323                     WARN("Failed to query based on 2mx recipient",
  324                                     spf_response_2mx);
  325                     FREE_RESPONSE(spf_response_2mx);
  326                 }
  327                 else {
  328                     spf_response = SPF_response_combine(spf_response,
  329                                     spf_response_2mx);
  330                     spf_response_2mx = NULL;    /* freed */
  331                 }
  332 
  333                 if (!p_end)
  334                     break;
  335                 p = p_end + 1;
  336             }
  337         }
  338     }
  339 
  340     if (spfd_config.fallback) {
  341         UNLESS(SPF_request_query_fallback(spf_request,
  342                         &spf_response, spfd_config.fallback)) {
  343             FAIL("Querying fallback record");
  344         }
  345     }
  346 
  347     goto ok;
  348 
  349 fail:
  350     req->spf_err = err;
  351     FREE_RESPONSE(spf_response);
  352     FREE_REQUEST(spf_request);
  353 
  354 ok:
  355     // response_print("Result: ", spf_response);
  356     (void)response_print;
  357 
  358     req->spf_response = spf_response;
  359     req->spf_request = spf_request;
  360 }
  361 
  362 /* This is needed on HP/UX, IIRC */
  363 static inline const char *
  364 W(const char *c)
  365 {
  366     if (c)
  367         return c;
  368     return "(null)";
  369 }
  370 
  371 static void
  372 request_format(request_t *req)
  373 {
  374     SPF_response_t  *spf_response;
  375 
  376     spf_response = req->spf_response;
  377 
  378     if (spf_response) {
  379         req->fmtlen = snprintf(req->fmt, 4095,
  380             "ip=%s\n"
  381             "sender=%s\n"
  382             "result=%s\n"
  383             "reason=%s\n"
  384             "smtp_comment=%s\n"
  385             "header_comment=%s\n"
  386             "error=%s\n"
  387             , req->ip, req->sender
  388             , W(SPF_strresult(SPF_response_result(spf_response)))
  389             , W(SPF_strreason(SPF_response_reason(spf_response)))
  390             , W(SPF_response_get_smtp_comment(spf_response))
  391             , W(SPF_response_get_header_comment(spf_response))
  392             , W(SPF_strerror(SPF_response_errcode(spf_response)))
  393             );
  394     }
  395     else {
  396         req->fmtlen = snprintf(req->fmt, 4095,
  397             "ip=%s\n"
  398             "sender=%s\n"
  399             "result=unknown\n"
  400             "error=%s\n"
  401             , req->ip, req->sender
  402             , SPF_strerror(req->spf_err)
  403             );
  404     }
  405 
  406     req->fmt[4095] = '\0';
  407 }
  408 
  409 static void
  410 request_handle(request_t *req)
  411 {
  412     printf("| %s\n", req->sender); fflush(stdout);
  413     if (!request_check(req)) {
  414         request_query(req);
  415         request_format(req);
  416     }
  417     // printf("==\n%s\n", req->fmt);
  418 }
  419 
  420 static const struct option longopts[] = {
  421     { "debug",      required_argument,  NULL,   'd', },
  422     { "tcpport",    required_argument,  NULL,   't', },
  423     { "udpport",    required_argument,  NULL,   'p', },
  424     { "path",       required_argument,  NULL,   'f', },
  425 #ifdef HAVE_PWD_H
  426     { "pathuser",   required_argument,  NULL,   'x', },
  427 #endif
  428 #ifdef HAVE_GRP_H
  429     { "pathgroup",  required_argument,  NULL,   'y', },
  430 #endif
  431     { "pathmode",   required_argument,  NULL,   'm', },
  432 #ifdef HAVE_PWD_H
  433     { "setuser",    required_argument,  NULL,   'u', },
  434 #endif
  435 #ifdef HAVE_GRP_H
  436     { "setgroup",   required_argument,  NULL,   'g', },
  437 #endif
  438     { "help",       no_argument,        NULL,   'h', },
  439 };
  440 
  441 static const char *shortopts = "d:t:p:f:x:y:m:u:g:h:";
  442 
  443 void usage (void) {
  444     fprintf(stdout,"Flags\n");
  445     fprintf(stdout,"\t-tcpport\n");
  446     fprintf(stdout,"\t-udpport\n");
  447     fprintf(stdout,"\t-path\n");
  448 #ifdef HAVE_PWD_H
  449     fprintf(stdout,"\t-pathuser\n");
  450 #endif
  451 #ifdef HAVE_GRP_H
  452     fprintf(stdout,"\t-pathgroup\n");
  453 #endif
  454     fprintf(stdout,"\t-pathmode\n");
  455 #ifdef HAVE_PWD_H
  456     fprintf(stdout,"\t-setuser\n");
  457 #endif
  458 #ifdef HAVE_GRP_H
  459     fprintf(stdout,"\t-setgroup\n");
  460 #endif
  461     fprintf(stdout,"\t-help\n");
  462 
  463 }
  464 
  465 #define DIE(x) do { fprintf(stderr, "%s\n", x); exit(1); } while(0)
  466 
  467 #ifdef HAVE_PWD_H
  468 static gid_t
  469 daemon_get_user(const char *arg)
  470 {
  471     struct passwd   *pwd;
  472     if (isdigit(arg[0]))
  473         pwd = getpwuid(atol(arg));
  474     else
  475         pwd = getpwnam(arg);
  476     if (pwd == NULL) {
  477         fprintf(stderr, "Failed to find user %s\n", arg);
  478         DIE("Unknown user");
  479     }
  480     return pwd->pw_uid;
  481 }
  482 #endif
  483 
  484 #ifdef HAVE_GRP_H
  485 static gid_t
  486 daemon_get_group(const char *arg)
  487 {
  488     struct group    *grp;
  489     if (isdigit(arg[0]))
  490         grp = getgrgid(atol(arg));
  491     else
  492         grp = getgrnam(arg);
  493     if (grp == NULL) {
  494         fprintf(stderr, "Failed to find user %s\n", arg);
  495         DIE("Unknown group");
  496     }
  497     return grp->gr_gid;
  498 }
  499 #endif
  500 
  501 static void
  502 daemon_config(int argc, char *argv[])
  503 {
  504     int      idx;
  505     char     c;
  506 
  507     memset(&spfd_config, 0, sizeof(spfd_config));
  508 
  509     while ((c =
  510         getopt_long(argc, argv, shortopts, longopts, &idx)
  511             ) != -1) {
  512         switch (c) {
  513             case 't':
  514                 spfd_config.tcpport = atol(optarg);
  515                 break;
  516             case 'p':
  517                 spfd_config.udpport = atol(optarg);
  518                 break;
  519             case 'f':
  520                 spfd_config.path = optarg;
  521                 break;
  522 
  523             case 'd':
  524                 spfd_config.debug = atol(optarg);
  525                 break;
  526 
  527 #ifdef HAVE_PWD_H
  528             case 'x':
  529                 spfd_config.pathuser = daemon_get_user(optarg);
  530                 break;
  531 #endif
  532 #ifdef HAVE_GRP_H
  533             case 'y':
  534                 spfd_config.pathgroup = daemon_get_group(optarg);
  535                 break;
  536 #endif
  537 
  538             case 'm':
  539                 spfd_config.pathmode = atol(optarg);
  540                 break;
  541 
  542 #ifdef HAVE_PWD_H
  543             case 'u':
  544                 spfd_config.setuser = daemon_get_user(optarg);
  545                 break;
  546 #endif
  547 #ifdef HAVE_GRP_H
  548             case 'g':
  549                 spfd_config.setgroup = daemon_get_group(optarg);
  550                 break;
  551 #endif
  552 
  553             case 0:
  554             case '?':
  555                 usage();
  556                 DIE("Invalid argument");
  557                 break;
  558             case 'h' :
  559                 usage();
  560                 DIE("");
  561                 break;
  562 
  563             default:
  564                 fprintf(stderr, "Error: getopt returned character code 0%o ??\n", c);
  565                 DIE("WHAT?");
  566         }
  567     }
  568 }
  569 
  570 static int
  571 daemon_bind_inet_udp()
  572 {
  573     struct sockaddr_in   addr;
  574     int                  sock;
  575 
  576     if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
  577         perror("socket");
  578         DIE("Failed to create socket");
  579     }
  580     memset(&addr, 0, sizeof(addr));
  581     addr.sin_family = AF_INET;
  582     addr.sin_port = htons(spfd_config.udpport);
  583     addr.sin_addr.s_addr = INADDR_ANY;
  584     if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
  585         perror("bind");
  586         DIE("Failed to bind socket");
  587     }
  588 
  589     fprintf(stderr, "Accepting datagrams on %d\n", spfd_config.udpport);
  590 
  591     return sock;
  592 }
  593 
  594 static int
  595 daemon_bind_inet_tcp()
  596 {
  597     struct sockaddr_in   addr;
  598     int                  sock;
  599 
  600     int                  optval;
  601     size_t               optlen;
  602 
  603     if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  604         perror("socket");
  605         DIE("Failed to create socket");
  606     }
  607 
  608     optval = 1;
  609     optlen = sizeof(int);
  610     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
  611 
  612     memset(&addr, 0, sizeof(addr));
  613     addr.sin_family = AF_INET;
  614     addr.sin_port = htons(spfd_config.tcpport);
  615     addr.sin_addr.s_addr = INADDR_ANY;
  616     if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
  617         perror("bind");
  618         DIE("Failed to bind socket");
  619     }
  620 
  621     if (listen(sock, 5) < 0) {
  622         perror("listen");
  623         DIE("Failed to listen on socket");
  624     }
  625 
  626     fprintf(stderr, "Accepting connections on %d\n", spfd_config.tcpport);
  627 
  628     return sock;
  629 }
  630 
  631 static int
  632 daemon_bind_unix()
  633 {
  634     struct sockaddr_un   addr;
  635     int                  sock;
  636 
  637     if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
  638         perror("socket");
  639         DIE("Failed to create socket");
  640     }
  641     memset(&addr, 0, sizeof(addr));
  642     addr.sun_family = AF_UNIX;
  643     strncpy(addr.sun_path, spfd_config.path, sizeof(addr.sun_path) - 1);
  644     if (unlink(spfd_config.path) < 0) {
  645         if (errno != ENOENT) {
  646             perror("unlink");
  647             DIE("Failed to unlink socket");
  648         }
  649     }
  650     if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
  651         perror("bind");
  652         DIE("Failed to bind socket");
  653     }
  654     if (listen(sock, 5) < 0) {
  655         perror("listen");
  656         DIE("Failed to listen on socket");
  657     }
  658 
  659     fprintf(stderr, "Accepting connections on %s\n", spfd_config.path);
  660 
  661     return sock;
  662 }
  663 
  664 static void
  665 daemon_init()
  666 {
  667     SPF_response_t  *spf_response = NULL;
  668     SPF_errcode_t    err;
  669 
  670     memset(&spfd_state, 0, sizeof(spfd_state));
  671 
  672     spf_server = SPF_server_new(SPF_DNS_CACHE, spfd_config.debug);
  673 
  674     if (spfd_config.rec_dom) {
  675         UNLESS(SPF_server_set_rec_dom(spf_server,
  676                         spfd_config.rec_dom)) {
  677             DIE("Failed to set receiving domain name");
  678         }
  679     }
  680 
  681     if (spfd_config.sanitize) {
  682         UNLESS(SPF_server_set_sanitize(spf_server,
  683                         spfd_config.sanitize)) {
  684             DIE("Failed to set server sanitize flag");
  685         }
  686     }
  687 
  688     if (spfd_config.max_lookup) {
  689         UNLESS(SPF_server_set_max_dns_mech(spf_server,
  690                         spfd_config.max_lookup)){
  691             DIE("Failed to set maximum DNS requests");
  692         }
  693     }
  694 
  695     if (spfd_config.localpolicy) {
  696         UNLESS(SPF_server_set_localpolicy(spf_server,
  697                         spfd_config.localpolicy,
  698                         spfd_config.use_trusted,
  699                         &spf_response)){
  700             response_print_errors("Compiling local policy",
  701                             spf_response, err);
  702             DIE("Failed to set local policy");
  703         }
  704         FREE_RESPONSE(spf_response);
  705     }
  706 
  707     if (spfd_config.explanation) {
  708         UNLESS(SPF_server_set_explanation(spf_server,
  709                         spfd_config.explanation,
  710                         &spf_response)){
  711             response_print_errors("Setting default explanation",
  712                             spf_response, err);
  713             DIE("Failed to set default explanation");
  714         }
  715         FREE_RESPONSE(spf_response);
  716     }
  717 
  718     if (spfd_config.udpport)
  719         spfd_state.sock_udp = daemon_bind_inet_udp();
  720     if (spfd_config.tcpport)
  721         spfd_state.sock_tcp = daemon_bind_inet_tcp();
  722     if (spfd_config.path)
  723         spfd_state.sock_unix = daemon_bind_unix();
  724     /* XXX Die if none of the above. */
  725 }
  726 
  727 /* This has a return value so we can decide whether to malloc and/or
  728  * free in the caller. */
  729 static char **
  730 find_field(request_t *req, const char *key)
  731 {
  732 #define STREQ(a, b) (strcmp((a), (b)) == 0)
  733 
  734     if (STREQ(key, "ip"))
  735         return &req->ip;
  736     if (STREQ(key, "helo"))
  737         return &req->helo;
  738     if (STREQ(key, "sender"))
  739         return &req->sender;
  740     if (STREQ(key, "rcpt"))
  741         return &req->rcpt_to;
  742     fprintf(stderr, "Invalid key %s\n", key);
  743     return NULL;
  744 }
  745 
  746 /* This is called with req->data malloc'd */
  747 static void *
  748 handle_datagram(void *arg)
  749 {
  750     request_t   *req;
  751     char        **fp;
  752     char        *key;
  753     char        *value;
  754     char        *end;
  755     int          err;
  756 
  757     req = (request_t *)arg;
  758     key = req->data;
  759 
  760     // printf("req: %s\n", key);
  761 
  762     while (key < (req->data + req->datalen)) {
  763         end = key + strcspn(key, "\r\n");
  764         *end = '\0';
  765         value = strchr(key, '=');
  766 
  767         /* Did that line contain an '='? */
  768         if (!value) /* XXX WARN */
  769             continue;
  770 
  771         *value++ = '\0';
  772         fp = find_field(req, key);
  773         if (fp != NULL)
  774             *fp = value;
  775         else
  776             /* warned already */ ;
  777 
  778         key = end + 1;
  779         while (key < (req->data + req->datalen)) {
  780             if (strchr("\r\n", *key))
  781                 key++;
  782             else
  783                 break;
  784         }
  785     }
  786 
  787     request_handle(req);
  788 
  789 #ifdef DEBUG
  790     printf("Target address length is %d: %s:%d\n", req->addrlen,
  791                     inet_ntoa(req->addr.in.sin_addr),
  792                     req->addr.in.sin_port);
  793 #endif
  794 
  795     printf("- %s\n", req->sender); fflush(stdout);
  796     err = sendto(req->sock, req->fmt, req->fmtlen, 0,
  797             (struct sockaddr *)(&req->addr.in), req->addrlen);
  798     if (err == -1)
  799         perror("sendto");
  800 
  801     FREE_RESPONSE(req->spf_response);
  802     FREE_REQUEST(req->spf_request);
  803 
  804     FREE_STRING(req->data);
  805     free(arg);
  806     return NULL;
  807 }
  808 
  809 /* Only req is malloc'd in this. */
  810 static void *
  811 handle_stream(void *arg)
  812 {
  813     request_t   *req;
  814     char        **fp;
  815     FILE        *stream;
  816     char         key[BUFSIZ];
  817     char        *value;
  818     char        *end;
  819 
  820     req = (request_t *)arg;
  821     stream = fdopen(req->sock, "r");
  822 
  823     do {
  824         while (fgets(key, BUFSIZ, stream) != NULL) {
  825             key[strcspn(key, "\r\n")] = '\0';
  826 
  827             /* Break on a blank line and permit another query */
  828             if (*key == '\0')
  829                 break;
  830 
  831             end = key + strcspn(key, "\r\n");
  832             *end = '\0';
  833             value = strchr(key, '=');
  834 
  835             if (!value) /* XXX WARN */
  836                 continue;
  837 
  838             *value++ = '\0';
  839             fp = find_field(req, key);
  840             if (fp != NULL)
  841                 *fp = strdup(value);
  842             else
  843                 /* warned already */ ;
  844         }
  845 
  846         request_handle(req);
  847 
  848         printf("- %s\n", req->sender); fflush(stdout);
  849         send(req->sock, req->fmt, req->fmtlen, 0);
  850 
  851         FREE_STRING(req->ip);
  852         FREE_STRING(req->helo);
  853         FREE_STRING(req->sender);
  854         FREE_STRING(req->rcpt_to);
  855     } while (!feof(stream));
  856 
  857     free(arg);
  858     return NULL;
  859 }
  860 
  861 static void
  862 daemon_main()
  863 {
  864     pthread_attr_t   attr;
  865     pthread_t        th;
  866 
  867     request_t       *req;
  868     char             buf[4096];
  869     fd_set           rfd;
  870     fd_set           sfd;
  871     int              maxfd;
  872 
  873 
  874     pthread_attr_init(&attr);
  875     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  876 
  877     FD_ZERO(&rfd);
  878     maxfd = 0;
  879 
  880     if (spfd_state.sock_udp) {
  881         // printf("UDP socket is %d\n", spfd_state.sock_udp);
  882         FD_SET(spfd_state.sock_udp, &rfd);
  883         if (spfd_state.sock_udp > maxfd)
  884             maxfd = spfd_state.sock_udp;
  885     }
  886     if (spfd_state.sock_tcp) {
  887         // printf("TCP socket is %d\n", spfd_state.sock_tcp);
  888         FD_SET(spfd_state.sock_tcp, &rfd);
  889         if (spfd_state.sock_tcp > maxfd)
  890             maxfd = spfd_state.sock_tcp;
  891     }
  892     if (spfd_state.sock_unix) {
  893         // printf("UNIX socket is %d\n", spfd_state.sock_unix);
  894         FD_SET(spfd_state.sock_unix, &rfd);
  895         if (spfd_state.sock_unix > maxfd)
  896             maxfd = spfd_state.sock_unix;
  897     }
  898     // printf("MaxFD is %d\n", maxfd);
  899 
  900 #define NEW_REQUEST ((request_t *)calloc(1, sizeof(request_t)));
  901 
  902     for (;;) {
  903         memcpy(&sfd, &rfd, sizeof(rfd));
  904         if (select(maxfd + 1, &sfd, NULL, NULL, NULL) == -1)
  905             break;
  906 
  907         if (spfd_state.sock_udp) {
  908             if (FD_ISSET(spfd_state.sock_udp, &sfd)) {
  909                 req = NEW_REQUEST;
  910                 req->addrlen = sizeof(req->addr);
  911                 // printf("UDP\n");
  912                 req->sock = spfd_state.sock_udp;
  913                 req->datalen = recvfrom(spfd_state.sock_udp, buf,4095,0,
  914                     (struct sockaddr *)(&req->addr.in), &req->addrlen);
  915                 if (req->datalen >= 0) {
  916                     buf[req->datalen] = '\0';
  917                     req->data = strdup(buf);
  918                     pthread_create(&th, &attr, handle_datagram, req);
  919                 }
  920                 else {
  921                     free(req);
  922                 }
  923             }
  924         }
  925         if (spfd_state.sock_tcp) {
  926             if (FD_ISSET(spfd_state.sock_tcp, &sfd)) {
  927                 req = NEW_REQUEST;
  928                 req->addrlen = sizeof(req->addr);
  929                 // printf("TCP\n");
  930                 req->sock = accept(spfd_state.sock_tcp,
  931                     (struct sockaddr *)(&req->addr.in), &req->addrlen);
  932                 if (req->sock >= 0)
  933                     pthread_create(&th, &attr, handle_stream, req);
  934                 else
  935                     free(req);
  936             }
  937         }
  938         if (spfd_state.sock_unix) {
  939             if (FD_ISSET(spfd_state.sock_unix, &sfd)) {
  940                 req = NEW_REQUEST;
  941                 req->addrlen = sizeof(req->addr);
  942                 // printf("UNIX\n");
  943                 req->sock = accept(spfd_state.sock_unix,
  944                     (struct sockaddr *)(&req->addr.un), &req->addrlen);
  945                 if (req->sock >= 0)
  946                     pthread_create(&th, &attr, handle_stream, req);
  947                 else
  948                     free(req);
  949             }
  950         }
  951     }
  952 
  953     pthread_attr_destroy(&attr);
  954 }
  955 
  956 int
  957 main(int argc, char *argv[])
  958 {
  959     daemon_config(argc, argv);
  960     daemon_init();
  961     daemon_main();
  962     return 0;
  963 }