X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/key-file.c diff --git a/key-file.c b/key-file.c deleted file mode 100644 index 3245b93..0000000 --- a/key-file.c +++ /dev/null @@ -1,338 +0,0 @@ -/* -*-c-*- - * - * $Id$ - * - * System-dependent key filing operations - * - * (c) 1999 Straylight/Edgeware - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of Catacomb. - * - * Catacomb is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * Catacomb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with Catacomb; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -/*----- Header files ------------------------------------------------------*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "key.h" - -/*----- Main code ---------------------------------------------------------*/ - -/* --- @fdcopy@ --- * - * - * Arguments: @int source@ = source file descriptor - * @int dest@ = destination file descriptor - * - * Returns: Zero if OK, nonzero otherwise. - * - * Use: Copies data from one file descriptor to another. - */ - -static int fdcopy(int source, int dest) -{ - char buf[4096]; - char *p; - - if (lseek(source, 0, SEEK_SET) < 0|| - lseek(dest, 0, SEEK_SET) < 0 || - ftruncate(dest, 0) < 0) - return (-1); - for (;;) { - int n = read(source, buf, sizeof(buf)); - if (n < 0) - return (-1); - else if (n == 0) - break; - p = buf; - while (n) { - int nn = write(dest, p, n); - if (nn < 0) - return (-1); - p += nn; - n -= nn; - } - } - return (0); -} - -/* --- @key_save@ --- * - * - * Arguments: @key_file *f@ = pointer to key file block - * - * Returns: A @KWRITE_@ code indicating how well it worked. - * - * Use: Writes a key file's data back to the actual file. This code - * is extremely careful about error handling. It should usually - * be able to back out somewhere sensible, but it can tell when - * it's got itself into a real pickle and starts leaving well - * alone. - * - * Callers, please make sure that you ring alarm bells when this - * function returns @KWRITE_BROKEN@. - */ - -int key_save(key_file *f) -{ - dstr n_older = DSTR_INIT, n_old = DSTR_INIT, n_new = DSTR_INIT; - int rc = KWRITE_FAIL; - - if (!(f->f & KF_MODIFIED)) - return (KWRITE_OK); - if (!f->fp) - return (KWRITE_FAIL); - - /* --- Write a new key file out --- * - * - * Check for an error after each key line. This ought to be enough. - * Checking after each individual byte write and @fprintf@ isn't much fun. - */ - - dstr_putf(&n_new, "%s.new", f->name); - - { - key *k; - key_iter i; - FILE *fp; - - if ((fp = fopen(n_new.buf, "w")) == 0) - goto fail_open; - - for (key_mkiter(&i, f); (k = key_next(&i)) != 0; ) { - if (key_extract(f, k, fp, 0)) { - fclose(fp); - goto fail_write; - } - } - - if (fclose(fp)) - goto fail_write; - } - - /* --- Set up the other filenames --- */ - - dstr_putf(&n_older, "%s.older", f->name); - dstr_putf(&n_old, "%s.old", f->name); - - /* --- Move the current backup on one --- * - * - * If the `older' file exists, then we're in need of attention. - */ - - { - struct stat st; - if (stat(n_older.buf, &st) == 0 || errno != ENOENT) { - errno = EEXIST; - rc = KWRITE_BROKEN; - goto fail_shift; - } - if (rename(n_old.buf, n_older.buf) && errno != ENOENT) - goto fail_shift; - } - - /* --- Copy the current file to the backup --- */ - - { - int fd; - if ((fd = open(n_old.buf, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0) - goto fail_backup; - if (fdcopy(fileno(f->fp), fd)) { - close(fd); - goto fail_backup; - } - if (close(fd)) - goto fail_backup; - } - - /* --- Copy the newly created file to the current one --- * - * - * This is the dangerous bit. - */ - - { - int fd; - if ((fd = open(n_new.buf, O_RDONLY)) < 0) - goto fail_update; - if (fdcopy(fd, fileno(f->fp))) { - close(fd); - goto fail_update; - } - close(fd); - if (fsync(fileno(f->fp))) - goto fail_update; - } - - /* --- Clean up --- * - * - * Remove the `new' file and the `older' backup. Then we're done. - */ - - unlink(n_new.buf); - unlink(n_older.buf); - dstr_destroy(&n_new); - dstr_destroy(&n_old); - dstr_destroy(&n_older); - return (KWRITE_OK); - - /* --- Failure while writing the new key file --- * - * - * I need to copy the backup back. If that fails then I'm really stuffed. - * If not, then I might as well try to get the backups sorted back out - * again. - */ - -fail_update: - { - int fd; - int e = errno; - - if ((fd = open(n_old.buf, O_RDONLY)) < 0) - rc = KWRITE_BROKEN; - else if (fdcopy(fd, fileno(f->fp))) { - close(fd); - rc = KWRITE_BROKEN; - } else { - close(fd); - if (fsync(fileno(f->fp))) - rc = KWRITE_BROKEN; - } - - errno = e; - if (rc == KWRITE_BROKEN) - goto fail_shift; - } - /* Now drop through */ - - /* --- Failure while writing the new backup --- * - * - * The new backup isn't any use. Try to recover the old one. - */ - -fail_backup: - { - int e = errno; - unlink(n_old.buf); - if (rename(n_older.buf, n_old.buf) && errno != ENOENT) - rc = KWRITE_BROKEN; - errno = e; - } - /* Now drop through */ - - /* --- Failure while demoting the current backup --- * - * - * Leave the completed output file there for the operator in case he wants - * to clean up. - */ - -fail_shift: - dstr_destroy(&n_new); - dstr_destroy(&n_old); - dstr_destroy(&n_older); - return (rc); - - /* --- Failure during write of new data --- * - * - * Clean up the new file and return. These errors can never cause - * breakage. - */ - -fail_write: - unlink(n_new.buf); -fail_open: - dstr_destroy(&n_new); - return (rc); -} - -/* --- @key_lockfile@ --- * - * - * Arguments: @key_file *f@ = pointer to file structure to initialize - * @const char *file@ = pointer to the file name - * @unsigned how@ = opening options (@KOPEN_*@). - * - * Returns: Zero if it worked, nonzero otherwise. - * - * Use: Opens a keyfile and stores the information needed for - * continued access in the structure. - * - * If the file is opened with @KOPEN_WRITE@, it's created if - * necessary with read and write permissions for owner only, and - * locked for update while it's open. - * - * This is a system-dependent routine, and only really intended - * for the private use of @key_open@. - */ - -int key_lockfile(key_file *f, const char *file, unsigned how) -{ - int of, lf; - const char *ff; - int fd; - - /* --- Handle the magic no-file option --- */ - - if (how & KOPEN_NOFILE) { - f->fp = 0; - return (0); - } - - /* --- Lots of things depend on whether we're writing --- */ - - switch (how & KOPEN_MASK) { - case KOPEN_READ: - of = O_RDONLY; - lf = LOCK_NONEXCL; - ff = "r"; - break; - case KOPEN_WRITE: - of = O_RDWR | O_CREAT; - lf = LOCK_EXCL; - ff = "r+"; - break; - default: - errno = EINVAL; - return (-1); - } - - /* --- Open and lock the file --- */ - - if ((fd = open(file, of, 0600)) < 0) - return (-1); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 || - lock_file(fd, lf) < 0 || - (f->fp = fdopen(fd, ff)) == 0) { - close(fd); - return (-1); - } - - return (0); -} - -/*----- That's all, folks -------------------------------------------------*/