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