You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

postsrsd.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* PostSRSd - Sender Rewriting Scheme daemon for Postfix
  2. * Copyright (c) 2012 Timo Röhling <timo.roehling@gmx.de>
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /* This program uses the libsrs2 library. The relevant source
  18. * files have been added to this distribution. */
  19. #include "srs2.h"
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netdb.h>
  23. #include <errno.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include <pwd.h>
  27. #include <string.h>
  28. #include <poll.h>
  29. #include <wait.h>
  30. #ifndef VERSION
  31. #define VERSION "1.0"
  32. #endif
  33. static char *self = NULL;
  34. static int bind_service (const char *service, int family)
  35. {
  36. struct addrinfo *addr, *it;
  37. struct addrinfo hints;
  38. int err, sock, flags;
  39. static const int one = 1;
  40. memset (&hints, 0, sizeof(hints));
  41. hints.ai_family = family;
  42. hints.ai_socktype = SOCK_STREAM;
  43. hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
  44. err = getaddrinfo(NULL, service, &hints, &addr);
  45. if (err != 0) {
  46. fprintf(stderr, "%s: bind_service(%s): %s\n", self, service, gai_strerror(err));
  47. return -1;
  48. }
  49. sock = -1;
  50. for (it = addr; it; it = it->ai_next) {
  51. sock = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
  52. if (sock < 0) goto fail;
  53. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) goto fail;
  54. if (bind(sock, it->ai_addr, it->ai_addrlen) < 0) goto fail;
  55. if (listen(sock, 10) < 0) goto fail;
  56. flags = fcntl (sock, F_GETFL, 0);
  57. if (flags < 0) goto fail;
  58. if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) goto fail;
  59. break;
  60. fail:
  61. err = errno;
  62. if (sock >= 0) close (sock);
  63. sock = -1;
  64. }
  65. freeaddrinfo (addr);
  66. if (sock < 0)
  67. fprintf (stderr, "%s: bind_service(%s): %s\n", self, service, strerror(err));
  68. return sock;
  69. }
  70. static int is_hexdigit (char c)
  71. {
  72. return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
  73. }
  74. static char hex2num (char c)
  75. {
  76. if (c >= '0' && c <= '9') return c - '0';
  77. if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  78. if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  79. }
  80. static char num2hex (char c)
  81. {
  82. if (c < 10) return '0' + c;
  83. return 'a' + c - 10;
  84. }
  85. static char hex2char (const char *s)
  86. {
  87. return 16 * hex2num(s[0]) + hex2num(s[1]);
  88. }
  89. static void char2hex (char c, char *buf)
  90. {
  91. buf[0] = num2hex((c >> 4) & 0xf);
  92. buf[1] = num2hex((c ) & 0xf);
  93. }
  94. static char* url_decode (char *buf, size_t len, const char *input)
  95. {
  96. char *output = buf;
  97. if (!input || !output || len == 0) return NULL;
  98. while (*input && --len) {
  99. if (*input == '%' && is_hexdigit(input[1]) && is_hexdigit(input[2])) {
  100. *output++ = hex2char(++input);
  101. input += 2;
  102. } else {
  103. *output++ = *input++;
  104. }
  105. }
  106. *output = 0;
  107. return buf;
  108. }
  109. static char* url_encode (char* buf, size_t len, const char *input)
  110. {
  111. char *output = buf;
  112. if (!input || !output || len == 0) return NULL;
  113. while (*input && --len) {
  114. if (isspace(*input)) {
  115. if (len <= 2) break;
  116. *output++ = '%';
  117. char2hex(*input, output);
  118. output += 2; len -= 2;
  119. } else {
  120. *output++ = *input++;
  121. }
  122. }
  123. *output = 0;
  124. return buf;
  125. }
  126. static void handle_forward (srs_t *srs, FILE *fp, const char *address, const char *domain)
  127. {
  128. int result;
  129. char value[1024];
  130. char outputbuf[1024], *output;
  131. result = srs_forward(srs, value, sizeof(value), address, domain);
  132. if (result == SRS_SUCCESS) {
  133. output = url_encode(outputbuf, sizeof(outputbuf), value);
  134. fprintf (fp, "200 %s\n", output);
  135. } else {
  136. fprintf (fp, "500 %s\n", srs_strerror(result));
  137. }
  138. fflush (fp);
  139. }
  140. static void handle_reverse (srs_t *srs, FILE *fp, const char *address, const char *domain)
  141. {
  142. int result;
  143. char value[1024];
  144. char outputbuf[1024], *output;
  145. result = srs_reverse(srs, value, sizeof(value), address);
  146. if (result == SRS_SUCCESS) {
  147. output = url_encode(outputbuf, sizeof(outputbuf), value);
  148. fprintf (fp, "200 %s\n", output);
  149. } else {
  150. fprintf (fp, "500 %s\n", srs_strerror(result));
  151. }
  152. fflush (fp);
  153. }
  154. static void show_help ()
  155. {
  156. fprintf (stdout,
  157. "Sender Rewriting Scheme implementation for Postfix.\n\n"
  158. "Implements two TCP lookup tables to rewrite mail addresses\n"
  159. "as needed. The forward SRS is for sender envelope addresses\n"
  160. "to prevent SPF-related bounces. The reverse SRS is for\n"
  161. "recipient envelope addresses so that bounced mails can be\n"
  162. "routed back to their original sender.\n"
  163. "\n"
  164. "Usage: %s -s<file> -d<domain> [other options]\n"
  165. "Options:\n"
  166. " -s<file> read secret from file (required)\n"
  167. " -d<domain> set domain name for rewrite (required)\n"
  168. " -f<port> set port for the forward SRS lookup (default: 10001)\n"
  169. " -r<port> set port for the reverse SRS lookup (default: 10002)\n"
  170. " -p<pidfile> write process ID to pidfile (default: none)\n"
  171. " -u<user> switch user id after port bind (default: none)\n"
  172. " -t<seconds> timeout for idle client connections (default: 1800)\n"
  173. " -D fork into background\n"
  174. " -4 force IPv4 socket (default: any)\n"
  175. " -6 force IPv6 socket (default: any)\n"
  176. " -h show this help\n"
  177. " -v show version\n"
  178. "\n",
  179. self
  180. );
  181. }
  182. typedef void(*handle_t)(srs_t*, FILE*, const char*, const char*);
  183. int main (int argc, char **argv)
  184. {
  185. int opt, timeout = 1800, family = AF_UNSPEC;
  186. int daemonize = FALSE;
  187. char *forward_service = NULL, *reverse_service = NULL,
  188. *user = NULL, *domain = NULL;
  189. int forward_sock, reverse_sock;
  190. char *secret_file = NULL, *pid_file = NULL;
  191. FILE *pf = NULL;
  192. char secret[1024];
  193. char *tmp;
  194. srs_t *srs;
  195. struct pollfd fds[3];
  196. handle_t handler[2] = { handle_forward, handle_reverse };
  197. tmp = strrchr(argv[0], '/');
  198. if (tmp) self = strdup(tmp + 1); else self = strdup(argv[0]);
  199. while ((opt = getopt(argc, argv, "46d:f:r:s:u:t:p:Dhv")) != -1) {
  200. switch (opt) {
  201. case '?':
  202. return EXIT_FAILURE;
  203. case '4':
  204. family = AF_INET;
  205. break;
  206. case '6':
  207. family = AF_INET6;
  208. break;
  209. case 'd':
  210. domain = strdup(optarg);
  211. break;
  212. case 'f':
  213. forward_service = strdup(optarg);
  214. break;
  215. case 'r':
  216. reverse_service = strdup(optarg);
  217. break;
  218. case 't':
  219. timeout = atoi(optarg);
  220. break;
  221. case 's':
  222. secret_file = strdup(optarg);
  223. break;
  224. case 'p':
  225. pid_file = strdup(optarg);
  226. break;
  227. case 'u':
  228. user = strdup(optarg);
  229. break;
  230. case 'D':
  231. daemonize = TRUE;
  232. break;
  233. case 'h':
  234. show_help();
  235. return EXIT_SUCCESS;
  236. case 'v':
  237. fprintf (stdout, "%s\n", VERSION);
  238. return EXIT_SUCCESS;
  239. }
  240. }
  241. if (pid_file) {
  242. pf = fopen (pid_file, "w");
  243. if (pf == NULL) {
  244. fprintf (stderr, "%s: Cannot write PID: %s\n\n", self, pid_file);
  245. return EXIT_FAILURE;
  246. }
  247. }
  248. if (domain == NULL) {
  249. fprintf (stderr, "%s: You must set a home domain (-d)\n", self);
  250. show_help();
  251. return EXIT_FAILURE;
  252. }
  253. if (secret_file != NULL) {
  254. size_t len;
  255. FILE *fp = fopen(secret_file, "rb");
  256. if (fp == NULL) {
  257. fprintf (stderr, "%s: Cannot open file with secret: %s\n", self, secret_file);
  258. return EXIT_FAILURE;
  259. }
  260. len = fread(secret, 1, sizeof(secret) - 1, fp);
  261. if (len == 0 || len > sizeof(secret) - 1) {
  262. fprintf (stderr, "%s: Cannot read secret from file: %s\n", self, secret_file);
  263. return EXIT_FAILURE;
  264. }
  265. secret[len] = 0;
  266. fclose (fp);
  267. } else {
  268. fprintf (stderr, "%s: You must set a secret (-s)\n", self);
  269. show_help();
  270. return EXIT_FAILURE;
  271. }
  272. if (forward_service != NULL) {
  273. forward_sock = bind_service(forward_service, family);
  274. free (forward_service);
  275. } else {
  276. forward_sock = bind_service("10001", family);
  277. }
  278. if (forward_sock < 0) return EXIT_FAILURE;
  279. if (reverse_service != NULL) {
  280. reverse_sock = bind_service(reverse_service, family);
  281. free (reverse_service);
  282. } else {
  283. reverse_sock = bind_service("10002", family);
  284. }
  285. if (reverse_sock < 0) return EXIT_FAILURE;
  286. if (user) {
  287. struct passwd *pwd;
  288. errno = 0;
  289. pwd = getpwnam(user);
  290. if (pwd == NULL) {
  291. if (errno != 0)
  292. fprintf (stderr, "%s: Failed to lookup user: %s\n", self, strerror(errno));
  293. else
  294. fprintf (stderr, "%s: No such user: %s\n", self, user);
  295. return EXIT_FAILURE;
  296. }
  297. if (setuid(pwd->pw_uid) < 0) {
  298. fprintf (stderr, "%s: Failed to switch user id: %s\n", self, strerror(errno));
  299. return EXIT_FAILURE;
  300. }
  301. }
  302. if (daemonize) {
  303. close(0); close(1); close(2);
  304. if (fork() != 0) return EXIT_SUCCESS;
  305. setsid();
  306. if (fork() != 0) return EXIT_SUCCESS;
  307. }
  308. if (pf) {
  309. fprintf (pf, "%d", (int)getpid());
  310. fclose (pf);
  311. }
  312. srs = srs_new();
  313. srs_add_secret (srs, secret);
  314. srs_set_separator (srs, '+');
  315. fds[0].fd = forward_sock;
  316. fds[0].events = POLLIN;
  317. fds[1].fd = reverse_sock;
  318. fds[1].events = POLLIN;
  319. while(TRUE) {
  320. int i, conn;
  321. FILE *fp;
  322. char linebuf[1024], *line;
  323. char keybuf[1024], *key;
  324. if (poll(fds, 2, 1000) < 0) {
  325. if (!daemonize) fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
  326. return EXIT_FAILURE;
  327. }
  328. for (i = 0; i < 2; ++i) {
  329. if (fds[i].revents) {
  330. conn = accept(fds[i].fd, NULL, NULL);
  331. if (conn < 0) continue;
  332. if (fork() == 0) {
  333. fp = fdopen(conn, "r+");
  334. if (fp == NULL) exit(EXIT_FAILURE);
  335. fds[2].fd = conn;
  336. fds[2].events = POLLIN;
  337. if (poll(&fds[2], 1, timeout * 1000) <= 0) return EXIT_FAILURE;
  338. line = fgets(linebuf, sizeof(linebuf), fp);
  339. while (line) {
  340. char* token;
  341. token = strtok(line, " \r\n");
  342. if (token == NULL || strcmp(token, "get") != 0) {
  343. fprintf (fp, "500 Invalid request\n");
  344. return EXIT_FAILURE;
  345. }
  346. token = strtok(NULL, "\r\n");
  347. if (!token) {
  348. fprintf (fp, "500 Invalid request\n");
  349. return EXIT_FAILURE;
  350. }
  351. key = url_decode(keybuf, sizeof(keybuf), token);
  352. if (!key) break;
  353. handler[i](srs, fp, key, domain);
  354. if (poll(&fds[2], 1, timeout * 1000) <= 0) break;
  355. line = fgets(linebuf, sizeof(linebuf), fp);
  356. }
  357. fclose (fp);
  358. return EXIT_SUCCESS;
  359. }
  360. close (conn);
  361. }
  362. }
  363. waitpid(-1, NULL, WNOHANG);
  364. }
  365. return EXIT_SUCCESS;
  366. }