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