/* $Id: chngproc.c,v 1.11 2016/10/29 22:25:48 kristaps Exp $ */ /* * Copyright (c) 2016 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include "extern.h" int chngproc(int netsock, const char *root, const char *challenge) { char *tok = NULL, *th = NULL, *fmt = NULL, *fmtbuf = NULL; char **fs = NULL; size_t i, fsz = 0, sz; ssize_t ssz; int rc = 0, fd = -1, cc; long lval; enum chngop op; void *pp; #ifdef WCMEDBGCHNGPROC doddbg ("(%d) %d %s %s", __LINE__, netsock, root, challenge); #endif /* File-system and sandbox jailing. */ if ( ! sandbox_before()) goto out; else if ( ! dropfs(NULL != challenge ? PATH_VAR_EMPTY : root)) goto out; else if ( ! sandbox_after(NULL != challenge)) goto out; /* * Loop while we wait to get a thumbprint and token. * We'll get this for each SAN request. */ for (;;) { #ifdef WCMEDBGCHNGPROC doddbg ("(%d)", __LINE__); #endif op = CHNG__MAX; if (0 == (lval = readop(netsock, COMM_CHNG_OP))) op = CHNG_STOP; else if (CHNG_SYN == lval) op = lval; #ifdef WCMEDBGCHNGPROC doddbg ("(%d) %d", __LINE__, op); #endif if (CHNG__MAX == op) { warnx("unknown operation from netproc"); goto out; } else if (CHNG_STOP == op) break; assert(CHNG_SYN == op); /* * Read the thumbprint and token. * The token is the filename, so store that in a vector * of tokens that we'll later clean up. */ if (NULL == (th = readstr(netsock, COMM_THUMB))) #ifndef WCMEDBGCHNGPROC goto out; #else { doddbg ("(%d)", __LINE__); goto out; } #endif else if (NULL == (tok = readstr(netsock, COMM_TOK))) goto out; #ifdef WCMEDBGCHNGPROC doddbg ("(%d)", __LINE__); #endif /* Vector appending... */ pp = realloc(fs, (fsz + 1) * sizeof(char *)); if (NULL == pp) { warn("realloc"); goto out; } fs = pp; fs[fsz] = tok; tok = NULL; fsz++; if (NULL != challenge) { /* * If we have a specific challenge request, then * we write the request and thumbprint to stdout * and wait for a reply (which must be an echo * of the output) to indicate that all's well. */ fmt = doasprintf("%s.%s\n", fs[fsz - 1], th); if (NULL == fmt) { warn("asprintf"); goto out; } else if (NULL == (fmtbuf = strdup(fmt))) { warn("strdup"); goto out; } sz = strlen(fmt); ssz = write(STDOUT_FILENO, fmt, sz); if (-1 == ssz) { warn(""); goto out; } else if ((size_t)ssz != sz) { warnx(": short write"); goto out; } doddbg("%s: challenge written", fs[fsz - 1]); ssz = read(STDIN_FILENO, fmt, sz); if (-1 == ssz) { warn(""); goto out; } else if ((size_t)ssz != sz) { warnx(": short read"); goto out; } else if (strcmp(fmt, fmtbuf)) { warnx(": token mismatch"); goto out; } doddbg("%s: challenge read", fs[fsz - 1]); } else { /* * Create and write to our challenge file. * Note: we use file descriptors instead of FILE * because we want to minimise our pledges. */ fmt = doasprintf("%s.%s", fs[fsz - 1], th); if (NULL == fmt) { warn("asprintf"); goto out; } #ifndef WCMEIDIOM fd = open(fs[fsz - 1], O_WRONLY|O_EXCL|O_CREAT, 0444); #else { char *sptr; UtilSysPrv(); /* WCME confines to ODS-2 semantics */ fd = open(sptr = UtilOds2FileName((char*)root,fs[fsz-1]), /* use 0777 to propagate protections */ O_WRONLY|O_TRUNC|O_CREAT, 0777); UtilMereMortal(); free (sptr); #ifdef WCMEDBGCHNGPROC doddbg ("(%d) %d %%X%08.08x %d %s", __LINE__, fd, vaxc$errno, errno, strerror(errno)); #endif } #endif if (-1 == fd) { warn("%s", fs[fsz - 1]); goto out; } if (-1 == write(fd, fmt, strlen(fmt))) { warn("%s", fs[fsz - 1]); goto out; } else if (-1 == close(fd)) { warn("%s", fs[fsz - 1]); goto out; } fd = -1; dodbg("%s/%s: created", root, fs[fsz - 1]); } free(th); free(fmt); free(fmtbuf); th = fmt = fmtbuf = NULL; /* * Write our acknowledgement. * Ignore reader failure. */ cc = writeop(netsock, COMM_CHNG_ACK, CHNG_ACK); if (0 == cc) break; if (cc < 0) goto out; } rc = 1; out: #ifdef WCMEDBGCHNGPROC doddbg ("(%d) %d", __LINE__, rc); #endif close(netsock); if (-1 != fd) close(fd); if (NULL == challenge) for (i = 0; i < fsz; i++) { #ifndef __VMS if (-1 == unlink(fs[i]) && ENOENT != errno) warn("%s", fs[i]); #else UtilSysPrv(); if (remove(fs[i]) && ENOENT != errno) warn("%s", fs[i]); else /* all versions */ while (!remove (fs[i])); UtilMereMortal(); #endif free(fs[i]); } free(fs); free(fmt); free(fmtbuf); free(th); free(tok); return(rc); }