/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#include "fdpass.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "llist.h"
#include "hostpid.h"
#include "var-expand.h"
#include "process-title.h"
#include "randgen.h"
#include "restrict-access.h"
#include "settings-parser.h"
#include "master-service.h"
#include "master-interface.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-namespace.h"
#include "imap-url.h"
#include "imap-msgpart-url.h"
#include "imap-urlauth.h"
#include "imap-urlauth-fetch.h"
#include "imap-urlauth-worker-settings.h"
#include <unistd.h>
#include <sysexits.h>
/* max. length of input lines (URLs) */
/* Disconnect client after idling this many milliseconds */
#define IS_STANDALONE() \
struct client {
/* settings: */
};
unsigned int imap_urlauth_worker_client_count;
static void imap_urlauth_worker_refresh_proctitle(void)
{
if (!verbose_proctitle)
return;
switch (imap_urlauth_worker_client_count) {
case 0:
break;
case 1:
else {
}
break;
default:
break;
}
}
{
"Session closed for inactivity in reading our output");
} else {
}
}
{
/* always use nonblocking I/O */
return client;
}
static struct client *
const char *const *access_applications,
{
/* always use nonblocking I/O */
else {
}
if (access_applications != NULL) {
}
}
i_set_failure_prefix("imap-urlauth[%s](%s): ",
return client;
}
{
}
{
char **app;
i_set_failure_prefix("imap-urlauth[%s](%s): ",
/* deinitialize url */
(void)client_run_url(client);
}
}
{
const unsigned char *data;
break;
break;
if (ret == 0)
return 0;
}
}
return -1;
}
return 1;
}
return 0;
}
static void clients_destroy_all(void)
{
while (imap_urlauth_worker_clients != NULL)
}
{
return;
T_BEGIN {
} T_END;
}
static int
const char **bpstruct_r, bool *binary_with_nuls_r,
const char **errormsg_r)
{
const char *error;
int ret;
*bpstruct_r = NULL;
*errormsg_r = NULL;
if (ret <= 0) {
if (ret < 0)
return -1;
/* don't leak info about existence/accessibility
of mailboxes */
if (error_code == MAIL_ERROR_PARAMS)
*errormsg_r = error;
return 0;
}
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0)
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE) != 0) {
bpstruct_r, &error);
if (ret <= 0) {
return ret;
}
}
/* if requested, read the message part the URL points to */
if ((url_flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0 ||
(url_flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0) {
if (ret <= 0) {
return ret;
}
}
return 1;
}
{
bool binary_with_nuls;
int ret;
client->msg_part_size = 0;
/* fetch URL */
&binary_with_nuls, &errormsg);
if (ret <= 0) {
/* fetch failed */
/* don't send error details to anonymous users: just to be sure
that no information about the target user account is unduly
leaked. */
else {
}
if (ret < 0) {
/* fetch failed badly */
}
return 0;
}
if (binary_with_nuls)
i_debug("Fetched URLAUTH yielded BODYPARTSTRUCTURE (%s)",
bpstruct);
}
}
/* return content */
/* empty */
i_debug("Fetched URLAUTH yielded empty result");
} else {
/* actual content */
}
if (client_run_url(client) < 0) {
"Session aborted: Fatal failure while transferring URL");
return 0;
}
}
/* URL not finished */
}
}
static int
{
int ret;
/* "URL"["\tbody"]["\tbinary"]["\tbpstruct"]"\t"<url>:
fetch URL (meta)data */
const char *url;
*error_r = "URL: Missing URL parameter";
return -1;
}
args++;
args++;
}
if (url_flags == 0)
T_BEGIN {
} T_END;
return ret;
}
/* "END": unselect current user (closes worker) */
*error_r = "END: Invalid number of parameters";
return -1;
}
return 0;
}
return -1;
}
static int
{
const char *error;
unsigned int count;
int ret;
/* "USER\t"<username> */
/* check command syntax */
return -1;
}
*error_r = "USER: Invalid number of parameters";
return -1;
}
/* lookup user */
if (ret < 0) {
return 0;
} else if (ret == 0) {
return 1;
}
/* drop privileges */
&error) <= 0) {
"Session aborted: Failed to expand settings: %s", error));
return 0;
}
if (set->verbose_proctitle) {
}
i_debug("Found user account `%s' on behalf of user `%s'",
}
/* initialize urlauth context */
i_error("imap_urlauth_host setting is not configured for user %s",
return 0;
}
i_debug("Providing access to user account `%s' on behalf of user `%s' "
}
i_set_failure_prefix("imap-urlauth[%s](%s->%s): ",
return 1;
}
{
int ret;
/* we're still processing a URL. wait until it's
finished. */
return TRUE;
}
}
case -1:
/* disconnected */
return FALSE;
case -2:
/* line too long, kill it */
return FALSE;
}
continue;
else
if (ret <= 0) {
if (ret == 0)
break;
return FALSE;
}
}
return TRUE;
}
{
(void)client_handle_input(client);
}
{
return 1;
}
if (client_run_url(client) < 0) {
return 1;
}
if (!client_handle_input(client)) {
/* client got destroyed */
return 1;
}
}
}
/* url not finished yet */
return 0;
/* data still in output buffer, get back here to add IO */
return 0;
} else {
return 1;
}
}
static int
{
unsigned char data = 0;
}
}
if (ret == 0) {
/* unexpectedly disconnected */
return 0;
} else if (ret < 0) {
return 0;
i_error("fd_read() failed: %m");
return -1;
} else if (data != '0') {
return -1;
}
i_error("Handshake is missing a file descriptor");
return -1;
}
client->ctrl_input =
return 1;
}
{
const char *const *args;
const char *line;
int ret;
if (ret < 0)
return;
}
}
case -1:
/* disconnected */
return;
case -2:
/* line too long, kill it */
"Control session aborted: Input line too long");
return;
}
if (!client->version_received) {
return;
i_error("imap-urlauth-worker client not compatible with this server "
"(mixed old and new binaries?) %s", line);
return;
}
return;
}
}
if (client->access_received) {
return;
}
return;
return;
}
args++;
return;
}
if (**args != '\0') {
} else {
}
args++;
i_set_failure_prefix("imap-urlauth[%s](%s): ",
args++;
/* debug */
/* apps=<access-application>[,<access-application,...] */
i_debug("User %s has URLAUTH %s access",
}
apps++;
}
} else {
return;
}
args++;
}
return;
}
i_debug("Worker activated for access by user `%s' using service `%s'",
}
}
static void imap_urlauth_worker_die(void)
{
/* do nothing */
}
const char *const *access_applications)
{
bool debug;
access_user = getlogin();
if (access_user == NULL)
i_fatal("USER environment missing");
}
{
}
{
};
int c;
if (IS_STANDALONE()) {
} else {
}
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'a': {
break;
}
default:
return FATAL_DEFAULT;
}
}
}
}
/* fake that we're running, so we know if client was destroyed
while handling its initial input */
if (IS_STANDALONE()) {
T_BEGIN {
if (array_count(&access_apps) > 0) {
(void)array_append_space(&access_apps);
} else {
}
} T_END;
} else {
}
return 0;
}