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 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