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