]>
Commit | Line | Data |
---|---|---|
321d8d57 MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
07623986 | 4 | * File functions for the CUPS scheduler. |
321d8d57 | 5 | * |
07623986 MS |
6 | * Copyright 2007-2014 by Apple Inc. |
7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. | |
321d8d57 | 8 | * |
07623986 MS |
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/". | |
321d8d57 MS |
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 | |
26 | static 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 | */ | |
cb7f98ee | 34 | |
321d8d57 MS |
35 | void |
36 | cupsdCleanFiles(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 | ||
cb7f98ee | 56 | cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path); |
321d8d57 MS |
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 | |
cb7f98ee | 72 | status = cupsdUnlinkOrRemoveFile(filename); |
321d8d57 MS |
73 | |
74 | if (status) | |
75 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename, | |
76 | strerror(errno)); | |
321d8d57 MS |
77 | } |
78 | ||
79 | cupsDirClose(dir); | |
80 | } | |
81 | ||
82 | ||
83 | /* | |
84 | * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move | |
85 | * into place. | |
86 | */ | |
87 | ||
88 | int /* O - 0 on success, -1 on error */ | |
89 | cupsdCloseCreatedConfFile( | |
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 | ||
8a259669 MS |
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 | ||
321d8d57 MS |
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 | ||
cb7f98ee | 135 | if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) || |
321d8d57 MS |
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 | ||
152 | void | |
153 | cupsdClosePipe(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 | ||
177 | cups_file_t * /* O - File pointer */ | |
178 | cupsdCreateConfFile( | |
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 | ||
215 | cups_file_t * /* O - File pointer */ | |
216 | cupsdOpenConfFile(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 | ||
247 | int /* O - 0 on success, -1 on error */ | |
248 | cupsdOpenPipe(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 | /* | |
cb7f98ee | 297 | * 'cupsdRemoveFile()' - Remove a file securely. |
321d8d57 MS |
298 | */ |
299 | ||
300 | int /* O - 0 on success, -1 on error */ | |
301 | cupsdRemoveFile(const char *filename) /* I - File to remove */ | |
302 | { | |
303 | #ifdef HAVE_REMOVEFILE | |
cb7f98ee MS |
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)); | |
321d8d57 MS |
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 | ||
cb7f98ee MS |
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 | ||
321d8d57 MS |
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 | /* | |
cb7f98ee | 364 | * Overwrite the file with random data. |
321d8d57 MS |
365 | */ |
366 | ||
321d8d57 MS |
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 | ||
321d8d57 | 377 | /* |
cb7f98ee | 378 | * Close the file, which will lead to the actual deletion, and return... |
321d8d57 MS |
379 | */ |
380 | ||
cb7f98ee | 381 | return (close(fd)); |
321d8d57 MS |
382 | #endif /* HAVE_REMOVEFILE */ |
383 | } | |
384 | ||
385 | ||
cb7f98ee MS |
386 | /* |
387 | * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending | |
388 | * on the configuration. | |
389 | */ | |
390 | ||
391 | int /* O - 0 on success, -1 on error */ | |
392 | cupsdUnlinkOrRemoveFile( | |
393 | const char *filename) /* I - Filename */ | |
394 | { | |
395 | if (Classification) | |
396 | return (cupsdRemoveFile(filename)); | |
397 | else | |
398 | return (unlink(filename)); | |
399 | } | |
400 | ||
401 | ||
321d8d57 MS |
402 | #ifndef HAVE_REMOVEFILE |
403 | /* | |
404 | * 'overwrite_data()' - Overwrite the data in a file. | |
405 | */ | |
406 | ||
407 | static int /* O - 0 on success, -1 on error */ | |
408 | overwrite_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 | ||
07623986 | 434 | if ((bytes = write(fd, buffer, (size_t)bytes)) < 0) |
321d8d57 MS |
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$". | |
451 | */ |