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