1/* 2 * "$Id: file.c 11203 2013-07-26 21:32:33Z msweet $" 3 * 4 * File functions for the CUPS scheduler. 5 * 6 * Copyright 2007-2013 by Apple Inc. 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * "LICENSE" which should have been included with this file. If this 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * Contents: 16 * 17 * cupsdCleanFiles() - Clean out old files. 18 * cupsdCloseCreatedConfFile() - Close a created configuration file and move 19 * into place. 20 * cupsdClosePipe() - Close a pipe as necessary. 21 * cupsdCreateConfFile() - Create a configuration file safely. 22 * cupsdOpenConfFile() - Open a configuration file. 23 * cupsdOpenPipe() - Create a pipe which is closed on exec. 24 * cupsdRemoveFile() - Remove a file securely. 25 * cupsdUnlinkOrRemoveFile() - Unlink or securely remove a file depending 26 * on the configuration. 27 * overwrite_data() - Overwrite the data in a file. 28 */ 29 30/* 31 * Include necessary headers... 32 */ 33 34#include "cupsd.h" 35#include <cups/dir.h> 36#include <fnmatch.h> 37#ifdef HAVE_REMOVEFILE 38# include <removefile.h> 39#else 40static int overwrite_data(int fd, const char *buffer, int bufsize, 41 int filesize); 42#endif /* HAVE_REMOVEFILE */ 43 44 45/* 46 * 'cupsdCleanFiles()' - Clean out old files. 47 */ 48 49void 50cupsdCleanFiles(const char *path, /* I - Directory to clean */ 51 const char *pattern) /* I - Filename pattern or NULL */ 52{ 53 cups_dir_t *dir; /* Directory */ 54 cups_dentry_t *dent; /* Directory entry */ 55 char filename[1024]; /* Filename */ 56 int status; /* Status from unlink/rmdir */ 57 58 59 cupsdLogMessage(CUPSD_LOG_DEBUG, 60 "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path, 61 pattern ? pattern : "(null)"); 62 63 if ((dir = cupsDirOpen(path)) == NULL) 64 { 65 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s", 66 path, strerror(errno)); 67 return; 68 } 69 70 cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path); 71 72 while ((dent = cupsDirRead(dir)) != NULL) 73 { 74 if (pattern && fnmatch(pattern, dent->filename, 0)) 75 continue; 76 77 snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename); 78 79 if (S_ISDIR(dent->fileinfo.st_mode)) 80 { 81 cupsdCleanFiles(filename, pattern); 82 83 status = rmdir(filename); 84 } 85 else 86 status = cupsdUnlinkOrRemoveFile(filename); 87 88 if (status) 89 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename, 90 strerror(errno)); 91 } 92 93 cupsDirClose(dir); 94} 95 96 97/* 98 * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move 99 * into place. 100 */ 101 102int /* O - 0 on success, -1 on error */ 103cupsdCloseCreatedConfFile( 104 cups_file_t *fp, /* I - File to close */ 105 const char *filename) /* I - Filename */ 106{ 107 char newfile[1024], /* filename.N */ 108 oldfile[1024]; /* filename.O */ 109 110 111 /* 112 * Synchronize changes to disk if SyncOnClose is enabled. 113 */ 114 115 if (SyncOnClose) 116 { 117 if (cupsFileFlush(fp)) 118 { 119 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s", 120 filename, strerror(errno)); 121 cupsFileClose(fp); 122 return (-1); 123 } 124 125 if (fsync(cupsFileNumber(fp))) 126 { 127 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s", 128 filename, strerror(errno)); 129 cupsFileClose(fp); 130 return (-1); 131 } 132 } 133 134 /* 135 * First close the file... 136 */ 137 138 if (cupsFileClose(fp)) 139 return (-1); 140 141 /* 142 * Then remove "filename.O", rename "filename" to "filename.O", and rename 143 * "filename.N" to "filename". 144 */ 145 146 snprintf(newfile, sizeof(newfile), "%s.N", filename); 147 snprintf(oldfile, sizeof(oldfile), "%s.O", filename); 148 149 if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) || 150 (rename(filename, oldfile) && errno != ENOENT) || 151 rename(newfile, filename)) 152 { 153 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s", 154 filename, strerror(errno)); 155 return (-1); 156 } 157 158 return (0); 159} 160 161 162/* 163 * 'cupsdClosePipe()' - Close a pipe as necessary. 164 */ 165 166void 167cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */ 168{ 169 /* 170 * Close file descriptors as needed... 171 */ 172 173 if (fds[0] >= 0) 174 { 175 close(fds[0]); 176 fds[0] = -1; 177 } 178 179 if (fds[1] >= 0) 180 { 181 close(fds[1]); 182 fds[1] = -1; 183 } 184} 185 186 187/* 188 * 'cupsdCreateConfFile()' - Create a configuration file safely. 189 */ 190 191cups_file_t * /* O - File pointer */ 192cupsdCreateConfFile( 193 const char *filename, /* I - Filename */ 194 mode_t mode) /* I - Permissions */ 195{ 196 cups_file_t *fp; /* File pointer */ 197 char newfile[1024]; /* filename.N */ 198 199 200 snprintf(newfile, sizeof(newfile), "%s.N", filename); 201 if ((fp = cupsFileOpen(newfile, "w")) == NULL) 202 { 203 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile, 204 strerror(errno)); 205 } 206 else 207 { 208 if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group)) 209 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s", 210 newfile, strerror(errno)); 211 212 if (fchmod(cupsFileNumber(fp), mode)) 213 cupsdLogMessage(CUPSD_LOG_WARN, 214 "Unable to change permissions for \"%s\": %s", 215 newfile, strerror(errno)); 216 } 217 218 return (fp); 219} 220 221 222/* 223 * 'cupsdOpenConfFile()' - Open a configuration file. 224 * 225 * This function looks for "filename.O" if "filename" does not exist and does 226 * a rename as needed. 227 */ 228 229cups_file_t * /* O - File pointer */ 230cupsdOpenConfFile(const char *filename) /* I - Filename */ 231{ 232 cups_file_t *fp; /* File pointer */ 233 234 235 if ((fp = cupsFileOpen(filename, "r")) == NULL) 236 { 237 if (errno == ENOENT) 238 { 239 /* 240 * Try opening the backup file... 241 */ 242 243 char oldfile[1024]; /* filename.O */ 244 245 snprintf(oldfile, sizeof(oldfile), "%s.O", filename); 246 fp = cupsFileOpen(oldfile, "r"); 247 } 248 else 249 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename, 250 strerror(errno)); 251 } 252 253 return (fp); 254} 255 256 257/* 258 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec. 259 */ 260 261int /* O - 0 on success, -1 on error */ 262cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */ 263{ 264 /* 265 * Create the pipe... 266 */ 267 268 if (pipe(fds)) 269 { 270 fds[0] = -1; 271 fds[1] = -1; 272 273 return (-1); 274 } 275 276 /* 277 * Set the "close on exec" flag on each end of the pipe... 278 */ 279 280 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC)) 281 { 282 close(fds[0]); 283 close(fds[1]); 284 285 fds[0] = -1; 286 fds[1] = -1; 287 288 return (-1); 289 } 290 291 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC)) 292 { 293 close(fds[0]); 294 close(fds[1]); 295 296 fds[0] = -1; 297 fds[1] = -1; 298 299 return (-1); 300 } 301 302 /* 303 * Return 0 indicating success... 304 */ 305 306 return (0); 307} 308 309 310/* 311 * 'cupsdRemoveFile()' - Remove a file securely. 312 */ 313 314int /* O - 0 on success, -1 on error */ 315cupsdRemoveFile(const char *filename) /* I - File to remove */ 316{ 317#ifdef HAVE_REMOVEFILE 318 /* 319 * See if the file exists... 320 */ 321 322 if (access(filename, 0)) 323 return (0); 324 325 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename); 326 327 /* 328 * Remove the file... 329 */ 330 331 return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS)); 332 333#else 334 int fd; /* File descriptor */ 335 struct stat info; /* File information */ 336 char buffer[512]; /* Data buffer */ 337 int i; /* Looping var */ 338 339 340 /* 341 * See if the file exists... 342 */ 343 344 if (access(filename, 0)) 345 return (0); 346 347 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename); 348 349 /* 350 * First open the file for writing in exclusive mode. 351 */ 352 353 if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0) 354 return (-1); 355 356 /* 357 * Delete the file now - it will still be around as long as the file is 358 * open... 359 */ 360 361 if (unlink(filename)) 362 { 363 close(fd); 364 return (-1); 365 } 366 367 /* 368 * Then get the file size... 369 */ 370 371 if (fstat(fd, &info)) 372 { 373 close(fd); 374 return (-1); 375 } 376 377 /* 378 * Overwrite the file with random data. 379 */ 380 381 CUPS_SRAND(time(NULL)); 382 383 for (i = 0; i < sizeof(buffer); i ++) 384 buffer[i] = CUPS_RAND(); 385 if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size)) 386 { 387 close(fd); 388 return (-1); 389 } 390 391 /* 392 * Close the file, which will lead to the actual deletion, and return... 393 */ 394 395 return (close(fd)); 396#endif /* HAVE_REMOVEFILE */ 397} 398 399 400/* 401 * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending 402 * on the configuration. 403 */ 404 405int /* O - 0 on success, -1 on error */ 406cupsdUnlinkOrRemoveFile( 407 const char *filename) /* I - Filename */ 408{ 409 if (Classification) 410 return (cupsdRemoveFile(filename)); 411 else 412 return (unlink(filename)); 413} 414 415 416#ifndef HAVE_REMOVEFILE 417/* 418 * 'overwrite_data()' - Overwrite the data in a file. 419 */ 420 421static int /* O - 0 on success, -1 on error */ 422overwrite_data(int fd, /* I - File descriptor */ 423 const char *buffer, /* I - Buffer to write */ 424 int bufsize, /* I - Size of buffer */ 425 int filesize) /* I - Size of file */ 426{ 427 int bytes; /* Bytes to write/written */ 428 429 430 /* 431 * Start at the beginning of the file... 432 */ 433 434 if (lseek(fd, 0, SEEK_SET) < 0) 435 return (-1); 436 437 /* 438 * Fill the file with the provided data... 439 */ 440 441 while (filesize > 0) 442 { 443 if (filesize > bufsize) 444 bytes = bufsize; 445 else 446 bytes = filesize; 447 448 if ((bytes = write(fd, buffer, bytes)) < 0) 449 return (-1); 450 451 filesize -= bytes; 452 } 453 454 /* 455 * Force the changes to disk... 456 */ 457 458 return (fsync(fd)); 459} 460#endif /* HAVE_REMOVEFILE */ 461 462 463/* 464 * End of "$Id: file.c 11203 2013-07-26 21:32:33Z msweet $". 465 */ 466