commands.c revision e7b1f9db0128384b152b58ea65303d66484c9d7b
/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "str.h"
#include "strescape.h"
#include "hostpid.h"
#include "istream.h"
#include "istream-concat.h"
#include "ostream.h"
#include "istream-dot.h"
#include "safe-mkstemp.h"
#include "restrict-access.h"
#include "master-service.h"
#include "rfc822-parser.h"
#include "message-date.h"
#include "auth-master.h"
#include "mail-storage-service.h"
#include "index/raw/raw-storage.h"
#include "lda-settings.h"
#include "lmtp-settings.h"
#include "mail-namespace.h"
#include "mail-deliver.h"
#include "main.h"
#include "client.h"
#include "commands.h"
#include "lmtp-proxy.h"
#include <stdlib.h>
#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
#define ERRSTR_TEMP_USERDB_FAIL \
ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
{
struct rfc822_parser_context parser;
const char *p;
int ret = 0;
if (*args == '\0') {
return 0;
}
/* domain / address-literal */
NULL);
if (*args != '[')
else {
if (*p == '\\' || *p == '[')
break;
}
if (strcmp(p, "]") != 0)
ret = -1;
}
if (ret < 0) {
str_truncate(domain, 0);
}
return 0;
}
const char **rest_r)
{
const char *start;
if (*str++ != '<')
return -1;
if (*str == '"') {
/* "quoted-string"@domain */
if (*str == '\\')
str++;
if (*str == '\0')
return -1;
}
str++;
}
return -1;
}
if (*str++ != '>')
return -1;
if (*str == ' ')
str++;
else if (*str != '\0')
return -1;
return 0;
}
{
return 0;
}
return 0;
}
else {
"501 5.5.4 Unsupported options");
return 0;
}
}
return 0;
}
static bool
{
if (p == NULL) {
value = "";
} else {
value = p + 1;
}
if (!port_set)
} else {
return FALSE;
}
/* changing the username */
} else {
/* just ignore it */
}
}
i_error("proxy: host not given");
return FALSE;
}
return proxying;
}
static bool
const struct lmtp_proxy_settings *set)
{
return FALSE;
return FALSE;
return FALSE;
return TRUE;
}
static const char *
const char *detail)
{
const char *domain;
else {
}
}
{
struct auth_master_connection *auth_conn;
struct lmtp_proxy_settings set;
struct auth_user_info info;
struct mail_storage_service_input input;
int ret;
if (ret <= 0) {
pool_unref(&pool);
if (ret < 0) {
return TRUE;
} else {
/* user not found from passdb. try userdb also. */
return FALSE;
}
}
/* not proxying this user */
pool_unref(&pool);
return FALSE;
}
/* username changed. change the address as well */
if (*detail == '\0')
else
"Proxying loops to itself", address);
pool_unref(&pool);
return TRUE;
}
address);
pool_unref(&pool);
return TRUE;
}
args = " BODY=8BITMIME";
args = " BODY=7BIT";
else
args = "";
}
else
pool_unref(&pool);
return TRUE;
}
static const char *lmtp_unescape_address(const char *name)
{
const char *p;
if (*name != '"')
return name;
/* quoted-string local-part. drop the quotes unless there's a
'@' character inside or there's an error. */
if (*p == '\0')
return name;
if (*p == '\\') {
if (p[1] == '\0') {
/* error */
return name;
}
p++;
}
if (*p == '@')
return name;
str_append_c(str, *p);
}
p++;
if (*p != '@' && *p != '\0')
return name;
str_append(str, p);
}
const char **username_r, const char **detail_r)
{
const char *p, *domain;
*username_r = address;
*detail_r = "";
return;
/* user+detail@domain */
*detail_r = p+1;
else {
}
}
}
{
unsigned int len;
if (*transpos == '\0')
return;
/* check that string matches up to the first '%' */
if (p == NULL)
else
return;
while (*transpos != '\0') {
switch (transpos[1]) {
case 'n':
case 'u':
break;
case 'd':
break;
default:
return;
}
transpos += 2;
/* find where the next string starts */
if (*transpos == '\0') {
break;
}
if (p == NULL)
else
if (p == NULL)
return;
}
}
{
struct mail_recipient rcpt;
struct mail_storage_service_input input;
int ret = 0;
return 0;
}
return 0;
}
if (*args != '\0') {
return 0;
}
return 0;
}
/* NOTE: if this restriction is ever removed, we'll also need
to send different message bodies to local and proxy
(with and without Return-Path: header) */
address);
return 0;
}
if (ret < 0) {
username);
return 0;
}
if (ret == 0) {
"550 5.1.1 <%s> User doesn't exist: %s",
return 0;
}
return 0;
}
{
return -1;
}
{
return 0;
}
{
return 0;
}
{
return 0;
}
static int
{
struct mail_deliver_context dctx;
struct mail_storage *storage;
const struct mail_storage_service_input *input;
struct mail_namespace *ns;
void **sets;
enum mail_error mail_error;
int ret;
return -1;
}
}
else {
}
}
ret = 0;
/* This shouldn't happen */
i_error("BUG: Saving failed to unknown storage");
ret = -1;
} else {
if (mail_error == MAIL_ERROR_NOSPACE) {
"452 4.2.2" : "552 5.2.2",
} else {
}
ret = -1;
}
return ret;
}
struct mail_deliver_session *session)
{
const struct mail_recipient *rcpts;
unsigned int count;
int ret;
if (ret == 0)
return TRUE;
/* failed. try the next one. */
}
return FALSE;
}
{
const struct mail_recipient *rcpt;
}
}
{
FALSE);
} else {
}
i_stream_unref(&inputs[0]);
return cinput;
}
{
static const char *wanted_headers[] = {
"From", "To", "Message-ID", "Subject", "Return-Path",
};
struct mailbox_transaction_context *trans;
struct mailbox_header_lookup_ctx *headers_ctx;
enum mail_error error;
&box) < 0) {
i_error("Can't open delivery mail as raw: %s",
mailbox_free(&box);
return -1;
}
return 0;
}
static void
{
struct mail_deliver_session *session;
return;
else {
/* use the first saved message to save it elsewhere too.
this might allow hard linking the files. */
}
}
/* just in case these functions are going to write anything,
change uid back to user's own one */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
i_fatal("seteuid() failed: %m");
}
mailbox_free(&box);
}
if (old_uid == 0) {
/* switch back to running as root, since that's what we're
practically doing anyway. it's also important in case we
lose e.g. config connection and need to reconnect to it. */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
/* enable core dumping again. we need to chdir also to
root-owned directory to get core dumps. */
}
}
{
}
static void client_proxy_finish(void *context)
{
}
{
const struct mail_recipient *rcpt =
}
/* don't set Return-Path when proxying so it won't get added twice */
}
}
{
}
return ret;
}
{
int fd;
/* continue writing to file */
return -1;
return 0;
}
/* move everything to a temporary file. */
if (fd == -1) {
return -1;
}
/* we just want the fd, unlink it */
/* shouldn't happen.. */
return -1;
}
return -1;
return -1;
return 0;
}
static int
{
return 0;
} else {
}
}
{
const unsigned char *data;
"Temporary internal failure");
return;
}
}
if (ret == 0)
return;
/* client probably disconnected */
return;
}
}
{
if (client_input_read(client) < 0)
return;
}
{
return 0;
}
return 0;
}
return -1;
}