From: Stephan Bosch Date: Tue, 16 Oct 2018 22:59:02 +0000 (+0200) Subject: lib-smtp: client: Add support for recording extra (non-standard) capabilities from... X-Git-Tag: 2.3.5~75 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e559e8207f587394e97ed90c9a9709bcfa14c326;p=thirdparty%2Fdovecot%2Fcore.git lib-smtp: client: Add support for recording extra (non-standard) capabilities from server. --- diff --git a/src/lib-smtp/smtp-client-connection.c b/src/lib-smtp/smtp-client-connection.c index 35f9f1ed7c..9387588d9d 100644 --- a/src/lib-smtp/smtp-client-connection.c +++ b/src/lib-smtp/smtp-client-connection.c @@ -56,6 +56,33 @@ uoff_t smtp_client_connection_get_size_capability( return conn->caps.size; } +void smtp_client_connection_accept_extra_capability( + struct smtp_client_connection *conn, const char *cap_name) +{ + cap_name = p_strdup(conn->pool, cap_name); + + if (!array_is_created(&conn->extra_capabilities)) + p_array_init(&conn->extra_capabilities, conn->pool, 8); + array_append(&conn->extra_capabilities, &cap_name, 1); +} + +const struct smtp_capability_extra * +smtp_client_connection_get_extra_capability(struct smtp_client_connection *conn, + const char *name) +{ + const struct smtp_capability_extra *cap; + + if (!array_is_created(&conn->caps.extra)) + return NULL; + + array_foreach(&conn->caps.extra, cap) { + if (strcasecmp(cap->name, name) == 0) + return cap; + } + + return NULL; +} + /* * Logging */ @@ -875,6 +902,42 @@ smtp_client_connection_starttls(struct smtp_client_connection *conn) return smtp_client_connection_init_xclient(conn); } +static bool +smtp_client_connection_has_extra_capability(struct smtp_client_connection *conn, + const char *cap_name) +{ + const char *const *cap_idx; + + if (!array_is_created(&conn->extra_capabilities)) + return FALSE; + array_foreach(&conn->extra_capabilities, cap_idx) { + if (strcasecmp(*cap_idx, cap_name) == 0) + return TRUE; + } + return FALSE; +} + +static void +smtp_client_connection_record_exta_capability( + struct smtp_client_connection *conn, const char *cap_name, + const char *const *params) +{ + struct smtp_capability_extra cap_extra; + pool_t pool = conn->cap_pool; + + if (!smtp_client_connection_has_extra_capability(conn, cap_name)) + return; + + if (!array_is_created(&conn->caps.extra)) + p_array_init(&conn->caps.extra, pool, 4); + + i_zero(&cap_extra); + cap_extra.name = p_strdup(pool, cap_name); + cap_extra.params = p_strarray_dup(pool, params); + + array_append(&conn->caps.extra, &cap_extra, 1); +} + static void smtp_client_connection_handshake_cb(const struct smtp_reply *reply, struct smtp_client_connection *conn) @@ -952,6 +1015,10 @@ smtp_client_connection_handshake_cb(const struct smtp_reply *reply, conn->caps.xclient_args = p_strarray_dup(conn->cap_pool, params); break; + case SMTP_CAPABILITY_NONE: + smtp_client_connection_record_exta_capability( + conn, cap_name, params); + break; default: break; } @@ -1772,6 +1839,10 @@ smtp_client_connection_do_create(struct smtp_client *client, const char *name, conn->set.my_hostname = p_strdup(pool, set->my_hostname); conn->set.forced_capabilities |= set->forced_capabilities; + if (set->extra_capabilities != NULL) { + conn->set.extra_capabilities = + p_strarray_dup(pool, set->extra_capabilities); + } if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0') conn->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir); @@ -1826,6 +1897,18 @@ smtp_client_connection_do_create(struct smtp_client *client, const char *name, conn->set.peer_trusted = set->peer_trusted; } + + if (set != NULL && set->extra_capabilities != NULL) { + const char *const *extp; + + p_array_init(&conn->extra_capabilities, pool, + str_array_length(set->extra_capabilities) + 8); + for (extp = set->extra_capabilities; *extp != NULL; extp++) { + const char *ext = p_strdup(pool, *extp); + array_append(&conn->extra_capabilities, &ext, 1); + } + } + i_assert(conn->set.my_hostname != NULL && *conn->set.my_hostname != '\0'); diff --git a/src/lib-smtp/smtp-client-connection.h b/src/lib-smtp/smtp-client-connection.h index 08eb3d30f9..dc0d886138 100644 --- a/src/lib-smtp/smtp-client-connection.h +++ b/src/lib-smtp/smtp-client-connection.h @@ -73,6 +73,12 @@ enum smtp_capability smtp_client_connection_get_capabilities(struct smtp_client_connection *conn); uoff_t smtp_client_connection_get_size_capability( struct smtp_client_connection *conn); +void smtp_client_connection_accept_extra_capability( + struct smtp_client_connection *conn, const char *cap_name); +const struct smtp_capability_extra * +smtp_client_connection_get_extra_capability(struct smtp_client_connection *conn, + const char *name); + enum smtp_client_connection_state smtp_client_connection_get_state(struct smtp_client_connection *conn); diff --git a/src/lib-smtp/smtp-client-private.h b/src/lib-smtp/smtp-client-private.h index d144b5e63d..5f5da07967 100644 --- a/src/lib-smtp/smtp-client-private.h +++ b/src/lib-smtp/smtp-client-private.h @@ -152,10 +152,12 @@ struct smtp_client_connection { struct smtp_client_settings set; char *password; + ARRAY_TYPE(const_string) extra_capabilities; pool_t cap_pool; struct { enum smtp_capability standard; + ARRAY(struct smtp_capability_extra) extra; const char **auth_mechanisms; const char **xclient_args; uoff_t size; diff --git a/src/lib-smtp/smtp-client.c b/src/lib-smtp/smtp-client.c index 6e50491333..f1e5abb72e 100644 --- a/src/lib-smtp/smtp-client.c +++ b/src/lib-smtp/smtp-client.c @@ -35,6 +35,10 @@ struct smtp_client *smtp_client_init(const struct smtp_client_settings *set) client->set.my_hostname = p_strdup(pool, set->my_hostname); client->set.forced_capabilities = set->forced_capabilities; + if (set->extra_capabilities != NULL) { + client->set.extra_capabilities = + p_strarray_dup(pool, set->extra_capabilities); + } client->set.dns_client = set->dns_client; client->set.dns_client_socket_path = diff --git a/src/lib-smtp/smtp-client.h b/src/lib-smtp/smtp-client.h index cefe24b19a..fe8fd55f22 100644 --- a/src/lib-smtp/smtp-client.h +++ b/src/lib-smtp/smtp-client.h @@ -45,6 +45,8 @@ struct smtp_client_settings { /* Capabilities that are assumed to be enabled no matter whether the server indicates support. */ enum smtp_capability forced_capabilities; + /* Record these extra capabilities if returned in the EHLO response */ + const char *const *extra_capabilities; struct dns_client *dns_client; const char *dns_client_socket_path; diff --git a/src/lib-smtp/smtp-common.h b/src/lib-smtp/smtp-common.h index c257a16bca..598f96544a 100644 --- a/src/lib-smtp/smtp-common.h +++ b/src/lib-smtp/smtp-common.h @@ -47,10 +47,17 @@ enum smtp_capability { SMTP_CAPABILITY__ORCPT = BIT(24), }; + struct smtp_capability_name { const char *name; enum smtp_capability capability; }; + +struct smtp_capability_extra { + const char *name; + const char *const *params; +}; + extern const struct smtp_capability_name smtp_capability_names[]; enum smtp_capability smtp_capability_find_by_name(const char *cap_name);