1255767Sdes/* $Id: util.c,v 1.14 2024/06/19 13:13:25 claudio Exp $ */ 276259Sgreen/* 365668Skris * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv> 492555Sdes * 565668Skris * Permission to use, copy, modify, and distribute this software for any 665668Skris * purpose with or without fee is hereby granted, provided that the above 765668Skris * copyright notice and this permission notice appear in all copies. 865668Skris * 965668Skris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1065668Skris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1165668Skris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1265668Skris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1365668Skris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1465668Skris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1565668Skris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1665668Skris */ 1765668Skris 1865668Skris#include <sys/wait.h> 1965668Skris 2065668Skris#include <assert.h> 2165668Skris#include <err.h> 2265668Skris#include <errno.h> 2365668Skris#include <limits.h> 2465668Skris#include <stdarg.h> 2565668Skris#include <stdio.h> 2658582Skris#include <stdlib.h> 2758582Skris#include <stdint.h> 2858582Skris#include <string.h> 29204917Sdes#include <unistd.h> 3076259Sgreen 3176259Sgreen#include "extern.h" 32221420Sdes 33221420Sdesstatic const char *const comps[COMP__MAX] = { 34221420Sdes "netproc", /* COMP_NET */ 3576259Sgreen "keyproc", /* COMP_KEY */ 3658582Skris "certproc", /* COMP_CERT */ 3758582Skris "acctproc", /* COMP_ACCOUNT */ 3876259Sgreen "challengeproc", /* COMP_CHALLENGE */ 3958582Skris "fileproc", /* COMP_FILE */ 4058582Skris "dnsproc", /* COMP_DNS */ 41221420Sdes "revokeproc", /* COMP_REVOKE */ 42204917Sdes}; 43204917Sdes 44221420Sdesstatic const char *const comms[COMM__MAX] = { 45215116Sdes "req", /* COMM_REQ */ 46215116Sdes "thumbprint", /* COMM_THUMB */ 4776259Sgreen "cert", /* COMM_CERT */ 4858582Skris "payload", /* COMM_PAY */ 4976259Sgreen "nonce", /* COMM_NONCE */ 5076259Sgreen "token", /* COMM_TOK */ 51240075Sdes "challenge-op", /* COMM_CHNG_OP */ 52240075Sdes "challenge-ack", /* COMM_CHNG_ACK */ 5376259Sgreen "account", /* COMM_ACCT */ 5476259Sgreen "acctpro-status", /* COMM_ACCT_STAT */ 5576259Sgreen "csr", /* COMM_CSR */ 56181111Sdes "csr-op", /* COMM_CSR_OP */ 57181111Sdes "issuer", /* COMM_ISSUER */ 5876259Sgreen "chain", /* COMM_CHAIN */ 5992555Sdes "chain-op", /* COMM_CHAIN_OP */ 6092555Sdes "dns", /* COMM_DNS */ 6192555Sdes "dnsq", /* COMM_DNSQ */ 6292555Sdes "dns-address", /* COMM_DNSA */ 63204917Sdes "dns-family", /* COMM_DNSF */ 64204917Sdes "dns-length", /* COMM_DNSLEN */ 65204917Sdes "keyproc-status", /* COMM_KEY_STAT */ 66204917Sdes "revoke-op", /* COMM_REVOKE_OP */ 67215116Sdes "revoke-check", /* COMM_REVOKE_CHECK */ 68204917Sdes "revoke-response", /* COMM_REVOKE_RESP */ 69204917Sdes}; 70204917Sdes 71204917Sdes/* 72215116Sdes * This will read a long-sized operation. 73215116Sdes * Operations are usually enums, so this should be alright. 74204917Sdes * We return 0 on EOF and LONG_MAX on failure. 75204917Sdes */ 76204917Sdeslong 7758582Skrisreadop(int fd, enum comm comm) 7892555Sdes{ 7992555Sdes ssize_t ssz; 8058582Skris long op; 8158582Skris 82221420Sdes ssz = read(fd, &op, sizeof(long)); 83221420Sdes if (ssz == -1) { 84221420Sdes warn("read: %s", comms[comm]); 85221420Sdes return LONG_MAX; 86221420Sdes } else if (ssz && ssz != sizeof(long)) { 87221420Sdes warnx("short read: %s", comms[comm]); 88204917Sdes return LONG_MAX; 8958582Skris } else if (ssz == 0) 9058582Skris return 0; 91126274Sdes 92204917Sdes return op; 93126274Sdes} 94126274Sdes 95126274Sdeschar * 96204917Sdesreadstr(int fd, enum comm comm) 97126274Sdes{ 98255767Sdes size_t sz; 99248619Sdes 100126274Sdes return readbuf(fd, comm, &sz); 101207319Sdes} 102126274Sdes 103126274Sdes/* 104126274Sdes * Read a buffer from the sender. 10558582Skris * This consists of two parts: the length of the buffer, and the buffer 10692555Sdes * itself. 107126274Sdes * We allow the buffer to be binary, but NUL-terminate it anyway. 10892555Sdes */ 109204917Sdeschar * 110204917Sdesreadbuf(int fd, enum comm comm, size_t *sz) 111215116Sdes{ 112204917Sdes ssize_t ssz; 113204917Sdes size_t rsz, lsz; 114204917Sdes char *p = NULL; 115204917Sdes 116204917Sdes if ((ssz = read(fd, sz, sizeof(size_t))) == -1) { 117248619Sdes warn("read: %s length", comms[comm]); 11876259Sgreen return NULL; 119221420Sdes } else if ((size_t)ssz != sizeof(size_t)) { 120221420Sdes warnx("short read: %s length", comms[comm]); 121255767Sdes return NULL; 122221420Sdes } else if (*sz > SIZE_MAX - 1) { 123221420Sdes warnx("integer overflow"); 124221420Sdes return NULL; 125221420Sdes } else if ((p = calloc(1, *sz + 1)) == NULL) { 126255767Sdes warn("malloc"); 127221420Sdes return NULL; 128221420Sdes } 129221420Sdes 130255767Sdes /* Catch this over several reads. */ 131221420Sdes 132126274Sdes rsz = 0; 133126274Sdes lsz = *sz; 134126274Sdes while (lsz) { 135221420Sdes if ((ssz = read(fd, p + rsz, lsz)) == -1) { 136126274Sdes warn("read: %s", comms[comm]); 13776259Sgreen break; 138126274Sdes } else if (ssz > 0) { 139126274Sdes assert((size_t)ssz <= lsz); 14076259Sgreen rsz += (size_t)ssz; 141126274Sdes lsz -= (size_t)ssz; 142126274Sdes } 143221420Sdes } 144221420Sdes 145126274Sdes if (lsz) { 146126274Sdes warnx("couldn't read buffer: %s", comms[comm]); 147113908Sdes free(p); 148221420Sdes return NULL; 149221420Sdes } 150221420Sdes 15158582Skris return p; 152221420Sdes} 153221420Sdes 154/* 155 * Wring a long-value to a communication pipe. 156 * Returns 0 if the reader has terminated, -1 on error, 1 on success. 157 */ 158int 159writeop(int fd, enum comm comm, long op) 160{ 161 ssize_t ssz; 162 int er; 163 164 if ((ssz = write(fd, &op, sizeof(long))) == -1) { 165 if ((er = errno) != EPIPE) 166 warn("write: %s", comms[comm]); 167 return er == EPIPE ? 0 : -1; 168 } 169 170 if ((size_t)ssz != sizeof(long)) { 171 warnx("short write: %s", comms[comm]); 172 return -1; 173 } 174 175 return 1; 176} 177 178/* 179 * Fully write the given buffer. 180 * Returns 0 if the reader has terminated, -1 on error, 1 on success. 181 */ 182int 183writebuf(int fd, enum comm comm, const void *v, size_t sz) 184{ 185 ssize_t ssz; 186 int er, rc = -1; 187 188 /* 189 * First, try to write the length. 190 * If the other end of the pipe has closed, we allow the short 191 * write to propagate as a return value of zero. 192 */ 193 194 if ((ssz = write(fd, &sz, sizeof(size_t))) == -1) { 195 if ((er = errno) != EPIPE) 196 warn("write: %s length", comms[comm]); 197 return er == EPIPE ? 0 : -1; 198 } 199 200 /* Now write errors cause us to bail. */ 201 202 if ((size_t)ssz != sizeof(size_t)) 203 warnx("short write: %s length", comms[comm]); 204 else if ((ssz = write(fd, v, sz)) == -1) { 205 if (errno == EPIPE) 206 rc = 0; 207 else 208 warn("write: %s", comms[comm]); 209 } else if (sz != (size_t)ssz) 210 warnx("short write: %s", comms[comm]); 211 else 212 rc = 1; 213 214 return rc; 215} 216 217int 218writestr(int fd, enum comm comm, const char *v) 219{ 220 221 return writebuf(fd, comm, v, strlen(v)); 222} 223 224/* 225 * Make sure that the given process exits properly, i.e., properly 226 * exiting with EXIT_SUCCESS. 227 * Returns non-zero on success and zero on failure. 228 */ 229int 230checkexit(pid_t pid, enum comp comp) 231{ 232 int c, cc; 233 const char *cp; 234 235 if (waitpid(pid, &c, 0) == -1) { 236 warn("waitpid"); 237 return 0; 238 } else if (!WIFEXITED(c) && WIFSIGNALED(c)) { 239 cp = strsignal(WTERMSIG(c)); 240 warnx("signal: %s(%u): %s", comps[comp], pid, cp); 241 return 0; 242 } else if (!WIFEXITED(c)) { 243 warnx("did not exit: %s(%u)", comps[comp], pid); 244 return 0; 245 } else if (WEXITSTATUS(c) != EXIT_SUCCESS) { 246 cc = WEXITSTATUS(c); 247 dodbg("bad exit: %s(%u): %d", comps[comp], pid, cc); 248 return 0; 249 } 250 251 return 1; 252} 253 254/* 255 * Make sure that the given process exits properly, i.e., properly 256 * exiting with EXIT_SUCCESS *or* 2. 257 * Returns non-zero on success and zero on failure and sets the "rc" 258 * value to be the exit status. 259 */ 260int 261checkexit_ext(int *rc, pid_t pid, enum comp comp) 262{ 263 int c; 264 const char *cp; 265 266 *rc = EXIT_FAILURE; 267 268 if (waitpid(pid, &c, 0) == -1) { 269 warn("waitpid"); 270 return 0; 271 } 272 273 if (!WIFEXITED(c) && WIFSIGNALED(c)) { 274 cp = strsignal(WTERMSIG(c)); 275 warnx("signal: %s(%u): %s", comps[comp], pid, cp); 276 return 0; 277 } else if (!WIFEXITED(c)) { 278 warnx("did not exit: %s(%u)", comps[comp], pid); 279 return 0; 280 } 281 282 /* Now check extended status. */ 283 284 if ((*rc = WEXITSTATUS(c)) != EXIT_SUCCESS && *rc != 2) { 285 dodbg("bad exit: %s(%u): %d", comps[comp], pid, *rc); 286 return 0; 287 } 288 return 1; 289} 290