sdbox-file.c revision 1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "eacces-error.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mkdir-parents.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "sdbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "sdbox-file.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdio.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void sdbox_file_init_paths(struct sdbox_file *file, const char *fname)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(file->file.primary_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(file->file.alt_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.primary_path =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_strdup_printf("%s/%s", file->mbox->ibox.box.path, fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (file->mbox->alt_path != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.alt_path =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_strdup_printf("%s/%s", file->mbox->alt_path, fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_file *sdbox_file_init(struct sdbox_mailbox *mbox, uint32_t uid)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_file *file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *fname;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file = i_new(struct sdbox_file, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.storage = &mbox->storage->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->mbox = mbox;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (uid != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fname = t_strdup_printf(SDBOX_MAIL_FILE_FORMAT, uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_file_init_paths(file, fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->uid = uid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.primary_path =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_strdup_printf("%s/%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->mbox->ibox.box.path,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_generate_tmp_filename());
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_init(&file->file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (uid == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.fd = file->file.storage->v.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file_create_fd(&file->file, file->file.primary_path,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &file->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_file_assign_uid(struct sdbox_file *file, uint32_t uid)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *old_path, *new_fname, *new_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file->uid == 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(uid != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_path = file->file.cur_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_fname = t_strdup_printf(SDBOX_MAIL_FILE_FORMAT, uid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_path = t_strdup_printf("%s/%s", file->mbox->ibox.box.path,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (rename(old_path, new_path) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(&file->file.storage->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "rename(%s, %s) failed: %m",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_path, new_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen sdbox_file_init_paths(file, new_fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->uid = uid;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_file_create_fd(struct dbox_file *file, const char *path, bool parents)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox *box = &sfile->mbox->ibox.box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *p, *dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mode_t old_mask;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_mask = umask(0666 & ~box->file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen umask(old_mask);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (fd == -1 && errno == ENOENT && parents &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (p = strrchr(path, '/')) != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir = t_strdup_until(path, p);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mkdir_parents_chgrp(dir, box->dir_create_mode,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box->file_create_gid,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box->file_create_gid_origin) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(box->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "mkdir_parents(%s) failed: %m", dir);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* try again */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_mask = umask(0666 & ~box->file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen umask(old_mask);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (fd == -1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(box->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "open(%s, O_CREAT) failed: %m", path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (box->file_create_gid == (gid_t)-1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* no group change */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (errno == EPERM) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(box->storage, "%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen eperm_error_get_chgrp("fchown", path,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box->file_create_gid,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box->file_create_gid_origin));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(box->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "fchown(%s, -1, %ld) failed: %m",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path, (long)box->file_create_gid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* continue anyway */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}