--- /dev/null
+/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "auth-proxy.h"
+
+static const char *maybe_strdup(pool_t pool, const char *str)
+{
+ return pool == NULL ? str : p_strdup(pool, str);
+}
+
+int auth_proxy_settings_parse(struct auth_proxy_settings *set, pool_t pool,
+ const char *key, const char *value,
+ const char **error_r)
+{
+ if (strcmp(key, "proxy") == 0)
+ set->proxy = TRUE;
+ else if (strcmp(key, "host") == 0) {
+ if (value[0] == '\0') {
+ *error_r = "Empty host";
+ return -1;
+ }
+ set->host = maybe_strdup(pool, value);
+ } else if (strcmp(key, "hostip") == 0) {
+ if (value[0] != '\0' && net_addr2ip(value, &set->host_ip) < 0) {
+ *error_r = "Not a valid IP address";
+ return -1;
+ }
+ } else if (strcmp(key, "port") == 0) {
+ if (net_str2port(value, &set->port) < 0) {
+ *error_r = "Not a valid port number";
+ return -1;
+ }
+ } else if (strcmp(key, "ssl") == 0) {
+ set->ssl_flags |= AUTH_PROXY_SSL_FLAG_YES;
+ if (strcmp(value, "any-cert") == 0)
+ set->ssl_flags |= AUTH_PROXY_SSL_FLAG_ANY_CERT;
+ } else if (strcmp(key, "starttls") == 0) {
+ set->ssl_flags |= AUTH_PROXY_SSL_FLAG_YES |
+ AUTH_PROXY_SSL_FLAG_STARTTLS;
+ if (strcmp(value, "any-cert") == 0)
+ set->ssl_flags |= AUTH_PROXY_SSL_FLAG_ANY_CERT;
+ } else if (strcmp(key, "source_ip") == 0) {
+ if (value[0] != '\0' &&
+ net_addr2ip(value, &set->source_ip) < 0) {
+ *error_r = "Not a valid IP address";
+ return -1;
+ }
+ } else if (strcmp(key, "destuser") == 0)
+ set->username = maybe_strdup(pool, value);
+ else if (strcmp(key, "master") == 0) {
+ /* ignore empty master field */
+ if (*value != '\0')
+ set->master_user = maybe_strdup(pool, value);
+ } else if (strcmp(key, "pass") == 0)
+ set->password = maybe_strdup(pool, value);
+ else if (strcmp(key, "proxy_mech") == 0)
+ set->sasl_mechanism = maybe_strdup(pool, value);
+ else if (strcmp(key, "proxy_timeout") == 0) {
+ /* backwards compatibility: plain number is seconds */
+ if (str_to_uint(value, &set->timeout_msecs) == 0)
+ set->timeout_msecs *= 1000;
+ else if (settings_get_time_msecs(value,
+ &set->timeout_msecs, error_r) < 0) {
+ return -1;
+ }
+ } else if (strcmp(key, "proxy_nopipelining") == 0)
+ set->nopipelining = TRUE;
+ else if (strcmp(key, "proxy_noauth") == 0)
+ set->noauth = TRUE;
+ else if (strcmp(key, "proxy_not_trusted") == 0)
+ set->remote_not_trusted = TRUE;
+ else if (strcmp(key, "proxy_redirect_reauth") == 0)
+ set->redirect_reauth = TRUE;
+ else
+ return 0;
+ return 1;
+}
--- /dev/null
+#ifndef AUTH_PROXY_H
+#define AUTH_PROXY_H
+
+#include "net.h"
+
+enum auth_proxy_ssl_flags {
+ /* Use SSL/TLS */
+ AUTH_PROXY_SSL_FLAG_YES = BIT(0),
+ /* Don't do SSL handshake immediately after connected */
+ AUTH_PROXY_SSL_FLAG_STARTTLS = BIT(1),
+ /* Don't require that the received certificate is valid */
+ AUTH_PROXY_SSL_FLAG_ANY_CERT = BIT(2),
+};
+
+struct auth_proxy_settings {
+ /* TRUE if proxying is enabled */
+ bool proxy;
+
+ /* Destination hostname or IP */
+ const char *host;
+ /* Destination IP address, parsed from "hostip" or "host" field */
+ struct ip_addr host_ip;
+ /* Destination port */
+ in_port_t port;
+ /* SSL connection options */
+ enum auth_proxy_ssl_flags ssl_flags;
+
+ /* If family != 0, source IP address to use for the outgoing
+ connection. */
+ struct ip_addr source_ip;
+
+ /* Login user/master/password */
+ const char *username;
+ const char *master_user;
+ const char *password;
+ /* SASL mechanism to use for authentication. */
+ const char *sasl_mechanism;
+
+ /* Abort proxy connection in this many milliseconds (0 = default) */
+ unsigned int timeout_msecs;
+
+ /* Disable pipelining commands to destination server */
+ bool nopipelining:1;
+ /* Submission service: Disable logging into the destination server.
+ Use XCLIENT LOGIN instead. */
+ bool noauth:1;
+ /* Remote server isn't trusted - don't use any ID/XCLIENT extensions
+ to send the original client information. */
+ bool remote_not_trusted:1;
+ /* If redirect/referral is received, do another PASS lookup instead of
+ directly connecting to the redirected host. */
+ bool redirect_reauth:1;
+};
+
+/* Apply key/value into auth_proxy_settings. Returns 1 if successful, 0 if
+ key isn't a proxy setting, -1 if the value was invalid. If pool is NULL,
+ values are directly stored to settings. */
+int auth_proxy_settings_parse(struct auth_proxy_settings *set, pool_t pool,
+ const char *key, const char *value,
+ const char **error_r);
+
+#endif