libspf2  1.2.10
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 };
442 
443 static const char *shortopts = "d:t:p:f:x:y:m:u:g:h:";
444 
445 void usage (void) {
446  fprintf(stdout,"Flags\n");
447  fprintf(stdout,"\t-tcpport\n");
448  fprintf(stdout,"\t-udpport\n");
449  fprintf(stdout,"\t-path\n");
450 #ifdef HAVE_PWD_H
451  fprintf(stdout,"\t-pathuser\n");
452 #endif
453 #ifdef HAVE_GRP_H
454  fprintf(stdout,"\t-pathgroup\n");
455 #endif
456  fprintf(stdout,"\t-pathmode\n");
457 #ifdef HAVE_PWD_H
458  fprintf(stdout,"\t-setuser\n");
459 #endif
460 #ifdef HAVE_GRP_H
461  fprintf(stdout,"\t-setgroup\n");
462 #endif
463  fprintf(stdout,"\t-onerequest\n");
464  fprintf(stdout,"\t-help\n");
465 
466 }
467 
468 #define DIE(x) do { fprintf(stderr, "%s\n", x); exit(1); } while(0)
469 
470 #ifdef HAVE_PWD_H
471 static gid_t
472 daemon_get_user(const char *arg)
473 {
474  struct passwd *pwd;
475  if (isdigit(arg[0]))
476  pwd = getpwuid(atol(arg));
477  else
478  pwd = getpwnam(arg);
479  if (pwd == NULL) {
480  fprintf(stderr, "Failed to find user %s\n", arg);
481  DIE("Unknown user");
482  }
483  return pwd->pw_uid;
484 }
485 #endif
486 
487 #ifdef HAVE_GRP_H
488 static gid_t
489 daemon_get_group(const char *arg)
490 {
491  struct group *grp;
492  if (isdigit(arg[0]))
493  grp = getgrgid(atol(arg));
494  else
495  grp = getgrnam(arg);
496  if (grp == NULL) {
497  fprintf(stderr, "Failed to find user %s\n", arg);
498  DIE("Unknown group");
499  }
500  return grp->gr_gid;
501 }
502 #endif
503 
504 static void
505 daemon_config(int argc, char *argv[])
506 {
507  int idx;
508  char c;
509 
510  memset(&spfd_config, 0, sizeof(spfd_config));
511 
512  while ((c =
513  getopt_long(argc, argv, shortopts, longopts, &idx)
514  ) != -1) {
515  switch (c) {
516  case 't':
517  spfd_config.tcpport = atol(optarg);
518  break;
519  case 'p':
520  spfd_config.udpport = atol(optarg);
521  break;
522  case 'f':
523  spfd_config.path = optarg;
524  break;
525 
526  case 'd':
527  spfd_config.debug = atol(optarg);
528  break;
529 
530 #ifdef HAVE_PWD_H
531  case 'x':
532  spfd_config.pathuser = daemon_get_user(optarg);
533  break;
534 #endif
535 #ifdef HAVE_GRP_H
536  case 'y':
537  spfd_config.pathgroup = daemon_get_group(optarg);
538  break;
539 #endif
540 
541  case 'm':
542  spfd_config.pathmode = atol(optarg);
543  break;
544 
545 #ifdef HAVE_PWD_H
546  case 'u':
547  spfd_config.setuser = daemon_get_user(optarg);
548  break;
549 #endif
550 #ifdef HAVE_GRP_H
551  case 'g':
552  spfd_config.setgroup = daemon_get_group(optarg);
553  break;
554 #endif
555  case 'o':
556  spfd_config.onerequest = 1;
557  fprintf(stdout, "One request mode\n");
558  break;
559 
560  case 0:
561  case '?':
562  usage();
563  DIE("Invalid argument");
564  break;
565  case 'h' :
566  usage();
567  DIE("");
568  break;
569 
570  default:
571  fprintf(stderr, "Error: getopt returned character code 0%o ??\n", c);
572  DIE("WHAT?");
573  }
574  }
575 }
576 
577 static int
578 daemon_bind_inet_udp()
579 {
580  struct sockaddr_in addr;
581  int sock;
582 
583  if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
584  perror("socket");
585  DIE("Failed to create socket");
586  }
587  memset(&addr, 0, sizeof(addr));
588  addr.sin_family = AF_INET;
589  addr.sin_port = htons(spfd_config.udpport);
590  addr.sin_addr.s_addr = INADDR_ANY;
591  if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
592  perror("bind");
593  DIE("Failed to bind socket");
594  }
595 
596  fprintf(stderr, "Accepting datagrams on %d\n", spfd_config.udpport);
597 
598  return sock;
599 }
600 
601 static int
602 daemon_bind_inet_tcp()
603 {
604  struct sockaddr_in addr;
605  int sock;
606 
607  int optval;
608  size_t optlen;
609 
610  if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
611  perror("socket");
612  DIE("Failed to create socket");
613  }
614 
615  optval = 1;
616  optlen = sizeof(int);
617  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
618 
619  memset(&addr, 0, sizeof(addr));
620  addr.sin_family = AF_INET;
621  addr.sin_port = htons(spfd_config.tcpport);
622  addr.sin_addr.s_addr = INADDR_ANY;
623  if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
624  perror("bind");
625  DIE("Failed to bind socket");
626  }
627 
628  if (listen(sock, 5) < 0) {
629  perror("listen");
630  DIE("Failed to listen on socket");
631  }
632 
633  fprintf(stderr, "Accepting connections on %d\n", spfd_config.tcpport);
634 
635  return sock;
636 }
637 
638 static int
639 daemon_bind_unix()
640 {
641  struct sockaddr_un addr;
642  int sock;
643 
644  if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
645  perror("socket");
646  DIE("Failed to create socket");
647  }
648  memset(&addr, 0, sizeof(addr));
649  addr.sun_family = AF_UNIX;
650  strncpy(addr.sun_path, spfd_config.path, sizeof(addr.sun_path) - 1);
651  if (unlink(spfd_config.path) < 0) {
652  if (errno != ENOENT) {
653  perror("unlink");
654  DIE("Failed to unlink socket");
655  }
656  }
657  if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
658  perror("bind");
659  DIE("Failed to bind socket");
660  }
661  if (listen(sock, 5) < 0) {
662  perror("listen");
663  DIE("Failed to listen on socket");
664  }
665 
666  fprintf(stderr, "Accepting connections on %s\n", spfd_config.path);
667 
668  return sock;
669 }
670 
671 static void
672 daemon_init()
673 {
674  SPF_response_t *spf_response = NULL;
675  SPF_errcode_t err;
676 
677  memset(&spfd_state, 0, sizeof(spfd_state));
678 
679  spf_server = SPF_server_new(SPF_DNS_CACHE, spfd_config.debug);
680 
681  if (spfd_config.rec_dom) {
682  UNLESS(SPF_server_set_rec_dom(spf_server,
683  spfd_config.rec_dom)) {
684  DIE("Failed to set receiving domain name");
685  }
686  }
687 
688  if (spfd_config.sanitize) {
689  UNLESS(SPF_server_set_sanitize(spf_server,
690  spfd_config.sanitize)) {
691  DIE("Failed to set server sanitize flag");
692  }
693  }
694 
695  if (spfd_config.max_lookup) {
696  UNLESS(SPF_server_set_max_dns_mech(spf_server,
697  spfd_config.max_lookup)){
698  DIE("Failed to set maximum DNS requests");
699  }
700  }
701 
702  if (spfd_config.localpolicy) {
704  spfd_config.localpolicy,
705  spfd_config.use_trusted,
706  &spf_response)){
707  response_print_errors("Compiling local policy",
708  spf_response, err);
709  DIE("Failed to set local policy");
710  }
711  FREE_RESPONSE(spf_response);
712  }
713 
714  if (spfd_config.explanation) {
716  spfd_config.explanation,
717  &spf_response)){
718  response_print_errors("Setting default explanation",
719  spf_response, err);
720  DIE("Failed to set default explanation");
721  }
722  FREE_RESPONSE(spf_response);
723  }
724 
725  if (spfd_config.udpport)
726  spfd_state.sock_udp = daemon_bind_inet_udp();
727  if (spfd_config.tcpport)
728  spfd_state.sock_tcp = daemon_bind_inet_tcp();
729  if (spfd_config.path)
730  spfd_state.sock_unix = daemon_bind_unix();
731  /* XXX Die if none of the above. */
732 }
733 
734 /* This has a return value so we can decide whether to malloc and/or
735  * free in the caller. */
736 static char **
737 find_field(request_t *req, const char *key)
738 {
739 #define STREQ(a, b) (strcmp((a), (b)) == 0)
740 
741  if (STREQ(key, "ip"))
742  return &req->ip;
743  if (STREQ(key, "helo"))
744  return &req->helo;
745  if (STREQ(key, "sender"))
746  return &req->sender;
747  if (STREQ(key, "rcpt"))
748  return &req->rcpt_to;
749  fprintf(stderr, "Invalid key %s\n", key);
750  return NULL;
751 }
752 
753 /* This is called with req->data malloc'd */
754 static void *
755 handle_datagram(void *arg)
756 {
757  request_t *req;
758  char **fp;
759  char *key;
760  char *value;
761  char *end;
762  int err;
763 
764  req = (request_t *)arg;
765  key = req->data;
766 
767  // printf("req: %s\n", key);
768 
769  while (key < (req->data + req->datalen)) {
770  end = key + strcspn(key, "\r\n");
771  *end = '\0';
772  value = strchr(key, '=');
773 
774  /* Did that line contain an '='? */
775  if (!value) /* XXX WARN */
776  continue;
777 
778  *value++ = '\0';
779  fp = find_field(req, key);
780  if (fp != NULL)
781  *fp = value;
782  else
783  /* warned already */ ;
784 
785  key = end + 1;
786  while (key < (req->data + req->datalen)) {
787  if (strchr("\r\n", *key))
788  key++;
789  else
790  break;
791  }
792  }
793 
794  request_handle(req);
795 
796 #ifdef DEBUG
797  printf("Target address length is %d: %s:%d\n", req->addrlen,
798  inet_ntoa(req->addr.in.sin_addr),
799  req->addr.in.sin_port);
800 #endif
801 
802  printf("- %s\n", req->sender); fflush(stdout);
803  err = sendto(req->sock, req->fmt, req->fmtlen, 0,
804  (struct sockaddr *)(&req->addr.in), req->addrlen);
805  if (err == -1)
806  perror("sendto");
807 
810 
811  FREE_STRING(req->data);
812  free(arg);
813  return NULL;
814 }
815 
816 /* Only req is malloc'd in this. */
817 static void *
818 handle_stream(void *arg)
819 {
820  request_t *req;
821  char **fp;
822  FILE *stream;
823  char key[BUFSIZ];
824  char *value;
825  char *end;
826 
827  req = (request_t *)arg;
828  stream = fdopen(req->sock, "r");
829 
830  do {
831  while (fgets(key, BUFSIZ, stream) != NULL) {
832  key[strcspn(key, "\r\n")] = '\0';
833 
834  /* Break on a blank line and permit another query */
835  if (*key == '\0')
836  break;
837 
838  end = key + strcspn(key, "\r\n");
839  *end = '\0';
840  value = strchr(key, '=');
841 
842  if (!value) /* XXX WARN */
843  continue;
844 
845  *value++ = '\0';
846  fp = find_field(req, key);
847  if (fp != NULL)
848  *fp = strdup(value);
849  else
850  /* warned already */ ;
851  }
852 
853  request_handle(req);
854 
855  printf("- %s\n", req->sender); fflush(stdout);
856  send(req->sock, req->fmt, req->fmtlen, 0);
857 
858  FREE_STRING(req->ip);
859  FREE_STRING(req->helo);
860  FREE_STRING(req->sender);
861  FREE_STRING(req->rcpt_to);
862  } while (! (spfd_config.onerequest || feof(stream)));
863 
864  shutdown(req->sock, SHUT_RDWR);
865  fclose(stream);
866 
867  free(arg);
868  return NULL;
869 }
870 
871 static void
872 daemon_main()
873 {
874  pthread_attr_t attr;
875  pthread_t th;
876 
877  request_t *req;
878  char buf[4096];
879  fd_set rfd;
880  fd_set sfd;
881  int maxfd;
882 
883 
884  pthread_attr_init(&attr);
885  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
886 
887  FD_ZERO(&rfd);
888  maxfd = 0;
889 
890  if (spfd_state.sock_udp) {
891  // printf("UDP socket is %d\n", spfd_state.sock_udp);
892  FD_SET(spfd_state.sock_udp, &rfd);
893  if (spfd_state.sock_udp > maxfd)
894  maxfd = spfd_state.sock_udp;
895  }
896  if (spfd_state.sock_tcp) {
897  // printf("TCP socket is %d\n", spfd_state.sock_tcp);
898  FD_SET(spfd_state.sock_tcp, &rfd);
899  if (spfd_state.sock_tcp > maxfd)
900  maxfd = spfd_state.sock_tcp;
901  }
902  if (spfd_state.sock_unix) {
903  // printf("UNIX socket is %d\n", spfd_state.sock_unix);
904  FD_SET(spfd_state.sock_unix, &rfd);
905  if (spfd_state.sock_unix > maxfd)
906  maxfd = spfd_state.sock_unix;
907  }
908  // printf("MaxFD is %d\n", maxfd);
909 
910 #define NEW_REQUEST ((request_t *)calloc(1, sizeof(request_t)));
911 
912  for (;;) {
913  memcpy(&sfd, &rfd, sizeof(rfd));
914  if (select(maxfd + 1, &sfd, NULL, NULL, NULL) == -1)
915  break;
916 
917  if (spfd_state.sock_udp) {
918  if (FD_ISSET(spfd_state.sock_udp, &sfd)) {
919  req = NEW_REQUEST;
920  req->addrlen = sizeof(req->addr);
921  // printf("UDP\n");
922  req->sock = spfd_state.sock_udp;
923  req->datalen = recvfrom(spfd_state.sock_udp, buf,4095,0,
924  (struct sockaddr *)(&req->addr.in), &req->addrlen);
925  if (req->datalen >= 0) {
926  buf[req->datalen] = '\0';
927  req->data = strdup(buf);
928  pthread_create(&th, &attr, handle_datagram, req);
929  }
930  else {
931  free(req);
932  }
933  }
934  }
935  if (spfd_state.sock_tcp) {
936  if (FD_ISSET(spfd_state.sock_tcp, &sfd)) {
937  req = NEW_REQUEST;
938  req->addrlen = sizeof(req->addr);
939  // printf("TCP\n");
940  req->sock = accept(spfd_state.sock_tcp,
941  (struct sockaddr *)(&req->addr.in), &req->addrlen);
942  if (req->sock >= 0)
943  pthread_create(&th, &attr, handle_stream, req);
944  else
945  free(req);
946  }
947  }
948  if (spfd_state.sock_unix) {
949  if (FD_ISSET(spfd_state.sock_unix, &sfd)) {
950  req = NEW_REQUEST;
951  req->addrlen = sizeof(req->addr);
952  // printf("UNIX\n");
953  req->sock = accept(spfd_state.sock_unix,
954  (struct sockaddr *)(&req->addr.un), &req->addrlen);
955  if (req->sock >= 0)
956  pthread_create(&th, &attr, handle_stream, req);
957  else
958  free(req);
959  }
960  }
961  }
962 
963  pthread_attr_destroy(&attr);
964 }
965 
966 int
967 main(int argc, char *argv[])
968 {
969  daemon_config(argc, argv);
970  daemon_init();
971  daemon_main();
972  return 0;
973 }
const char * SPF_strresult(SPF_result_t result)
Definition: spf_utils.c:81
const char * SPF_strreason(SPF_reason_t reason)
Definition: spf_utils.c:128
const char * SPF_strerror(SPF_errcode_t spf_err)
Definition: spf_strerror.c:33
A testing layer for DNS.
#define NULL
Definition: spf_internal.h:28
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:106
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
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
Definition: spf_request.c:139
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
Definition: spf_request.c:117
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition: spf_request.c:41
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition: spf_request.c:95
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
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
Definition: spf_request.c:270
@ SPF_RESULT_PASS
Definition: spf_response.h:82
const char * SPF_error_message(SPF_error_t *err)
Definition: spf_response.c:320
const char * SPF_response_get_header_comment(SPF_response_t *rp)
Definition: spf_response.c:165
SPF_errcode_t SPF_response_errcode(SPF_response_t *rp)
Definition: spf_response.c:147
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
Definition: spf_response.c:308
SPF_response_t * SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
Definition: spf_response.c:90
int SPF_response_messages(SPF_response_t *rp)
Definition: spf_response.c:290
char SPF_error_errorp(SPF_error_t *err)
Definition: spf_response.c:326
SPF_errcode_t
Definition: spf_response.h:119
@ SPF_E_SUCCESS
Definition: spf_response.h:120
SPF_result_t SPF_response_result(SPF_response_t *rp)
Definition: spf_response.c:135
SPF_reason_t SPF_response_reason(SPF_response_t *rp)
Definition: spf_response.c:141
const char * SPF_response_get_smtp_comment(SPF_response_t *rp)
Definition: spf_response.c:171
@ SPF_DNS_CACHE
Definition: spf_server.h:73
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
Definition: spf_server.c:235
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
Definition: spf_server.c:132
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
Definition: spf_server.c:228
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
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
Definition: spf_server.c:215
#define no_argument
Definition: getopt.h:95
#define required_argument
Definition: getopt.h:96
int getopt_long()
char * optarg
#define FREE_STRING(x)
Definition: spfd.c:131
int main(int argc, char *argv[])
Definition: spfd.c:967
#define FREE_RESPONSE(x)
Definition: spfd.c:130
#define WARN(x, r)
#define FAIL(x)
#define NEW_REQUEST
#define FREE_REQUEST(x)
Definition: spfd.c:129
#define DIE(x)
Definition: spfd.c:468
void usage(void)
Definition: spfd.c:445
#define STREQ(a, b)
#define UNLESS(x)
Definition: getopt.h:80
Definition: spfd.c:134
bool sec_mx
Definition: spfd.c:153
int tcpport
Definition: spfd.c:135
int udpport
Definition: spfd.c:136
char * rec_dom
Definition: spfd.c:156
char * fallback
Definition: spfd.c:154
bool use_trusted
Definition: spfd.c:160
char * localpolicy
Definition: spfd.c:159
char * explanation
Definition: spfd.c:161
char * path
Definition: spfd.c:137
bool sanitize
Definition: spfd.c:157
int pathmode
Definition: spfd.c:144
int debug
Definition: spfd.c:152
int max_lookup
Definition: spfd.c:158
bool onerequest
Definition: spfd.c:162
SPF_response_t * spf_response
Definition: spfd.c:183
int sock
Definition: spfd.c:167
union request_t::@1 addr
char * ip
Definition: spfd.c:176
int datalen
Definition: spfd.c:174
int fmtlen
Definition: spfd.c:186
char fmt[4096]
Definition: spfd.c:185
char * sender
Definition: spfd.c:178
char * rcpt_to
Definition: spfd.c:179
SPF_request_t * spf_request
Definition: spfd.c:182
struct sockaddr_un un
Definition: spfd.c:170
struct sockaddr_in in
Definition: spfd.c:169
char * data
Definition: spfd.c:173
SPF_errcode_t spf_err
Definition: spfd.c:181
socklen_t addrlen
Definition: spfd.c:172
char * helo
Definition: spfd.c:177
Definition: spfd.c:190
int sock_unix
Definition: spfd.c:193
int sock_tcp
Definition: spfd.c:192
int sock_udp
Definition: spfd.c:191