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

Line Branch Exec Source
1
/*	$Id: fileproc.c,v 1.14 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 <err.h>
19
#include <errno.h>
20
#include <fcntl.h>
21
#include <limits.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "extern.h"
28
29
static int
30
serialise(const char *tmp, const char *real,
31
    const char *v, size_t vsz, const char *v2, size_t v2sz)
32
{
33
	int	 fd;
34
35
	/*
36
	 * Write into backup location, overwriting.
37
	 * Then atomically (?) do the rename.
38
	 */
39
40
	fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0444);
41
	if (fd == -1) {
42
		warn("%s", tmp);
43
		return 0;
44
	} else if ((ssize_t)vsz != write(fd, v, vsz)) {
45
		warnx("%s", tmp);
46
		close(fd);
47
		return 0;
48
	} else if (v2 != NULL && write(fd, v2, v2sz) != (ssize_t)v2sz) {
49
		warnx("%s", tmp);
50
		close(fd);
51
		return 0;
52
	} else if (close(fd) == -1) {
53
		warn("%s", tmp);
54
		return 0;
55
	} else if (rename(tmp, real) == -1) {
56
		warn("%s", real);
57
		return 0;
58
	}
59
60
	return 1;
61
}
62
63
int
64
fileproc(int certsock, const char *certdir, const char *certfile, const char
65
    *chainfile, const char *fullchainfile)
66
{
67
	char		*csr = NULL, *ch = NULL;
68
	char		*certfile_bak = NULL, *chainfile_bak = NULL;
69
	char		*fullchainfile_bak = NULL;
70
	size_t		 chsz, csz;
71
	int		 rc = 0;
72
	long		 lval;
73
	enum fileop	 op;
74
75
	/* File-system and sandbox jailing. */
76
77
	if (chroot(certdir) == -1) {
78
		warn("chroot");
79
		goto out;
80
	}
81
	if (chdir("/") == -1) {
82
		warn("chdir");
83
		goto out;
84
	}
85
86
	/*
87
	 * rpath and cpath for rename, wpath and cpath for
88
	 * writing to the temporary.
89
	 */
90
	if (pledge("stdio cpath wpath rpath flock", NULL) == -1) {
91
		warn("pledge");
92
		goto out;
93
	}
94
95
	/* Read our operation. */
96
97
	op = FILE__MAX;
98
	if ((lval = readop(certsock, COMM_CHAIN_OP)) == 0)
99
		op = FILE_STOP;
100
	else if (lval == FILE_CREATE || lval == FILE_REMOVE)
101
		op = lval;
102
103
	if (FILE_STOP == op) {
104
		rc = 1;
105
		goto out;
106
	} else if (FILE__MAX == op) {
107
		warnx("unknown operation from certproc");
108
		goto out;
109
	}
110
111
	/*
112
	 * If revoking certificates, just unlink the files.
113
	 * We return the special error code of 2 to indicate that the
114
	 * certificates were removed.
115
	 */
116
117
	if (FILE_REMOVE == op) {
118
		if (certfile) {
119
			if (unlink(certfile) == -1 && errno != ENOENT) {
120
				warn("%s/%s", certdir, certfile);
121
				goto out;
122
			} else
123
				dodbg("%s/%s: unlinked", certdir, certfile);
124
		}
125
126
		if (chainfile) {
127
			if (unlink(chainfile) == -1 && errno != ENOENT) {
128
				warn("%s/%s", certdir, chainfile);
129
				goto out;
130
			} else
131
				dodbg("%s/%s: unlinked", certdir, chainfile);
132
		}
133
134
		if (fullchainfile) {
135
			if (unlink(fullchainfile) == -1 && errno != ENOENT) {
136
				warn("%s/%s", certdir, fullchainfile);
137
				goto out;
138
			} else
139
				dodbg("%s/%s: unlinked", certdir,
140
				    fullchainfile);
141
		}
142
143
		rc = 2;
144
		goto out;
145
	}
146
147
	/*
148
	 * Start by downloading the chain PEM as a buffer.
149
	 * This is not NUL-terminated, but we're just going to guess
150
	 * that it's well-formed and not actually touch the data.
151
	 * Once downloaded, dump it into CHAIN_BAK.
152
	 */
153
154
	if (certfile)
155
		if (asprintf(&certfile_bak, "%s~", certfile) == -1) {
156
			warn("asprintf");
157
			goto out;
158
		}
159
160
	if (chainfile)
161
		if (asprintf(&chainfile_bak, "%s~", chainfile) == -1) {
162
			warn("asprintf");
163
			goto out;
164
		}
165
166
	if (fullchainfile)
167
		if (asprintf(&fullchainfile_bak, "%s~", fullchainfile) == -1) {
168
			warn("asprintf");
169
			goto out;
170
		}
171
172
	if ((ch = readbuf(certsock, COMM_CHAIN, &chsz)) == NULL)
173
		goto out;
174
175
	if (chainfile) {
176
		if (!serialise(chainfile_bak, chainfile, ch, chsz, NULL, 0))
177
			goto out;
178
179
		dodbg("%s/%s: created", certdir, chainfile);
180
	}
181
182
	/*
183
	 * Next, wait until we receive the DER encoded (signed)
184
	 * certificate from the network process.
185
	 * This comes as a stream of bytes: we don't know how many, so
186
	 * just keep downloading.
187
	 */
188
189
	if ((csr = readbuf(certsock, COMM_CSR, &csz)) == NULL)
190
		goto out;
191
192
	if (certfile) {
193
		if (!serialise(certfile_bak, certfile, csr, csz, NULL, 0))
194
			goto out;
195
196
		dodbg("%s/%s: created", certdir, certfile);
197
	}
198
199
	/*
200
	 * Finally, create the full-chain file.
201
	 * This is just the concatenation of the certificate and chain.
202
	 * We return the special error code 2 to indicate that the
203
	 * on-file certificates were changed.
204
	 */
205
	if (fullchainfile) {
206
		if (!serialise(fullchainfile_bak, fullchainfile, csr, csz, ch,
207
		    chsz))
208
			goto out;
209
210
		dodbg("%s/%s: created", certdir, fullchainfile);
211
	}
212
213
	rc = 2;
214
out:
215
	close(certsock);
216
	free(csr);
217
	free(ch);
218
	free(certfile_bak);
219
	free(chainfile_bak);
220
	free(fullchainfile_bak);
221
	return rc;
222
}