safe-mkstemp.c revision 4ded3d18fa391ae5908f9834f1390cf55e8c99d5
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "lib.h"
d6499957ea59e6d9729d3350d9ac5eae992635f6Timo Sirainen#include "str.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "hex-binary.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "randgen.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "hostpid.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "safe-mkstemp.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include <unistd.h>
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen#include <fcntl.h>
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include <sys/stat.h>
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenint safe_mkstemp(string_t *prefix, mode_t mode, uid_t uid, gid_t gid)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen{
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen size_t prefix_len;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen struct stat st;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen unsigned char randbuf[8];
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen mode_t old_umask;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen int fd;
4c0aff96fc7e6d779be43458f96cbf015849a3deTimo Sirainen
4c0aff96fc7e6d779be43458f96cbf015849a3deTimo Sirainen prefix_len = str_len(prefix);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen for (;;) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen do {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen random_fill_weak(randbuf, sizeof(randbuf));
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen str_truncate(prefix, prefix_len);
4c0aff96fc7e6d779be43458f96cbf015849a3deTimo Sirainen str_append(prefix,
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen binary_to_hex(randbuf, sizeof(randbuf)));
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen } while (lstat(str_c(prefix), &st) == 0);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (errno != ENOENT) {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen i_error("stat(%s) failed: %m", str_c(prefix));
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return -1;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen }
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen old_umask = umask(0666 ^ mode);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen fd = open(str_c(prefix), O_RDWR | O_EXCL | O_CREAT, 0666);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen umask(old_umask);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (fd != -1)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen break;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (errno != EEXIST) {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (errno != ENOENT && errno != EACCES)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen i_error("open(%s) failed: %m", str_c(prefix));
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return -1;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen }
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen if (uid != (uid_t)-1 || gid != (gid_t)-1) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (fchown(fd, uid, gid) < 0) {
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen i_error("fchown(%s, %ld, %ld) failed: %m",
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen str_c(prefix),
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen uid == (uid_t)-1 ? -1L : (long)uid,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen gid == (gid_t)-1 ? -1L : (long)gid);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen (void)close(fd);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen (void)unlink(str_c(prefix));
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return -1;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen }
d6499957ea59e6d9729d3350d9ac5eae992635f6Timo Sirainen }
4c0aff96fc7e6d779be43458f96cbf015849a3deTimo Sirainen return fd;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenint safe_mkstemp_hostpid(string_t *prefix, mode_t mode, uid_t uid, gid_t gid)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen{
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen str_printfa(prefix, "%s.%s.", my_hostname, my_pid);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return safe_mkstemp(prefix, mode, uid, gid);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen