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