#include "cupsd.h"
#include <cups/dir.h>
#include <fnmatch.h>
#ifdef HAVE_REMOVEFILE
# include <removefile.h>
#else
static int overwrite_data(int fd, const char *buffer, int bufsize,
int filesize);
#endif
void
cupsdCleanFiles(const char *path,
const char *pattern)
{
cups_dir_t *dir;
cups_dentry_t *dent;
char filename[1024];
int status;
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
pattern ? pattern : "(null)");
if ((dir = cupsDirOpen(path)) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
path, strerror(errno));
return;
}
cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path);
while ((dent = cupsDirRead(dir)) != NULL)
{
if (pattern && fnmatch(pattern, dent->filename, 0))
continue;
snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
if (S_ISDIR(dent->fileinfo.st_mode))
{
cupsdCleanFiles(filename, pattern);
status = rmdir(filename);
}
else
status = cupsdUnlinkOrRemoveFile(filename);
if (status)
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
strerror(errno));
}
cupsDirClose(dir);
}
int
cupsdCloseCreatedConfFile(
cups_file_t *fp,
const char *filename)
{
char newfile[1024],
oldfile[1024];
if (SyncOnClose)
{
if (cupsFileFlush(fp))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s",
filename, strerror(errno));
cupsFileClose(fp);
return (-1);
}
if (fsync(cupsFileNumber(fp)))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s",
filename, strerror(errno));
cupsFileClose(fp);
return (-1);
}
}
if (cupsFileClose(fp))
return (-1);
snprintf(newfile, sizeof(newfile), "%s.N", filename);
snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
(rename(filename, oldfile) && errno != ENOENT) ||
rename(newfile, filename))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
filename, strerror(errno));
return (-1);
}
return (0);
}
void
cupsdClosePipe(int *fds)
{
if (fds[0] >= 0)
{
close(fds[0]);
fds[0] = -1;
}
if (fds[1] >= 0)
{
close(fds[1]);
fds[1] = -1;
}
}
cups_file_t *
cupsdCreateConfFile(
const char *filename,
mode_t mode)
{
cups_file_t *fp;
char newfile[1024];
snprintf(newfile, sizeof(newfile), "%s.N", filename);
if ((fp = cupsFileOpen(newfile, "w")) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
strerror(errno));
}
else
{
if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
newfile, strerror(errno));
if (fchmod(cupsFileNumber(fp), mode))
cupsdLogMessage(CUPSD_LOG_WARN,
"Unable to change permissions for \"%s\": %s",
newfile, strerror(errno));
}
return (fp);
}
cups_file_t *
cupsdOpenConfFile(const char *filename)
{
cups_file_t *fp;
if ((fp = cupsFileOpen(filename, "r")) == NULL)
{
if (errno == ENOENT)
{
char oldfile[1024];
snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
fp = cupsFileOpen(oldfile, "r");
}
else
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
strerror(errno));
}
return (fp);
}
int
cupsdOpenPipe(int *fds)
{
if (pipe(fds))
{
fds[0] = -1;
fds[1] = -1;
return (-1);
}
if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
{
close(fds[0]);
close(fds[1]);
fds[0] = -1;
fds[1] = -1;
return (-1);
}
if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
{
close(fds[0]);
close(fds[1]);
fds[0] = -1;
fds[1] = -1;
return (-1);
}
return (0);
}
int
cupsdRemoveFile(const char *filename)
{
#ifdef HAVE_REMOVEFILE
if (access(filename, 0))
return (0);
cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS));
#else
int fd;
struct stat info;
char buffer[512];
int i;
if (access(filename, 0))
return (0);
cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
return (-1);
if (unlink(filename))
{
close(fd);
return (-1);
}
if (fstat(fd, &info))
{
close(fd);
return (-1);
}
CUPS_SRAND(time(NULL));
for (i = 0; i < sizeof(buffer); i ++)
buffer[i] = CUPS_RAND();
if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
{
close(fd);
return (-1);
}
return (close(fd));
#endif
}
int
cupsdUnlinkOrRemoveFile(
const char *filename)
{
if (Classification)
return (cupsdRemoveFile(filename));
else
return (unlink(filename));
}
#ifndef HAVE_REMOVEFILE
static int
overwrite_data(int fd,
const char *buffer,
int bufsize,
int filesize)
{
int bytes;
if (lseek(fd, 0, SEEK_SET) < 0)
return (-1);
while (filesize > 0)
{
if (filesize > bufsize)
bytes = bufsize;
else
bytes = filesize;
if ((bytes = write(fd, buffer, (size_t)bytes)) < 0)
return (-1);
filesize -= bytes;
}
return (fsync(fd));
}
#endif