diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py
index 7eed403e4bd..88adcfbf28e 100644
--- a/src/config/SSSDConfig/sssdoptions.py
+++ b/src/config/SSSDConfig/sssdoptions.py
@@ -207,6 +207,9 @@ def __init__(self):
'dyndns_force_tcp': _("Whether the nsupdate utility should default to using TCP"),
'dyndns_auth': _("What kind of authentication should be used to perform the DNS update"),
'dyndns_server': _("Override the DNS server used to perform the DNS update"),
+ 'dyndns_dot_cacert': _("The file of the certificate authorities certificates for DoT"),
+ 'dyndns_dot_cert': _("The certificate(s) file for authentication for the DoT transport"),
+ 'dyndns_dot_key': _("The key file for authenticated encryption for the DoT transport"),
'subdomain_enumerate': _('Control enumeration of trusted domains'),
'subdomain_refresh_interval': _('How often should subdomains list be refreshed'),
'subdomain_refresh_interval_offset': _('Maximum period deviation when refreshing the subdomain list'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index 6087f6e085b..e67f47c5e5e 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -567,6 +567,9 @@ def testListOptions(self):
'dyndns_force_tcp',
'dyndns_auth',
'dyndns_server',
+ 'dyndns_dot_cacert',
+ 'dyndns_dot_cert',
+ 'dyndns_dot_key',
'subdomain_enumerate',
'override_gid',
'case_sensitive',
@@ -928,6 +931,9 @@ def testRemoveProvider(self):
'dyndns_force_tcp',
'dyndns_auth',
'dyndns_server',
+ 'dyndns_dot_cacert',
+ 'dyndns_dot_cert',
+ 'dyndns_dot_key',
'subdomain_enumerate',
'override_gid',
'case_sensitive',
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 950eae630fb..920902209c5 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -443,6 +443,9 @@ option = dyndns_force_tcp
option = dyndns_auth
option = dyndns_auth_ptr
option = dyndns_server
+option = dyndns_dot_cacert
+option = dyndns_dot_cert
+option = dyndns_dot_key
# files provider specific options
option = passwd_files
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 4377a1fc571..2ab4a92a29c 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -216,6 +216,9 @@ dyndns_update_ptr = bool, None, false
dyndns_force_tcp = bool, None, false
dyndns_auth = str, None, false
dyndns_server = str, None, false
+dyndns_dot_cacert = str, None, false
+dyndns_dot_cert = str, None, false
+dyndns_dot_key = str, None, false
# Special providers
[provider/permit]
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index 79724fff5da..67239917dd1 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -1328,12 +1328,26 @@ ad_gpo_map_deny = +my_pam_service
Setting this option makes sense for environments
where the DNS server is different from the identity
- server.
+ server or when we use encrypted DNS.
+
+
+ The parameter can be a simple string containing
+ DNS name or IP address. It can also be an URI.
+ The URI can look like
+ dns://servername/ or
+ dns+tls://1.2.3.4:853#servername/.
+
+
+ The second example enables DNS-over-TLS protocol for
+ DNS updates. The nsupdate utility must support DoT -
+ check the man nsupdate before
+ enabling it in SSSD.
Please note that this option will be only used in
fallback attempt when previous attempt using
- autodetected settings failed.
+ autodetected settings failed or when DNS-over-TLS
+ is enabled.
Default: None (let nsupdate choose the server)
@@ -1356,6 +1370,56 @@ ad_gpo_map_deny = +my_pam_service
+
+ dyndns_dot_cacert (string)
+
+
+ This option specifies the file of the certificate
+ authorities certificates (in PEM format) in order
+ to verify the remote server TLS certificate when
+ using DoT.
+
+
+ Default: None (use global certificate store)
+
+
+
+
+
+ dyndns_dot_cert (string)
+
+
+ This option sets the certificate(s) file for
+ authentication for the DoT transport to the remote
+ server. The certificate chain file is expected to
+ be in PEM format.
+
+
+ The dyndns_dot_cert and
+ dyndns_dot_key options must be
+ both set to achieve mutual TLS authentication.
+
+
+ Default: None (Do not use TLS authentication)
+
+
+
+
+
+ dyndns_dot_key (string)
+
+
+ This option sets the key file for authenticated
+ encryption for the DoT transport to the remote
+ server. The private key file is expected to
+ be in PEM format.
+
+
+ Default: None (Do not use TLS authentication)
+
+
+
+
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 5adfaefcd7d..57a55bef961 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -321,12 +321,26 @@
Setting this option makes sense for environments
where the DNS server is different from the identity
- server.
+ server or when we use encrypted DNS.
+
+
+ The parameter can be a simple string containing
+ DNS name or IP address. It can also be an URI.
+ The URI can look like
+ dns://servername/ or
+ dns+tls://1.2.3.4:853#servername/.
+
+
+ The second example enables DNS-over-TLS protocol for
+ DNS updates. The nsupdate utility must support DoT -
+ check the man nsupdate before
+ enabling it in SSSD.
Please note that this option will be only used in
fallback attempt when previous attempt using
- autodetected settings failed.
+ autodetected settings failed or when DNS-over-TLS
+ is enabled.
Default: None (let nsupdate choose the server)
@@ -349,6 +363,56 @@
+
+ dyndns_dot_cacert (string)
+
+
+ This option specifies the file of the certificate
+ authorities certificates (in PEM format) in order
+ to verify the remote server TLS certificate when
+ using DoT.
+
+
+ Default: None (use global certificate store)
+
+
+
+
+
+ dyndns_dot_cert (string)
+
+
+ This option sets the certificate(s) file for
+ authentication for the DoT transport to the remote
+ server. The certificate chain file is expected to
+ be in PEM format.
+
+
+ The dyndns_dot_cert and
+ dyndns_dot_key options must be
+ both set to achieve mutual TLS authentication.
+
+
+ Default: None (Do not use TLS authentication)
+
+
+
+
+
+ dyndns_dot_key (string)
+
+
+ This option sets the key file for authenticated
+ encryption for the DoT transport to the remote
+ server. The private key file is expected to
+ be in PEM format.
+
+
+ Default: None (Do not use TLS authentication)
+
+
+
+
ipa_access_order (string)
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index e00777e68d5..a3dd0547b7a 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -325,6 +325,9 @@ struct dp_option ad_dyndns_opts[] = {
{ "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
{ "dyndns_auth_ptr", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_key", DP_OPT_STRING, NULL_STRING, NULL_STRING },
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/be_dyndns.c b/src/providers/be_dyndns.c
index 8274f10cf9a..253b7da3b15 100644
--- a/src/providers/be_dyndns.c
+++ b/src/providers/be_dyndns.c
@@ -23,6 +23,7 @@
along with this program. If not, see .
*/
+#include
#include
#include
#include
@@ -30,6 +31,7 @@
#include
#include
#include
+#include "util/debug.h"
#include "util/util.h"
#include "confdb/confdb.h"
#include "util/child_common.h"
@@ -267,7 +269,8 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
static char *
nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
- const char *hostname, int ttl, uint8_t remove_af, bool update_per_family)
+ const char *hostname, int ttl, uint8_t remove_af,
+ bool update_per_family)
{
struct sss_iface_addr *new_record;
char ip_addr[INET6_ADDRSTRLEN];
@@ -445,7 +448,7 @@ nsupdate_msg_add_realm_cmd(TALLOC_CTX *mem_ctx, const char *realm)
static char *
nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
- const char *servername)
+ struct sss_parsed_dns_uri *server_uri)
{
char *realm_directive;
char *update_msg;
@@ -462,14 +465,16 @@ nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
/* The realm_directive would now either contain an empty string or be
* completely empty so we don't need to add another newline here
*/
- if (servername) {
+ if (server_uri) {
DEBUG(SSSDBG_FUNC_DATA,
"Creating update message for server [%s] and realm [%s].\n",
- servername, realm);
+ server_uri->address, realm);
/* Add the server, realm and headers */
- update_msg = talloc_asprintf(tmp_ctx, "server %s\n%s",
- servername, realm_directive);
+ update_msg = talloc_asprintf(tmp_ctx, "server %s %s\n%s",
+ server_uri->address,
+ sss_get_dns_port(server_uri),
+ realm_directive);
} else if (realm != NULL) {
DEBUG(SSSDBG_FUNC_DATA,
"Creating update message for realm [%s].\n", realm);
@@ -496,7 +501,7 @@ nsupdate_msg_create_common(TALLOC_CTX *mem_ctx, const char *realm,
errno_t
be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *servername,
+ struct sss_parsed_dns_uri *server_uri,
const char *hostname, const unsigned int ttl,
uint8_t remove_af, struct sss_iface_addr *addresses,
bool update_per_family,
@@ -514,7 +519,7 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) return ENOMEM;
- update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername);
+ update_msg = nsupdate_msg_create_common(tmp_ctx, realm, server_uri);
if (update_msg == NULL) {
ret = ENOMEM;
goto done;
@@ -542,7 +547,7 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
errno_t
be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *servername,
+ struct sss_parsed_dns_uri *server_uri,
const char *hostname, const unsigned int ttl,
uint8_t remove_af, struct sss_iface_addr *addresses,
bool update_per_family,
@@ -560,7 +565,7 @@ be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) return ENOMEM;
- update_msg = nsupdate_msg_create_common(tmp_ctx, realm, servername);
+ update_msg = nsupdate_msg_create_common(tmp_ctx, realm, server_uri);
if (update_msg == NULL) {
ret = ENOMEM;
goto done;
@@ -1040,13 +1045,21 @@ struct be_nsupdate_state {
static void be_nsupdate_done(struct tevent_req *subreq);
static const char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
enum be_nsupdate_auth auth_type,
- bool force_tcp);
+ bool force_tcp,
+ struct sss_parsed_dns_uri *server_uri,
+ const char *dot_cacert,
+ const char *dot_cert,
+ const char *dot_key);
struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
enum be_nsupdate_auth auth_type,
char *nsupdate_msg,
- bool force_tcp)
+ bool force_tcp,
+ struct sss_parsed_dns_uri *server_uri,
+ const char *dot_cacert,
+ const char *dot_cert,
+ const char *dot_key)
{
int pipefd_to_child[2] = PIPE_INIT;
int pipefd_from_child[2] = PIPE_INIT;
@@ -1078,7 +1091,8 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
goto done;
}
- args = be_nsupdate_args(state, auth_type, force_tcp);
+ args = be_nsupdate_args(state, auth_type, force_tcp,
+ server_uri, dot_cacert, dot_cert, dot_key);
if (args == NULL) {
ret = ENOMEM;
goto done;
@@ -1126,16 +1140,35 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
static const char **
be_nsupdate_args(TALLOC_CTX *mem_ctx,
enum be_nsupdate_auth auth_type,
- bool force_tcp)
+ bool force_tcp,
+ struct sss_parsed_dns_uri *server_uri,
+ const char *dot_cacert,
+ const char *dot_cert,
+ const char *dot_key)
{
const char **argv;
int argc = 0;
+ bool use_dot;
+ bool have_dot_cert;
+ bool have_dot_key;
- argv = talloc_zero_array(mem_ctx, const char *, 6);
+ argv = talloc_zero_array(mem_ctx, const char *, 14);
if (argv == NULL) {
return NULL;
}
+ if (!sss_is_valid_dns_scheme(server_uri)) {
+ sss_log(SSS_LOG_WARNING,
+ "Invalid DNS scheme in SSSD config file: %s, using dns://\n",
+ server_uri->scheme);
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Invalid DNS scheme in SSSD config file: %s, using dns://\n",
+ server_uri->scheme);
+ }
+
+ use_dot = sss_is_dot_scheme(server_uri);
+ DEBUG(SSSDBG_FUNC_DATA, "nsupdate DoT: %i\n", use_dot);
+
switch (auth_type) {
case BE_NSUPDATE_AUTH_NONE:
DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: none\n");
@@ -1179,6 +1212,62 @@ be_nsupdate_args(TALLOC_CTX *mem_ctx,
argc++;
}
+ if (use_dot) {
+ DEBUG(SSSDBG_FUNC_DATA, "DoT option is set\n");
+ argv[argc] = talloc_strdup(argv, "-S");
+ if (argv[argc] == NULL) {
+ goto fail;
+ }
+ argc++;
+
+ /* DoT server name */
+ argv[argc] = talloc_strdup(argv, server_uri->host);
+ if (argv[argc] == NULL) {
+ goto fail;
+ }
+ argc++;
+ argv[argc] = talloc_strdup(argv, "-H");
+ if (argv[argc] == NULL) {
+ goto fail;
+ }
+ argc++;
+
+ /* DoT CA cert file */
+ if (dot_cacert != NULL && dot_cacert[0] != 0) {
+ argv[argc + 1] = talloc_strdup(argv, "-A");
+ argv[argc] = talloc_strdup(argv, dot_cacert);
+ if (argv[argc] == NULL || argv[argc+1] == NULL) {
+ goto fail;
+ }
+ argc += 2;
+ }
+
+ /* DoT cert and key must be set both or none */
+ have_dot_cert = (dot_cert != NULL && dot_cert[0] != 0);
+ have_dot_key = (dot_key != NULL && dot_key[0] != 0);
+ if (have_dot_key != have_dot_cert) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "The dyndns_dot_cert and dyndns_dot_key must be set both "
+ "(or none of them)\n");
+ goto fail;
+ }
+ if (have_dot_cert && have_dot_key) {
+ /* we have both, key and cert file paths */
+ argv[argc + 1] = talloc_strdup(argv, "-E");
+ argv[argc] = talloc_strdup(argv, dot_cert);
+ if (argv[argc] == NULL || argv[argc+1] == NULL) {
+ goto fail;
+ }
+ argc += 2;
+
+ argv[argc + 1] = talloc_strdup(argv, "-K");
+ argv[argc] = talloc_strdup(argv, dot_key);
+ if (argv[argc] == NULL || argv[argc+1] == NULL) {
+ goto fail;
+ }
+ argc += 2;
+ }
+ }
return argv;
fail:
@@ -1259,6 +1348,9 @@ struct dp_option default_dyndns_opts[] = {
{ "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
{ "dyndns_auth_ptr", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_key", DP_OPT_STRING, NULL_STRING, NULL_STRING },
DP_OPTION_TERMINATOR
};
@@ -1420,3 +1512,40 @@ errno_t sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
talloc_free(tmp_ctx);
return ret;
}
+
+bool
+sss_is_valid_dns_scheme(struct sss_parsed_dns_uri *uri)
+{
+ return
+ uri == NULL ||
+ uri->scheme == NULL || /* use default DNS scheme */
+ strcasecmp(uri->scheme, "dns") == 0 ||
+ strcasecmp(uri->scheme, "dns+tls") == 0;
+}
+
+bool
+sss_is_dot_scheme(struct sss_parsed_dns_uri *uri)
+{
+ return
+ uri != NULL &&
+ uri->scheme != NULL &&
+ strcasecmp(uri->scheme, "dns+tls") == 0;
+}
+
+const char *
+sss_get_dns_port(struct sss_parsed_dns_uri *uri)
+{
+ if (uri == NULL) {
+ return "53";
+ }
+
+ if (uri->port != NULL) {
+ return uri->port;
+ }
+
+ if (sss_is_dot_scheme(uri)) {
+ return "853";
+ }
+
+ return "53";
+}
diff --git a/src/providers/be_dyndns.h b/src/providers/be_dyndns.h
index 719c1394255..505b8fc5e12 100644
--- a/src/providers/be_dyndns.h
+++ b/src/providers/be_dyndns.h
@@ -27,6 +27,7 @@
#define DP_DYNDNS_H_
/* dynamic dns helpers */
+#include
struct sss_iface_addr;
typedef void (*nsupdate_timer_fn_t)(void *pvt);
@@ -60,6 +61,9 @@ enum dp_dyndns_opts {
DP_OPT_DYNDNS_AUTH,
DP_OPT_DYNDNS_AUTH_PTR,
DP_OPT_DYNDNS_SERVER,
+ DP_OPT_DYNDNS_DOT_CACERT,
+ DP_OPT_DYNDNS_DOT_CERT,
+ DP_OPT_DYNDNS_DOT_KEY,
DP_OPT_DYNDNS /* attrs counter */
};
@@ -86,7 +90,7 @@ sss_iface_addr_list_as_str_list(TALLOC_CTX *mem_ctx,
errno_t
be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *servername,
+ struct sss_parsed_dns_uri *server_uri,
const char *hostname, const unsigned int ttl,
uint8_t remove_af, struct sss_iface_addr *addresses,
bool update_per_family,
@@ -94,7 +98,7 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
errno_t
be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
- const char *servername,
+ struct sss_parsed_dns_uri *server_uri,
const char *hostname, const unsigned int ttl,
uint8_t remove_af, struct sss_iface_addr *addresses,
bool update_per_family,
@@ -110,7 +114,11 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
enum be_nsupdate_auth auth_type,
char *nsupdate_msg,
- bool force_tcp);
+ bool force_tcp,
+ struct sss_parsed_dns_uri *server_uri,
+ const char *dot_cacert,
+ const char *dot_cert,
+ const char *dot_key);
errno_t be_nsupdate_recv(struct tevent_req *req, int *child_status);
struct tevent_req * nsupdate_get_addrs_send(TALLOC_CTX *mem_ctx,
@@ -138,4 +146,13 @@ sss_iface_addr_get_next(struct sss_iface_addr *address);
struct sockaddr *
sss_iface_addr_get_address(struct sss_iface_addr *address);
+bool
+sss_is_valid_dns_scheme(struct sss_parsed_dns_uri *uri);
+
+bool
+sss_is_dot_scheme(struct sss_parsed_dns_uri *uri);
+
+const char *
+sss_get_dns_port(struct sss_parsed_dns_uri *uri);
+
#endif /* DP_DYNDNS_H_ */
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index 62423f868e2..5bfd65a6717 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -69,6 +69,9 @@ struct dp_option ipa_dyndns_opts[] = {
{ "dyndns_auth", DP_OPT_STRING, { "gss-tsig" }, NULL_STRING },
{ "dyndns_auth_ptr", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_cert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+ { "dyndns_dot_key", DP_OPT_STRING, NULL_STRING, NULL_STRING },
DP_OPTION_TERMINATOR
};
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index 3535fb42658..ef99d4666a1 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -48,7 +48,8 @@ struct sdap_dyndns_update_state {
const char *hostname;
const char *realm;
- const char *servername;
+ struct sss_parsed_dns_uri *server_uri;
+ bool dot;
int ttl;
struct sss_iface_addr *addresses;
@@ -112,7 +113,8 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
state->update_ptr = dp_opt_get_bool(opts, DP_OPT_DYNDNS_UPDATE_PTR);
state->hostname = hostname;
state->realm = realm;
- state->servername = NULL;
+ state->server_uri = NULL;
+ state->dot = false;
state->fallback_mode = false;
state->ttl = ttl;
state->be_res = be_ctx->be_res;
@@ -124,7 +126,11 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
/* fallback servername is overridden by user option */
conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
if (conf_servername != NULL) {
- state->servername = conf_servername;
+ ret = sss_parse_dns_uri(mem_ctx, conf_servername, &state->server_uri);
+ if (ret != EOK) {
+ goto done;
+ }
+ state->dot = sss_is_dot_scheme(state->server_uri);
}
if (ifname) {
@@ -324,20 +330,24 @@ sdap_dyndns_update_step(struct tevent_req *req)
{
errno_t ret;
struct sdap_dyndns_update_state *state;
- const char *servername;
+ struct sss_parsed_dns_uri *server_uri;
const char *realm;
struct tevent_req *subreq;
state = tevent_req_data(req, struct sdap_dyndns_update_state);
- servername = NULL;
+ server_uri = NULL;
realm = NULL;
+ if (state->dot) {
+ /* in DoT we have to set the server */
+ state->fallback_mode = true;
+ }
if (state->fallback_mode) {
- servername = state->servername;
+ server_uri = state->server_uri;
realm = state->realm;
}
- ret = be_nsupdate_create_fwd_msg(state, realm, servername,
+ ret = be_nsupdate_create_fwd_msg(state, realm, server_uri,
state->hostname,
state->ttl, state->remove_af,
state->addresses,
@@ -352,7 +362,14 @@ sdap_dyndns_update_step(struct tevent_req *req)
subreq = be_nsupdate_send(state, state->ev, state->auth_type,
state->update_msg,
dp_opt_get_bool(state->opts,
- DP_OPT_DYNDNS_FORCE_TCP));
+ DP_OPT_DYNDNS_FORCE_TCP),
+ state->server_uri,
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_CACERT),
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_CERT),
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_KEY));
if (subreq == NULL) {
return EIO;
}
@@ -409,20 +426,24 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
{
errno_t ret;
struct sdap_dyndns_update_state *state;
- const char *servername;
+ struct sss_parsed_dns_uri *server_uri;
const char *realm;
struct tevent_req *subreq;
state = tevent_req_data(req, struct sdap_dyndns_update_state);
- servername = NULL;
+ server_uri = NULL;
realm = NULL;
+ if (state->dot == true) {
+ /* in DoT we have to set the server */
+ state->fallback_mode = true;
+ }
if (state->fallback_mode == true) {
- servername = state->servername;
+ server_uri = state->server_uri;
realm = state->realm;
}
- ret = be_nsupdate_create_ptr_msg(state, realm, servername,
+ ret = be_nsupdate_create_ptr_msg(state, realm, server_uri,
state->hostname,
state->ttl, state->remove_af,
state->addresses,
@@ -438,7 +459,14 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
subreq = be_nsupdate_send(state, state->ev, state->auth_ptr_type,
state->update_msg,
dp_opt_get_bool(state->opts,
- DP_OPT_DYNDNS_FORCE_TCP));
+ DP_OPT_DYNDNS_FORCE_TCP),
+ state->server_uri,
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_CACERT),
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_CERT),
+ dp_opt_get_string(state->opts,
+ DP_OPT_DYNDNS_DOT_KEY));
if (subreq == NULL) {
return EIO;
}
diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
index 7526c16a86d..e3f8b7b35c2 100644
--- a/src/tests/cmocka/test_dyndns.c
+++ b/src/tests/cmocka/test_dyndns.c
@@ -35,6 +35,7 @@
#include "tests/cmocka/common_mock.h"
#include "tests/cmocka/common_mock_be.h"
#include "src/providers/be_dyndns.h"
+#include "util/util.h"
#define TESTS_PATH "tp_" BASE_FILE_STEM
#define TEST_CONF_DB "test_dyndns_conf.ldb"
@@ -361,6 +362,7 @@ void dyndns_test_create_fwd_msg(void **state)
errno_t ret;
char *msg;
struct sss_iface_addr *addrlist;
+ struct sss_parsed_dns_uri *uri;
int i;
check_leaks_push(dyndns_test_ctx);
@@ -411,14 +413,15 @@ void dyndns_test_create_fwd_msg(void **state)
talloc_zfree(msg);
/* fallback case realm and server */
- ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", "Winterfell",
+ sss_parse_dns_uri(dyndns_test_ctx, "Winterfell", &uri);
+ ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", uri,
"bran_stark",
1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
addrlist, true, &msg);
assert_int_equal(ret, EOK);
assert_string_equal(msg,
- "server Winterfell\n"
+ "server Winterfell 53\n"
"realm North\n"
"update delete bran_stark. in A\n"
"update add bran_stark. 1234 in A 192.168.0.2\n"
@@ -446,14 +449,14 @@ void dyndns_test_create_fwd_msg(void **state)
talloc_zfree(msg);
/* just server */
- ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, "Winterfell",
+ ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, uri,
"bran_stark",
1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
addrlist, true, &msg);
assert_int_equal(ret, EOK);
assert_string_equal(msg,
- "server Winterfell\n"
+ "server Winterfell 53\n"
"\n"
"update delete bran_stark. in A\n"
"update add bran_stark. 1234 in A 192.168.0.2\n"
@@ -492,6 +495,7 @@ void dyndns_test_create_fwd_msg(void **state)
talloc_zfree(msg);
talloc_free(addrlist);
+ talloc_free(uri);
assert_true(check_leaks_pop(dyndns_test_ctx) == true);
}
@@ -879,7 +883,8 @@ void dyndns_test_ok(void **state)
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
- discard_const("test message"), false);
+ discard_const("test message"), false,
+ false, NULL, NULL, NULL);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
@@ -910,7 +915,8 @@ void dyndns_test_error(void **state)
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
- discard_const("test message"), false);
+ discard_const("test message"), false,
+ false, NULL, NULL, NULL);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
@@ -941,7 +947,8 @@ void dyndns_test_timeout(void **state)
req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
BE_NSUPDATE_AUTH_GSS_TSIG,
- discard_const("test message"), false);
+ discard_const("test message"), false,
+ false, NULL, NULL, NULL);
assert_non_null(req);
tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index 760e7130723..d07c1b4d5d7 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -2370,6 +2370,63 @@ static void test_sss_filter_sanitize_dn(void **state)
talloc_free(tmp_ctx);
}
+static void test_sss_parse_uri(void **state)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct sss_parsed_dns_uri *parsed_uri;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ assert_non_null(tmp_ctx);
+
+ ret = sss_parse_dns_uri(tmp_ctx, "http://host", &parsed_uri);
+ assert_non_null(parsed_uri);
+ assert_int_equal(ret, EOK);
+ assert_string_equal(parsed_uri->scheme, "http");
+ assert_string_equal(parsed_uri->host, "host");
+ assert_string_equal(parsed_uri->address, "host");
+ assert_null(parsed_uri->port);
+ talloc_free(parsed_uri);
+
+ ret = sss_parse_dns_uri(tmp_ctx, "http://10.0.0.1#host", &parsed_uri);
+ assert_int_equal(ret, EOK);
+ assert_non_null(parsed_uri);
+ assert_string_equal(parsed_uri->scheme, "http");
+ assert_string_equal(parsed_uri->host, "host");
+ assert_string_equal(parsed_uri->address, "10.0.0.1");
+ assert_null(parsed_uri->port);
+ talloc_free(parsed_uri);
+
+ ret = sss_parse_dns_uri(tmp_ctx, " dns+tls://10.0.0.1:853#host", &parsed_uri);
+ assert_int_equal(ret, EOK);
+ assert_non_null(parsed_uri);
+ assert_string_equal(parsed_uri->scheme, "dns+tls");
+ assert_string_equal(parsed_uri->host, "host");
+ assert_string_equal(parsed_uri->address, "10.0.0.1");
+ assert_string_equal(parsed_uri->port, "853");
+ talloc_free(parsed_uri);
+
+ ret = sss_parse_dns_uri(tmp_ctx, "host", &parsed_uri);
+ assert_int_equal(ret, EOK);
+ assert_non_null(parsed_uri);
+ assert_null(parsed_uri->scheme);
+ assert_string_equal(parsed_uri->host, "host");
+ assert_string_equal(parsed_uri->address, "host");
+ assert_null(parsed_uri->port);
+ talloc_free(parsed_uri);
+
+ ret = sss_parse_dns_uri(tmp_ctx, "dns+tls://[cafe::1]:853#host", &parsed_uri);
+ assert_int_equal(ret, EOK);
+ assert_non_null(parsed_uri);
+ assert_string_equal(parsed_uri->scheme, "dns+tls");
+ assert_string_equal(parsed_uri->host, "host");
+ assert_string_equal(parsed_uri->address, "[cafe::1]");
+ assert_string_equal(parsed_uri->port, "853");
+ talloc_free(parsed_uri);
+
+ talloc_free(tmp_ctx);
+}
+
int main(int argc, const char *argv[])
{
poptContext pc;
@@ -2495,6 +2552,9 @@ int main(int argc, const char *argv[])
cmocka_unit_test_setup_teardown(test_mod_defaults_list,
setup_leak_tests,
teardown_leak_tests),
+ cmocka_unit_test_setup_teardown(test_sss_parse_uri,
+ setup_leak_tests,
+ teardown_leak_tests),
};
/* Set debug level to invalid value so we can decide if -d 0 was used. */
diff --git a/src/util/child_common.c b/src/util/child_common.c
index 2633863396c..fb82cce2d0d 100644
--- a/src/util/child_common.c
+++ b/src/util/child_common.c
@@ -22,14 +22,17 @@
along with this program. If not, see .
*/
+#include
#include
#include
#include
+#include
#include
#include
#include
#include
+#include "util/debug.h"
#include "util/util.h"
#include "util/find_uid.h"
#include "db/sysdb.h"
@@ -835,6 +838,30 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
return ret;
}
+static void log_child_command(TALLOC_CTX *mem_ctx, const char *binary,
+ char *argv[]) {
+ int n;
+ char *command;
+
+ if(DEBUG_IS_SET(SSSDBG_TRACE_INTERNAL)){
+ command = talloc_strdup(mem_ctx, "");
+ if (command == NULL) {
+ return;
+ }
+ if (argv != NULL) {
+ for (n = 0; argv[n] != NULL; ++n) {
+ command = talloc_asprintf_append(command, " %s", argv[n]);
+ if (command == NULL) {
+ return;
+ }
+ }
+ }
+ /* child proccess might have no log file open */
+ fprintf(stderr, "exec_child_ex command: [%s] %s\n", binary, command);
+ talloc_free(command);
+ }
+}
+
void exec_child_ex(TALLOC_CTX *mem_ctx,
int *pipefd_to_child, int *pipefd_from_child,
const char *binary, const char *logfile,
@@ -882,6 +909,7 @@ void exec_child_ex(TALLOC_CTX *mem_ctx,
exit(EXIT_FAILURE);
}
+ log_child_command(mem_ctx, binary, argv);
execv(binary, argv);
err = errno;
DEBUG(SSSDBG_OP_FAILURE, "execv failed [%d][%s].\n", err, strerror(err));
diff --git a/src/util/util.c b/src/util/util.c
index 226c746c693..bc34b0ba662 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1091,3 +1091,83 @@ errno_t sss_getenv(TALLOC_CTX *mem_ctx,
return value != NULL ? EOK : ENOENT;
}
+
+errno_t sss_parse_dns_uri(TALLOC_CTX *mem_ctx,
+ const char *uri,
+ struct sss_parsed_dns_uri **_parsed_uri)
+{
+ char *s, *p;
+ const char *start;
+ struct sss_parsed_dns_uri *parsed_uri;
+ errno_t ret = EOK;
+
+ if (uri == NULL || _parsed_uri == NULL) {
+ return EINVAL;
+ }
+
+ parsed_uri = talloc_zero(mem_ctx, struct sss_parsed_dns_uri);
+ if (parsed_uri == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ start = uri;
+ while(isspace(start[0])) {
+ start++;
+ }
+
+ parsed_uri->data = talloc_strdup(parsed_uri, start);
+ if (parsed_uri->data == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ s = parsed_uri->data;
+
+ /* scheme */
+ p = strstr(s, "://");
+ if (p != NULL) {
+ parsed_uri->scheme = s;
+ *p = '\000';
+ s = &p[3];
+ }
+
+ /* path part */
+ p = strchr(s, '/');
+ if (p != NULL) {
+ parsed_uri->path = &p[1];
+ *p = '\000';
+ }
+
+ p = strchr(s, '#');
+ if (p != NULL) {
+ parsed_uri->host = &p[1];
+ *p = '\000';
+ }
+
+ if (s[0] == '[') {
+ /* IPv6 address */
+ p = strstr(s, "]:");
+ if (p != NULL) {
+ ++p;
+ }
+ } else {
+ p = strchr(s, ':');
+ }
+ if (p != NULL) {
+ parsed_uri->port = &p[1];
+ *p = '\000';
+ }
+
+ parsed_uri->address = s;
+ if (parsed_uri->host == NULL) {
+ parsed_uri->host = parsed_uri->address;
+ }
+
+ *_parsed_uri = parsed_uri;
+ return EOK;
+
+ fail:
+ talloc_free(parsed_uri);
+ *_parsed_uri = NULL;
+ return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 8674c6c9dbd..3c2b032088e 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -878,4 +878,20 @@ static inline struct timeval sss_tevent_timeval_current_ofs_time_t(time_t secs)
uint32_t secs32 = (secs > UINT_MAX ? UINT_MAX : secs);
return tevent_timeval_current_ofs(secs32, 0);
}
+
+/* parsed uri */
+struct sss_parsed_dns_uri {
+ const char *scheme;
+ const char *address;
+ const char *port;
+ const char *host;
+ const char *path;
+
+ char *data;
+};
+
+errno_t sss_parse_dns_uri(TALLOC_CTX *ctx,
+ const char *uri,
+ struct sss_parsed_dns_uri **_parsed_uri);
+
#endif /* __SSSD_UTIL_H__ */