commands.c revision a192134d1aaf3ff73bff040c7cd9ab3e9a8fe1dd
/* Copyright (c) 2009-2014 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 "settings-parser.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);
}
if (client_is_trusted(client))
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_rcpt_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_rcpt_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;
}
i_error("Proxying to <%s> appears to be looping (TTL=0)",
username);
"Proxying appears to be looping (TTL=0)",
username);
pool_unref(&pool);
return TRUE;
}
address);
pool_unref(&pool);
return TRUE;
}
struct lmtp_proxy_settings proxy_set;
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;
}
}
static int
const struct mail_recipient *rcpt)
{
struct mail_namespace *ns;
struct mailbox_status status;
const char *errstr;
enum mail_error error;
int ret;
return 0;
if (ret < 0)
return -1;
if (ret < 0) {
if (error == MAIL_ERROR_NOSPACE) {
ret = 1;
}
}
mailbox_free(&box);
return ret;
}
{
struct mail_recipient rcpt;
struct mail_storage_service_input input;
int ret = 0;
return 0;
}
return 0;
}
if (*args != '\0') {
return 0;
}
return 0;
}
if (ret < 0) {
username);
return 0;
}
if (ret == 0) {
"550 5.1.1 <%s> User doesn't exist: %s",
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;
}
return 0;
}
if (ret == 0) {
}
return 0;
}
{
/* don't log the (state name) for successful QUITs */
return -1;
}
{
return 0;
}
{
return 0;
}
{
return 0;
}
static int
struct mail_deliver_session *session)
{
struct mail_deliver_context dctx;
struct mail_storage *storage;
const struct mail_storage_service_input *input;
const struct mail_storage_settings *mail_set;
struct lda_settings *lda_set;
struct mail_namespace *ns;
struct setting_parser_context *set_parser;
void **sets;
enum mail_error mail_error;
int ret;
if (client->proxy_timeout_secs > 0 &&
(mail_set->mail_max_lock_timeout == 0 ||
/* set lock timeout waits to be less than when proxy has
advertised that it's going to timeout the connection.
this avoids duplicate deliveries in case the delivery
succeeds after the proxy has already disconnected from us. */
i_unreached();
}
&dest_user) < 0) {
return -1;
}
}
else {
}
ret = 0;
if (mail_error == MAIL_ERROR_NOSPACE) {
"452 4.2.2" : "552 5.2.2",
} else {
}
ret = -1;
ret = -1;
} else {
/* This shouldn't happen */
i_error("BUG: Saving failed to unknown storage");
ret = -1;
}
return ret;
}
struct mail_deliver_session *session)
{
const struct mail_recipient *rcpts;
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}
{
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;
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 */
}
if (host[0] != '\0')
}
{
}
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.. */
i_close_fd(&fd);
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;
}
/* send the DATA reply immediately before we start handling any data */
return -1;
}
{
const char *const *tmp;
if (!client_is_trusted(client)) {
return 0;
}
}
}
if (!args_ok) {
return 0;
}
/* args ok, set them and reset the state */
if (remote_port != 0)
return 0;
}