]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-auth: Add API for parsing proxy settings from passdb lookup results
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 17 Jun 2021 10:00:49 +0000 (13:00 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
src/lib-auth/Makefile.am
src/lib-auth/auth-proxy.c [new file with mode: 0644]
src/lib-auth/auth-proxy.h [new file with mode: 0644]

index 4aff5f8442ea40b075ef2ae342866e540d84c191..b3b59b5f3210046e3d80e3d27bf20803387fdd1e 100644 (file)
@@ -3,19 +3,22 @@ noinst_LTLIBRARIES = libauth.la
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-master \
+       -I$(top_srcdir)/src/lib-settings \
        -I$(top_srcdir)/src/lib-test
 
 libauth_la_SOURCES = \
        auth-client.c \
        auth-client-request.c \
        auth-client-connection.c \
-       auth-master.c
+       auth-master.c \
+       auth-proxy.c
 
 headers = \
        auth-client.h \
        auth-client-interface.h \
        auth-client-private.h \
-       auth-master.h
+       auth-master.h \
+       auth-proxy.h
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
@@ -27,12 +30,14 @@ noinst_PROGRAMS = $(test_programs)
 
 test_libs = \
        $(noinst_LTLIBRARIES) \
+       ../lib-settings/libsettings.la \
        ../lib-test/libtest.la \
        ../lib/liblib.la \
        $(MODULE_LIBS)
 
 test_deps = \
        $(noinst_LTLIBRARIES) \
+       ../lib-settings/libsettings.la \
        ../lib-test/libtest.la \
        ../lib/liblib.la
 
diff --git a/src/lib-auth/auth-proxy.c b/src/lib-auth/auth-proxy.c
new file mode 100644 (file)
index 0000000..29d075d
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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;
+}
diff --git a/src/lib-auth/auth-proxy.h b/src/lib-auth/auth-proxy.h
new file mode 100644 (file)
index 0000000..90e5f65
--- /dev/null
@@ -0,0 +1,62 @@
+#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