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