3 * $Id: key-file.c,v 1.2 2001/02/03 11:57:38 mdw Exp $
5 * System-dependent key filing operations
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
32 * $Log: key-file.c,v $
33 * Revision 1.2 2001/02/03 11:57:38 mdw
34 * Allow creating keyfiles with no file attached.
36 * Revision 1.1 1999/12/22 15:47:48 mdw
37 * Major key-management revision.
41 /*----- Header files ------------------------------------------------------*/
48 #include <sys/types.h>
54 #include <mLib/dstr.h>
55 #include <mLib/lock.h>
59 /*----- Main code ---------------------------------------------------------*/
63 * Arguments: @int source@ = source file descriptor
64 * @int dest@ = destination file descriptor
66 * Returns: Zero if OK, nonzero otherwise.
68 * Use: Copies data from one file descriptor to another.
71 static int fdcopy(int source
, int dest
)
75 if (lseek(source
, 0, SEEK_SET
) < 0||
76 lseek(dest
, 0, SEEK_SET
) < 0 ||
77 ftruncate(dest
, 0) < 0)
80 int n
= read(source
, buf
, sizeof(buf
));
85 else if (write(dest
, buf
, n
) < 0)
91 /* --- @key_save@ --- *
93 * Arguments: @key_file *f@ = pointer to key file block
95 * Returns: A @KWRITE_@ code indicating how well it worked.
97 * Use: Writes a key file's data back to the actual file. This code
98 * is extremely careful about error handling. It should usually
99 * be able to back out somewhere sensible, but it can tell when
100 * it's got itself into a real pickle and starts leaving well
103 * Callers, please make sure that you ring alarm bells when this
104 * function returns @KWRITE_BROKEN@.
107 int key_save(key_file
*f
)
109 dstr n_older
= DSTR_INIT
, n_old
= DSTR_INIT
, n_new
= DSTR_INIT
;
110 int rc
= KWRITE_FAIL
;
112 if (!(f
->f
& KF_MODIFIED
))
115 return (KWRITE_FAIL
);
117 /* --- Write a new key file out --- *
119 * Check for an error after each key line. This ought to be enough.
120 * Checking after each individual byte write and @fprintf@ isn't much fun.
123 dstr_putf(&n_new
, "%s.new", f
->name
);
130 if ((fp
= fopen(n_new
.buf
, "w")) == 0)
133 for (key_mkiter(&i
, f
); (k
= key_next(&i
)) != 0; ) {
134 if (key_extract(f
, k
, fp
, 0)) {
144 /* --- Set up the other filenames --- */
146 dstr_putf(&n_older
, "%s.older", f
->name
);
147 dstr_putf(&n_old
, "%s.old", f
->name
);
149 /* --- Move the current backup on one --- *
151 * If the `older' file exists, then we're in need of attention.
156 if (stat(n_older
.buf
, &st
) == 0 || errno
!= ENOENT
) {
161 if (rename(n_old
.buf
, n_older
.buf
) && errno
!= ENOENT
)
165 /* --- Copy the current file to the backup --- */
169 if ((fd
= open(n_old
.buf
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600)) < 0)
171 if (fdcopy(fileno(f
->fp
), fd
)) {
179 /* --- Copy the newly created file to the current one --- *
181 * This is the dangerous bit.
186 if ((fd
= open(n_new
.buf
, O_RDONLY
)) < 0)
188 if (fdcopy(fd
, fileno(f
->fp
))) {
193 if (fsync(fileno(f
->fp
)))
197 /* --- Clean up --- *
199 * Remove the `new' file and the `older' backup. Then we're done.
206 /* --- Failure while writing the new key file --- *
208 * I need to copy the backup back. If that fails then I'm really stuffed.
209 * If not, then I might as well try to get the backups sorted back out
218 if ((fd
= open(n_old
.buf
, O_RDONLY
)) < 0)
220 else if (fdcopy(fd
, fileno(f
->fp
))) {
225 if (fsync(fileno(f
->fp
)))
230 if (rc
== KWRITE_BROKEN
)
233 /* Now drop through */
235 /* --- Failure while writing the new backup --- *
237 * The new backup isn't any use. Try to recover the old one.
244 if (rename(n_older
.buf
, n_old
.buf
) && errno
!= ENOENT
)
248 /* Now drop through */
250 /* --- Failure while demoting the current backup --- *
252 * Leave the completed output file there for the operator in case he wants
257 dstr_destroy(&n_new
);
258 dstr_destroy(&n_old
);
259 dstr_destroy(&n_older
);
262 /* --- Failure during write of new data --- *
264 * Clean up the new file and return. These errors can never cause
271 dstr_destroy(&n_new
);
275 /* --- @key_lockfile@ --- *
277 * Arguments: @key_file *f@ = pointer to file structure to initialize
278 * @const char *file@ = pointer to the file name
279 * @unsigned how@ = opening options (@KOPEN_*@).
281 * Returns: Zero if it worked, nonzero otherwise.
283 * Use: Opens a keyfile and stores the information needed for
284 * continued access in the structure.
286 * If the file is opened with @KOPEN_WRITE@, it's created if
287 * necessary with read and write permissions for owner only, and
288 * locked for update while it's open.
290 * This is a system-dependent routine, and only really intended
291 * for the private use of @key_open@.
294 int key_lockfile(key_file
*f
, const char *file
, unsigned how
)
300 /* --- Handle the magic no-file option --- */
302 if (how
& KOPEN_NOFILE
) {
307 /* --- Lots of things depend on whether we're writing --- */
309 switch (how
& KOPEN_MASK
) {
316 of
= O_RDWR
| O_CREAT
;
325 /* --- Open and lock the file --- */
327 if ((fd
= open(file
, of
, 0600)) < 0)
329 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) < 0 ||
330 lock_file(fd
, lf
) < 0 ||
331 (f
->fp
= fdopen(fd
, ff
)) == 0) {
339 /*----- That's all, folks -------------------------------------------------*/