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