1*d7c05bd5Sclaudio /* $Id: util.c,v 1.14 2024/06/19 13:13:25 claudio Exp $ */
2de579d12Sflorian /*
3de579d12Sflorian * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
4de579d12Sflorian *
5de579d12Sflorian * Permission to use, copy, modify, and distribute this software for any
6de579d12Sflorian * purpose with or without fee is hereby granted, provided that the above
7de579d12Sflorian * copyright notice and this permission notice appear in all copies.
8de579d12Sflorian *
9de579d12Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10de579d12Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11de579d12Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12de579d12Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13de579d12Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14de579d12Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15de579d12Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16de579d12Sflorian */
17de579d12Sflorian
18de579d12Sflorian #include <sys/wait.h>
19de579d12Sflorian
20de579d12Sflorian #include <assert.h>
21de579d12Sflorian #include <err.h>
22de579d12Sflorian #include <errno.h>
23de579d12Sflorian #include <limits.h>
24de579d12Sflorian #include <stdarg.h>
25de579d12Sflorian #include <stdio.h>
26de579d12Sflorian #include <stdlib.h>
27de579d12Sflorian #include <stdint.h>
28de579d12Sflorian #include <string.h>
29de579d12Sflorian #include <unistd.h>
30de579d12Sflorian
31de579d12Sflorian #include "extern.h"
32de579d12Sflorian
33de579d12Sflorian static const char *const comps[COMP__MAX] = {
34de579d12Sflorian "netproc", /* COMP_NET */
35de579d12Sflorian "keyproc", /* COMP_KEY */
36de579d12Sflorian "certproc", /* COMP_CERT */
37de579d12Sflorian "acctproc", /* COMP_ACCOUNT */
38de579d12Sflorian "challengeproc", /* COMP_CHALLENGE */
39de579d12Sflorian "fileproc", /* COMP_FILE */
40de579d12Sflorian "dnsproc", /* COMP_DNS */
41de579d12Sflorian "revokeproc", /* COMP_REVOKE */
42de579d12Sflorian };
43de579d12Sflorian
44de579d12Sflorian static const char *const comms[COMM__MAX] = {
45de579d12Sflorian "req", /* COMM_REQ */
46de579d12Sflorian "thumbprint", /* COMM_THUMB */
47de579d12Sflorian "cert", /* COMM_CERT */
48de579d12Sflorian "payload", /* COMM_PAY */
49de579d12Sflorian "nonce", /* COMM_NONCE */
50de579d12Sflorian "token", /* COMM_TOK */
51de579d12Sflorian "challenge-op", /* COMM_CHNG_OP */
52de579d12Sflorian "challenge-ack", /* COMM_CHNG_ACK */
53de579d12Sflorian "account", /* COMM_ACCT */
54de579d12Sflorian "acctpro-status", /* COMM_ACCT_STAT */
55de579d12Sflorian "csr", /* COMM_CSR */
56de579d12Sflorian "csr-op", /* COMM_CSR_OP */
57de579d12Sflorian "issuer", /* COMM_ISSUER */
58de579d12Sflorian "chain", /* COMM_CHAIN */
59de579d12Sflorian "chain-op", /* COMM_CHAIN_OP */
60de579d12Sflorian "dns", /* COMM_DNS */
61de579d12Sflorian "dnsq", /* COMM_DNSQ */
62de579d12Sflorian "dns-address", /* COMM_DNSA */
63de579d12Sflorian "dns-family", /* COMM_DNSF */
64de579d12Sflorian "dns-length", /* COMM_DNSLEN */
65de579d12Sflorian "keyproc-status", /* COMM_KEY_STAT */
66de579d12Sflorian "revoke-op", /* COMM_REVOKE_OP */
67de579d12Sflorian "revoke-check", /* COMM_REVOKE_CHECK */
68de579d12Sflorian "revoke-response", /* COMM_REVOKE_RESP */
69de579d12Sflorian };
70de579d12Sflorian
71de579d12Sflorian /*
72de579d12Sflorian * This will read a long-sized operation.
73de579d12Sflorian * Operations are usually enums, so this should be alright.
74de579d12Sflorian * We return 0 on EOF and LONG_MAX on failure.
75de579d12Sflorian */
76de579d12Sflorian long
readop(int fd,enum comm comm)77de579d12Sflorian readop(int fd, enum comm comm)
78de579d12Sflorian {
79de579d12Sflorian ssize_t ssz;
80de579d12Sflorian long op;
81de579d12Sflorian
82de579d12Sflorian ssz = read(fd, &op, sizeof(long));
83df69c215Sderaadt if (ssz == -1) {
84de579d12Sflorian warn("read: %s", comms[comm]);
8534335c11Sjsing return LONG_MAX;
86de579d12Sflorian } else if (ssz && ssz != sizeof(long)) {
87de579d12Sflorian warnx("short read: %s", comms[comm]);
8834335c11Sjsing return LONG_MAX;
897cd8f039Sjsing } else if (ssz == 0)
9034335c11Sjsing return 0;
91de579d12Sflorian
9234335c11Sjsing return op;
93de579d12Sflorian }
94de579d12Sflorian
95de579d12Sflorian char *
readstr(int fd,enum comm comm)96de579d12Sflorian readstr(int fd, enum comm comm)
97de579d12Sflorian {
98de579d12Sflorian size_t sz;
99de579d12Sflorian
10034335c11Sjsing return readbuf(fd, comm, &sz);
101de579d12Sflorian }
102de579d12Sflorian
103de579d12Sflorian /*
104de579d12Sflorian * Read a buffer from the sender.
10557e2f549Ssthen * This consists of two parts: the length of the buffer, and the buffer
106de579d12Sflorian * itself.
107b8ee2fe2Sderaadt * We allow the buffer to be binary, but NUL-terminate it anyway.
108de579d12Sflorian */
109de579d12Sflorian char *
readbuf(int fd,enum comm comm,size_t * sz)110de579d12Sflorian readbuf(int fd, enum comm comm, size_t *sz)
111de579d12Sflorian {
112de579d12Sflorian ssize_t ssz;
113de579d12Sflorian size_t rsz, lsz;
1147bce6888Sderaadt char *p = NULL;
115de579d12Sflorian
116df69c215Sderaadt if ((ssz = read(fd, sz, sizeof(size_t))) == -1) {
117de579d12Sflorian warn("read: %s length", comms[comm]);
11834335c11Sjsing return NULL;
119de579d12Sflorian } else if ((size_t)ssz != sizeof(size_t)) {
120de579d12Sflorian warnx("short read: %s length", comms[comm]);
12134335c11Sjsing return NULL;
122de579d12Sflorian } else if (*sz > SIZE_MAX - 1) {
123de579d12Sflorian warnx("integer overflow");
12434335c11Sjsing return NULL;
1257cd8f039Sjsing } else if ((p = calloc(1, *sz + 1)) == NULL) {
126de579d12Sflorian warn("malloc");
12734335c11Sjsing return NULL;
128de579d12Sflorian }
129de579d12Sflorian
130de579d12Sflorian /* Catch this over several reads. */
131de579d12Sflorian
132de579d12Sflorian rsz = 0;
133de579d12Sflorian lsz = *sz;
134de579d12Sflorian while (lsz) {
135df69c215Sderaadt if ((ssz = read(fd, p + rsz, lsz)) == -1) {
136de579d12Sflorian warn("read: %s", comms[comm]);
137de579d12Sflorian break;
138de579d12Sflorian } else if (ssz > 0) {
139de579d12Sflorian assert((size_t)ssz <= lsz);
140de579d12Sflorian rsz += (size_t)ssz;
141de579d12Sflorian lsz -= (size_t)ssz;
142de579d12Sflorian }
143de579d12Sflorian }
144de579d12Sflorian
145de579d12Sflorian if (lsz) {
146de579d12Sflorian warnx("couldn't read buffer: %s", comms[comm]);
147de579d12Sflorian free(p);
14834335c11Sjsing return NULL;
149de579d12Sflorian }
150de579d12Sflorian
15134335c11Sjsing return p;
152de579d12Sflorian }
153de579d12Sflorian
154de579d12Sflorian /*
155de579d12Sflorian * Wring a long-value to a communication pipe.
156de579d12Sflorian * Returns 0 if the reader has terminated, -1 on error, 1 on success.
157de579d12Sflorian */
158de579d12Sflorian int
writeop(int fd,enum comm comm,long op)159de579d12Sflorian writeop(int fd, enum comm comm, long op)
160de579d12Sflorian {
161de579d12Sflorian ssize_t ssz;
162de579d12Sflorian int er;
163de579d12Sflorian
164df69c215Sderaadt if ((ssz = write(fd, &op, sizeof(long))) == -1) {
1657cd8f039Sjsing if ((er = errno) != EPIPE)
166de579d12Sflorian warn("write: %s", comms[comm]);
16734335c11Sjsing return er == EPIPE ? 0 : -1;
168de579d12Sflorian }
169de579d12Sflorian
170de579d12Sflorian if ((size_t)ssz != sizeof(long)) {
171de579d12Sflorian warnx("short write: %s", comms[comm]);
17234335c11Sjsing return -1;
173de579d12Sflorian }
174de579d12Sflorian
17534335c11Sjsing return 1;
176de579d12Sflorian }
177de579d12Sflorian
178de579d12Sflorian /*
179de579d12Sflorian * Fully write the given buffer.
180de579d12Sflorian * Returns 0 if the reader has terminated, -1 on error, 1 on success.
181de579d12Sflorian */
182de579d12Sflorian int
writebuf(int fd,enum comm comm,const void * v,size_t sz)183de579d12Sflorian writebuf(int fd, enum comm comm, const void *v, size_t sz)
184de579d12Sflorian {
185de579d12Sflorian ssize_t ssz;
1867bce6888Sderaadt int er, rc = -1;
187de579d12Sflorian
188de579d12Sflorian /*
189de579d12Sflorian * First, try to write the length.
190de579d12Sflorian * If the other end of the pipe has closed, we allow the short
1913a50f0a9Sjmc * write to propagate as a return value of zero.
192de579d12Sflorian */
193de579d12Sflorian
194df69c215Sderaadt if ((ssz = write(fd, &sz, sizeof(size_t))) == -1) {
1957cd8f039Sjsing if ((er = errno) != EPIPE)
196de579d12Sflorian warn("write: %s length", comms[comm]);
19734335c11Sjsing return er == EPIPE ? 0 : -1;
198de579d12Sflorian }
199de579d12Sflorian
200de579d12Sflorian /* Now write errors cause us to bail. */
201de579d12Sflorian
202de579d12Sflorian if ((size_t)ssz != sizeof(size_t))
203de579d12Sflorian warnx("short write: %s length", comms[comm]);
204df69c215Sderaadt else if ((ssz = write(fd, v, sz)) == -1) {
2054e296eecSotto if (errno == EPIPE)
2064e296eecSotto rc = 0;
2074e296eecSotto else
208de579d12Sflorian warn("write: %s", comms[comm]);
2094e296eecSotto } else if (sz != (size_t)ssz)
210de579d12Sflorian warnx("short write: %s", comms[comm]);
211de579d12Sflorian else
212de579d12Sflorian rc = 1;
213de579d12Sflorian
21434335c11Sjsing return rc;
215de579d12Sflorian }
216de579d12Sflorian
217de579d12Sflorian int
writestr(int fd,enum comm comm,const char * v)218de579d12Sflorian writestr(int fd, enum comm comm, const char *v)
219de579d12Sflorian {
220de579d12Sflorian
22134335c11Sjsing return writebuf(fd, comm, v, strlen(v));
222de579d12Sflorian }
223de579d12Sflorian
224de579d12Sflorian /*
225de579d12Sflorian * Make sure that the given process exits properly, i.e., properly
226de579d12Sflorian * exiting with EXIT_SUCCESS.
227de579d12Sflorian * Returns non-zero on success and zero on failure.
228de579d12Sflorian */
229de579d12Sflorian int
checkexit(pid_t pid,enum comp comp)230de579d12Sflorian checkexit(pid_t pid, enum comp comp)
231de579d12Sflorian {
232de579d12Sflorian int c, cc;
233de579d12Sflorian const char *cp;
234de579d12Sflorian
2357cd8f039Sjsing if (waitpid(pid, &c, 0) == -1) {
236de579d12Sflorian warn("waitpid");
23734335c11Sjsing return 0;
238de579d12Sflorian } else if (!WIFEXITED(c) && WIFSIGNALED(c)) {
239de579d12Sflorian cp = strsignal(WTERMSIG(c));
240de579d12Sflorian warnx("signal: %s(%u): %s", comps[comp], pid, cp);
24134335c11Sjsing return 0;
242de579d12Sflorian } else if (!WIFEXITED(c)) {
243de579d12Sflorian warnx("did not exit: %s(%u)", comps[comp], pid);
24434335c11Sjsing return 0;
2457cd8f039Sjsing } else if (WEXITSTATUS(c) != EXIT_SUCCESS) {
246de579d12Sflorian cc = WEXITSTATUS(c);
247de579d12Sflorian dodbg("bad exit: %s(%u): %d", comps[comp], pid, cc);
24834335c11Sjsing return 0;
249de579d12Sflorian }
250de579d12Sflorian
25134335c11Sjsing return 1;
252de579d12Sflorian }
253de579d12Sflorian
254de579d12Sflorian /*
255de579d12Sflorian * Make sure that the given process exits properly, i.e., properly
256de579d12Sflorian * exiting with EXIT_SUCCESS *or* 2.
257de579d12Sflorian * Returns non-zero on success and zero on failure and sets the "rc"
258de579d12Sflorian * value to be the exit status.
259de579d12Sflorian */
260de579d12Sflorian int
checkexit_ext(int * rc,pid_t pid,enum comp comp)261de579d12Sflorian checkexit_ext(int *rc, pid_t pid, enum comp comp)
262de579d12Sflorian {
263de579d12Sflorian int c;
264de579d12Sflorian const char *cp;
265de579d12Sflorian
266de579d12Sflorian *rc = EXIT_FAILURE;
267de579d12Sflorian
2687cd8f039Sjsing if (waitpid(pid, &c, 0) == -1) {
269de579d12Sflorian warn("waitpid");
27034335c11Sjsing return 0;
271de579d12Sflorian }
272de579d12Sflorian
273de579d12Sflorian if (!WIFEXITED(c) && WIFSIGNALED(c)) {
274de579d12Sflorian cp = strsignal(WTERMSIG(c));
275de579d12Sflorian warnx("signal: %s(%u): %s", comps[comp], pid, cp);
27634335c11Sjsing return 0;
277de579d12Sflorian } else if (!WIFEXITED(c)) {
278de579d12Sflorian warnx("did not exit: %s(%u)", comps[comp], pid);
27934335c11Sjsing return 0;
280de579d12Sflorian }
281de579d12Sflorian
282de579d12Sflorian /* Now check extended status. */
283de579d12Sflorian
2847cd8f039Sjsing if ((*rc = WEXITSTATUS(c)) != EXIT_SUCCESS && *rc != 2) {
285de579d12Sflorian dodbg("bad exit: %s(%u): %d", comps[comp], pid, *rc);
28634335c11Sjsing return 0;
287de579d12Sflorian }
28834335c11Sjsing return 1;
289de579d12Sflorian }
290