예제 #1
0
static int
mkdir_chown_full(const char *path, mode_t mode, uid_t uid,
		 gid_t gid, const char *gid_origin)
{
	string_t *str;
	mode_t old_mask;
	int ret, orig_errno;

	old_mask = umask(0);
	ret = mkdir(path, mode);
	umask(old_mask);

	if (ret < 0) {
		if (errno == EISDIR || errno == ENOSYS) {
			/* EISDIR check is for BSD/OS which returns it if path
			   contains '/' at the end and it exists.

			   ENOSYS check is for NFS mount points. */
			errno = EEXIST;
		}
		return -1;
	}
	if (chown(path, uid, gid) < 0) {
		orig_errno = errno;
		if (rmdir(path) < 0)
			i_error("rmdir(%s) failed: %m", path);
		errno = orig_errno;

		if (errno == EPERM && uid == (uid_t)-1) {
			i_error("%s", eperm_error_get_chgrp("chown", path, gid,
							    gid_origin));
			return -1;
		}

		str = t_str_new(256);
		str_printfa(str, "chown(%s, %ld", path,
			    uid == (uid_t)-1 ? -1L : (long)uid);
		if (uid != (uid_t)-1) {
			struct passwd pw;

			if (i_getpwuid(uid, &pw) > 0)
				str_printfa(str, "(%s)", pw.pw_name);

		}
		str_printfa(str, ", %ld",
			    gid == (gid_t)-1 ? -1L : (long)gid);
		if (gid != (gid_t)-1) {
			struct group gr;

			if (i_getgrgid(uid, &gr) > 0)
				str_printfa(str, "(%s)", gr.gr_name);
		}
		errno = orig_errno;
		i_error("%s) failed: %m", str_c(str));
		return -1;
	}
	return 0;
}
예제 #2
0
static int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir,
			      const char **fname_r)
{
	struct mailbox *box = &mbox->box;
	const struct mailbox_permissions *perm = mailbox_get_permissions(box);
	unsigned int prefix_len;
	const char *tmp_fname;
	string_t *path;
	mode_t old_mask;
	int fd;

	path = t_str_new(256);
	str_append(path, dir);
	str_append_c(path, '/');
	prefix_len = str_len(path);

	do {
		tmp_fname = maildir_filename_generate();
		str_truncate(path, prefix_len);
		str_append(path, tmp_fname);

		/* the generated filename is unique. the only reason why it
		   might return an existing filename is if the time moved
		   backwards. so we'll use O_EXCL anyway, although it's mostly
		   useless. */
		old_mask = umask(0777 & ~perm->file_create_mode);
		fd = open(str_c(path),
			  O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0777);
		umask(old_mask);
	} while (fd == -1 && errno == EEXIST);

	*fname_r = tmp_fname;
	if (fd == -1) {
		if (ENOQUOTA(errno)) {
			mail_storage_set_error(box->storage,
				MAIL_ERROR_NOQUOTA, MAIL_ERRSTR_NO_QUOTA);
		} else {
			mail_storage_set_critical(box->storage,
				"open(%s) failed: %m", str_c(path));
		}
	} else if (perm->file_create_gid != (gid_t)-1) {
		if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
			if (errno == EPERM) {
				mail_storage_set_critical(box->storage, "%s",
					eperm_error_get_chgrp("fchown",
						str_c(path),
						perm->file_create_gid,
						perm->file_create_gid_origin));
			} else {
				mail_storage_set_critical(box->storage,
					"fchown(%s) failed: %m", str_c(path));
			}
		}
	}

	return fd;
}
예제 #3
0
safe_mkstemp_full(string_t *prefix, mode_t mode, uid_t uid, gid_t gid,
		  const char *gid_origin)
{
	size_t prefix_len;
	struct stat st;
	unsigned char randbuf[8];
	mode_t old_umask;
	int fd;

	prefix_len = str_len(prefix);
	for (;;) {
		do {
			random_fill_weak(randbuf, sizeof(randbuf));
			str_truncate(prefix, prefix_len);
			str_append(prefix,
				   binary_to_hex(randbuf, sizeof(randbuf)));
		} while (lstat(str_c(prefix), &st) == 0);

		if (errno != ENOENT) {
			i_error("stat(%s) failed: %m", str_c(prefix));
			str_truncate(prefix, prefix_len);
			return -1;
		}

		old_umask = umask(0666 ^ mode);
		fd = open(str_c(prefix), O_RDWR | O_EXCL | O_CREAT, 0666);
		umask(old_umask);
		if (fd != -1)
			break;

		if (errno != EEXIST) {
			if (errno != ENOENT && errno != EACCES)
				i_error("open(%s) failed: %m", str_c(prefix));
			str_truncate(prefix, prefix_len);
			return -1;
		}
	}
	if (uid == (uid_t)-1 && gid == (gid_t)-1)
		return fd;

	if (fchown(fd, uid, gid) < 0) {
		if (errno == EPERM) {
			i_error("%s", eperm_error_get_chgrp("fchown",
					str_c(prefix), gid, gid_origin));
		} else {
			i_error("fchown(%s, %ld, %ld) failed: %m",
				str_c(prefix),
				uid == (uid_t)-1 ? -1L : (long)uid,
				gid == (gid_t)-1 ? -1L : (long)gid);
		}
		i_close_fd(&fd);
		(void)unlink(str_c(prefix));
		return -1;
	}
	return fd;
}
예제 #4
0
int mdbox_file_create_fd(struct dbox_file *file, const char *path, bool parents)
{
	struct mdbox_file *mfile = (struct mdbox_file *)file;
	struct mdbox_map *map = mfile->storage->map;
	struct mailbox_permissions perm;
	mode_t old_mask;
	const char *p, *dir;
	int fd;

	mailbox_list_get_root_permissions(map->root_list, &perm);

	old_mask = umask(0666 & ~perm.file_create_mode);
	fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
	umask(old_mask);
	if (fd == -1 && errno == ENOENT && parents &&
	    (p = strrchr(path, '/')) != NULL) {
		dir = t_strdup_until(path, p);
		if (mailbox_list_mkdir_root(map->root_list, dir,
					    path != file->alt_path ?
					    MAILBOX_LIST_PATH_TYPE_DIR :
					    MAILBOX_LIST_PATH_TYPE_ALT_DIR) < 0) {
			mail_storage_copy_list_error(&file->storage->storage,
						     map->root_list);
			return -1;
		}
		/* try again */
		old_mask = umask(0666 & ~perm.file_create_mode);
		fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
		umask(old_mask);
	}
	if (fd == -1) {
		mail_storage_set_critical(&file->storage->storage,
			"open(%s, O_CREAT) failed: %m", path);
	} else if (perm.file_create_gid == (gid_t)-1) {
		/* no group change */
	} else if (fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
		if (errno == EPERM) {
			mail_storage_set_critical(&file->storage->storage, "%s",
				eperm_error_get_chgrp("fchown", path,
					perm.file_create_gid,
					perm.file_create_gid_origin));
		} else {
			mail_storage_set_critical(&file->storage->storage,
				"fchown(%s, -1, %ld) failed: %m",
				path, (long)perm.file_create_gid);
		}
		/* continue anyway */
	}
	return fd;
}
예제 #5
0
static void mailbox_uidvalidity_write(struct mailbox_list *list,
				      const char *path, uint32_t uid_validity)
{
	char buf[8+1];
	int fd;
	struct mailbox_permissions perm;
	mode_t old_mask;

	mailbox_list_get_root_permissions(list, &perm);

	old_mask = umask(0666 & ~perm.file_create_mode);
	fd = open(path, O_RDWR | O_CREAT, 0666);
	umask(old_mask);
	if (fd == -1) {
		i_error("open(%s) failed: %m", path);
		return;
	}
	if (perm.file_create_gid != (gid_t)-1 &&
	    fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
		if (errno == EPERM) {
			i_error("%s", eperm_error_get_chgrp("fchown", path,
						perm.file_create_gid,
						perm.file_create_gid_origin));
		} else {
			i_error("fchown(%s, -1, %ld) failed: %m",
				path, (long)perm.file_create_gid);
		}
	}

	if (i_snprintf(buf, sizeof(buf), "%08x", uid_validity) < 0)
		i_unreached();
	if (pwrite_full(fd, buf, strlen(buf), 0) < 0)
		i_error("write(%s) failed: %m", path);
	if (close(fd) < 0)
		i_error("close(%s) failed: %m", path);
}
예제 #6
0
static int maildir_keywords_write_fd(struct maildir_keywords *mk,
				     const char *path, int fd)
{
	struct maildir_mailbox *mbox = mk->mbox;
	struct mailbox *box = &mbox->box;
	const struct mailbox_permissions *perm = mailbox_get_permissions(box);
	const char *const *keywords;
	unsigned int i, count;
	string_t *str;
	struct stat st;

	str = t_str_new(256);
	keywords = array_get(&mk->list, &count);
	for (i = 0; i < count; i++) {
		if (keywords[i] != NULL)
			str_printfa(str, "%u %s\n", i, keywords[i]);
	}
	if (write_full(fd, str_data(str), str_len(str)) < 0) {
		mail_storage_set_critical(mk->storage,
					  "write_full(%s) failed: %m", path);
		return -1;
	}

	if (fstat(fd, &st) < 0) {
		mail_storage_set_critical(mk->storage,
					  "fstat(%s) failed: %m", path);
		return -1;
	}

	if (st.st_gid != perm->file_create_gid &&
	    perm->file_create_gid != (gid_t)-1) {
		if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
			if (errno == EPERM) {
				mail_storage_set_critical(mk->storage, "%s",
					eperm_error_get_chgrp("fchown", path,
						perm->file_create_gid,
						perm->file_create_gid_origin));
			} else {
				mail_storage_set_critical(mk->storage,
					"fchown(%s) failed: %m", path);
			}
		}
	}

	/* mtime must grow every time */
	if (st.st_mtime <= mk->synced_mtime) {
		struct utimbuf ut;

		mk->synced_mtime = ioloop_time <= mk->synced_mtime ?
			mk->synced_mtime + 1 : ioloop_time;
		ut.actime = ioloop_time;
		ut.modtime = mk->synced_mtime;
		if (utime(path, &ut) < 0) {
			mail_storage_set_critical(mk->storage,
				"utime(%s) failed: %m", path);
			return -1;
		}
	}

	if (fsync(fd) < 0) {
		mail_storage_set_critical(mk->storage,
			"fsync(%s) failed: %m", path);
		return -1;
	}
	return 0;
}