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