GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/acme-client/util.c Lines: 0 97 0.0 %
Date: 2017-11-07 Branches: 0 66 0.0 %

Line Branch Exec Source
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
}