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