1*bc5a8259Sbeck /* $Id: fileproc.c,v 1.18 2021/07/12 15:09:20 beck Exp $ */
2de579d12Sflorian /*
3de579d12Sflorian * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
4de579d12Sflorian *
5de579d12Sflorian * Permission to use, copy, modify, and distribute this software for any
6de579d12Sflorian * purpose with or without fee is hereby granted, provided that the above
7de579d12Sflorian * copyright notice and this permission notice appear in all copies.
8de579d12Sflorian *
9de579d12Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10de579d12Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11de579d12Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12de579d12Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13de579d12Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14de579d12Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15de579d12Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16de579d12Sflorian */
17de579d12Sflorian
184716c154Sbenno #include <sys/stat.h>
194716c154Sbenno
20de579d12Sflorian #include <err.h>
21de579d12Sflorian #include <errno.h>
22de579d12Sflorian #include <fcntl.h>
23de579d12Sflorian #include <limits.h>
24de579d12Sflorian #include <stdio.h>
25de579d12Sflorian #include <stdlib.h>
26de579d12Sflorian #include <string.h>
27de579d12Sflorian #include <unistd.h>
28de579d12Sflorian
29de579d12Sflorian #include "extern.h"
30de579d12Sflorian
31de579d12Sflorian static int
serialise(const char * real,const char * v,size_t vsz,const char * v2,size_t v2sz)324716c154Sbenno serialise(const char *real, const char *v, size_t vsz, const char *v2, size_t v2sz)
33de579d12Sflorian {
34de579d12Sflorian int fd;
354716c154Sbenno char *tmp;
36de579d12Sflorian
3747e51140Sflorian /* create backup hardlink */
3847e51140Sflorian if (asprintf(&tmp, "%s.1", real) == -1) {
3947e51140Sflorian warn("asprintf");
4047e51140Sflorian return 0;
4147e51140Sflorian }
4247e51140Sflorian (void) unlink(tmp);
4347e51140Sflorian if (link(real, tmp) == -1 && errno != ENOENT) {
4447e51140Sflorian warn("link");
4547e51140Sflorian free(tmp);
4647e51140Sflorian return 0;
4747e51140Sflorian }
4847e51140Sflorian free(tmp);
4947e51140Sflorian
50de579d12Sflorian /*
51de579d12Sflorian * Write into backup location, overwriting.
524716c154Sbenno * Then atomically do the rename.
53de579d12Sflorian */
54de579d12Sflorian
554716c154Sbenno if (asprintf(&tmp, "%s.XXXXXXXXXX", real) == -1) {
564716c154Sbenno warn("asprintf");
5734335c11Sjsing return 0;
58de579d12Sflorian }
594716c154Sbenno if ((fd = mkstemp(tmp)) == -1) {
604716c154Sbenno warn("mkstemp");
614716c154Sbenno goto out;
624716c154Sbenno }
634716c154Sbenno if (fchmod(fd, 0444) == -1) {
644716c154Sbenno warn("fchmod");
654716c154Sbenno goto out;
664716c154Sbenno }
674716c154Sbenno if ((ssize_t)vsz != write(fd, v, vsz)) {
684716c154Sbenno warnx("write");
694716c154Sbenno goto out;
704716c154Sbenno }
714716c154Sbenno if (v2 != NULL && write(fd, v2, v2sz) != (ssize_t)v2sz) {
724716c154Sbenno warnx("write");
734716c154Sbenno goto out;
744716c154Sbenno }
754716c154Sbenno if (close(fd) == -1)
764716c154Sbenno goto out;
774716c154Sbenno if (rename(tmp, real) == -1) {
784716c154Sbenno warn("%s", real);
794716c154Sbenno goto out;
804716c154Sbenno }
81de579d12Sflorian
824716c154Sbenno free(tmp);
8334335c11Sjsing return 1;
844716c154Sbenno out:
854716c154Sbenno if (fd != -1)
864716c154Sbenno close(fd);
874716c154Sbenno (void) unlink(tmp);
884716c154Sbenno free(tmp);
894716c154Sbenno return 0;
90de579d12Sflorian }
91de579d12Sflorian
92de579d12Sflorian int
fileproc(int certsock,const char * certdir,const char * certfile,const char * chainfile,const char * fullchainfile)9362492c74Sflorian fileproc(int certsock, const char *certdir, const char *certfile, const char
9462492c74Sflorian *chainfile, const char *fullchainfile)
95de579d12Sflorian {
967bce6888Sderaadt char *csr = NULL, *ch = NULL;
97de579d12Sflorian size_t chsz, csz;
987bce6888Sderaadt int rc = 0;
99de579d12Sflorian long lval;
100de579d12Sflorian enum fileop op;
101de579d12Sflorian
10261075b4cSflorian if (unveil(certdir, "rwc") == -1) {
103*bc5a8259Sbeck warn("unveil %s", certdir);
104de579d12Sflorian goto out;
105ec0d8c8bSderaadt }
106ec0d8c8bSderaadt
107ec0d8c8bSderaadt /*
108ec0d8c8bSderaadt * rpath and cpath for rename, wpath and cpath for
1094716c154Sbenno * writing to the temporary. fattr for fchmod.
110ec0d8c8bSderaadt */
1114716c154Sbenno if (pledge("stdio cpath wpath rpath fattr", NULL) == -1) {
112ec0d8c8bSderaadt warn("pledge");
113de579d12Sflorian goto out;
114ec0d8c8bSderaadt }
115de579d12Sflorian
116de579d12Sflorian /* Read our operation. */
117de579d12Sflorian
118de579d12Sflorian op = FILE__MAX;
1197cd8f039Sjsing if ((lval = readop(certsock, COMM_CHAIN_OP)) == 0)
120de579d12Sflorian op = FILE_STOP;
1217cd8f039Sjsing else if (lval == FILE_CREATE || lval == FILE_REMOVE)
122de579d12Sflorian op = lval;
123de579d12Sflorian
124de579d12Sflorian if (FILE_STOP == op) {
125de579d12Sflorian rc = 1;
126de579d12Sflorian goto out;
127de579d12Sflorian } else if (FILE__MAX == op) {
128de579d12Sflorian warnx("unknown operation from certproc");
129de579d12Sflorian goto out;
130de579d12Sflorian }
131de579d12Sflorian
132de579d12Sflorian /*
133de579d12Sflorian * If revoking certificates, just unlink the files.
134de579d12Sflorian * We return the special error code of 2 to indicate that the
135de579d12Sflorian * certificates were removed.
136de579d12Sflorian */
137de579d12Sflorian
138de579d12Sflorian if (FILE_REMOVE == op) {
13962492c74Sflorian if (certfile) {
1407cd8f039Sjsing if (unlink(certfile) == -1 && errno != ENOENT) {
14161075b4cSflorian warn("%s", certfile);
142de579d12Sflorian goto out;
143de579d12Sflorian } else
14461075b4cSflorian dodbg("%s: unlinked", certfile);
14562492c74Sflorian }
146de579d12Sflorian
14762492c74Sflorian if (chainfile) {
1487cd8f039Sjsing if (unlink(chainfile) == -1 && errno != ENOENT) {
14961075b4cSflorian warn("%s", chainfile);
150de579d12Sflorian goto out;
151de579d12Sflorian } else
15261075b4cSflorian dodbg("%s: unlinked", chainfile);
15362492c74Sflorian }
154de579d12Sflorian
15562492c74Sflorian if (fullchainfile) {
1567cd8f039Sjsing if (unlink(fullchainfile) == -1 && errno != ENOENT) {
15761075b4cSflorian warn("%s", fullchainfile);
158de579d12Sflorian goto out;
159de579d12Sflorian } else
16061075b4cSflorian dodbg("%s: unlinked", fullchainfile);
16162492c74Sflorian }
162de579d12Sflorian
163de579d12Sflorian rc = 2;
164de579d12Sflorian goto out;
165de579d12Sflorian }
166de579d12Sflorian
167de579d12Sflorian /*
168de579d12Sflorian * Start by downloading the chain PEM as a buffer.
169b8ee2fe2Sderaadt * This is not NUL-terminated, but we're just going to guess
170de579d12Sflorian * that it's well-formed and not actually touch the data.
171de579d12Sflorian */
1727cd8f039Sjsing if ((ch = readbuf(certsock, COMM_CHAIN, &chsz)) == NULL)
173de579d12Sflorian goto out;
17462492c74Sflorian
17562492c74Sflorian if (chainfile) {
1764716c154Sbenno if (!serialise(chainfile, ch, chsz, NULL, 0))
177de579d12Sflorian goto out;
178de579d12Sflorian
17961075b4cSflorian dodbg("%s: created", chainfile);
18062492c74Sflorian }
181de579d12Sflorian
182de579d12Sflorian /*
183de579d12Sflorian * Next, wait until we receive the DER encoded (signed)
184de579d12Sflorian * certificate from the network process.
185de579d12Sflorian * This comes as a stream of bytes: we don't know how many, so
186de579d12Sflorian * just keep downloading.
187de579d12Sflorian */
188de579d12Sflorian
1897cd8f039Sjsing if ((csr = readbuf(certsock, COMM_CSR, &csz)) == NULL)
190de579d12Sflorian goto out;
191d40ebfdcSflorian
192d40ebfdcSflorian if (certfile) {
1934716c154Sbenno if (!serialise(certfile, csr, csz, NULL, 0))
194de579d12Sflorian goto out;
195de579d12Sflorian
19661075b4cSflorian dodbg("%s: created", certfile);
197d40ebfdcSflorian }
198de579d12Sflorian
199de579d12Sflorian /*
200de579d12Sflorian * Finally, create the full-chain file.
201de579d12Sflorian * This is just the concatenation of the certificate and chain.
202de579d12Sflorian * We return the special error code 2 to indicate that the
203de579d12Sflorian * on-file certificates were changed.
204de579d12Sflorian */
20562492c74Sflorian if (fullchainfile) {
2064716c154Sbenno if (!serialise(fullchainfile, csr, csz, ch,
20762492c74Sflorian chsz))
208de579d12Sflorian goto out;
209de579d12Sflorian
21061075b4cSflorian dodbg("%s: created", fullchainfile);
21162492c74Sflorian }
212de579d12Sflorian
213de579d12Sflorian rc = 2;
214de579d12Sflorian out:
215de579d12Sflorian close(certsock);
216de579d12Sflorian free(csr);
217de579d12Sflorian free(ch);
21834335c11Sjsing return rc;
219de579d12Sflorian }
220