From 6dbba42b40b89d832d2c33494bc6b53e856974b3 Mon Sep 17 00:00:00 2001 From: kristaps <> Date: Thu, 28 Jul 2016 13:32:29 +0000 Subject: [PATCH] Initial backing-up of certificates. Suggested by https://github.com/kristapsdz/letskencrypt/issues/12 and https://github.com/kristapsdz/letskencrypt/issues/9 --- extern.h | 2 +- fileproc.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- main.c | 11 +++++++---- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/extern.h b/extern.h index 48fc4b0..b6a7d33 100644 --- a/extern.h +++ b/extern.h @@ -184,7 +184,7 @@ int chngproc(int, const char *, int); int dnsproc(int); int revokeproc(int, const char *, int, int, const char *const *, size_t); -int fileproc(int, const char *); +int fileproc(int, int, const char *); int keyproc(int, const char *, const char **, size_t, int); int netproc(int, int, int, int, int, int, int, int, int, diff --git a/fileproc.c b/fileproc.c index 5863b9f..9c8a7f5 100644 --- a/fileproc.c +++ b/fileproc.c @@ -21,9 +21,11 @@ #include #include #include +#include #include #include #include +#include #include #include "extern.h" @@ -64,13 +66,15 @@ serialise(const char *tmp, const char *real, } int -fileproc(int certsock, const char *certdir) +fileproc(int certsock, int backup, const char *certdir) { char *csr, *ch; size_t chsz, csz; int rc; long lval; enum fileop op; + time_t t; + char file[PATH_MAX]; csr = ch = NULL; rc = 0; @@ -99,6 +103,45 @@ fileproc(int certsock, const char *certdir) warnx("unknown operation from certproc"); goto out; } + + /* + * If we're backing up, then copy all files (found) by linking + * them to the file followed by the epoch in seconds. + * If we're going to remove, the unlink(2) will cause the + * original to go away. + * If we're going to update, the rename(2) will replace the + * certificate, leaving the backup as the only one. + */ + + if (backup) { + t = time(NULL); + snprintf(file, sizeof(file), + "cert-%llu.pem", (unsigned long long)t); + if (-1 == link(CERT_PEM, file) && ENOENT != errno) { + warnx("%s/%s", certdir, CERT_PEM); + goto out; + } else + dodbg("%s/%s: linked to %s", + certdir, CERT_PEM, file); + + snprintf(file, sizeof(file), + "chain-%llu.pem", (unsigned long long)t); + if (-1 == link(CHAIN_PEM, file) && ENOENT != errno) { + warnx("%s/%s", certdir, CHAIN_PEM); + goto out; + } else + dodbg("%s/%s: linked to %s", + certdir, CHAIN_PEM, file); + + snprintf(file, sizeof(file), + "fullchain-%llu.pem", (unsigned long long)t); + if (-1 == link(FCHAIN_PEM, file) && ENOENT != errno) { + warnx("%s/%s", certdir, FCHAIN_PEM); + goto out; + } else + dodbg("%s/%s: linked to %s", + certdir, FCHAIN_PEM, file); + } /* * If revoking certificates, just unlink the files. diff --git a/main.c b/main.c index a3a430c..1110bff 100644 --- a/main.c +++ b/main.c @@ -81,7 +81,7 @@ main(int argc, char *argv[]) rvk_fds[2]; pid_t pids[COMP__MAX]; int c, rc, newacct, remote, revoke, force, - staging, multidir, newkey; + staging, multidir, newkey, backup; extern int verbose; extern enum comp proccomp; size_t i, altsz, ne; @@ -89,11 +89,14 @@ main(int argc, char *argv[]) alts = NULL; newacct = remote = revoke = verbose = force = - multidir = staging = newkey = 0; + multidir = staging = newkey = backup = 0; certdir = keyfile = acctkey = chngdir = NULL; - while (-1 != (c = getopt(argc, argv, "FmnNrstvf:c:C:k:"))) + while (-1 != (c = getopt(argc, argv, "bFmnNrstvf:c:C:k:"))) switch (c) { + case ('b'): + backup = 1; + break; case ('c'): free(certdir); if (NULL == (certdir = strdup(optarg))) @@ -383,7 +386,7 @@ main(int argc, char *argv[]) free(alts); close(dns_fds[0]); close(rvk_fds[0]); - c = fileproc(file_fds[1], certdir); + c = fileproc(file_fds[1], backup, certdir); /* * This is different from the other processes in that it * can return 2 if the certificates were updated.