1*bf921b2aSclaudio /* $OpenBSD: queue_proc.c,v 1.14 2024/11/21 13:42:22 claudio Exp $ */ 23f70ecafSeric 33f70ecafSeric /* 43f70ecafSeric * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> 53f70ecafSeric * 63f70ecafSeric * Permission to use, copy, modify, and distribute this software for any 73f70ecafSeric * purpose with or without fee is hereby granted, provided that the above 83f70ecafSeric * copyright notice and this permission notice appear in all copies. 93f70ecafSeric * 103f70ecafSeric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 113f70ecafSeric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 123f70ecafSeric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 133f70ecafSeric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 143f70ecafSeric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 153f70ecafSeric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 163f70ecafSeric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 173f70ecafSeric */ 183f70ecafSeric 19369c9387Sclaudio #include <errno.h> 203f70ecafSeric #include <fcntl.h> 213f70ecafSeric #include <string.h> 223f70ecafSeric 233f70ecafSeric #include "smtpd.h" 243f70ecafSeric #include "log.h" 253f70ecafSeric 263f70ecafSeric static struct imsgbuf ibuf; 273f70ecafSeric static struct imsg imsg; 283f70ecafSeric static size_t rlen; 293f70ecafSeric static char *rdata; 303f70ecafSeric 313f70ecafSeric static void 323f70ecafSeric queue_proc_call(void) 333f70ecafSeric { 343f70ecafSeric ssize_t n; 353f70ecafSeric 36dd7efffeSclaudio if (imsgbuf_flush(&ibuf) == -1) { 37dd7efffeSclaudio log_warn("warn: queue-proc: imsgbuf_flush"); 383f70ecafSeric fatalx("queue-proc: exiting"); 393f70ecafSeric } 403f70ecafSeric 413f70ecafSeric while (1) { 423f70ecafSeric if ((n = imsg_get(&ibuf, &imsg)) == -1) { 433f70ecafSeric log_warn("warn: queue-proc: imsg_get"); 443f70ecafSeric break; 453f70ecafSeric } 463f70ecafSeric if (n) { 473f70ecafSeric rlen = imsg.hdr.len - IMSG_HEADER_SIZE; 483f70ecafSeric rdata = imsg.data; 493f70ecafSeric 503f70ecafSeric if (imsg.hdr.type != PROC_QUEUE_OK) { 513f70ecafSeric log_warnx("warn: queue-proc: bad response"); 523f70ecafSeric break; 533f70ecafSeric } 543f70ecafSeric return; 553f70ecafSeric } 563f70ecafSeric 5716b0c81bSclaudio if ((n = imsgbuf_read(&ibuf)) == -1) { 58dd7efffeSclaudio log_warn("warn: queue-proc: imsgbuf_read"); 593f70ecafSeric break; 603f70ecafSeric } 613f70ecafSeric 623f70ecafSeric if (n == 0) { 633f70ecafSeric log_warnx("warn: queue-proc: pipe closed"); 643f70ecafSeric break; 653f70ecafSeric } 663f70ecafSeric } 673f70ecafSeric 683f70ecafSeric fatalx("queue-proc: exiting"); 693f70ecafSeric } 703f70ecafSeric 713f70ecafSeric static void 723f70ecafSeric queue_proc_read(void *dst, size_t len) 733f70ecafSeric { 743f70ecafSeric if (len > rlen) { 753f70ecafSeric log_warnx("warn: queue-proc: bad msg len"); 763f70ecafSeric fatalx("queue-proc: exiting"); 773f70ecafSeric } 783f70ecafSeric 793f70ecafSeric memmove(dst, rdata, len); 803f70ecafSeric rlen -= len; 813f70ecafSeric rdata += len; 823f70ecafSeric } 833f70ecafSeric 843f70ecafSeric static void 853f70ecafSeric queue_proc_end(void) 863f70ecafSeric { 873f70ecafSeric if (rlen) { 883f70ecafSeric log_warnx("warn: queue-proc: bogus data"); 893f70ecafSeric fatalx("queue-proc: exiting"); 903f70ecafSeric } 913f70ecafSeric imsg_free(&imsg); 923f70ecafSeric } 933f70ecafSeric 943f70ecafSeric /* 953f70ecafSeric * API 963f70ecafSeric */ 973f70ecafSeric 983f70ecafSeric static int 9998f67d16Seric queue_proc_close(void) 10098f67d16Seric { 10198f67d16Seric int r; 10298f67d16Seric 103ef15259eSgilles imsg_compose(&ibuf, PROC_QUEUE_CLOSE, 0, 0, -1, NULL, 0); 10498f67d16Seric 10598f67d16Seric queue_proc_call(); 10698f67d16Seric queue_proc_read(&r, sizeof(r)); 10798f67d16Seric queue_proc_end(); 10898f67d16Seric 10998f67d16Seric return (r); 11098f67d16Seric } 11198f67d16Seric 11298f67d16Seric static int 1133f70ecafSeric queue_proc_message_create(uint32_t *msgid) 1143f70ecafSeric { 1153f70ecafSeric int r; 1163f70ecafSeric 1173f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_CREATE, 0, 0, -1, NULL, 0); 1183f70ecafSeric 1193f70ecafSeric queue_proc_call(); 1203f70ecafSeric queue_proc_read(&r, sizeof(r)); 1213f70ecafSeric if (r == 1) 1220d67db0cSeric queue_proc_read(msgid, sizeof(*msgid)); 1233f70ecafSeric queue_proc_end(); 1243f70ecafSeric 1253f70ecafSeric return (r); 1263f70ecafSeric } 1273f70ecafSeric 1283f70ecafSeric static int 1293f70ecafSeric queue_proc_message_commit(uint32_t msgid, const char *path) 1303f70ecafSeric { 1313f70ecafSeric int r, fd; 1323f70ecafSeric 1333f70ecafSeric fd = open(path, O_RDONLY); 1343f70ecafSeric if (fd == -1) { 1353f70ecafSeric log_warn("queue-proc: open: %s", path); 1363f70ecafSeric return (0); 1373f70ecafSeric } 1383f70ecafSeric 1393f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_COMMIT, 0, 0, fd, &msgid, 1403f70ecafSeric sizeof(msgid)); 1413f70ecafSeric 1423f70ecafSeric queue_proc_call(); 1433f70ecafSeric queue_proc_read(&r, sizeof(r)); 1443f70ecafSeric queue_proc_end(); 1453f70ecafSeric 1463f70ecafSeric return (r); 1473f70ecafSeric } 1483f70ecafSeric 1493f70ecafSeric static int 1503f70ecafSeric queue_proc_message_delete(uint32_t msgid) 1513f70ecafSeric { 1523f70ecafSeric int r; 1533f70ecafSeric 1543f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_DELETE, 0, 0, -1, &msgid, 1553f70ecafSeric sizeof(msgid)); 1563f70ecafSeric 1573f70ecafSeric queue_proc_call(); 1583f70ecafSeric queue_proc_read(&r, sizeof(r)); 1593f70ecafSeric queue_proc_end(); 1603f70ecafSeric 1613f70ecafSeric return (r); 1623f70ecafSeric } 1633f70ecafSeric 1643f70ecafSeric static int 1653f70ecafSeric queue_proc_message_fd_r(uint32_t msgid) 1663f70ecafSeric { 1673f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_FD_R, 0, 0, -1, &msgid, 1683f70ecafSeric sizeof(msgid)); 1693f70ecafSeric 1703f70ecafSeric queue_proc_call(); 1713f70ecafSeric queue_proc_end(); 1723f70ecafSeric 173510586acSclaudio return (imsg_get_fd(&imsg)); 1743f70ecafSeric } 1753f70ecafSeric 1763f70ecafSeric static int 1773f70ecafSeric queue_proc_envelope_create(uint32_t msgid, const char *buf, size_t len, 1783f70ecafSeric uint64_t *evpid) 1793f70ecafSeric { 1803f70ecafSeric struct ibuf *b; 1813f70ecafSeric int r; 1823f70ecafSeric 1833f70ecafSeric msgid = evpid_to_msgid(*evpid); 1843f70ecafSeric b = imsg_create(&ibuf, PROC_QUEUE_ENVELOPE_CREATE, 0, 0, 1853f70ecafSeric sizeof(msgid) + len); 1863f70ecafSeric if (imsg_add(b, &msgid, sizeof(msgid)) == -1 || 1873f70ecafSeric imsg_add(b, buf, len) == -1) 1883f70ecafSeric return (0); 1893f70ecafSeric imsg_close(&ibuf, b); 1903f70ecafSeric 1913f70ecafSeric queue_proc_call(); 1923f70ecafSeric queue_proc_read(&r, sizeof(r)); 1933f70ecafSeric if (r == 1) 1943f70ecafSeric queue_proc_read(evpid, sizeof(*evpid)); 1953f70ecafSeric queue_proc_end(); 1963f70ecafSeric 1973f70ecafSeric return (r); 1983f70ecafSeric } 1993f70ecafSeric 2003f70ecafSeric static int 2013f70ecafSeric queue_proc_envelope_delete(uint64_t evpid) 2023f70ecafSeric { 2033f70ecafSeric int r; 2043f70ecafSeric 2053f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_DELETE, 0, 0, -1, &evpid, 2063f70ecafSeric sizeof(evpid)); 2073f70ecafSeric 2083f70ecafSeric queue_proc_call(); 2093f70ecafSeric queue_proc_read(&r, sizeof(r)); 2103f70ecafSeric queue_proc_end(); 2113f70ecafSeric 2123f70ecafSeric return (r); 2133f70ecafSeric } 2143f70ecafSeric 2153f70ecafSeric static int 2163f70ecafSeric queue_proc_envelope_update(uint64_t evpid, const char *buf, size_t len) 2173f70ecafSeric { 2183f70ecafSeric struct ibuf *b; 2193f70ecafSeric int r; 2203f70ecafSeric 2213f70ecafSeric b = imsg_create(&ibuf, PROC_QUEUE_ENVELOPE_UPDATE, 0, 0, 2223f70ecafSeric len + sizeof(evpid)); 2233f70ecafSeric if (imsg_add(b, &evpid, sizeof(evpid)) == -1 || 2243f70ecafSeric imsg_add(b, buf, len) == -1) 2253f70ecafSeric return (0); 2263f70ecafSeric imsg_close(&ibuf, b); 2273f70ecafSeric 2283f70ecafSeric queue_proc_call(); 2293f70ecafSeric queue_proc_read(&r, sizeof(r)); 2303f70ecafSeric queue_proc_end(); 2313f70ecafSeric 2323f70ecafSeric return (r); 2333f70ecafSeric } 2343f70ecafSeric 2353f70ecafSeric static int 2363f70ecafSeric queue_proc_envelope_load(uint64_t evpid, char *buf, size_t len) 2373f70ecafSeric { 2383f70ecafSeric int r; 2393f70ecafSeric 2403f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_LOAD, 0, 0, -1, &evpid, 2413f70ecafSeric sizeof(evpid)); 2423f70ecafSeric 2433f70ecafSeric queue_proc_call(); 2443f70ecafSeric 2453f70ecafSeric if (rlen > len) { 2463f70ecafSeric log_warnx("warn: queue-proc: buf too small"); 2473f70ecafSeric fatalx("queue-proc: exiting"); 2483f70ecafSeric } 2493f70ecafSeric 2503f70ecafSeric r = rlen; 25198f67d16Seric queue_proc_read(buf, rlen); 2523f70ecafSeric queue_proc_end(); 2533f70ecafSeric 2543f70ecafSeric return (r); 2553f70ecafSeric } 2563f70ecafSeric 2573f70ecafSeric static int 2583f70ecafSeric queue_proc_envelope_walk(uint64_t *evpid, char *buf, size_t len) 2593f70ecafSeric { 2603f70ecafSeric int r; 2613f70ecafSeric 2623f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_WALK, 0, 0, -1, NULL, 0); 2633f70ecafSeric 2643f70ecafSeric queue_proc_call(); 2653f70ecafSeric queue_proc_read(&r, sizeof(r)); 2663f70ecafSeric 2673f70ecafSeric if (r > 0) { 2683f70ecafSeric queue_proc_read(evpid, sizeof(*evpid)); 2693f70ecafSeric if (rlen > len) { 2703f70ecafSeric log_warnx("warn: queue-proc: buf too small"); 2713f70ecafSeric fatalx("queue-proc: exiting"); 2723f70ecafSeric } 2733f70ecafSeric if (r != (int)rlen) { 2743f70ecafSeric log_warnx("warn: queue-proc: len mismatch"); 2753f70ecafSeric fatalx("queue-proc: exiting"); 2763f70ecafSeric } 27798f67d16Seric queue_proc_read(buf, rlen); 2783f70ecafSeric } 2793f70ecafSeric queue_proc_end(); 2803f70ecafSeric 2813f70ecafSeric return (r); 2823f70ecafSeric } 2833f70ecafSeric 2843f70ecafSeric static int 28598f67d16Seric queue_proc_init(struct passwd *pw, int server, const char *conf) 2863f70ecafSeric { 2873f70ecafSeric uint32_t version; 28898f67d16Seric int fd; 2893f70ecafSeric 2908380d000Sop fd = fork_proc_backend("queue", conf, "queue-proc", 0); 29198f67d16Seric if (fd == -1) 29298f67d16Seric fatalx("queue-proc: exiting"); 2933f70ecafSeric 294*bf921b2aSclaudio if (imsgbuf_init(&ibuf, fd) == -1) 295*bf921b2aSclaudio fatal("queue-proc: exiting"); 296*bf921b2aSclaudio imsgbuf_allow_fdpass(&ibuf); 2973f70ecafSeric 2983f70ecafSeric version = PROC_QUEUE_API_VERSION; 2993f70ecafSeric imsg_compose(&ibuf, PROC_QUEUE_INIT, 0, 0, -1, 3003f70ecafSeric &version, sizeof(version)); 3013f70ecafSeric 30298f67d16Seric queue_api_on_close(queue_proc_close); 3033f70ecafSeric queue_api_on_message_create(queue_proc_message_create); 3043f70ecafSeric queue_api_on_message_commit(queue_proc_message_commit); 3053f70ecafSeric queue_api_on_message_delete(queue_proc_message_delete); 3063f70ecafSeric queue_api_on_message_fd_r(queue_proc_message_fd_r); 3073f70ecafSeric queue_api_on_envelope_create(queue_proc_envelope_create); 3083f70ecafSeric queue_api_on_envelope_delete(queue_proc_envelope_delete); 3093f70ecafSeric queue_api_on_envelope_update(queue_proc_envelope_update); 3103f70ecafSeric queue_api_on_envelope_load(queue_proc_envelope_load); 3113f70ecafSeric queue_api_on_envelope_walk(queue_proc_envelope_walk); 3123f70ecafSeric 3133f70ecafSeric queue_proc_call(); 3143f70ecafSeric queue_proc_end(); 3153f70ecafSeric 3163f70ecafSeric return (1); 3173f70ecafSeric } 3183f70ecafSeric 3193f70ecafSeric struct queue_backend queue_backend_proc = { 3203f70ecafSeric queue_proc_init, 3213f70ecafSeric }; 322