Blame scheduler/file.c

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