xref: /openbsd/usr.sbin/acme-client/chngproc.c (revision 5a38ef86)
1 /*	$Id: chngproc.c,v 1.16 2021/07/12 15:09:20 beck 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 <assert.h>
19 #include <err.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "extern.h"
28 
29 int
30 chngproc(int netsock, const char *root)
31 {
32 	char		 *tok = NULL, *th = NULL, *fmt = NULL, **fs = NULL;
33 	size_t		  i, fsz = 0;
34 	int		  rc = 0, fd = -1, cc;
35 	long		  lval;
36 	enum chngop	  op;
37 	void		 *pp;
38 
39 
40 	if (unveil(root, "wc") == -1) {
41 		warn("unveil %s", root);
42 		goto out;
43 	}
44 
45 	if (pledge("stdio cpath wpath", NULL) == -1) {
46 		warn("pledge");
47 		goto out;
48 	}
49 
50 	/*
51 	 * Loop while we wait to get a thumbprint and token.
52 	 * We'll get this for each SAN request.
53 	 */
54 
55 	for (;;) {
56 		op = CHNG__MAX;
57 		if ((lval = readop(netsock, COMM_CHNG_OP)) == 0)
58 			op = CHNG_STOP;
59 		else if (lval == CHNG_SYN)
60 			op = lval;
61 
62 		if (op == CHNG__MAX) {
63 			warnx("unknown operation from netproc");
64 			goto out;
65 		} else if (op == CHNG_STOP)
66 			break;
67 
68 		assert(op == CHNG_SYN);
69 
70 		/*
71 		 * Read the thumbprint and token.
72 		 * The token is the filename, so store that in a vector
73 		 * of tokens that we'll later clean up.
74 		 */
75 
76 		if ((th = readstr(netsock, COMM_THUMB)) == NULL)
77 			goto out;
78 		else if ((tok = readstr(netsock, COMM_TOK)) == NULL)
79 			goto out;
80 
81 		if (asprintf(&fmt, "%s.%s", tok, th) == -1) {
82 			warn("asprintf");
83 			goto out;
84 		}
85 
86 		/* Vector appending... */
87 
88 		pp = reallocarray(fs, (fsz + 1), sizeof(char *));
89 		if (pp == NULL) {
90 			warn("realloc");
91 			goto out;
92 		}
93 		fs = pp;
94 		if (asprintf(&fs[fsz], "%s/%s", root, tok) == -1) {
95 			warn("asprintf");
96 			goto out;
97 		}
98 		fsz++;
99 		free(tok);
100 		tok = NULL;
101 
102 		/*
103 		 * Create and write to our challenge file.
104 		 * Note: we use file descriptors instead of FILE
105 		 * because we want to minimise our pledges.
106 		 */
107 		fd = open(fs[fsz - 1], O_WRONLY|O_CREAT|O_TRUNC, 0444);
108 		if (fd == -1) {
109 			warn("%s", fs[fsz - 1]);
110 			goto out;
111 		}
112 		if (write(fd, fmt, strlen(fmt)) == -1) {
113 			warn("%s", fs[fsz - 1]);
114 			goto out;
115 		}
116 		if (close(fd) == -1) {
117 			warn("%s", fs[fsz - 1]);
118 			goto out;
119 		}
120 		fd = -1;
121 
122 		free(th);
123 		free(fmt);
124 		th = fmt = NULL;
125 
126 		dodbg("%s: created", fs[fsz - 1]);
127 
128 		/*
129 		 * Write our acknowledgement.
130 		 * Ignore reader failure.
131 		 */
132 
133 		cc = writeop(netsock, COMM_CHNG_ACK, CHNG_ACK);
134 		if (cc == 0)
135 			break;
136 		if (cc < 0)
137 			goto out;
138 	}
139 
140 	rc = 1;
141 out:
142 	close(netsock);
143 	if (fd != -1)
144 		close(fd);
145 	for (i = 0; i < fsz; i++) {
146 		if (unlink(fs[i]) == -1 && errno != ENOENT)
147 			warn("%s", fs[i]);
148 		free(fs[i]);
149 	}
150 	free(fs);
151 	free(fmt);
152 	free(th);
153 	free(tok);
154 	return rc;
155 }
156