Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Capability items to be 'dynamic' #181

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 69 additions & 21 deletions src/imap-login/imap-login-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "imap-quote.h"
#include "imap-login-commands.h"
#include "imap-login-settings.h"
#include "imap-capability-list.h"

#if LOGIN_MAX_INBUF_SIZE < 1024+2
# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
Expand Down Expand Up @@ -92,31 +93,31 @@ static const char *get_capability(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;
string_t *cap_str = t_str_new(256);
bool explicit_capability = FALSE;

if (*imap_client->set->imap_capability == '\0')
str_append(cap_str, CAPABILITY_BANNER_STRING);
else if (*imap_client->set->imap_capability != '+') {
explicit_capability = TRUE;
str_append(cap_str, imap_client->set->imap_capability);
} else {
str_append(cap_str, CAPABILITY_BANNER_STRING);
str_append_c(cap_str, ' ');
str_append(cap_str, imap_client->set->imap_capability + 1);
}
/* imap-login is preauth by definition */
enum imap_capability_visibility visibility = IMAP_CAP_VISIBILITY_PREAUTH;

if (!explicit_capability) {
if (imap_client->set->imap_literal_minus)
str_append(cap_str, " LITERAL-");
else
str_append(cap_str, " LITERAL+");
}
/* is tls/ssl enabled? */
if (client->tls)
visibility |= IMAP_CAP_VISIBILITY_TLS_ACTIVE;
else
visibility |= IMAP_CAP_VISIBILITY_TLS_INACTIVE;

/* is login cmd disabled? */
if (is_login_cmd_disabled(client))
visibility |= IMAP_CAP_VISIBILITY_NO_LOGIN;

/* Are we secured? (localhost? tls? etc) */
if (imap_client->common.secured)
visibility |= IMAP_CAP_VISIBILITY_SECURE;
else
visibility |= IMAP_CAP_VISIBILITY_INSECURE;

if (client_is_tls_enabled(client) && !client->tls)
str_append(cap_str, " STARTTLS");
if (is_login_cmd_disabled(client))
str_append(cap_str, " LOGINDISABLED");
/* build capability string based on IMAP_CAP_VISIBILITY_ flags */
imap_capability_list_get_capability(imap_client->capability_list,
cap_str, visibility);

/* grab the AUTH= capabilities from auth server */
client_authenticate_get_capabilities(client, cap_str);
return str_c(cap_str);
}
Expand Down Expand Up @@ -374,6 +375,7 @@ static struct client *imap_client_alloc(pool_t pool)
static void imap_client_create(struct client *client, void **other_sets)
{
struct imap_client *imap_client = (struct imap_client *)client;
bool explicit_capability = FALSE;

imap_client->set = other_sets[0];
imap_client->parser =
Expand All @@ -382,13 +384,59 @@ static void imap_client_create(struct client *client, void **other_sets)
IMAP_LOGIN_MAX_LINE_LENGTH);
if (imap_client->set->imap_literal_minus)
imap_parser_enable_literal_minus(imap_client->parser);

/* create our capability list from CAPABILITY_BANNER_STRING */
imap_client->capability_list =
imap_capability_list_create(NULL);

if (*imap_client->set->imap_capability == '\0')
imap_capability_list_append_string(imap_client->capability_list,
CAPABILITY_BANNER_STRING);
else if (*imap_client->set->imap_capability != '+') {
imap_capability_list_append_string(imap_client->capability_list,
imap_client->set->imap_capability);
explicit_capability = TRUE;
} else {
/* add the capability banner string to the cap list */
imap_capability_list_append_string(imap_client->capability_list,
CAPABILITY_BANNER_STRING);
/* add everything after the plus to our cap list */
imap_capability_list_append_string(imap_client->capability_list,
imap_client->set->imap_capability + 1);
}

/* Add the LITERAL+/- if the capability isn't explicitly set */
if (!explicit_capability) {
if (imap_client->set->imap_literal_minus)
imap_capability_list_add(imap_client->capability_list, "LITERAL-",
IMAP_CAP_VISIBILITY_ALWAYS);
else
imap_capability_list_add(imap_client->capability_list, "LITERAL+",
IMAP_CAP_VISIBILITY_ALWAYS);
}

/* add STARTTLS to cap list if it is needed */
if (client_is_tls_enabled(client)) {
imap_capability_list_add(imap_client->capability_list, "STARTTLS",
IMAP_CAP_VISIBILITY_FLAG_REQUIRE_ALL |
IMAP_CAP_VISIBILITY_PREAUTH |
IMAP_CAP_VISIBILITY_TLS_INACTIVE);
}

/* add LOGINDISABLED to cap list */
imap_capability_list_add(imap_client->capability_list, "LOGINDISABLED",
IMAP_CAP_VISIBILITY_FLAG_REQUIRE_ALL |
IMAP_CAP_VISIBILITY_PREAUTH |
IMAP_CAP_VISIBILITY_NO_LOGIN);

client->io = io_add_istream(client->input, client_input, client);
}

static void imap_client_destroy(struct client *client)
{
struct imap_client *imap_client = (struct imap_client *)client;

imap_capability_list_unref(&imap_client->capability_list);
i_free_and_null(imap_client->proxy_backend_capability);
imap_parser_unref(&imap_client->parser);
}
Expand Down
1 change: 1 addition & 0 deletions src/imap-login/imap-login-client.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct imap_client {

const struct imap_login_settings *set;
struct imap_parser *parser;
struct imap_capability_list *capability_list;
char *proxy_backend_capability;

const char *cmd_tag, *cmd_name;
Expand Down
2 changes: 1 addition & 1 deletion src/imap/cmd-capability.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
bool cmd_capability(struct client_command_context *cmd)
{
client_send_line(cmd->client, t_strconcat(
"* CAPABILITY ", str_c(cmd->client->capability_string), NULL));
"* CAPABILITY ", client_gete_capability(cmd->client), NULL));

client_send_tagline(cmd, "OK Capability completed.");
return TRUE;
Expand Down
52 changes: 43 additions & 9 deletions src/imap/imap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "imap-notify.h"
#include "imap-commands.h"
#include "imap-feature.h"
#include "imap-capability-list.h"

#include <unistd.h>

Expand Down Expand Up @@ -157,17 +158,21 @@ struct client *client_create(int fd_in, int fd_out, bool unhibernated,
client->notify_flag_changes = TRUE;
p_array_init(&client->enabled_features, client->pool, 8);

client->capability_string =
str_new(client->pool, sizeof(CAPABILITY_STRING)+64);
client->capability_string = imap_capability_list_create(NULL);

if (*set->imap_capability == '\0')
str_append(client->capability_string, CAPABILITY_STRING);
imap_capability_list_append_string(client->capability_list,
CAPABILITY_STRING);
else if (*set->imap_capability != '+') {
str_append(client->capability_string, set->imap_capability);
imap_capability_list_append_string(client->capability_list,
set->imap_capability);
} else {
str_append(client->capability_string, CAPABILITY_STRING);
str_append_c(client->capability_string, ' ');
str_append(client->capability_string, set->imap_capability + 1);
/* add the capability banner string to the cap list */
imap_capability_list_append_string(client->capability_list,
CAPABILITY_STRING);
/* add everything after the plus to our cap list */
imap_capability_list_append_string(client->capability_list,
client->set->imap_capability + 1);
}
if (client->set->imap_literal_minus)
client_add_capability(client, "LITERAL-");
Expand Down Expand Up @@ -586,10 +591,39 @@ void client_add_capability(struct client *client, const char *capability)
/* explicit capability - don't change it */
return;
}
str_append_c(client->capability_string, ' ');
str_append(client->capability_string, capability);

/* add it to our capability list as CAP_ALWAYS */
imap_capability_list_add(client->capability_list,
capability, IMAP_CAP_VISIBILITY_ALWAYS);
}

const char *client_get_capability(struct client *client)
{
string_t *cap_str = t_str_new(256);

/* imap is postauth by definition */
enum imap_capability_visibility visibility = IMAP_CAP_VISIBILITY_POSTAUTH;

/* is the client secured by means of ssl? */
if (client->ssl_secured)
visibility |= IMAP_CAP_VISIBILITY_TLS_ACTIVE;
else
visibility |= IMAP_CAP_VISIBILITY_TLS_INACTIVE;

/* Are we secured? (localhost? tls? etc) */
if (client->secured)
visibility |= IMAP_CAP_VISIBILITY_SECURE;
else
visibility |= IMAP_CAP_VISIBILITY_INSECURE;

/* build capability string based on IMAP_CAP_VISIBILITY_ flags */
imap_capability_list_get_capability(client->capability_list,
cap_str, visibility);

return str_c(cap_str);
}


void client_send_line(struct client *client, const char *data)
{
(void)client_send_line_next(client, data);
Expand Down
7 changes: 6 additions & 1 deletion src/imap/imap-client.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ struct client {
struct mail_storage_service_user *service_user;
const struct imap_settings *set;
const struct smtp_submit_settings *smtp_set;
string_t *capability_string;
struct imap_capability_list *capability_list;
const char *disconnect_reason;

struct mail_user *user;
Expand Down Expand Up @@ -238,6 +238,8 @@ struct client {
bool mailbox_examined:1;
bool anvil_sent:1;
bool tls_compression:1;
bool secured:1;
bool ssl_secured:1;
bool input_skip_line:1; /* skip all the data until we've
found a new line */
bool modseqs_sent_since_sync:1;
Expand Down Expand Up @@ -289,6 +291,9 @@ void client_kick(struct client *client);
has an explicit capability, nothing is changed. */
void client_add_capability(struct client *client, const char *capability);

/* Generate the string of capabilities from the client */
const char *client_get_capability(struct client *client);

/* Send a line of data to client. */
void client_send_line(struct client *client, const char *data);
/* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full,
Expand Down
5 changes: 4 additions & 1 deletion src/imap/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ int client_create_from_input(const struct mail_storage_service_input *input,
event, mail_user, user, imap_set, smtp_set);
client->userdb_fields = input->userdb_fields == NULL ? NULL :
p_strarray_dup(client->pool, input->userdb_fields);
client->secured = input->conn_secured;
client->ssl_secured = input->conn_ssl_secured;
event_unref(&event);
*client_r = client;
return 0;
Expand Down Expand Up @@ -343,7 +345,7 @@ static void main_stdio_run(const char *username)

client_create_finish_io(client);
client_send_login_reply(client->output,
str_c(client->capability_string),
client_get_capability(client),
client->user->username, &request);
if (client_create_finish(client, &error) < 0)
i_fatal("%s", error);
Expand Down Expand Up @@ -407,6 +409,7 @@ login_client_connected(const struct master_login_client *login_client,
*/
client_create_finish_io(client);
client_send_login_reply(client->output,
client_get_capability(client),
str_c(client->capability_string),
NULL, &request);
if (client_create_finish(client, &error) < 0) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib-imap/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ libimap_la_SOURCES = \
imap-arg.c \
imap-base-subject.c \
imap-bodystructure.c \
imap-capability-list.c \
imap-date.c \
imap-envelope.c \
imap-id.c \
Expand All @@ -26,6 +27,7 @@ headers = \
imap-arg.h \
imap-base-subject.h \
imap-bodystructure.h \
imap-capability-list.h \
imap-date.h \
imap-envelope.h \
imap-id.h \
Expand Down
Loading