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

Generated on Sun May 29 13:28:09 2016 for libspf2 by  doxygen 1.5.1