xref: /openbsd-src/usr.sbin/acme-client/chngproc.c (revision 5b337cd6b5044e74beebf60578032c9c172b3672)
1*5b337cd6Sflorian /*	$Id: chngproc.c,v 1.17 2022/05/05 19:51:35 florian 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 <assert.h>
19*5b337cd6Sflorian #include <ctype.h>
20de579d12Sflorian #include <err.h>
21de579d12Sflorian #include <errno.h>
22de579d12Sflorian #include <fcntl.h>
23de579d12Sflorian #include <stdio.h>
24de579d12Sflorian #include <stdlib.h>
25de579d12Sflorian #include <string.h>
26de579d12Sflorian #include <unistd.h>
27de579d12Sflorian 
28de579d12Sflorian #include "extern.h"
29de579d12Sflorian 
30de579d12Sflorian int
chngproc(int netsock,const char * root)31383e31e9Sbenno chngproc(int netsock, const char *root)
32de579d12Sflorian {
337bce6888Sderaadt 	char		 *tok = NULL, *th = NULL, *fmt = NULL, **fs = NULL;
347bce6888Sderaadt 	size_t		  i, fsz = 0;
357bce6888Sderaadt 	int		  rc = 0, fd = -1, cc;
36de579d12Sflorian 	long		  lval;
37de579d12Sflorian 	enum chngop	  op;
38de579d12Sflorian 	void		 *pp;
39de579d12Sflorian 
4061075b4cSflorian 
4161075b4cSflorian 	if (unveil(root, "wc") == -1) {
42bc5a8259Sbeck 		warn("unveil %s", root);
43de579d12Sflorian 		goto out;
44ec0d8c8bSderaadt 	}
4561075b4cSflorian 
46ec0d8c8bSderaadt 	if (pledge("stdio cpath wpath", NULL) == -1) {
47ec0d8c8bSderaadt 		warn("pledge");
48de579d12Sflorian 		goto out;
49ec0d8c8bSderaadt 	}
50de579d12Sflorian 
51de579d12Sflorian 	/*
52de579d12Sflorian 	 * Loop while we wait to get a thumbprint and token.
53de579d12Sflorian 	 * We'll get this for each SAN request.
54de579d12Sflorian 	 */
55de579d12Sflorian 
56de579d12Sflorian 	for (;;) {
57de579d12Sflorian 		op = CHNG__MAX;
587cd8f039Sjsing 		if ((lval = readop(netsock, COMM_CHNG_OP)) == 0)
59de579d12Sflorian 			op = CHNG_STOP;
607cd8f039Sjsing 		else if (lval == CHNG_SYN)
61de579d12Sflorian 			op = lval;
62de579d12Sflorian 
634de82fa3Sderaadt 		if (op == CHNG__MAX) {
64de579d12Sflorian 			warnx("unknown operation from netproc");
65de579d12Sflorian 			goto out;
664de82fa3Sderaadt 		} else if (op == CHNG_STOP)
67de579d12Sflorian 			break;
68de579d12Sflorian 
694de82fa3Sderaadt 		assert(op == CHNG_SYN);
70de579d12Sflorian 
71de579d12Sflorian 		/*
72de579d12Sflorian 		 * Read the thumbprint and token.
73de579d12Sflorian 		 * The token is the filename, so store that in a vector
74de579d12Sflorian 		 * of tokens that we'll later clean up.
75de579d12Sflorian 		 */
76de579d12Sflorian 
777cd8f039Sjsing 		if ((th = readstr(netsock, COMM_THUMB)) == NULL)
78de579d12Sflorian 			goto out;
797cd8f039Sjsing 		else if ((tok = readstr(netsock, COMM_TOK)) == NULL)
80de579d12Sflorian 			goto out;
81*5b337cd6Sflorian 		else if (strlen(tok) < 1) {
82*5b337cd6Sflorian 			warnx("token is too short");
83*5b337cd6Sflorian 			goto out;
84*5b337cd6Sflorian 		}
85*5b337cd6Sflorian 
86*5b337cd6Sflorian 		for (i = 0; tok[i]; ++i) {
87*5b337cd6Sflorian 			int ch = (unsigned char)tok[i];
88*5b337cd6Sflorian 			if (!isalnum(ch) && ch != '-' && ch != '_') {
89*5b337cd6Sflorian 				warnx("token is not a valid base64url");
90*5b337cd6Sflorian 				goto out;
91*5b337cd6Sflorian 			}
92*5b337cd6Sflorian 		}
93de579d12Sflorian 
9461075b4cSflorian 		if (asprintf(&fmt, "%s.%s", tok, th) == -1) {
9561075b4cSflorian 			warn("asprintf");
9661075b4cSflorian 			goto out;
9761075b4cSflorian 		}
9861075b4cSflorian 
99de579d12Sflorian 		/* Vector appending... */
100de579d12Sflorian 
10182f95fa9Sderaadt 		pp = reallocarray(fs, (fsz + 1), sizeof(char *));
1027cd8f039Sjsing 		if (pp == NULL) {
103de579d12Sflorian 			warn("realloc");
104de579d12Sflorian 			goto out;
105de579d12Sflorian 		}
106de579d12Sflorian 		fs = pp;
10761075b4cSflorian 		if (asprintf(&fs[fsz], "%s/%s", root, tok) == -1) {
108de579d12Sflorian 			warn("asprintf");
109de579d12Sflorian 			goto out;
110de579d12Sflorian 		}
11161075b4cSflorian 		fsz++;
11261075b4cSflorian 		free(tok);
11361075b4cSflorian 		tok = NULL;
114de579d12Sflorian 
115de579d12Sflorian 		/*
116de579d12Sflorian 		 * Create and write to our challenge file.
117de579d12Sflorian 		 * Note: we use file descriptors instead of FILE
118de579d12Sflorian 		 * because we want to minimise our pledges.
119de579d12Sflorian 		 */
120cb135f92Sbenno 		fd = open(fs[fsz - 1], O_WRONLY|O_CREAT|O_TRUNC, 0444);
1217cd8f039Sjsing 		if (fd == -1) {
122de579d12Sflorian 			warn("%s", fs[fsz - 1]);
123de579d12Sflorian 			goto out;
124ec13f15cSnaddy 		}
125ec13f15cSnaddy 		if (write(fd, fmt, strlen(fmt)) == -1) {
126de579d12Sflorian 			warn("%s", fs[fsz - 1]);
127de579d12Sflorian 			goto out;
128ec13f15cSnaddy 		}
129ec13f15cSnaddy 		if (close(fd) == -1) {
130de579d12Sflorian 			warn("%s", fs[fsz - 1]);
131de579d12Sflorian 			goto out;
132de579d12Sflorian 		}
133de579d12Sflorian 		fd = -1;
134de579d12Sflorian 
135de579d12Sflorian 		free(th);
136de579d12Sflorian 		free(fmt);
137de579d12Sflorian 		th = fmt = NULL;
138de579d12Sflorian 
13961075b4cSflorian 		dodbg("%s: created", fs[fsz - 1]);
140de579d12Sflorian 
141de579d12Sflorian 		/*
142de579d12Sflorian 		 * Write our acknowledgement.
143de579d12Sflorian 		 * Ignore reader failure.
144de579d12Sflorian 		 */
145de579d12Sflorian 
146de579d12Sflorian 		cc = writeop(netsock, COMM_CHNG_ACK, CHNG_ACK);
1477cd8f039Sjsing 		if (cc == 0)
148de579d12Sflorian 			break;
149de579d12Sflorian 		if (cc < 0)
150de579d12Sflorian 			goto out;
151de579d12Sflorian 	}
152de579d12Sflorian 
153de579d12Sflorian 	rc = 1;
154de579d12Sflorian out:
155de579d12Sflorian 	close(netsock);
1567cd8f039Sjsing 	if (fd != -1)
157de579d12Sflorian 		close(fd);
158de579d12Sflorian 	for (i = 0; i < fsz; i++) {
1597cd8f039Sjsing 		if (unlink(fs[i]) == -1 && errno != ENOENT)
160de579d12Sflorian 			warn("%s", fs[i]);
161de579d12Sflorian 		free(fs[i]);
162de579d12Sflorian 	}
163de579d12Sflorian 	free(fs);
164de579d12Sflorian 	free(fmt);
165de579d12Sflorian 	free(th);
166de579d12Sflorian 	free(tok);
16734335c11Sjsing 	return rc;
168de579d12Sflorian }
169