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