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