[BACK]Return to chngproc.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / acme-client

File: [local] / src / usr.sbin / acme-client / chngproc.c (download)

Revision 1.17, Thu May 5 19:51:35 2022 UTC (2 years, 1 month ago) by florian
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, HEAD
Changes since 1.16: +14 -1 lines

Check that the challenge token which is turned into a filename is
base64url encoded.
We have only the challenge directory unveil(2)'ed so funny business
like ../ will not work, but we shouldn't generate garbage filenames
that someone else might trip over either.
Pointed out and diff by Ali Farzanrad (ali_farzanrad AT riseup.net)
OK beck

/*	$Id: chngproc.c,v 1.17 2022/05/05 19:51:35 florian Exp $ */
/*
 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
 *
 * 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.
 */

#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "extern.h"

int
chngproc(int netsock, const char *root)
{
	char		 *tok = NULL, *th = NULL, *fmt = NULL, **fs = NULL;
	size_t		  i, fsz = 0;
	int		  rc = 0, fd = -1, cc;
	long		  lval;
	enum chngop	  op;
	void		 *pp;


	if (unveil(root, "wc") == -1) {
		warn("unveil %s", root);
		goto out;
	}

	if (pledge("stdio cpath wpath", NULL) == -1) {
		warn("pledge");
		goto out;
	}

	/*
	 * Loop while we wait to get a thumbprint and token.
	 * We'll get this for each SAN request.
	 */

	for (;;) {
		op = CHNG__MAX;
		if ((lval = readop(netsock, COMM_CHNG_OP)) == 0)
			op = CHNG_STOP;
		else if (lval == CHNG_SYN)
			op = lval;

		if (op == CHNG__MAX) {
			warnx("unknown operation from netproc");
			goto out;
		} else if (op == CHNG_STOP)
			break;

		assert(op == CHNG_SYN);

		/*
		 * 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 ((th = readstr(netsock, COMM_THUMB)) == NULL)
			goto out;
		else if ((tok = readstr(netsock, COMM_TOK)) == NULL)
			goto out;
		else if (strlen(tok) < 1) {
			warnx("token is too short");
			goto out;
		}

		for (i = 0; tok[i]; ++i) {
			int ch = (unsigned char)tok[i];
			if (!isalnum(ch) && ch != '-' && ch != '_') {
				warnx("token is not a valid base64url");
				goto out;
			}
		}

		if (asprintf(&fmt, "%s.%s", tok, th) == -1) {
			warn("asprintf");
			goto out;
		}

		/* Vector appending... */

		pp = reallocarray(fs, (fsz + 1), sizeof(char *));
		if (pp == NULL) {
			warn("realloc");
			goto out;
		}
		fs = pp;
		if (asprintf(&fs[fsz], "%s/%s", root, tok) == -1) {
			warn("asprintf");
			goto out;
		}
		fsz++;
		free(tok);
		tok = NULL;

		/*
		 * Create and write to our challenge file.
		 * Note: we use file descriptors instead of FILE
		 * because we want to minimise our pledges.
		 */
		fd = open(fs[fsz - 1], O_WRONLY|O_CREAT|O_TRUNC, 0444);
		if (fd == -1) {
			warn("%s", fs[fsz - 1]);
			goto out;
		}
		if (write(fd, fmt, strlen(fmt)) == -1) {
			warn("%s", fs[fsz - 1]);
			goto out;
		}
		if (close(fd) == -1) {
			warn("%s", fs[fsz - 1]);
			goto out;
		}
		fd = -1;

		free(th);
		free(fmt);
		th = fmt = NULL;

		dodbg("%s: created", fs[fsz - 1]);

		/*
		 * Write our acknowledgement.
		 * Ignore reader failure.
		 */

		cc = writeop(netsock, COMM_CHNG_ACK, CHNG_ACK);
		if (cc == 0)
			break;
		if (cc < 0)
			goto out;
	}

	rc = 1;
out:
	close(netsock);
	if (fd != -1)
		close(fd);
	for (i = 0; i < fsz; i++) {
		if (unlink(fs[i]) == -1 && errno != ENOENT)
			warn("%s", fs[i]);
		free(fs[i]);
	}
	free(fs);
	free(fmt);
	free(th);
	free(tok);
	return rc;
}