sssd  2.2.3
About: SSSD provides a set of daemons to manage access to remote directories and authentication mechanisms such as LDAP, Kerberos or FreeIPA. It provides also an NSS and PAM interface toward the system.
  Fossies Dox: sssd-2.2.3.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ad_machine_pw_renewal.c
Go to the documentation of this file.
1 /*
2  SSSD
3 
4  Authors:
5  Sumit Bose <sbose@redhat.com>
6 
7  Copyright (C) 2016 Red Hat
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 3 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 
24 #include "util/util.h"
25 #include "util/strtonum.h"
26 #include "providers/be_ptask.h"
27 #include "providers/ad/ad_common.h"
28 
29 #ifndef RENEWAL_PROG_PATH
30 #define RENEWAL_PROG_PATH "/usr/sbin/adcli"
31 #endif
32 
33 struct renewal_data {
34  struct be_ctx *be_ctx;
35  char *prog_path;
36  const char **extra_args;
37 };
38 
39 static errno_t get_adcli_extra_args(const char *ad_domain,
40  const char *ad_hostname,
41  const char *ad_keytab,
42  size_t pw_lifetime_in_days,
43  size_t period,
44  size_t initial_delay,
45  struct renewal_data *renewal_data)
46 {
47  const char **args;
48  size_t c = 0;
49 
50  if (ad_domain == NULL || ad_hostname == NULL) {
51  DEBUG(SSSDBG_CRIT_FAILURE, "Missing AD domain or hostname.\n");
52  return EINVAL;
53  }
54 
56  if (renewal_data->prog_path == NULL) {
57  DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
58  return ENOMEM;
59  }
60 
61  args = talloc_array(renewal_data, const char *, 8);
62  if (args == NULL) {
63  DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
64  return ENOMEM;
65  }
66 
67  /* extra_args are added in revers order */
68  /* first add NULL as a placeholder for the server name which is determined
69  * at runtime */
70  args[c++] = NULL;
71  args[c++] = talloc_asprintf(args, "--computer-password-lifetime=%zu",
72  pw_lifetime_in_days);
73  args[c++] = talloc_asprintf(args, "--host-fqdn=%s", ad_hostname);
74  if (ad_keytab != NULL) {
75  args[c++] = talloc_asprintf(args, "--host-keytab=%s", ad_keytab);
76  }
77  args[c++] = talloc_asprintf(args, "--domain=%s", ad_domain);
79  args[c++] = talloc_strdup(args, "--verbose");
80  }
81  args[c++] = talloc_strdup(args, "update");
82  args[c] = NULL;
83 
84  do {
85  if (args[--c] == NULL) {
87  "talloc failed while copying arguments.\n");
88  talloc_free(args);
89  return ENOMEM;
90  }
91  } while (c != 1); /* it is expected that the first element is NULL */
92 
93  renewal_data->extra_args = args;
94 
95  return EOK;
96 }
97 
98 struct renewal_state {
101  struct tevent_timer *timeout_handler;
102  struct tevent_context *ev;
103 
104  struct child_io_fds *io;
105 };
106 
107 static void ad_machine_account_password_renewal_done(struct tevent_req *subreq);
108 static void
109 ad_machine_account_password_renewal_timeout(struct tevent_context *ev,
110  struct tevent_timer *te,
111  struct timeval tv, void *pvt);
112 
113 static struct tevent_req *
115  struct tevent_context *ev,
116  struct be_ctx *be_ctx,
117  struct be_ptask *be_ptask,
118  void *pvt)
119 {
120  struct renewal_data *renewal_data;
121  struct renewal_state *state;
122  struct tevent_req *req;
123  struct tevent_req *subreq;
124  pid_t child_pid;
125  struct timeval tv;
126  int pipefd_to_child[2] = PIPE_INIT;
127  int pipefd_from_child[2] = PIPE_INIT;
128  int ret;
129  const char **extra_args;
130  const char *server_name;
131 
132  req = tevent_req_create(mem_ctx, &state, struct renewal_state);
133  if (req == NULL) {
134  DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
135  return NULL;
136  }
137 
138  renewal_data = talloc_get_type(pvt, struct renewal_data);
139 
140  state->ev = ev;
141  state->child_status = EFAULT;
142  state->io = talloc(state, struct child_io_fds);
143  if (state->io == NULL) {
144  DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
145  ret = ENOMEM;
146  goto done;
147  }
148  state->io->write_to_child_fd = -1;
149  state->io->read_from_child_fd = -1;
150  talloc_set_destructor((void *) state->io, child_io_destructor);
151 
154  if (server_name != NULL) {
155  renewal_data->extra_args[0] = talloc_asprintf(renewal_data->extra_args,
156  "--domain-controller=%s",
157  server_name);
158  /* if talloc_asprintf() fails we let adcli try to find a server */
159  }
160 
161  extra_args = renewal_data->extra_args;
162  if (extra_args[0] == NULL) {
163  extra_args = &renewal_data->extra_args[1];
164  }
165 
166  ret = pipe(pipefd_from_child);
167  if (ret == -1) {
168  ret = errno;
170  "pipe failed [%d][%s].\n", ret, strerror(ret));
171  goto done;
172  }
173  ret = pipe(pipefd_to_child);
174  if (ret == -1) {
175  ret = errno;
177  "pipe failed [%d][%s].\n", ret, strerror(ret));
178  goto done;
179  }
180 
181  child_pid = fork();
182  if (child_pid == 0) { /* child */
183  exec_child_ex(state, pipefd_to_child, pipefd_from_child,
184  renewal_data->prog_path, -1,
185  extra_args, true,
186  STDIN_FILENO, STDERR_FILENO);
187 
188  /* We should never get here */
189  DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec renewal child\n");
190  } else if (child_pid > 0) { /* parent */
191 
192  state->io->read_from_child_fd = pipefd_from_child[0];
193  PIPE_FD_CLOSE(pipefd_from_child[1]);
195 
196  state->io->write_to_child_fd = pipefd_to_child[1];
197  PIPE_FD_CLOSE(pipefd_to_child[0]);
199 
200  /* Set up SIGCHLD handler */
201  ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
202  if (ret != EOK) {
203  DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
204  ret, sss_strerror(ret));
206  goto done;
207  }
208 
209  /* Set up timeout handler */
210  tv = tevent_timeval_current_ofs(be_ptask_get_timeout(be_ptask), 0);
211  state->timeout_handler = tevent_add_timer(ev, req, tv,
213  req);
214  if(state->timeout_handler == NULL) {
216  goto done;
217  }
218 
219  subreq = read_pipe_send(state, ev, state->io->read_from_child_fd);
220  if (subreq == NULL) {
221  DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
223  goto done;
224  }
225  tevent_req_set_callback(subreq,
227 
228  /* Now either wait for the timeout to fire or the child
229  * to finish
230  */
231  } else { /* error */
232  ret = errno;
233  DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
234  ret, sss_strerror(ret));
235  goto done;
236  }
237 
238  ret = EOK;
239 
240 done:
241  if (ret != EOK) {
242  PIPE_CLOSE(pipefd_from_child);
243  PIPE_CLOSE(pipefd_to_child);
244  tevent_req_error(req, ret);
245  tevent_req_post(req, ev);
246  }
247  return req;
248 }
249 
250 static void ad_machine_account_password_renewal_done(struct tevent_req *subreq)
251 {
252  uint8_t *buf;
253  ssize_t buf_len;
254  struct tevent_req *req = tevent_req_callback_data(subreq,
255  struct tevent_req);
256  struct renewal_state *state = tevent_req_data(req, struct renewal_state);
257  int ret;
258 
260 
261  ret = read_pipe_recv(subreq, state, &buf, &buf_len);
262  talloc_zfree(subreq);
263  if (ret != EOK) {
264  tevent_req_error(req, ret);
265  return;
266  }
267 
268  DEBUG(SSSDBG_TRACE_LIBS, "--- adcli output start---\n"
269  "%.*s"
270  "---adcli output end---\n",
271  (int) buf_len, buf);
272 
273  tevent_req_done(req);
274  return;
275 }
276 
277 static void
279  struct tevent_timer *te,
280  struct timeval tv, void *pvt)
281 {
282  struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
283  struct renewal_state *state = tevent_req_data(req, struct renewal_state);
284 
285  DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for AD renewal child.\n");
287  state->child_ctx = NULL;
288  state->child_status = ETIMEDOUT;
289  tevent_req_error(req, ERR_RENEWAL_CHILD);
290 }
291 
292 static errno_t
294 {
295 
297 
298  return EOK;
299 }
300 
302  struct ad_options *ad_opts)
303 {
304  int ret;
305  struct renewal_data *renewal_data;
306  int lifetime;
307  size_t period;
308  size_t initial_delay;
309  const char *dummy;
310  char **opt_list;
311  int opt_list_size;
312  char *endptr;
313 
314  ret = access(RENEWAL_PROG_PATH, X_OK);
315  if (ret != 0) {
316  ret = errno;
318  "The helper program ["RENEWAL_PROG_PATH"] for renewal "
319  "doesn't exist [%d]: %s\n", ret, strerror(ret));
320  return EOK;
321  }
322 
323  lifetime = dp_opt_get_int(ad_opts->basic,
325 
326  if (lifetime == 0) {
327  DEBUG(SSSDBG_CONF_SETTINGS, "Automatic machine account renewal disabled.\n");
328  return EOK;
329  }
330 
331  if (lifetime < 0) {
333  "Illegal value [%d] for password lifetime.\n", lifetime);
334  return EINVAL;
335  }
336 
337  renewal_data = talloc(be_ctx, struct renewal_data);
338  if (renewal_data == NULL) {
339  DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n");
340  return ENOMEM;
341  }
342 
343  dummy = dp_opt_get_cstring(ad_opts->basic,
345  ret = split_on_separator(renewal_data, dummy, ':', true, false,
346  &opt_list, &opt_list_size);
347  if (ret != EOK) {
348  DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed.\n");
349  goto done;
350  }
351 
352  if (opt_list_size != 2) {
353  DEBUG(SSSDBG_CRIT_FAILURE, "Wrong number of renewal options.\n");
354  ret = EINVAL;
355  goto done;
356  }
357 
358  errno = 0;
359  period = strtouint32(opt_list[0], &endptr, 10);
360  if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
361  DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse first renewal option.\n");
362  ret = EINVAL;
363  goto done;
364  }
365 
366  errno = 0;
367  initial_delay = strtouint32(opt_list[1], &endptr, 10);
368  if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) {
369  DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse second renewal option.\n");
370  ret = EINVAL;
371  goto done;
372  }
373 
378  lifetime, period, initial_delay, renewal_data);
379  if (ret != EOK) {
380  DEBUG(SSSDBG_OP_FAILURE, "get_adcli_extra_args failed.\n");
381  goto done;
382  }
383 
384  ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60, 0,
387  renewal_data,
388  "AD machine account password renewal",
391  NULL);
392  if (ret != EOK) {
393  DEBUG(SSSDBG_OP_FAILURE, "be_ptask_create failed.\n");
394  goto done;
395  }
396 
397  ret = EOK;
398 
399 done:
400  if (ret != EOK) {
401  talloc_free(renewal_data);
402  }
403 
404  return ret;
405 }
be_ptask.h
renewal_state::io
struct child_io_fds * io
Definition: ad_machine_pw_renewal.c:104
sss_strerror
const char * sss_strerror(errno_t error)
return a string describing the error number like strerror()
Definition: util_errors.c:150
BE_PTASK_SCHEDULE_FROM_LAST
#define BE_PTASK_SCHEDULE_FROM_LAST
Definition: be_ptask.h:48
AD_SERVICE_NAME
#define AD_SERVICE_NAME
Definition: ad_common.h:29
EOK
#define EOK
Definition: hbac_evaluator.c:40
child_io_fds::read_from_child_fd
int read_from_child_fd
Definition: child_common.h:52
AD_DOMAIN
@ AD_DOMAIN
Definition: ad_common.h:44
PIPE_FD_CLOSE
#define PIPE_FD_CLOSE(fd)
Definition: util.h:108
read_pipe_recv
int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint8_t **buf, ssize_t *len)
Definition: child_common.c:508
renewal_state::ev
struct tevent_context * ev
Definition: ad_machine_pw_renewal.c:102
ad_machine_account_password_renewal_timeout
static void ad_machine_account_password_renewal_timeout(struct tevent_context *ev, struct tevent_timer *te, struct timeval tv, void *pvt)
Definition: ad_machine_pw_renewal.c:278
be_ptask_create
errno_t be_ptask_create(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, time_t period, time_t first_delay, time_t enabled_delay, time_t random_offset, time_t timeout, time_t max_backoff, be_ptask_send_t send_fn, be_ptask_recv_t recv_fn, void *pvt, const char *name, uint32_t flags, struct be_ptask **_task)
The first execution is scheduled first_delay seconds after the task is created.
Definition: be_ptask.c:292
exec_child_ex
void exec_child_ex(TALLOC_CTX *mem_ctx, int *pipefd_to_child, int *pipefd_from_child, const char *binary, int debug_fd, const char *extra_argv[], bool extra_args_only, int child_in_fd, int child_out_fd)
Definition: child_common.c:726
child_io_fds::write_to_child_fd
int write_to_child_fd
Definition: child_common.h:53
renewal_state::child_ctx
struct sss_child_ctx_old * child_ctx
Definition: ad_machine_pw_renewal.c:100
ad_machine_account_password_renewal_done
static void ad_machine_account_password_renewal_done(struct tevent_req *subreq)
Definition: ad_machine_pw_renewal.c:250
ad_machine_account_password_renewal_send
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)
Definition: ad_machine_pw_renewal.c:114
strtouint32
uint32_t strtouint32(const char *nptr, char **endptr, int base)
Definition: strtonum.c:52
SDAP_KRB5_KEYTAB
@ SDAP_KRB5_KEYTAB
Definition: sdap.h:195
ERR_RENEWAL_CHILD
@ ERR_RENEWAL_CHILD
Definition: util_errors.h:118
BE_PTASK_OFFLINE_DISABLE
#define BE_PTASK_OFFLINE_DISABLE
Definition: be_ptask.h:56
DEBUG
#define DEBUG(level, format,...)
macro to generate debug messages
Definition: debug.h:123
child_handler_setup
int child_handler_setup(struct tevent_context *ev, int pid, sss_child_callback_t cb, void *pvt, struct sss_child_ctx_old **_child_ctx)
Definition: child_common.c:277
renewal_data
Definition: ad_machine_pw_renewal.c:33
split_on_separator
int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, const char sep, bool trim, bool skip_empty, char ***_list, int *size)
Definition: util_ext.c:32
sdap_options::basic
struct dp_option * basic
Definition: sdap.h:460
strtonum.h
ad_options
Definition: ad_common.h:87
AD_HOSTNAME
@ AD_HOSTNAME
Definition: ad_common.h:48
errno_t
int errno_t
Definition: hbac_evaluator.c:36
ad_options::basic
struct dp_option * basic
Definition: ad_common.h:89
dp_opt_get_int
#define dp_opt_get_int(o, i)
Definition: data_provider.h:245
ad_machine_account_password_renewal_init
errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, struct ad_options *ad_opts)
Definition: ad_machine_pw_renewal.c:301
ad_id_ctx::sdap_id_ctx
struct sdap_id_ctx * sdap_id_ctx
Definition: ad_common.h:75
PIPE_INIT
#define PIPE_INIT
Definition: util.h:106
read_pipe_send
struct tevent_req * read_pipe_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, int fd)
Definition: child_common.c:427
renewal_state
Definition: ad_machine_pw_renewal.c:98
be_fo_get_active_server_name
const char * be_fo_get_active_server_name(struct be_ctx *ctx, const char *service_name)
Definition: data_provider_fo.c:724
be_ptask
Definition: be_ptask_private.h:24
get_adcli_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)
Definition: ad_machine_pw_renewal.c:39
ad_common.h
PIPE_CLOSE
#define PIPE_CLOSE(p)
Definition: util.h:115
child_io_fds
Definition: child_common.h:51
sss_fd_nonblocking
errno_t sss_fd_nonblocking(int fd)
set file descriptor as nonblocking
Definition: util.c:801
SSSDBG_TRACE_LIBS
#define SSSDBG_TRACE_LIBS
Definition: debug.h:81
DEBUG_IS_SET
#define DEBUG_IS_SET(level)
checks whether level is set in debug_level
Definition: debug.h:137
be_ptask_get_timeout
time_t be_ptask_get_timeout(struct be_ptask *task)
Definition: be_ptask.c:430
ad_machine_account_password_renewal_recv
static errno_t ad_machine_account_password_renewal_recv(struct tevent_req *req)
Definition: ad_machine_pw_renewal.c:293
SSSDBG_CONF_SETTINGS
#define SSSDBG_CONF_SETTINGS
Definition: debug.h:78
AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE
@ AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE
Definition: ad_common.h:68
sdap_id_ctx::opts
struct sdap_options * opts
Definition: ldap_common.h:66
renewal_data::prog_path
char * prog_path
Definition: ad_machine_pw_renewal.c:35
dp_opt_get_cstring
#define dp_opt_get_cstring(o, i)
Definition: data_provider.h:242
ad_options::id_ctx
struct ad_id_ctx * id_ctx
Definition: ad_common.h:94
talloc_zfree
#define talloc_zfree(ptr)
Definition: util.h:121
child_handler_destroy
void child_handler_destroy(struct sss_child_ctx_old *ctx)
Definition: child_common.c:312
renewal_data::extra_args
const char ** extra_args
Definition: ad_machine_pw_renewal.c:36
SSSDBG_CRIT_FAILURE
#define SSSDBG_CRIT_FAILURE
Definition: debug.h:75
AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS
@ AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS
Definition: ad_common.h:69
sss_child_ctx_old
Definition: child_common.c:265
renewal_state::timeout_handler
struct tevent_timer * timeout_handler
Definition: ad_machine_pw_renewal.c:101
renewal_data::be_ctx
struct be_ctx * be_ctx
Definition: ad_machine_pw_renewal.c:34
TEVENT_REQ_RETURN_ON_ERROR
#define TEVENT_REQ_RETURN_ON_ERROR(req)
Definition: util.h:132
be_ctx
Definition: backend.h:75
NULL
#define NULL
Definition: util.h:67
SSSDBG_OP_FAILURE
#define SSSDBG_OP_FAILURE
Definition: debug.h:76
child_io_destructor
int child_io_destructor(void *ptr)
Definition: child_common.c:777
util.h
ret
errno_t ret
Definition: sbus_errors.c:31
RENEWAL_PROG_PATH
#define RENEWAL_PROG_PATH
Definition: ad_machine_pw_renewal.c:30
renewal_state::child_status
int child_status
Definition: ad_machine_pw_renewal.c:99