• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * File functions for the CUPS scheduler.
3  *
4  * Copyright © 2007-2014 by Apple Inc.
5  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
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  */
29 
30 void
cupsdCleanFiles(const char * path,const char * pattern)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 
51   cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path);
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
67       status = cupsdUnlinkOrRemoveFile(filename);
68 
69     if (status)
70       cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
71 		      strerror(errno));
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 */
cupsdCloseCreatedConfFile(cups_file_t * fp,const char * filename)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 
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 
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 
130   if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
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
cupsdClosePipe(int * fds)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 */
cupsdCreateConfFile(const char * filename,mode_t mode)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 */
cupsdOpenConfFile(const char * filename)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 */
cupsdOpenPipe(int * fds)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 /*
292  * 'cupsdRemoveFile()' - Remove a file securely.
293  */
294 
295 int					/* O - 0 on success, -1 on error */
cupsdRemoveFile(const char * filename)296 cupsdRemoveFile(const char *filename)	/* I - File to remove */
297 {
298 #ifdef HAVE_REMOVEFILE
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));
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 
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 
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  /*
359   * Overwrite the file with random data.
360   */
361 
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 
372  /*
373   * Close the file, which will lead to the actual deletion, and return...
374   */
375 
376   return (close(fd));
377 #endif /* HAVE_REMOVEFILE */
378 }
379 
380 
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 */
cupsdUnlinkOrRemoveFile(const char * filename)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 
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 */
overwrite_data(int fd,const char * buffer,int bufsize,int filesize)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 
429     if ((bytes = write(fd, buffer, (size_t)bytes)) < 0)
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 */
442