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