Blame scheduler/file.c

Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * File functions for the CUPS scheduler.
Packit Service 4ae4ad
 *
Packit Service 4ae4ad
 * Copyright 2007-2014 by Apple Inc.
Packit Service 4ae4ad
 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
Packit Service 4ae4ad
 *
Packit Service 4ae4ad
 * These coded instructions, statements, and computer programs are the
Packit Service 4ae4ad
 * property of Apple Inc. and are protected by Federal copyright
Packit Service 4ae4ad
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
Packit Service 4ae4ad
 * "LICENSE" which should have been included with this file.  If this
Packit Service 4ae4ad
 * file is missing or damaged, see the license at "http://www.cups.org/".
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * Include necessary headers...
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
#include "cupsd.h"
Packit Service 4ae4ad
#include <cups/dir.h>
Packit Service 4ae4ad
#include <fnmatch.h>
Packit Service 4ae4ad
#ifdef HAVE_REMOVEFILE
Packit Service 4ae4ad
#  include <removefile.h>
Packit Service 4ae4ad
#else
Packit Service 4ae4ad
static int	overwrite_data(int fd, const char *buffer, int bufsize,
Packit Service 4ae4ad
		               int filesize);
Packit Service 4ae4ad
#endif /* HAVE_REMOVEFILE */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdCleanFiles()' - Clean out old files.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
void
Packit Service 4ae4ad
cupsdCleanFiles(const char *path,	/* I - Directory to clean */
Packit Service 4ae4ad
                const char *pattern)	/* I - Filename pattern or NULL */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  cups_dir_t	*dir;			/* Directory */
Packit Service 4ae4ad
  cups_dentry_t	*dent;			/* Directory entry */
Packit Service 4ae4ad
  char		filename[1024];		/* Filename */
Packit Service 4ae4ad
  int		status;			/* Status from unlink/rmdir */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
  cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit Service 4ae4ad
                  "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
Packit Service 4ae4ad
		  pattern ? pattern : "(null)");
Packit Service 4ae4ad
Packit Service 4ae4ad
  if ((dir = cupsDirOpen(path)) == NULL)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
Packit Service 4ae4ad
		    path, strerror(errno));
Packit Service 4ae4ad
    return;
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path);
Packit Service 4ae4ad
Packit Service 4ae4ad
  while ((dent = cupsDirRead(dir)) != NULL)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    if (pattern && fnmatch(pattern, dent->filename, 0))
Packit Service 4ae4ad
      continue;
Packit Service 4ae4ad
Packit Service 4ae4ad
    snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
Packit Service 4ae4ad
Packit Service 4ae4ad
    if (S_ISDIR(dent->fileinfo.st_mode))
Packit Service 4ae4ad
    {
Packit Service 4ae4ad
      cupsdCleanFiles(filename, pattern);
Packit Service 4ae4ad
Packit Service 4ae4ad
      status = rmdir(filename);
Packit Service 4ae4ad
    }
Packit Service 4ae4ad
    else
Packit Service 4ae4ad
      status = cupsdUnlinkOrRemoveFile(filename);
Packit Service 4ae4ad
Packit Service 4ae4ad
    if (status)
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
Packit Service 4ae4ad
		      strerror(errno));
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  cupsDirClose(dir);
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move
Packit Service 4ae4ad
 *                                 into place.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
int					/* O - 0 on success, -1 on error */
Packit Service 4ae4ad
cupsdCloseCreatedConfFile(
Packit Service 4ae4ad
    cups_file_t *fp,			/* I - File to close */
Packit Service 4ae4ad
    const char  *filename)		/* I - Filename */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  char	newfile[1024],			/* filename.N */
Packit Service 4ae4ad
	oldfile[1024];			/* filename.O */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Synchronize changes to disk if SyncOnClose is enabled.
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (SyncOnClose)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    if (cupsFileFlush(fp))
Packit Service 4ae4ad
    {
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s",
Packit Service 4ae4ad
		      filename, strerror(errno));
Packit Service 4ae4ad
      cupsFileClose(fp);
Packit Service 4ae4ad
      return (-1);
Packit Service 4ae4ad
    }
Packit Service 4ae4ad
Packit Service 4ae4ad
    if (fsync(cupsFileNumber(fp)))
Packit Service 4ae4ad
    {
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s",
Packit Service 4ae4ad
		      filename, strerror(errno));
Packit Service 4ae4ad
      cupsFileClose(fp);
Packit Service 4ae4ad
      return (-1);
Packit Service 4ae4ad
    }
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * First close the file...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (cupsFileClose(fp))
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Then remove "filename.O", rename "filename" to "filename.O", and rename
Packit Service 4ae4ad
  * "filename.N" to "filename".
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  snprintf(newfile, sizeof(newfile), "%s.N", filename);
Packit Service 4ae4ad
  snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
Packit Service 4ae4ad
Packit Service 4ae4ad
  if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
Packit Service 4ae4ad
      (rename(filename, oldfile) && errno != ENOENT) ||
Packit Service 4ae4ad
      rename(newfile, filename))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
Packit Service 4ae4ad
                    filename, strerror(errno));
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (0);
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdClosePipe()' - Close a pipe as necessary.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
void
Packit Service 4ae4ad
cupsdClosePipe(int *fds)		/* I - Pipe file descriptors (2) */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Close file descriptors as needed...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (fds[0] >= 0)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fds[0]);
Packit Service 4ae4ad
    fds[0] = -1;
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (fds[1] >= 0)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fds[1]);
Packit Service 4ae4ad
    fds[1] = -1;
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdCreateConfFile()' - Create a configuration file safely.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
cups_file_t *				/* O - File pointer */
Packit Service 4ae4ad
cupsdCreateConfFile(
Packit Service 4ae4ad
    const char *filename,		/* I - Filename */
Packit Service 4ae4ad
    mode_t     mode)			/* I - Permissions */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  cups_file_t	*fp;			/* File pointer */
Packit Service 4ae4ad
  char		newfile[1024];		/* filename.N */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
  snprintf(newfile, sizeof(newfile), "%s.N", filename);
Packit Service 4ae4ad
  if ((fp = cupsFileOpen(newfile, "w")) == NULL)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
Packit Service 4ae4ad
		    strerror(errno));
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
  else
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
Packit Service 4ae4ad
		      newfile, strerror(errno));
Packit Service 4ae4ad
Packit Service 4ae4ad
    if (fchmod(cupsFileNumber(fp), mode))
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_WARN,
Packit Service 4ae4ad
                      "Unable to change permissions for \"%s\": %s",
Packit Service 4ae4ad
		      newfile, strerror(errno));
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (fp);
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdOpenConfFile()' - Open a configuration file.
Packit Service 4ae4ad
 *
Packit Service 4ae4ad
 * This function looks for "filename.O" if "filename" does not exist and does
Packit Service 4ae4ad
 * a rename as needed.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
cups_file_t *				/* O - File pointer */
Packit Service 4ae4ad
cupsdOpenConfFile(const char *filename)	/* I - Filename */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  cups_file_t	*fp;			/* File pointer */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
  if ((fp = cupsFileOpen(filename, "r")) == NULL)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    if (errno == ENOENT)
Packit Service 4ae4ad
    {
Packit Service 4ae4ad
     /*
Packit Service 4ae4ad
      * Try opening the backup file...
Packit Service 4ae4ad
      */
Packit Service 4ae4ad
Packit Service 4ae4ad
      char	oldfile[1024];		/* filename.O */
Packit Service 4ae4ad
Packit Service 4ae4ad
      snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
Packit Service 4ae4ad
      fp = cupsFileOpen(oldfile, "r");
Packit Service 4ae4ad
    }
Packit Service 4ae4ad
    else
Packit Service 4ae4ad
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
Packit Service 4ae4ad
		      strerror(errno));
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (fp);
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
int					/* O - 0 on success, -1 on error */
Packit Service 4ae4ad
cupsdOpenPipe(int *fds)			/* O - Pipe file descriptors (2) */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Create the pipe...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (pipe(fds))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    fds[0] = -1;
Packit Service 4ae4ad
    fds[1] = -1;
Packit Service 4ae4ad
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Set the "close on exec" flag on each end of the pipe...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fds[0]);
Packit Service 4ae4ad
    close(fds[1]);
Packit Service 4ae4ad
Packit Service 4ae4ad
    fds[0] = -1;
Packit Service 4ae4ad
    fds[1] = -1;
Packit Service 4ae4ad
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fds[0]);
Packit Service 4ae4ad
    close(fds[1]);
Packit Service 4ae4ad
Packit Service 4ae4ad
    fds[0] = -1;
Packit Service 4ae4ad
    fds[1] = -1;
Packit Service 4ae4ad
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Return 0 indicating success...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (0);
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdRemoveFile()' - Remove a file securely.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
int					/* O - 0 on success, -1 on error */
Packit Service 4ae4ad
cupsdRemoveFile(const char *filename)	/* I - File to remove */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
#ifdef HAVE_REMOVEFILE
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * See if the file exists...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (access(filename, 0))
Packit Service 4ae4ad
    return (0);
Packit Service 4ae4ad
Packit Service 4ae4ad
  cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Remove the file...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS));
Packit Service 4ae4ad
Packit Service 4ae4ad
#else
Packit Service 4ae4ad
  int			fd;		/* File descriptor */
Packit Service 4ae4ad
  struct stat		info;		/* File information */
Packit Service 4ae4ad
  char			buffer[512];	/* Data buffer */
Packit Service 4ae4ad
  int			i;		/* Looping var */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * See if the file exists...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (access(filename, 0))
Packit Service 4ae4ad
    return (0);
Packit Service 4ae4ad
Packit Service 4ae4ad
  cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * First open the file for writing in exclusive mode.
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Delete the file now - it will still be around as long as the file is
Packit Service 4ae4ad
  * open...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (unlink(filename))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fd);
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Then get the file size...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (fstat(fd, &info))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fd);
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Overwrite the file with random data.
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  CUPS_SRAND(time(NULL));
Packit Service 4ae4ad
Packit Service 4ae4ad
  for (i = 0; i < sizeof(buffer); i ++)
Packit Service 4ae4ad
    buffer[i] = CUPS_RAND();
Packit Service 4ae4ad
  if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    close(fd);
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Close the file, which will lead to the actual deletion, and return...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (close(fd));
Packit Service 4ae4ad
#endif /* HAVE_REMOVEFILE */
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending
Packit Service 4ae4ad
 *                               on the configuration.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
int					/* O - 0 on success, -1 on error */
Packit Service 4ae4ad
cupsdUnlinkOrRemoveFile(
Packit Service 4ae4ad
    const char *filename)		/* I - Filename */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  if (Classification)
Packit Service 4ae4ad
    return (cupsdRemoveFile(filename));
Packit Service 4ae4ad
  else
Packit Service 4ae4ad
    return (unlink(filename));
Packit Service 4ae4ad
}
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
#ifndef HAVE_REMOVEFILE
Packit Service 4ae4ad
/*
Packit Service 4ae4ad
 * 'overwrite_data()' - Overwrite the data in a file.
Packit Service 4ae4ad
 */
Packit Service 4ae4ad
Packit Service 4ae4ad
static int				/* O - 0 on success, -1 on error */
Packit Service 4ae4ad
overwrite_data(int        fd,		/* I - File descriptor */
Packit Service 4ae4ad
               const char *buffer,	/* I - Buffer to write */
Packit Service 4ae4ad
	       int        bufsize,	/* I - Size of buffer */
Packit Service 4ae4ad
               int        filesize)	/* I - Size of file */
Packit Service 4ae4ad
{
Packit Service 4ae4ad
  int	bytes;				/* Bytes to write/written */
Packit Service 4ae4ad
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Start at the beginning of the file...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  if (lseek(fd, 0, SEEK_SET) < 0)
Packit Service 4ae4ad
    return (-1);
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Fill the file with the provided data...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  while (filesize > 0)
Packit Service 4ae4ad
  {
Packit Service 4ae4ad
    if (filesize > bufsize)
Packit Service 4ae4ad
      bytes = bufsize;
Packit Service 4ae4ad
    else
Packit Service 4ae4ad
      bytes = filesize;
Packit Service 4ae4ad
Packit Service 4ae4ad
    if ((bytes = write(fd, buffer, (size_t)bytes)) < 0)
Packit Service 4ae4ad
      return (-1);
Packit Service 4ae4ad
Packit Service 4ae4ad
    filesize -= bytes;
Packit Service 4ae4ad
  }
Packit Service 4ae4ad
Packit Service 4ae4ad
 /*
Packit Service 4ae4ad
  * Force the changes to disk...
Packit Service 4ae4ad
  */
Packit Service 4ae4ad
Packit Service 4ae4ad
  return (fsync(fd));
Packit Service 4ae4ad
}
Packit Service 4ae4ad
#endif /* HAVE_REMOVEFILE */