576 lines
21 KiB
Diff
576 lines
21 KiB
Diff
|
From 70a669646ed841048346b451741e972a0ada703d Mon Sep 17 00:00:00 2001
|
||
|
From: Sumit Bose <sbose@redhat.com>
|
||
|
Date: Tue, 12 Jan 2016 11:05:02 +0100
|
||
|
Subject: [PATCH 41/49] AD: add task to renew the machine account password if
|
||
|
needed
|
||
|
|
||
|
AD expects its clients to renew the machine account password on a
|
||
|
regular basis, be default every 30 days. Even if a client does not renew
|
||
|
the password it might not cause issues because AD does not enforce the
|
||
|
renewal. But the password age might be used to identify unused machine
|
||
|
accounts in large environments which might get disabled or deleted
|
||
|
automatically.
|
||
|
|
||
|
With this patch SSSD calls an external program to check the age of the
|
||
|
machine account password and renew it if needed. Currently 'adcli' is
|
||
|
used as external program which is able to renew the password since
|
||
|
version 0.8.0.
|
||
|
|
||
|
Resolves https://fedorahosted.org/sssd/ticket/1041
|
||
|
|
||
|
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
|
||
|
(cherry picked from commit 5f7cd30c865046a7ea69944f7e07c85b4c43465a)
|
||
|
---
|
||
|
Makefile.am | 1 +
|
||
|
src/config/SSSDConfig/__init__.py.in | 2 +
|
||
|
src/config/etc/sssd.api.d/sssd-ad.conf | 2 +
|
||
|
src/man/sssd-ad.5.xml | 33 +++
|
||
|
src/providers/ad/ad_common.h | 5 +
|
||
|
src/providers/ad/ad_init.c | 7 +
|
||
|
src/providers/ad/ad_machine_pw_renewal.c | 372 +++++++++++++++++++++++++++++++
|
||
|
src/providers/ad/ad_opts.c | 2 +
|
||
|
src/util/util_errors.c | 1 +
|
||
|
src/util/util_errors.h | 1 +
|
||
|
10 files changed, 426 insertions(+)
|
||
|
create mode 100644 src/providers/ad/ad_machine_pw_renewal.c
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 1c0b1aada9804b2ef35a09cf1b7bf5e9c65ee4e5..a9099c07fcfe54a88bd56129364dde5262e901ed 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -3061,6 +3061,7 @@ libsss_ad_la_SOURCES = \
|
||
|
src/providers/ad/ad_common.h \
|
||
|
src/providers/ad/ad_init.c \
|
||
|
src/providers/ad/ad_dyndns.c \
|
||
|
+ src/providers/ad/ad_machine_pw_renewal.c \
|
||
|
src/providers/ad/ad_id.c \
|
||
|
src/providers/ad/ad_id.h \
|
||
|
src/providers/ad/ad_access.c \
|
||
|
diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
|
||
|
index 2cb857013fe4bddfd2e79e589d3ba9721dc3ca4f..b4a6fcb0d37469e1dda85eda95fd80825697902c 100644
|
||
|
--- a/src/config/SSSDConfig/__init__.py.in
|
||
|
+++ b/src/config/SSSDConfig/__init__.py.in
|
||
|
@@ -199,6 +199,8 @@ option_strings = {
|
||
|
'ad_gpo_map_deny' : _('PAM service names for which GPO-based access is always denied'),
|
||
|
'ad_gpo_default_right' : _('Default logon right (or permit/deny) to use for unmapped PAM service names'),
|
||
|
'ad_site' : _('a particular site to be used by the client'),
|
||
|
+ 'ad_maximum_machine_account_password_age' : _('Maximum age in days before the machine account password should be renewed'),
|
||
|
+ 'ad_machine_account_password_renewal_opts' : _('Option for tuing the machine account renewal task'),
|
||
|
|
||
|
# [provider/krb5]
|
||
|
'krb5_kdcip' : _('Kerberos server address'),
|
||
|
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
|
||
|
index 5eb546caac913b839112a70bd81dbde2c7ff2d9f..0ea73d14112d1c7cf7a6d4cbda0d2b2e53a3a7be 100644
|
||
|
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
|
||
|
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
|
||
|
@@ -17,6 +17,8 @@ ad_gpo_map_permit = str, None, false
|
||
|
ad_gpo_map_deny = str, None, false
|
||
|
ad_gpo_default_right = str, None, false
|
||
|
ad_site = str, None, false
|
||
|
+ad_maximum_machine_account_password_age = int, None, false
|
||
|
+ad_machine_account_password_renewal_opts = str, None, false
|
||
|
ldap_uri = str, None, false
|
||
|
ldap_backup_uri = str, None, false
|
||
|
ldap_search_base = str, None, false
|
||
|
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
|
||
|
index 173fb93009f66c2c83ab87ff5ca900fc10cbf5e8..4280eac5f4594b26d158a0ea58622f9fe7beb53e 100644
|
||
|
--- a/src/man/sssd-ad.5.xml
|
||
|
+++ b/src/man/sssd-ad.5.xml
|
||
|
@@ -719,6 +719,39 @@ ad_gpo_map_deny = +my_pam_service
|
||
|
</varlistentry>
|
||
|
|
||
|
<varlistentry>
|
||
|
+ <term>ad_maximum_machine_account_password_age (integer)</term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ SSSD will check once a day if the machine account
|
||
|
+ password is older than the given age in days and try
|
||
|
+ to renew it. A value of 0 will disable the renewal
|
||
|
+ attempt.
|
||
|
+ </para>
|
||
|
+ <para>
|
||
|
+ Default: 30 days
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
+
|
||
|
+ <varlistentry>
|
||
|
+ <term>ad_machine_account_password_renewal_opts (string)</term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ This option should only be used to test the machine
|
||
|
+ account renewal task. The option expect 2 integers
|
||
|
+ seperated by a colon (':'). The first integer
|
||
|
+ defines the interval in seconds how often the task
|
||
|
+ is run. The second specifies the inital timeout in
|
||
|
+ seconds before the task is run for the first time
|
||
|
+ after startup.
|
||
|
+ </para>
|
||
|
+ <para>
|
||
|
+ Default: 86400:750 (24h and 15m)
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
+
|
||
|
+ <varlistentry>
|
||
|
<term>dyndns_update (boolean)</term>
|
||
|
<listitem>
|
||
|
<para>
|
||
|
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
|
||
|
index 2dd4175487cd36215dad1aaa9111e316a1fc3a0a..5bb2e52d402e4279fdc60d4ab58afd2292358487 100644
|
||
|
--- a/src/providers/ad/ad_common.h
|
||
|
+++ b/src/providers/ad/ad_common.h
|
||
|
@@ -62,6 +62,8 @@ enum ad_basic_opt {
|
||
|
AD_GPO_DEFAULT_RIGHT,
|
||
|
AD_SITE,
|
||
|
AD_KRB5_CONFD_PATH,
|
||
|
+ AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE,
|
||
|
+ AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS,
|
||
|
|
||
|
AD_OPTS_BASIC /* opts counter */
|
||
|
};
|
||
|
@@ -180,4 +182,7 @@ int ad_autofs_init(struct be_ctx *be_ctx,
|
||
|
struct bet_ops **ops,
|
||
|
void **pvt_data);
|
||
|
|
||
|
+errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
|
||
|
+ struct ad_options *ad_opts);
|
||
|
+
|
||
|
#endif /* AD_COMMON_H_ */
|
||
|
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
|
||
|
index 72ce5536b0f0f69a530bda0ffc41ae93180c1a94..e40fb6f1d0eabae45581969f1ff73c8cf302fb4c 100644
|
||
|
--- a/src/providers/ad/ad_init.c
|
||
|
+++ b/src/providers/ad/ad_init.c
|
||
|
@@ -308,6 +308,13 @@ sssm_ad_id_init(struct be_ctx *bectx,
|
||
|
"will not work [%d]: %s\n", ret, strerror(ret));
|
||
|
}
|
||
|
|
||
|
+ ret = ad_machine_account_password_renewal_init(bectx, ad_options);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot setup task for machine account "
|
||
|
+ "password renewal.\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
*ops = &ad_id_ops;
|
||
|
*pvt_data = ad_ctx;
|
||
|
|
||
|
diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..e42c700e7aa3cf9a45acee025e36899b36642dad
|
||
|
--- /dev/null
|
||
|
+++ b/src/providers/ad/ad_machine_pw_renewal.c
|
||
|
@@ -0,0 +1,372 @@
|
||
|
+/*
|
||
|
+ SSSD
|
||
|
+
|
||
|
+ Authors:
|
||
|
+ Sumit Bose <sbose@redhat.com>
|
||
|
+
|
||
|
+ Copyright (C) 2016 Red Hat
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or modify
|
||
|
+ it under the terms of the GNU General Public License as published by
|
||
|
+ the Free Software Foundation; either version 3 of the License, or
|
||
|
+ (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ GNU General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License
|
||
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
+*/
|
||
|
+
|
||
|
+
|
||
|
+#include "util/util.h"
|
||
|
+#include "util/strtonum.h"
|
||
|
+#include "providers/dp_ptask.h"
|
||
|
+#include "providers/ad/ad_common.h"
|
||
|
+
|
||
|
+#ifndef RENEWAL_PROG_PATH
|
||
|
+#define RENEWAL_PROG_PATH "/usr/sbin/adcli"
|
||
|
+#endif
|
||
|
+
|
||
|
+struct renewal_data {
|
||
|
+ char *prog_path;
|
||
|
+ const char **extra_args;
|
||
|
+};
|
||
|
+
|
||
|
+static errno_t get_adcli_extra_args(const char *ad_domain,
|
||
|
+ const char *ad_hostname,
|
||
|
+ const char *ad_keytab,
|
||
|
+ size_t pw_lifetime_in_days,
|
||
|
+ size_t period,
|
||
|
+ size_t initial_delay,
|
||
|
+ struct renewal_data *renewal_data)
|
||
|
+{
|
||
|
+ const char **args;
|
||
|
+ size_t c = 0;
|
||
|
+
|
||
|
+ if (ad_domain == NULL || ad_hostname == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing AD domain or hostname.\n");
|
||
|
+ return EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ renewal_data->prog_path = talloc_strdup(renewal_data, RENEWAL_PROG_PATH);
|
||
|
+ if (renewal_data->prog_path == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ args = talloc_array(renewal_data, const char *, 7);
|
||
|
+ if (args == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* extra_args are added in revers order */
|
||
|
+ args[c++] = talloc_asprintf(args, "--computer-password-lifetime=%zu",
|
||
|
+ pw_lifetime_in_days);
|
||
|
+ args[c++] = talloc_asprintf(args, "--host-fqdn=%s", ad_hostname);
|
||
|
+ if (ad_keytab != NULL) {
|
||
|
+ args[c++] = talloc_asprintf(args, "--host-keytab=%s", ad_keytab);
|
||
|
+ }
|
||
|
+ args[c++] = talloc_asprintf(args, "--domain=%s", ad_domain);
|
||
|
+ if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
|
||
|
+ args[c++] = talloc_strdup(args, "--verbose");
|
||
|
+ }
|
||
|
+ args[c++] = talloc_strdup(args, "update");
|
||
|
+ args[c] = NULL;
|
||
|
+
|
||
|
+ do {
|
||
|
+ if (args[--c] == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
||
|
+ "talloc failed while copying arguments.\n");
|
||
|
+ talloc_free(args);
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+ } while (c != 0);
|
||
|
+
|
||
|
+ renewal_data->extra_args = args;
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
+
|
||
|
+struct renewal_state {
|
||
|
+ int child_status;
|
||
|
+ struct sss_child_ctx_old *child_ctx;
|
||
|
+ struct tevent_timer *timeout_handler;
|
||
|
+ struct tevent_context *ev;
|
||
|
+
|
||
|
+ int write_to_child_fd;
|
||
|
+ int read_from_child_fd;
|
||
|
+};
|
||
|
+
|
||
|
+static void ad_machine_account_password_renewal_done(struct tevent_req *subreq);
|
||
|
+static void
|
||
|
+ad_machine_account_password_renewal_timeout(struct tevent_context *ev,
|
||
|
+ struct tevent_timer *te,
|
||
|
+ struct timeval tv, void *pvt);
|
||
|
+
|
||
|
+static struct tevent_req *
|
||
|
+ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct be_ctx *be_ctx,
|
||
|
+ struct be_ptask *be_ptask,
|
||
|
+ void *pvt)
|
||
|
+{
|
||
|
+ struct renewal_data *renewal_data;
|
||
|
+ struct renewal_state *state;
|
||
|
+ struct tevent_req *req;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ pid_t child_pid;
|
||
|
+ struct timeval tv;
|
||
|
+ int pipefd_to_child[2];
|
||
|
+ int pipefd_from_child[2];
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_create(mem_ctx, &state, struct renewal_state);
|
||
|
+ if (req == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ renewal_data = talloc_get_type(pvt, struct renewal_data);
|
||
|
+
|
||
|
+ state->ev = ev;
|
||
|
+ state->child_status = EFAULT;
|
||
|
+ state->read_from_child_fd = -1;
|
||
|
+ state->write_to_child_fd = -1;
|
||
|
+
|
||
|
+ ret = pipe(pipefd_from_child);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ "pipe failed [%d][%s].\n", ret, strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ ret = pipe(pipefd_to_child);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ "pipe failed [%d][%s].\n", ret, strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ child_pid = fork();
|
||
|
+ if (child_pid == 0) { /* child */
|
||
|
+ ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child,
|
||
|
+ renewal_data->prog_path, -1,
|
||
|
+ renewal_data->extra_args, true,
|
||
|
+ STDIN_FILENO, STDERR_FILENO);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec renewal child: [%d][%s].\n",
|
||
|
+ ret, strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else if (child_pid > 0) { /* parent */
|
||
|
+
|
||
|
+ state->read_from_child_fd = pipefd_from_child[0];
|
||
|
+ close(pipefd_from_child[1]);
|
||
|
+ sss_fd_nonblocking(state->read_from_child_fd);
|
||
|
+
|
||
|
+ state->write_to_child_fd = pipefd_to_child[1];
|
||
|
+ close(pipefd_to_child[0]);
|
||
|
+ sss_fd_nonblocking(state->write_to_child_fd);
|
||
|
+
|
||
|
+ /* Set up SIGCHLD handler */
|
||
|
+ ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ ret = ERR_RENEWAL_CHILD;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Set up timeout handler */
|
||
|
+ tv = tevent_timeval_current_ofs(be_ptask_get_timeout(be_ptask), 0);
|
||
|
+ state->timeout_handler = tevent_add_timer(ev, req, tv,
|
||
|
+ ad_machine_account_password_renewal_timeout,
|
||
|
+ req);
|
||
|
+ if(state->timeout_handler == NULL) {
|
||
|
+ ret = ERR_RENEWAL_CHILD;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ subreq = read_pipe_send(state, ev, state->read_from_child_fd);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
|
||
|
+ ret = ERR_RENEWAL_CHILD;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ tevent_req_set_callback(subreq,
|
||
|
+ ad_machine_account_password_renewal_done, req);
|
||
|
+
|
||
|
+ /* Now either wait for the timeout to fire or the child
|
||
|
+ * to finish
|
||
|
+ */
|
||
|
+ } else { /* error */
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ tevent_req_post(req, ev);
|
||
|
+ }
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+static void ad_machine_account_password_renewal_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ uint8_t *buf;
|
||
|
+ ssize_t buf_len;
|
||
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
||
|
+ struct tevent_req);
|
||
|
+ struct renewal_state *state = tevent_req_data(req, struct renewal_state);
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ talloc_zfree(state->timeout_handler);
|
||
|
+
|
||
|
+ ret = read_pipe_recv(subreq, state, &buf, &buf_len);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_LIBS, "--- adcli output start---\n"
|
||
|
+ "%.*s"
|
||
|
+ "---adcli output end---\n",
|
||
|
+ (int) buf_len, buf);
|
||
|
+
|
||
|
+ close(state->read_from_child_fd);
|
||
|
+ state->read_from_child_fd = -1;
|
||
|
+
|
||
|
+
|
||
|
+ tevent_req_done(req);
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ad_machine_account_password_renewal_timeout(struct tevent_context *ev,
|
||
|
+ struct tevent_timer *te,
|
||
|
+ struct timeval tv, void *pvt)
|
||
|
+{
|
||
|
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
|
||
|
+ struct renewal_state *state = tevent_req_data(req, struct renewal_state);
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for AD renewal child.\n");
|
||
|
+ child_handler_destroy(state->child_ctx);
|
||
|
+ state->child_ctx = NULL;
|
||
|
+ state->child_status = ETIMEDOUT;
|
||
|
+ tevent_req_error(req, ERR_RENEWAL_CHILD);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ad_machine_account_password_renewal_recv(struct tevent_req *req)
|
||
|
+{
|
||
|
+
|
||
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx,
|
||
|
+ struct ad_options *ad_opts)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ struct renewal_data *renewal_data;
|
||
|
+ int lifetime;
|
||
|
+ size_t period;
|
||
|
+ size_t initial_delay;
|
||
|
+ const char *dummy;
|
||
|
+ char **opt_list;
|
||
|
+ int opt_list_size;
|
||
|
+ char *endptr;
|
||
|
+
|
||
|
+ lifetime = dp_opt_get_int(ad_opts->basic,
|
||
|
+ AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE);
|
||
|
+
|
||
|
+ if (lifetime == 0) {
|
||
|
+ DEBUG(SSSDBG_CONF_SETTINGS, "Automatic machine account renewal disabled.\n");
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (lifetime < 0) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ "Illegal value [%d] for password lifetime.\n", lifetime);
|
||
|
+ return EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ renewal_data = talloc(be_ctx, struct renewal_data);
|
||
|
+ if (renewal_data == NULL) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ dummy = dp_opt_get_cstring(ad_opts->basic,
|
||
|
+ AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS);
|
||
|
+ ret = split_on_separator(renewal_data, dummy, ':', true, false,
|
||
|
+ &opt_list, &opt_list_size);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed.\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (opt_list_size != 2) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Wrong number of renewal options.\n");
|
||
|
+ ret = EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ period = strtouint32(opt_list[0], &endptr, 10);
|
||
|
+ if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse first renewal option.\n");
|
||
|
+ ret = EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ initial_delay = strtouint32(opt_list[1], &endptr, 10);
|
||
|
+ if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse second renewal option.\n");
|
||
|
+ ret = EINVAL;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = get_adcli_extra_args(dp_opt_get_cstring(ad_opts->basic, AD_DOMAIN),
|
||
|
+ dp_opt_get_cstring(ad_opts->basic, AD_HOSTNAME),
|
||
|
+ dp_opt_get_cstring(ad_opts->id_ctx->sdap_id_ctx->opts->basic,
|
||
|
+ SDAP_KRB5_KEYTAB),
|
||
|
+ lifetime, period, initial_delay, renewal_data);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "get_adcli_extra_args failed.\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60,
|
||
|
+ BE_PTASK_OFFLINE_DISABLE, 0,
|
||
|
+ ad_machine_account_password_renewal_send,
|
||
|
+ ad_machine_account_password_renewal_recv,
|
||
|
+ renewal_data,
|
||
|
+ "AD machine account password renewal", NULL);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "be_ptask_create failed.\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ talloc_free(renewal_data);
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
|
||
|
index 4ea96637ca7264c76109ed8c2f7b5e8a94f73bfe..8b2841eadc0236b51f8c9c2c02b7c98837fbe416 100644
|
||
|
--- a/src/providers/ad/ad_opts.c
|
||
|
+++ b/src/providers/ad/ad_opts.c
|
||
|
@@ -48,6 +48,8 @@ struct dp_option ad_basic_opts[] = {
|
||
|
{ "ad_gpo_default_right", DP_OPT_STRING, NULL_STRING, NULL_STRING },
|
||
|
{ "ad_site", DP_OPT_STRING, NULL_STRING, NULL_STRING },
|
||
|
{ "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING },
|
||
|
+ { "ad_maximum_machine_account_password_age", DP_OPT_NUMBER, { .number = 30 }, NULL_NUMBER },
|
||
|
+ { "ad_machine_account_password_renewal_opts", DP_OPT_STRING, { "86400:750" }, NULL_STRING },
|
||
|
DP_OPTION_TERMINATOR
|
||
|
};
|
||
|
|
||
|
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
|
||
|
index ed19346d9b588a711367af4c891b1298cd4f067e..1d684d387b90b8db37609d5bc022e06fcac708f9 100644
|
||
|
--- a/src/util/util_errors.c
|
||
|
+++ b/src/util/util_errors.c
|
||
|
@@ -82,6 +82,7 @@ struct err_string error_to_str[] = {
|
||
|
{ "Address family not supported" }, /* ERR_ADDR_FAMILY_NOT_SUPPORTED */
|
||
|
{ "Message sender is the bus" }, /* ERR_SBUS_SENDER_BUS */
|
||
|
{ "Subdomain is inactive" }, /* ERR_SUBDOM_INACTIVE */
|
||
|
+ { "AD renewal child failed" }, /* ERR_RENEWAL_CHILD */
|
||
|
{ "ERR_LAST" } /* ERR_LAST */
|
||
|
};
|
||
|
|
||
|
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
|
||
|
index c1d081912a382d645c27809a3ac336ff90047cdf..5c02fdd8b4c6e0c59f7fd6f66a3fc8a8e48dc607 100644
|
||
|
--- a/src/util/util_errors.h
|
||
|
+++ b/src/util/util_errors.h
|
||
|
@@ -104,6 +104,7 @@ enum sssd_errors {
|
||
|
ERR_ADDR_FAMILY_NOT_SUPPORTED,
|
||
|
ERR_SBUS_SENDER_BUS,
|
||
|
ERR_SUBDOM_INACTIVE,
|
||
|
+ ERR_RENEWAL_CHILD,
|
||
|
ERR_LAST /* ALWAYS LAST */
|
||
|
};
|
||
|
|
||
|
--
|
||
|
2.5.0
|
||
|
|