1/*++
2/* NAME
3/*	edit_file 3
4/* SUMMARY
5/*	simple cooperative file updating protocol
6/* SYNOPSIS
7/*	#include <edit_file.h>
8/*
9/*	typedef struct {
10/* .in +4
11/*		char	*tmp_path;	/* temp. pathname */
12/*		VSTREAM *tmp_fp;	/* temp. stream */
13/*		/* private members... */
14/* .in -4
15/*	} EDIT_FILE;
16/*
17/*	EDIT_FILE *edit_file_open(original_path, output_flags, output_mode)
18/*	const char *original_path;
19/*	int	output_flags;
20/*	mode_t	output_mode;
21/*
22/*	int	edit_file_close(edit_file)
23/*	EDIT_FILE *edit_file;
24/*
25/*	void	edit_file_cleanup(edit_file)
26/*	EDIT_FILE *edit_file;
27/* DESCRIPTION
28/*	This module implements a simple protocol for cooperative
29/*	processes to update one file. The idea is to 1) create a
30/*	new file under a deterministic temporary pathname, 2)
31/*	populate the new file with updated information, and 3)
32/*	rename the new file into the place of the original file.
33/*	This module provides 1) and 3), and leaves 2) to the
34/*	application. The temporary pathname is deterministic to
35/*	avoid accumulation of thrash after program crashes.
36/*
37/*	edit_file_open() implements the first phase of the protocol.
38/*	It creates or opens an output file with a deterministic
39/*	temporary pathname, obtained by appending the suffix defined
40/*	with EDIT_FILE_SUFFIX to the specified original file pathname.
41/*	The original file itself is not opened.  edit_file_open()
42/*	then locks the output file for exclusive access, and verifies
43/*	that the file still exists under the temporary pathname.
44/*	At this point in the protocol, the current process controls
45/*	both the output file content and its temporary pathname.
46/*
47/*	In the second phase, the application opens the original
48/*	file if needed, and updates the output file via the
49/*	\fBtmp_fp\fR member of the EDIT_FILE data structure.  This
50/*	phase is not implemented by the edit_file() module.
51/*
52/*	edit_file_close() implements the third and final phase of
53/*	the protocol.  It flushes the output file to persistent
54/*	storage, and renames the output file from its temporary
55/*	pathname into the place of the original file. When any of
56/*	these operations fails, edit_file_close() behaves as if
57/*	edit_file_cleanup() was called. Regardless of whether these
58/*	operations suceed, edit_file_close() releases the exclusive
59/*	lock, closes the output file, and frees up memory that was
60/*	allocated by edit_file_open().
61/*
62/*	edit_file_cleanup() aborts the protocol. It discards the
63/*	output file, releases the exclusive lock, closes the output
64/*	file, and frees up memory that was allocated by edit_file_open().
65/*
66/*	Arguments:
67/* .IP original_path
68/*	The pathname of the original file that will be replaced by
69/*	the output file. The temporary pathname for the output file
70/*	is obtained by appending the suffix defined with EDIT_FILE_SUFFIX
71/*	to a copy of the specified original file pathname, and is
72/*	made available via the \fBtmp_path\fR member of the EDIT_FILE
73/*	data structure.
74/* .IP output_flags
75/*	Flags for opening the output file. These are as with open(2),
76/*	except that the O_TRUNC flag is ignored.  edit_file_open()
77/*	always truncates the output file after it has obtained
78/*	exclusive control over the output file content and temporary
79/*	pathname.
80/* .IP output_mode
81/*	Permissions for the output file. These are as with open(2),
82/*	except that the output file is initially created with no
83/*	group or other access permissions. The specified output
84/*	file permissions are applied by edit_file_close().
85/* .IP edit_file
86/*	Pointer to data structure that is returned upon successful
87/*	completion by edit_file_open(), and that must be passed to
88/*	edit_file_close() or edit_file_cleanup().
89/* DIAGNOSTICS
90/*	Fatal errors: memory allocation failure, fstat() failure,
91/*	unlink() failure, lock failure, ftruncate() failure.
92/*
93/*	edit_file_open() immediately returns a null pointer when
94/*	it cannot open the output file.
95/*
96/*	edit_file_close() returns zero on success, VSTREAM_EOF on
97/*	failure.
98/*
99/*	With both functions, the global errno variable indicates
100/*	the nature of the problem.  All errors are relative to the
101/*	temporary output's pathname. With both functions, this
102/*	pathname is not available via the EDIT_FILE data structure,
103/*	because that structure was already destroyed, or not created.
104/* BUGS
105/*	In the non-error case, edit_file_open() will not return
106/*	until it obtains exclusive control over the output file
107/*	content and temporary pathname.  Applications that are
108/*	concerned about deadlock should protect the edit_file_open()
109/*	call with a watchdog timer.
110/*
111/*	When interrupted, edit_file_close() may leave behind a
112/*	world-readable output file under the temporary pathname.
113/*	On some systems this can be used to inflict a shared-lock
114/*	DOS on the protocol.  Applications that are concerned about
115/*	maximal safety should protect the edit_file_close() call
116/*	with sigdelay() and sigresume() calls, but this introduces
117/*	the risk that the program will get stuck forever.
118/* LICENSE
119/* .ad
120/* .fi
121/*	The Secure Mailer license must be distributed with this software.
122/* AUTHOR(S)
123/*	Based on code originally by:
124/*	Victor Duchovni
125/*	Morgan Stanley
126/*
127/*	Packaged into one module with minor improvements by:
128/*	Wietse Venema
129/*	IBM T.J. Watson Research
130/*	P.O. Box 704
131/*	Yorktown Heights, NY 10598, USA
132/*--*/
133
134/* System library. */
135
136#include <sys_defs.h>
137#include <sys/stat.h>
138#include <stdio.h>			/* rename(2) */
139#include <errno.h>
140
141 /*
142  * This mask selects all permission bits in the st_mode stat data. There is
143  * no portable definition (unlike S_IFMT, which is defined for the file type
144  * bits). For example, BSD / Linux have ALLPERMS, while Solaris has S_IAMB.
145  */
146#define FILE_PERM_MASK \
147	(S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
148
149/* Utility Library. */
150
151#include <msg.h>
152#include <vstream.h>
153#include <mymalloc.h>
154#include <stringops.h>
155#include <myflock.h>
156#include <edit_file.h>
157#include <warn_stat.h>
158
159 /*
160  * Do we reuse and truncate an output file that persists after a crash, or
161  * do we unlink it and create a new file?
162  */
163#define EDIT_FILE_REUSE_AFTER_CRASH
164
165 /*
166  * Protocol internals: the temporary file permissions.
167  */
168#define EDIT_FILE_MODE	(S_IRUSR | S_IWUSR)	/* temp file mode */
169
170 /*
171  * Make complex operations more readable. We could use functions, instead.
172  * The main thing is that we keep the _alloc and _free code together.
173  */
174#define EDIT_FILE_ALLOC(ep, path, mode) do { \
175	(ep) = (EDIT_FILE *) mymalloc(sizeof(EDIT_FILE)); \
176	(ep)->final_path = mystrdup(path); \
177	(ep)->final_mode = (mode); \
178	(ep)->tmp_path = concatenate((path), EDIT_FILE_SUFFIX, (char *) 0); \
179	(ep)->tmp_fp = 0; \
180    } while (0)
181
182#define EDIT_FILE_FREE(ep) do { \
183	myfree((ep)->final_path); \
184	myfree((ep)->tmp_path); \
185	myfree((char *) (ep)); \
186    } while (0)
187
188/* edit_file_open - open and lock file with deterministic temporary pathname */
189
190EDIT_FILE *edit_file_open(const char *path, int flags, mode_t mode)
191{
192    struct stat before_lock;
193    struct stat after_lock;
194    int     saved_errno;
195    EDIT_FILE *ep;
196
197    /*
198     * Initialize. Do not bother to optimize for the error case.
199     */
200    EDIT_FILE_ALLOC(ep, path, mode);
201
202    /*
203     * As long as the output file can be opened under the temporary pathname,
204     * this code can loop or block forever.
205     *
206     * Applications that are concerned about deadlock should protect the
207     * edit_file_open() call with a watchdog timer.
208     */
209    for ( /* void */ ; /* void */ ; (void) vstream_fclose(ep->tmp_fp)) {
210
211	/*
212	 * Try to open the output file under the temporary pathname. This
213	 * succeeds or fails immediately. To avoid creating a shared-lock DOS
214	 * opportunity after we crash, we create the output file with no
215	 * group or other permissions, and set the final permissions at the
216	 * end (this is one reason why we try to get exclusive control over
217	 * the output file instead of the original file). We postpone file
218	 * truncation until we have obtained exclusive control over the file
219	 * content and temporary pathname. If the open operation fails, we
220	 * give up immediately. The caller can retry the call if desirable.
221	 *
222	 * XXX If we replace the vstream_fopen() call by safe_open(), then we
223	 * should replace the stat() call below by lstat().
224	 */
225	if ((ep->tmp_fp = vstream_fopen(ep->tmp_path, flags & ~(O_TRUNC),
226				    EDIT_FILE_MODE)) == 0) {
227	    saved_errno = errno;
228	    EDIT_FILE_FREE(ep);
229	    errno = saved_errno;
230	    return (0);
231	}
232
233	/*
234	 * At this point we may have opened an existing output file that was
235	 * already locked. Try to lock the open file exclusively. This may
236	 * take some time.
237	 */
238	if (myflock(vstream_fileno(ep->tmp_fp), INTERNAL_LOCK,
239		    MYFLOCK_OP_EXCLUSIVE) < 0)
240	    msg_fatal("lock %s: %m", ep->tmp_path);
241
242	/*
243	 * At this point we have an exclusive lock, but some other process
244	 * may have renamed or removed the output file while we were waiting
245	 * for the lock. If that is the case, back out and try again.
246	 */
247	if (fstat(vstream_fileno(ep->tmp_fp), &before_lock) < 0)
248	    msg_fatal("open %s: %m", ep->tmp_path);
249	if (stat(ep->tmp_path, &after_lock) < 0
250	    || before_lock.st_dev != after_lock.st_dev
251	    || before_lock.st_ino != after_lock.st_ino
252#ifdef HAS_ST_GEN
253	    || before_lock.st_gen != after_lock.st_gen
254#endif
255	/* No need to compare st_rdev or st_nlink here. */
256	    ) {
257	    continue;
258	}
259
260	/*
261	 * At this point we have exclusive control over the output file
262	 * content and its temporary pathname (within the rules of the
263	 * cooperative protocol). But wait, there is more.
264	 *
265	 * There are many opportunies for trouble when opening a pre-existing
266	 * output file. Here are just a few.
267	 *
268	 * - Victor observes that a system crash in the middle of the
269	 * final-phase rename() operation may result in the output file
270	 * having both the temporary pathname and the final pathname. In that
271	 * case we must not write to the output file.
272	 *
273	 * - Wietse observes that crashes may also leave the output file in
274	 * other inconsistent states. To avoid permission-related trouble, we
275	 * simply refuse to work with an output file that has the wrong
276	 * temporary permissions. This won't stop the shared-lock DOS if we
277	 * crash after changing the file permissions, though.
278	 *
279	 * To work around these crash-related problems, remove the temporary
280	 * pathname, back out, and try again.
281	 */
282	if (!S_ISREG(after_lock.st_mode)
283#ifndef EDIT_FILE_REUSE_AFTER_CRASH
284	    || after_lock.st_size > 0
285#endif
286	    || after_lock.st_nlink > 1
287	    || (after_lock.st_mode & FILE_PERM_MASK) != EDIT_FILE_MODE) {
288	    if (unlink(ep->tmp_path) < 0 && errno != ENOENT)
289		msg_fatal("unlink %s: %m", ep->tmp_path);
290	    continue;
291	}
292
293	/*
294	 * Settle the final details.
295	 */
296#ifdef EDIT_FILE_REUSE_AFTER_CRASH
297	if (ftruncate(vstream_fileno(ep->tmp_fp), 0) < 0)
298	    msg_fatal("truncate %s: %m", ep->tmp_path);
299#endif
300	return (ep);
301    }
302}
303
304/* edit_file_cleanup - clean up without completing the protocol */
305
306void    edit_file_cleanup(EDIT_FILE *ep)
307{
308
309    /*
310     * Don't touch the file after we lose the exclusive lock!
311     */
312    if (unlink(ep->tmp_path) < 0 && errno != ENOENT)
313	msg_fatal("unlink %s: %m", ep->tmp_path);
314    (void) vstream_fclose(ep->tmp_fp);
315    EDIT_FILE_FREE(ep);
316}
317
318/* edit_file_close - rename the file into place and and close the file */
319
320int     edit_file_close(EDIT_FILE *ep)
321{
322    VSTREAM *fp = ep->tmp_fp;
323    int     fd = vstream_fileno(fp);
324    int     saved_errno;
325
326    /*
327     * The rename/unlock portion of the protocol is relatively simple. The
328     * only things that really matter here are that we change permissions as
329     * late as possible, and that we rename the file to its final pathname
330     * before we lose the exclusive lock.
331     *
332     * Applications that are concerned about maximal safety should protect the
333     * edit_file_close() call with sigdelay() and sigresume() calls. It is
334     * not safe for us to call these functions directly, because the calls do
335     * not nest. It is also not nice to force every caller to run with
336     * interrupts turned off.
337     */
338    if (vstream_fflush(fp) < 0
339	|| fchmod(fd, ep->final_mode) < 0
340#ifdef HAS_FSYNC
341	|| fsync(fd) < 0
342#endif
343	|| rename(ep->tmp_path, ep->final_path) < 0) {
344	saved_errno = errno;
345	edit_file_cleanup(ep);
346	errno = saved_errno;
347	return (VSTREAM_EOF);
348    } else {
349	(void) vstream_fclose(ep->tmp_fp);
350	EDIT_FILE_FREE(ep);
351	return (0);
352    }
353}
354