spfd.c

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of either:
00004  * 
00005  *   a) The GNU Lesser General Public License as published by the Free
00006  *      Software Foundation; either version 2.1, or (at your option) any
00007  *      later version,
00008  * 
00009  *   OR
00010  * 
00011  *   b) The two-clause BSD license.
00012  *
00013  * These licenses can be found with the distribution in the file LICENSES
00014  *
00015  *
00016  *
00017  * This program is really a badly smashed together copy of spfquery.c and
00018  * the public domain "helloserver" example daemon.
00019  *
00020  * The original helloserver code contained the following copyright notice:
00021  *
00022  * HELLOSERVER.C - a 'Hello World' TCP/IP based server daemon
00023  *
00024  * Implements a skeleton of a single process iterative server
00025  * daemon.
00026  *
00027  * Wherever possible the code adheres to POSIX.
00028  *
00029  * David Gillies <daggillies@yahoo.com> Sep 2003
00030  *
00031  * Placed in the public domain. Unrestricted use or modification
00032  * of this code is permitted without attribution to the author.
00033  */
00034 
00035 
00036 #ifdef __GNUC__
00037 #define _GNU_SOURCE /* for strsignal() */
00038 #endif
00039 
00040 #ifdef HAVE_CONFIG_H
00041 # include "config.h"
00042 #endif
00043 
00044 #ifdef STDC_HEADERS
00045 # include <stdio.h>
00046 # include <stdlib.h>       /* malloc / free */
00047 # include <stddef.h>
00048 # include <stdarg.h>
00049 #endif
00050 
00051 #ifdef HAVE_SYS_TYPES_H
00052 #include <sys/types.h>    /* types (u_char .. etc..) */
00053 #endif
00054 
00055 #ifdef HAVE_INTTYPES_H
00056 #include <inttypes.h>
00057 #endif
00058 
00059 #ifdef HAVE_STRING_H
00060 # include <string.h>       /* strstr / strdup */
00061 #else
00062 # ifdef HAVE_STRINGS_H
00063 #  include <strings.h>       /* strstr / strdup */
00064 # endif
00065 #endif
00066 
00067 #ifdef HAVE_SYS_SOCKET_H
00068 # include <sys/socket.h>   /* inet_ functions / structs */
00069 #endif
00070 #ifdef HAVE_NETINET_IN_H
00071 # include <netinet/in.h>   /* inet_ functions / structs */
00072 #endif
00073 #ifdef HAVE_ARPA_INET_H
00074 # include <arpa/inet.h>    /* in_addr struct */
00075 #endif
00076 
00077 #ifdef HAVE_ARPA_NAMESER_H
00078 # include <arpa/nameser.h> /* DNS HEADER struct */
00079 #endif
00080 
00081 #include <sys/types.h>
00082 
00083 #ifdef HAVE_PWD_H
00084 #include <pwd.h>
00085 #endif
00086 
00087 #ifdef HAVE_GRP_H
00088 #include <grp.h>
00089 #endif
00090 
00091 #define _GNU_SOURCE
00092 #include <getopt.h>
00093 
00094 #include <unistd.h>
00095 #include <netdb.h>
00096 #include <fcntl.h>
00097 #include <time.h>
00098 #include <signal.h>
00099 #include <syslog.h>
00100 #include <errno.h>
00101 #include <sys/types.h>
00102 #include <sys/stat.h>
00103 #include <sys/socket.h>
00104 #include <sys/un.h>
00105 #include <netinet/in.h>
00106 #include <ctype.h>
00107 #include <sys/wait.h>
00108 
00109 #include <pthread.h>
00110 
00111 #include "spf.h"
00112 #include "spf_dns.h"
00113 #include "spf_dns_null.h"
00114 #include "spf_dns_resolv.h"
00115 #include "spf_dns_test.h"
00116 #include "spf_dns_cache.h"
00117 
00118 
00119 #define TRUE 1
00120 #define FALSE 0
00121 
00122 #define bool int
00123 
00124 #define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
00125 #define FREE_REQUEST(x) FREE((x), SPF_request_free)
00126 #define FREE_RESPONSE(x) FREE((x), SPF_response_free)
00127 #define FREE_STRING(x) FREE((x), free)
00128 
00129 typedef
00130 struct _config_t {
00131         int              tcpport;
00132         int              udpport;
00133         char    *path;
00134 #ifdef HAVE_PWD_H
00135         uid_t    pathuser;
00136 #endif
00137 #ifdef HAVE_GRP_H
00138         gid_t    pathgroup;
00139 #endif
00140         int              pathmode;
00141 #ifdef HAVE_PWD_H
00142         uid_t    setuser;
00143 #endif
00144 #ifdef HAVE_GRP_H
00145         gid_t    setgroup;
00146 #endif
00147 
00148         int              debug;
00149         bool     sec_mx;
00150         char    *fallback;
00151 
00152         char    *rec_dom;
00153         bool     sanitize;
00154         int              max_lookup;
00155         char    *localpolicy;
00156         bool     use_trusted;
00157         char    *explanation;
00158 } config_t;
00159 
00160 typedef
00161 struct _request_t {
00162         int              sock;
00163         union {
00164                 struct sockaddr_in      in;
00165                 struct sockaddr_un      un;
00166         } addr;
00167         socklen_t        addrlen;
00168         char            *data;
00169         int                      datalen;
00170 
00171         char            *ip;
00172         char            *helo;
00173         char            *sender;
00174         char            *rcpt_to;
00175 
00176         SPF_errcode_t    spf_err;
00177         SPF_request_t   *spf_request;
00178         SPF_response_t  *spf_response;
00179 
00180         char             fmt[4096];
00181         int                      fmtlen;
00182 } request_t;
00183 
00184 typedef
00185 struct _state_t {
00186         int     sock_udp;
00187         int     sock_tcp;
00188         int     sock_unix;
00189 } state_t;
00190 
00191 static SPF_server_t     *spf_server;
00192 static config_t          spfd_config;
00193 static state_t           spfd_state;
00194 
00195 static void
00196 response_print_errors(const char *context,
00197                                 SPF_response_t *spf_response, SPF_errcode_t err)
00198 {
00199         SPF_error_t     *spf_error;
00200         int                      i;
00201 
00202         if (context != NULL)
00203                 printf("Context: %s\n", context);
00204         if (err != SPF_E_SUCCESS)
00205                 printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
00206 
00207         if (spf_response != NULL) {
00208                 for (i = 0; i < SPF_response_messages(spf_response); i++) {
00209                         spf_error = SPF_response_message(spf_response, i);
00210                         printf( "%s: %s%s\n",
00211                                         SPF_error_errorp(spf_error) ? "Error" : "Warning",
00212                                         ((SPF_error_errorp(spf_error) && (!err))
00213                                                         ? "[UNRETURNED] "
00214                                                         : ""),
00215                                         SPF_error_message(spf_error) );
00216                 }
00217         }
00218         else {
00219                 printf("Error: libspf2 gave a NULL spf_response");
00220         }
00221 }
00222 
00223 static void
00224 response_print(const char *context, SPF_response_t *spf_response)
00225 {
00226         printf("--vv--\n");
00227         printf("Context: %s\n", context);
00228         if (spf_response == NULL) {
00229                 printf("NULL RESPONSE!\n");
00230         }
00231         else {
00232                 printf("Response result: %s\n",
00233                                         SPF_strresult(SPF_response_result(spf_response)));
00234                 printf("Response reason: %s\n",
00235                                         SPF_strreason(SPF_response_reason(spf_response)));
00236                 printf("Response err: %s\n",
00237                                         SPF_strerror(SPF_response_errcode(spf_response)));
00238                 response_print_errors(NULL, spf_response,
00239                                                 SPF_response_errcode(spf_response));
00240         }
00241         printf("--^^--\n");
00242 }
00243 
00244 static const char *
00245 request_check(request_t *req)
00246 {
00247         const char      *msg = NULL;
00248         if (!req->ip)
00249                 msg = "No IP address given";
00250         else if (!req->sender)
00251                 msg = "No sender address given";
00252         else
00253                 return NULL;
00254         snprintf(req->fmt, 4095,
00255                 "result=unknown\n"
00256                 "reason=%s\n",
00257                 msg);
00258         return msg;
00259 }
00260 
00261 static void
00262 request_query(request_t *req)
00263 {
00264         SPF_request_t   *spf_request = NULL;
00265         SPF_response_t  *spf_response = NULL;
00266         SPF_response_t  *spf_response_2mx = NULL;
00267         SPF_errcode_t    err;
00268         char                    *p, *p_end;
00269 
00270 #define UNLESS(x) err = (x); if (err)
00271 // #define FAIL(x) do { response_print_errors((x), spf_response, err); goto fail; } while(0)
00272 #define FAIL(x) do { goto fail; } while(0)
00273 #define WARN(x, r) response_print_errors((x), (r), err)
00274 
00275         spf_request = SPF_request_new(spf_server);
00276 
00277         if (strchr(req->ip, ':')) {
00278                 UNLESS(SPF_request_set_ipv6_str(spf_request, req->ip)) {
00279                         FAIL("Setting IPv6 address");
00280                 }
00281         }
00282         else {
00283                 UNLESS(SPF_request_set_ipv4_str(spf_request, req->ip)) {
00284                         FAIL("Setting IPv4 address");
00285                 }
00286         }
00287 
00288         if (req->helo) {
00289                 UNLESS(SPF_request_set_helo_dom(spf_request, req->helo)) {
00290                         FAIL("Failed to set HELO domain");
00291                 }
00292                 /* XXX Set some flag saying to query on helo */
00293         }
00294 
00295         if (req->sender) {
00296                 UNLESS(SPF_request_set_env_from(spf_request, req->sender)) {
00297                         FAIL("Failed to set envelope-from address");
00298                 }
00299                 /* XXX Set some flag saying to query on sender */
00300         }
00301 
00302         /* XXX If flag not set, FAIL() */
00303 
00304         UNLESS(SPF_request_query_mailfrom(spf_request, &spf_response)) {
00305                 FAIL("Failed to query based on mail-from address");
00306         }
00307 
00308         if (spfd_config.sec_mx) {
00309                 if (req->rcpt_to && *req->rcpt_to) {
00310                         p = req->rcpt_to;
00311                         p_end = p + strcspn(p, " ,;");
00312                         while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
00313                                 if (*p_end)
00314                                         *p_end = '\0';
00315                                 else
00316                                         p_end = NULL;   /* Note this is last rcpt */
00317                                 UNLESS(SPF_request_query_rcptto(spf_request,
00318                                                                 &spf_response_2mx, p)) {
00319                                         WARN("Failed to query based on 2mx recipient",
00320                                                                         spf_response_2mx);
00321                                         FREE_RESPONSE(spf_response_2mx);
00322                                 }
00323                                 else {
00324                                         spf_response = SPF_response_combine(spf_response,
00325                                                                         spf_response_2mx);
00326                                         spf_response_2mx = NULL;        /* freed */
00327                                 }
00328 
00329                                 if (!p_end)
00330                                         break;
00331                                 p = p_end + 1;
00332                         }
00333                 }
00334         }
00335 
00336         if (spfd_config.fallback) {
00337                 UNLESS(SPF_request_query_fallback(spf_request,
00338                                                 &spf_response, spfd_config.fallback)) {
00339                         FAIL("Querying fallback record");
00340                 }
00341         }
00342 
00343         goto ok;
00344 
00345 fail:
00346         req->spf_err = err;
00347         FREE_RESPONSE(spf_response);
00348         FREE_REQUEST(spf_request);
00349 
00350 ok:
00351         // response_print("Result: ", spf_response);
00352         (void)response_print;
00353 
00354         req->spf_response = spf_response;
00355         req->spf_request = spf_request;
00356 }
00357 
00358 /* This is needed on HP/UX, IIRC */
00359 static inline const char *
00360 W(const char *c)
00361 {
00362         if (c)
00363                 return c;
00364         return "(null)";
00365 }
00366 
00367 static void
00368 request_format(request_t *req)
00369 {
00370         SPF_response_t  *spf_response;
00371 
00372         spf_response = req->spf_response;
00373 
00374         if (spf_response) {
00375                 req->fmtlen = snprintf(req->fmt, 4095,
00376                         "ip=%s\n"
00377                         "sender=%s\n"
00378                         "result=%s\n"
00379                         "reason=%s\n"
00380                         "smtp_comment=%s\n"
00381                         "header_comment=%s\n"
00382                         "error=%s\n"
00383                         , req->ip, req->sender
00384                         , W(SPF_strresult(SPF_response_result(spf_response)))
00385                         , W(SPF_strreason(SPF_response_reason(spf_response)))
00386                         , W(SPF_response_get_smtp_comment(spf_response))
00387                         , W(SPF_response_get_header_comment(spf_response))
00388                         , W(SPF_strerror(SPF_response_errcode(spf_response)))
00389                         );
00390         }
00391         else {
00392                 req->fmtlen = snprintf(req->fmt, 4095,
00393                         "ip=%s\n"
00394                         "sender=%s\n"
00395                         "result=unknown\n"
00396                         "error=%s\n"
00397                         , req->ip, req->sender
00398                         , SPF_strerror(req->spf_err)
00399                         );
00400         }
00401 
00402         req->fmt[4095] = '\0';
00403 }
00404 
00405 static void
00406 request_handle(request_t *req)
00407 {
00408         printf("| %s\n", req->sender); fflush(stdout);
00409         if (!request_check(req)) {
00410                 request_query(req);
00411                 request_format(req);
00412         }
00413         // printf("==\n%s\n", req->fmt);
00414 }
00415 
00416 static const struct option longopts[] = {
00417         { "debug",              required_argument,      NULL,   'd', },
00418         { "tcpport",    required_argument,      NULL,   't', },
00419         { "udpport",    required_argument,      NULL,   'p', },
00420         { "path",               required_argument,      NULL,   'f', },
00421 #ifdef HAVE_PWD_H
00422         { "pathuser",   required_argument,      NULL,   'x', },
00423 #endif
00424 #ifdef HAVE_GRP_H
00425         { "pathgroup",  required_argument,      NULL,   'y', },
00426 #endif
00427         { "pathmode",   required_argument,      NULL,   'm', },
00428 #ifdef HAVE_PWD_H
00429         { "setuser",    required_argument,      NULL,   'u', },
00430 #endif
00431 #ifdef HAVE_GRP_H
00432         { "setgroup",   required_argument,      NULL,   'g', },
00433 #endif
00434         { "help",       no_argument,            NULL,   'h', },
00435 };
00436 
00437 static const char *shortopts = "d:t:p:f:x:y:m:u:g:h:";
00438 
00439 void usage (void) {
00440         fprintf(stdout,"Flags\n");
00441         fprintf(stdout,"\t-tcpport\n");
00442         fprintf(stdout,"\t-udpport\n");
00443         fprintf(stdout,"\t-path\n");
00444 #ifdef HAVE_PWD_H
00445         fprintf(stdout,"\t-pathuser\n");
00446 #endif
00447 #ifdef HAVE_GRP_H
00448         fprintf(stdout,"\t-pathgroup\n");
00449 #endif
00450         fprintf(stdout,"\t-pathmode\n");
00451 #ifdef HAVE_PWD_H
00452         fprintf(stdout,"\t-setuser\n");
00453 #endif
00454 #ifdef HAVE_GRP_H
00455         fprintf(stdout,"\t-setgroup\n");
00456 #endif
00457         fprintf(stdout,"\t-help\n");
00458 
00459 }
00460 
00461 #define DIE(x) do { fprintf(stderr, "%s\n", x); exit(1); } while(0)
00462 
00463 #ifdef HAVE_PWD_H
00464 static gid_t
00465 daemon_get_user(const char *arg)
00466 {
00467         struct passwd   *pwd;
00468         if (isdigit(arg[0]))
00469                 pwd = getpwuid(atol(arg));
00470         else
00471                 pwd = getpwnam(arg);
00472         if (pwd == NULL) {
00473                 fprintf(stderr, "Failed to find user %s\n", arg);
00474                 DIE("Unknown user");
00475         }
00476         return pwd->pw_uid;
00477 }
00478 #endif
00479 
00480 #ifdef HAVE_GRP_H
00481 static gid_t
00482 daemon_get_group(const char *arg)
00483 {
00484         struct group    *grp;
00485         if (isdigit(arg[0]))
00486                 grp = getgrgid(atol(arg));
00487         else
00488                 grp = getgrnam(arg);
00489         if (grp == NULL) {
00490                 fprintf(stderr, "Failed to find user %s\n", arg);
00491                 DIE("Unknown group");
00492         }
00493         return grp->gr_gid;
00494 }
00495 #endif
00496 
00497 static void
00498 daemon_config(int argc, char *argv[])
00499 {
00500         int              idx;
00501         char     c;
00502 
00503         memset(&spfd_config, 0, sizeof(spfd_config));
00504 
00505         while ((c =
00506                 getopt_long(argc, argv, shortopts, longopts, &idx)
00507                         ) != -1) {
00508                 switch (c) {
00509                         case 't':
00510                                 spfd_config.tcpport = atol(optarg);
00511                                 break;
00512                         case 'p':
00513                                 spfd_config.udpport = atol(optarg);
00514                                 break;
00515                         case 'f':
00516                                 spfd_config.path = optarg;
00517                                 break;
00518 
00519                         case 'd':
00520                                 spfd_config.debug = atol(optarg);
00521                                 break;
00522 
00523 #ifdef HAVE_PWD_H
00524                         case 'x':
00525                                 spfd_config.pathuser = daemon_get_user(optarg);
00526                                 break;
00527 #endif
00528 #ifdef HAVE_GRP_H
00529                         case 'y':
00530                                 spfd_config.pathgroup = daemon_get_group(optarg);
00531                                 break;
00532 #endif
00533 
00534                         case 'm':
00535                                 spfd_config.pathmode = atol(optarg);
00536                                 break;
00537 
00538 #ifdef HAVE_PWD_H
00539                         case 'u':
00540                                 spfd_config.setuser = daemon_get_user(optarg);
00541                                 break;
00542 #endif
00543 #ifdef HAVE_GRP_H
00544                         case 'g':
00545                                 spfd_config.setgroup = daemon_get_group(optarg);
00546                                 break;
00547 #endif
00548 
00549                         case 0:
00550                         case '?':
00551                                 usage();
00552                                 DIE("Invalid argument");
00553                                 break;
00554                         case 'h' :
00555                                 usage();
00556                                 DIE("");
00557                                 break;
00558 
00559                         default:
00560                                 fprintf(stderr, "Error: getopt returned character code 0%o ??\n", c);
00561                                 DIE("WHAT?");
00562                 }
00563         }
00564 }
00565 
00566 static int
00567 daemon_bind_inet_udp()
00568 {
00569         struct sockaddr_in       addr;
00570         int                                      sock;
00571 
00572         if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
00573                 perror("socket");
00574                 DIE("Failed to create socket");
00575         }
00576         memset(&addr, 0, sizeof(addr));
00577         addr.sin_family = AF_INET;
00578         addr.sin_port = htons(spfd_config.udpport);
00579         addr.sin_addr.s_addr = INADDR_ANY;
00580         if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
00581                 perror("bind");
00582                 DIE("Failed to bind socket");
00583         }
00584 
00585         fprintf(stderr, "Accepting datagrams on %d\n", spfd_config.udpport);
00586 
00587         return sock;
00588 }
00589 
00590 static int
00591 daemon_bind_inet_tcp()
00592 {
00593         struct sockaddr_in       addr;
00594         int                                      sock;
00595 
00596         int                                      optval;
00597         size_t                           optlen;
00598 
00599         if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
00600                 perror("socket");
00601                 DIE("Failed to create socket");
00602         }
00603 
00604         optval = 1;
00605         optlen = sizeof(int);
00606         setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
00607 
00608         memset(&addr, 0, sizeof(addr));
00609         addr.sin_family = AF_INET;
00610         addr.sin_port = htons(spfd_config.tcpport);
00611         addr.sin_addr.s_addr = INADDR_ANY;
00612         if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
00613                 perror("bind");
00614                 DIE("Failed to bind socket");
00615         }
00616 
00617         if (listen(sock, 5) < 0) {
00618                 perror("listen");
00619                 DIE("Failed to listen on socket");
00620         }
00621 
00622         fprintf(stderr, "Accepting connections on %d\n", spfd_config.tcpport);
00623 
00624         return sock;
00625 }
00626 
00627 static int
00628 daemon_bind_unix()
00629 {
00630         struct sockaddr_un       addr;
00631         int                                      sock;
00632 
00633         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
00634                 perror("socket");
00635                 DIE("Failed to create socket");
00636         }
00637         memset(&addr, 0, sizeof(addr));
00638         addr.sun_family = AF_UNIX;
00639         strncpy(addr.sun_path, spfd_config.path, sizeof(addr.sun_path) - 1);
00640         if (unlink(spfd_config.path) < 0) {
00641                 if (errno != ENOENT) {
00642                         perror("unlink");
00643                         DIE("Failed to unlink socket");
00644                 }
00645         }
00646         if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
00647                 perror("bind");
00648                 DIE("Failed to bind socket");
00649         }
00650         if (listen(sock, 5) < 0) {
00651                 perror("listen");
00652                 DIE("Failed to listen on socket");
00653         }
00654 
00655         fprintf(stderr, "Accepting connections on %s\n", spfd_config.path);
00656 
00657         return sock;
00658 }
00659 
00660 static void
00661 daemon_init()
00662 {
00663         SPF_response_t  *spf_response = NULL;
00664         SPF_errcode_t    err;
00665 
00666         memset(&spfd_state, 0, sizeof(spfd_state));
00667 
00668         spf_server = SPF_server_new(SPF_DNS_CACHE, spfd_config.debug);
00669 
00670         if (spfd_config.rec_dom) {
00671                 UNLESS(SPF_server_set_rec_dom(spf_server,
00672                                                 spfd_config.rec_dom)) {
00673                         DIE("Failed to set receiving domain name");
00674                 }
00675         }
00676 
00677         if (spfd_config.sanitize) {
00678                 UNLESS(SPF_server_set_sanitize(spf_server,
00679                                                 spfd_config.sanitize)) {
00680                         DIE("Failed to set server sanitize flag");
00681                 }
00682         }
00683 
00684         if (spfd_config.max_lookup) {
00685                 UNLESS(SPF_server_set_max_dns_mech(spf_server,
00686                                                 spfd_config.max_lookup)){
00687                         DIE("Failed to set maximum DNS requests");
00688                 }
00689         }
00690 
00691         if (spfd_config.localpolicy) {
00692                 UNLESS(SPF_server_set_localpolicy(spf_server,
00693                                                 spfd_config.localpolicy,
00694                                                 spfd_config.use_trusted,
00695                                                 &spf_response)){
00696                         response_print_errors("Compiling local policy",
00697                                                         spf_response, err);
00698                         DIE("Failed to set local policy");
00699                 }
00700                 FREE_RESPONSE(spf_response);
00701         }
00702 
00703         if (spfd_config.explanation) {
00704                 UNLESS(SPF_server_set_explanation(spf_server,
00705                                                 spfd_config.explanation,
00706                                                 &spf_response)){
00707                         response_print_errors("Setting default explanation",
00708                                                         spf_response, err);
00709                         DIE("Failed to set default explanation");
00710                 }
00711                 FREE_RESPONSE(spf_response);
00712         }
00713 
00714         if (spfd_config.udpport)
00715                 spfd_state.sock_udp = daemon_bind_inet_udp();
00716         if (spfd_config.tcpport)
00717                 spfd_state.sock_tcp = daemon_bind_inet_tcp();
00718         if (spfd_config.path)
00719                 spfd_state.sock_unix = daemon_bind_unix();
00720         /* XXX Die if none of the above. */
00721 }
00722 
00723 /* This has a return value so we can decide whether to malloc and/or
00724  * free in the caller. */
00725 static char **
00726 find_field(request_t *req, const char *key)
00727 {
00728 #define STREQ(a, b) (strcmp((a), (b)) == 0)
00729 
00730         if (STREQ(key, "ip"))
00731                 return &req->ip;
00732         if (STREQ(key, "helo"))
00733                 return &req->helo;
00734         if (STREQ(key, "sender"))
00735                 return &req->sender;
00736         if (STREQ(key, "rcpt"))
00737                 return &req->rcpt_to;
00738         fprintf(stderr, "Invalid key %s\n", key);
00739         return NULL;
00740 }
00741 
00742 /* This is called with req->data malloc'd */
00743 static void *
00744 handle_datagram(void *arg)
00745 {
00746         request_t       *req;
00747         char            **fp;
00748         char            *key;
00749         char            *value;
00750         char            *end;
00751         int                      err;
00752 
00753         req = (request_t *)arg;
00754         key = req->data;
00755 
00756         // printf("req: %s\n", key);
00757 
00758         while (key < (req->data + req->datalen)) {
00759                 end = key + strcspn(key, "\r\n");
00760                 *end = '\0';
00761                 value = strchr(key, '=');
00762 
00763                 /* Did that line contain an '='? */
00764                 if (!value)     /* XXX WARN */
00765                         continue;
00766 
00767                 *value++ = '\0';
00768                 fp = find_field(req, key);
00769                 if (fp != NULL)
00770                         *fp = value;
00771                 else
00772                         /* warned already */ ;
00773 
00774                 key = end + 1;
00775                 while (key < (req->data + req->datalen)) {
00776                         if (strchr("\r\n", *key))
00777                                 key++;
00778                         else
00779                                 break;
00780                 }
00781         }
00782 
00783         request_handle(req);
00784 
00785 #ifdef DEBUG
00786         printf("Target address length is %d: %s:%d\n", req->addrlen,
00787                                         inet_ntoa(req->addr.in.sin_addr),
00788                                         req->addr.in.sin_port);
00789 #endif
00790 
00791         printf("- %s\n", req->sender); fflush(stdout);
00792         err = sendto(req->sock, req->fmt, req->fmtlen, 0,
00793                         (struct sockaddr *)(&req->addr.in), req->addrlen);
00794         if (err == -1)
00795                 perror("sendto");
00796 
00797         FREE_RESPONSE(req->spf_response);
00798         FREE_REQUEST(req->spf_request);
00799 
00800         FREE_STRING(req->data);
00801         free(arg);
00802         return NULL;
00803 }
00804 
00805 /* Only req is malloc'd in this. */
00806 static void *
00807 handle_stream(void *arg)
00808 {
00809         request_t       *req;
00810         char            **fp;
00811         FILE            *stream;
00812         char             key[BUFSIZ];
00813         char            *value;
00814         char            *end;
00815 
00816         req = (request_t *)arg;
00817         stream = fdopen(req->sock, "r");
00818 
00819         do {
00820                 while (fgets(key, BUFSIZ, stream) != NULL) {
00821                         key[strcspn(key, "\r\n")] = '\0';
00822 
00823                         /* Break on a blank line and permit another query */
00824                         if (*key == '\0')
00825                                 break;
00826 
00827                         end = key + strcspn(key, "\r\n");
00828                         *end = '\0';
00829                         value = strchr(key, '=');
00830 
00831                         if (!value)     /* XXX WARN */
00832                                 continue;
00833 
00834                         *value++ = '\0';
00835                         fp = find_field(req, key);
00836                         if (fp != NULL)
00837                                 *fp = strdup(value);
00838                         else
00839                                 /* warned already */ ;
00840                 }
00841 
00842                 request_handle(req);
00843 
00844                 printf("- %s\n", req->sender); fflush(stdout);
00845                 send(req->sock, req->fmt, req->fmtlen, 0);
00846 
00847                 FREE_STRING(req->ip);
00848                 FREE_STRING(req->helo);
00849                 FREE_STRING(req->sender);
00850                 FREE_STRING(req->rcpt_to);
00851         } while (!feof(stream));
00852 
00853         free(arg);
00854         return NULL;
00855 }
00856 
00857 static void
00858 daemon_main()
00859 {
00860         pthread_attr_t   attr;
00861         pthread_t                th;
00862 
00863         request_t               *req;
00864         char                     buf[4096];
00865         fd_set                   rfd;
00866         fd_set                   sfd;
00867         int                              maxfd;
00868 
00869 
00870         pthread_attr_init(&attr);
00871         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00872 
00873         FD_ZERO(&rfd);
00874         maxfd = 0;
00875 
00876         if (spfd_state.sock_udp) {
00877                 // printf("UDP socket is %d\n", spfd_state.sock_udp);
00878                 FD_SET(spfd_state.sock_udp, &rfd);
00879                 if (spfd_state.sock_udp > maxfd)
00880                         maxfd = spfd_state.sock_udp;
00881         }
00882         if (spfd_state.sock_tcp) {
00883                 // printf("TCP socket is %d\n", spfd_state.sock_tcp);
00884                 FD_SET(spfd_state.sock_tcp, &rfd);
00885                 if (spfd_state.sock_tcp > maxfd)
00886                         maxfd = spfd_state.sock_tcp;
00887         }
00888         if (spfd_state.sock_unix) {
00889                 // printf("UNIX socket is %d\n", spfd_state.sock_unix);
00890                 FD_SET(spfd_state.sock_unix, &rfd);
00891                 if (spfd_state.sock_unix > maxfd)
00892                         maxfd = spfd_state.sock_unix;
00893         }
00894         // printf("MaxFD is %d\n", maxfd);
00895 
00896 #define NEW_REQUEST     ((request_t *)calloc(1, sizeof(request_t)));
00897 
00898         for (;;) {
00899                 memcpy(&sfd, &rfd, sizeof(rfd));
00900                 if (select(maxfd + 1, &sfd, NULL, NULL, NULL) == -1)
00901                         break;
00902 
00903                 if (spfd_state.sock_udp) {
00904                         if (FD_ISSET(spfd_state.sock_udp, &sfd)) {
00905                                 req = NEW_REQUEST;
00906                                 req->addrlen = sizeof(req->addr);
00907                                 // printf("UDP\n");
00908                                 req->sock = spfd_state.sock_udp;
00909                                 req->datalen = recvfrom(spfd_state.sock_udp, buf,4095,0,
00910                                         (struct sockaddr *)(&req->addr.in), &req->addrlen);
00911                                 if (req->datalen >= 0) {
00912                                         buf[req->datalen] = '\0';
00913                                         req->data = strdup(buf);
00914                                         pthread_create(&th, &attr, handle_datagram, req);
00915                                 }
00916                                 else {
00917                                         free(req);
00918                                 }
00919                         }
00920                 }
00921                 if (spfd_state.sock_tcp) {
00922                         if (FD_ISSET(spfd_state.sock_tcp, &sfd)) {
00923                                 req = NEW_REQUEST;
00924                                 req->addrlen = sizeof(req->addr);
00925                                 // printf("TCP\n");
00926                                 req->sock = accept(spfd_state.sock_tcp,
00927                                         (struct sockaddr *)(&req->addr.in), &req->addrlen);
00928                                 if (req->sock >= 0)
00929                                         pthread_create(&th, &attr, handle_stream, req);
00930                                 else
00931                                         free(req);
00932                         }
00933                 }
00934                 if (spfd_state.sock_unix) {
00935                         if (FD_ISSET(spfd_state.sock_unix, &sfd)) {
00936                                 req = NEW_REQUEST;
00937                                 req->addrlen = sizeof(req->addr);
00938                                 // printf("UNIX\n");
00939                                 req->sock = accept(spfd_state.sock_unix,
00940                                         (struct sockaddr *)(&req->addr.un), &req->addrlen);
00941                                 if (req->sock >= 0)
00942                                         pthread_create(&th, &attr, handle_stream, req);
00943                                 else
00944                                         free(req);
00945                         }
00946                 }
00947         }
00948 
00949         pthread_attr_destroy(&attr);
00950 }
00951 
00952 int
00953 main(int argc, char *argv[])
00954 {
00955         daemon_config(argc, argv);
00956         daemon_init();
00957         daemon_main();
00958         return 0;
00959 }

Generated on 29 May 2016 for libspf2 by  doxygen 1.6.1