mail-process.c revision 9e89f1d9d0ef06a4ae086a13270b57d76074cfe6
/* Copyright (C) 2002 Timo Sirainen */
#include "common.h"
#include "fd-close-on-exec.h"
#include "env-util.h"
#include "str.h"
#include "network.h"
#include "restrict-access.h"
#include "restrict-process-size.h"
#include "var-expand.h"
#include "mail-process.h"
#include "login-process.h"
#include "log.h"
#include <stdlib.h>
#include <unistd.h>
#include <grp.h>
#include <syslog.h>
static unsigned int mail_process_count = 0;
const char *user)
{
if (uid == 0) {
return FALSE;
}
i_error("Logins with login process UID %s (user %s) "
"not permitted (see login_user in config file).",
}
i_error("Logins with UID %s (user %s) not permitted "
"(see first_valid_uid in config file)",
return FALSE;
}
i_error("Logins for users with primary group ID %s (user %s) "
"not permitted (see first_valid_gid in config file).",
return FALSE;
}
return TRUE;
}
{
const char *const *chroot_dirs;
if (*dir == '\0')
return FALSE;
return FALSE;
while (*chroot_dirs != NULL) {
if (**chroot_dirs != '\0' &&
return TRUE;
chroot_dirs++;
}
return FALSE;
}
static const struct var_expand_table *
get_var_expand_table(const char *protocol,
{
static struct var_expand_table static_tab[] = {
{ 'u', NULL },
{ 'n', NULL },
{ 'd', NULL },
{ 'p', NULL },
{ 'h', NULL },
{ 'l', NULL },
{ 'r', NULL },
{ 'P', NULL },
{ '\0', NULL }
};
struct var_expand_table *tab;
return tab;
}
static const char *
{
const char *p;
/* it's either type:data or just data */
if (p != NULL) {
while (env != p) {
env++;
}
}
/* expand home */
}
/* expand %vars */
}
static void
const struct var_expand_table *table)
{
const char *location;
unsigned int i;
if (default_location == NULL)
default_location = "";
t_push();
}
}
/* expand variables, eg. ~%u/ can be useful */
}
t_pop();
}
}
static void
const struct var_expand_table *var_expand_table)
{
if (set->mail_save_crlf)
env_put("MAIL_SAVE_CRLF=1");
if (set->mail_read_mmaped)
env_put("MAIL_READ_MMAPED=1");
if (set->mmap_disable)
env_put("MMAP_DISABLE=1");
if (set->mmap_no_write)
env_put("MMAP_NO_WRITE=1");
if (set->fcntl_locks_disable)
env_put("FCNTL_LOCKS_DISABLE=1");
if (set->maildir_stat_dirs)
env_put("MAILDIR_STAT_DIRS=1");
env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
env_put("MAILDIR_CHECK_CONTENT_CHANGES=1");
env_put("FULL_FILESYSTEM_ACCESS=1");
if (set->pop3_mails_keep_recent)
env_put("POP3_MAILS_KEEP_RECENT=1");
if (set->mbox_dirty_syncs)
env_put("MBOX_DIRTY_SYNCS=1");
set->mbox_lock_timeout));
if (set->mail_use_modules &&
}
/* user given environment - may be malicious. virtual_user comes from
auth process, but don't trust that too much either. Some auth
mechanism might allow leaving extra data there. */
}
}
{
int i;
/* very simple argument splitting. */
i = 0;
argv[i]++;
i++;
}
if (title[0] != '\0')
/* hide the path, it's ugly */
}
{
const struct var_expand_table *var_expand_table;
break;
}
}
else
getenv("TCPLOCALIP"),
}
{
const struct var_expand_table *var_expand_table;
char title[1024];
// FIXME: per-group
i_error("Maximum number of mail processes exceeded");
return FALSE;
}
return FALSE;
i_error("Invalid chroot directory '%s' (user %s) "
"(see valid_chroot_dirs in config file)",
chroot_dir, user);
return FALSE;
}
if (pid < 0) {
i_error("fork() failed: %m");
return FALSE;
}
if (pid != 0) {
/* master */
return TRUE;
}
/* move the client socket into stdin and stdout fds, log to stderr */
i_fatal("dup2(stdin) failed: %m");
i_fatal("dup2(stdout) failed: %m");
i_fatal("dup2(stderr) failed: %m");
for (i = 0; i < 3; i++)
fd_close_on_exec(i, FALSE);
/* setup environment - set the most important environment first
(paranoia about filling up environment without noticing) */
if (*home_dir == '\0')
ret = -1;
else {
/* NOTE: if home directory is NFS-mounted, we might not
have access to it as root. Change the effective UID
temporarily to make it work. */
/* If user's home directory doesn't exist and we're not
trying to chroot anywhere, fallback to /tmp as the mails
could be stored elsewhere. */
i_fatal("chdir(%s) failed with uid %s: %m",
}
}
if (ret < 0) {
/* We still have to change to some directory where we have
rx-access. /tmp should exist everywhere. */
if (chdir("/tmp") < 0)
i_fatal("chdir(/tmp) failed: %m");
}
env_put("LOGGED_IN=1");
if (!set->verbose_proctitle)
title[0] = '\0';
else {
addr = "??";
}
/* make sure we don't leak syslog fd, but do it last so that
any errors above will be logged */
closelog();
for (i = 0; i < 3; i++)
(void)close(i);
/* not reached */
return FALSE;
}
{
}