2e556e937978c0e29ae8eb8d8169db5b5c14575d
[u/mdw/catacomb] / key-file.c
1 /* -*-c-*-
2 *
3 * $Id: key-file.c,v 1.2 2001/02/03 11:57:38 mdw Exp $
4 *
5 * System-dependent key filing operations
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
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.
18 *
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.
23 *
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,
27 * MA 02111-1307, USA.
28 */
29
30 /*----- Revision history --------------------------------------------------*
31 *
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.
35 *
36 * Revision 1.1 1999/12/22 15:47:48 mdw
37 * Major key-management revision.
38 *
39 */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 #include <errno.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <sys/types.h>
49 #include <sys/time.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <fcntl.h>
53
54 #include <mLib/dstr.h>
55 #include <mLib/lock.h>
56
57 #include "key.h"
58
59 /*----- Main code ---------------------------------------------------------*/
60
61 /* --- @fdcopy@ --- *
62 *
63 * Arguments: @int source@ = source file descriptor
64 * @int dest@ = destination file descriptor
65 *
66 * Returns: Zero if OK, nonzero otherwise.
67 *
68 * Use: Copies data from one file descriptor to another.
69 */
70
71 static int fdcopy(int source, int dest)
72 {
73 char buf[4096];
74
75 if (lseek(source, 0, SEEK_SET) < 0||
76 lseek(dest, 0, SEEK_SET) < 0 ||
77 ftruncate(dest, 0) < 0)
78 return (-1);
79 for (;;) {
80 int n = read(source, buf, sizeof(buf));
81 if (n < 0)
82 return (-1);
83 else if (n == 0)
84 break;
85 else if (write(dest, buf, n) < 0)
86 return (-1);
87 }
88 return (0);
89 }
90
91 /* --- @key_save@ --- *
92 *
93 * Arguments: @key_file *f@ = pointer to key file block
94 *
95 * Returns: A @KWRITE_@ code indicating how well it worked.
96 *
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
101 * alone.
102 *
103 * Callers, please make sure that you ring alarm bells when this
104 * function returns @KWRITE_BROKEN@.
105 */
106
107 int key_save(key_file *f)
108 {
109 dstr n_older = DSTR_INIT, n_old = DSTR_INIT, n_new = DSTR_INIT;
110 int rc = KWRITE_FAIL;
111
112 if (!(f->f & KF_MODIFIED))
113 return (KWRITE_OK);
114 if (!f->fp)
115 return (KWRITE_FAIL);
116
117 /* --- Write a new key file out --- *
118 *
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.
121 */
122
123 dstr_putf(&n_new, "%s.new", f->name);
124
125 {
126 key *k;
127 key_iter i;
128 FILE *fp;
129
130 if ((fp = fopen(n_new.buf, "w")) == 0)
131 goto fail_open;
132
133 for (key_mkiter(&i, f); (k = key_next(&i)) != 0; ) {
134 if (key_extract(f, k, fp, 0)) {
135 fclose(fp);
136 goto fail_write;
137 }
138 }
139
140 if (fclose(fp))
141 goto fail_write;
142 }
143
144 /* --- Set up the other filenames --- */
145
146 dstr_putf(&n_older, "%s.older", f->name);
147 dstr_putf(&n_old, "%s.old", f->name);
148
149 /* --- Move the current backup on one --- *
150 *
151 * If the `older' file exists, then we're in need of attention.
152 */
153
154 {
155 struct stat st;
156 if (stat(n_older.buf, &st) == 0 || errno != ENOENT) {
157 errno = EEXIST;
158 rc = KWRITE_BROKEN;
159 goto fail_shift;
160 }
161 if (rename(n_old.buf, n_older.buf) && errno != ENOENT)
162 goto fail_shift;
163 }
164
165 /* --- Copy the current file to the backup --- */
166
167 {
168 int fd;
169 if ((fd = open(n_old.buf, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0)
170 goto fail_backup;
171 if (fdcopy(fileno(f->fp), fd)) {
172 close(fd);
173 goto fail_backup;
174 }
175 if (close(fd))
176 goto fail_backup;
177 }
178
179 /* --- Copy the newly created file to the current one --- *
180 *
181 * This is the dangerous bit.
182 */
183
184 {
185 int fd;
186 if ((fd = open(n_new.buf, O_RDONLY)) < 0)
187 goto fail_update;
188 if (fdcopy(fd, fileno(f->fp))) {
189 close(fd);
190 goto fail_update;
191 }
192 close(fd);
193 if (fsync(fileno(f->fp)))
194 goto fail_update;
195 }
196
197 /* --- Clean up --- *
198 *
199 * Remove the `new' file and the `older' backup. Then we're done.
200 */
201
202 unlink(n_new.buf);
203 unlink(n_older.buf);
204 return (KWRITE_OK);
205
206 /* --- Failure while writing the new key file --- *
207 *
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
210 * again.
211 */
212
213 fail_update:
214 {
215 int fd;
216 int e = errno;
217
218 if ((fd = open(n_old.buf, O_RDONLY)) < 0)
219 rc = KWRITE_BROKEN;
220 else if (fdcopy(fd, fileno(f->fp))) {
221 close(fd);
222 rc = KWRITE_BROKEN;
223 } else {
224 close(fd);
225 if (fsync(fileno(f->fp)))
226 rc = KWRITE_BROKEN;
227 }
228
229 errno = e;
230 if (rc == KWRITE_BROKEN)
231 goto fail_shift;
232 }
233 /* Now drop through */
234
235 /* --- Failure while writing the new backup --- *
236 *
237 * The new backup isn't any use. Try to recover the old one.
238 */
239
240 fail_backup:
241 {
242 int e = errno;
243 unlink(n_old.buf);
244 if (rename(n_older.buf, n_old.buf) && errno != ENOENT)
245 rc = KWRITE_BROKEN;
246 errno = e;
247 }
248 /* Now drop through */
249
250 /* --- Failure while demoting the current backup --- *
251 *
252 * Leave the completed output file there for the operator in case he wants
253 * to clean up.
254 */
255
256 fail_shift:
257 dstr_destroy(&n_new);
258 dstr_destroy(&n_old);
259 dstr_destroy(&n_older);
260 return (rc);
261
262 /* --- Failure during write of new data --- *
263 *
264 * Clean up the new file and return. These errors can never cause
265 * breakage.
266 */
267
268 fail_write:
269 unlink(n_new.buf);
270 fail_open:
271 dstr_destroy(&n_new);
272 return (rc);
273 }
274
275 /* --- @key_lockfile@ --- *
276 *
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_*@).
280 *
281 * Returns: Zero if it worked, nonzero otherwise.
282 *
283 * Use: Opens a keyfile and stores the information needed for
284 * continued access in the structure.
285 *
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.
289 *
290 * This is a system-dependent routine, and only really intended
291 * for the private use of @key_open@.
292 */
293
294 int key_lockfile(key_file *f, const char *file, unsigned how)
295 {
296 int of, lf;
297 const char *ff;
298 int fd;
299
300 /* --- Handle the magic no-file option --- */
301
302 if (how & KOPEN_NOFILE) {
303 f->fp = 0;
304 return (0);
305 }
306
307 /* --- Lots of things depend on whether we're writing --- */
308
309 switch (how & KOPEN_MASK) {
310 case KOPEN_READ:
311 of = O_RDONLY;
312 lf = LOCK_NONEXCL;
313 ff = "r";
314 break;
315 case KOPEN_WRITE:
316 of = O_RDWR | O_CREAT;
317 lf = LOCK_EXCL;
318 ff = "r+";
319 break;
320 default:
321 errno = EINVAL;
322 return (-1);
323 }
324
325 /* --- Open and lock the file --- */
326
327 if ((fd = open(file, of, 0600)) < 0)
328 return (-1);
329 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 ||
330 lock_file(fd, lf) < 0 ||
331 (f->fp = fdopen(fd, ff)) == 0) {
332 close(fd);
333 return (-1);
334 }
335
336 return (0);
337 }
338
339 /*----- That's all, folks -------------------------------------------------*/