Line data Source code
1 : /*
2 : SSSD
3 :
4 : Kerberos 5 Backend Module - Manage krb5_child
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2010 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "util/util.h"
26 : #include "util/child_common.h"
27 : #include "providers/krb5/krb5_common.h"
28 : #include "providers/krb5/krb5_auth.h"
29 : #include "src/providers/krb5/krb5_utils.h"
30 :
31 : #ifndef KRB5_CHILD_DIR
32 : #ifndef SSSD_LIBEXEC_PATH
33 : #error "SSSD_LIBEXEC_PATH not defined"
34 : #endif /* SSSD_LIBEXEC_PATH */
35 :
36 : #define KRB5_CHILD_DIR SSSD_LIBEXEC_PATH
37 : #endif /* KRB5_CHILD_DIR */
38 :
39 : #define KRB5_CHILD KRB5_CHILD_DIR"/krb5_child"
40 :
41 : #define TIME_T_MAX LONG_MAX
42 : #define int64_to_time_t(val) ((time_t)((val) < TIME_T_MAX ? val : TIME_T_MAX))
43 :
44 : struct handle_child_state {
45 : struct tevent_context *ev;
46 : struct krb5child_req *kr;
47 : uint8_t *buf;
48 : ssize_t len;
49 :
50 : struct tevent_timer *timeout_handler;
51 : pid_t child_pid;
52 :
53 : struct child_io_fds *io;
54 : };
55 :
56 0 : static errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
57 : struct sss_auth_token *tok)
58 : {
59 : uint32_t auth_token_type;
60 0 : uint32_t auth_token_length = 0;
61 : const char *data;
62 : size_t len;
63 0 : errno_t ret = EOK;
64 :
65 0 : auth_token_type = sss_authtok_get_type(tok);
66 :
67 0 : switch (auth_token_type) {
68 : case SSS_AUTHTOK_TYPE_EMPTY:
69 0 : auth_token_length = 0;
70 0 : data = "";
71 0 : break;
72 : case SSS_AUTHTOK_TYPE_PASSWORD:
73 0 : ret = sss_authtok_get_password(tok, &data, &len);
74 0 : auth_token_length = len + 1;
75 0 : break;
76 : case SSS_AUTHTOK_TYPE_CCFILE:
77 0 : ret = sss_authtok_get_ccfile(tok, &data, &len);
78 0 : auth_token_length = len + 1;
79 0 : break;
80 : case SSS_AUTHTOK_TYPE_2FA:
81 0 : data = (char *) sss_authtok_get_data(tok);
82 0 : auth_token_length = sss_authtok_get_size(tok);
83 0 : break;
84 : default:
85 0 : ret = EINVAL;
86 : }
87 :
88 0 : if (ret == EOK) {
89 0 : SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp);
90 0 : SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp);
91 0 : safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp);
92 : }
93 :
94 0 : return ret;
95 : }
96 :
97 0 : static errno_t create_send_buffer(struct krb5child_req *kr,
98 : struct io_buffer **io_buf)
99 : {
100 : struct io_buffer *buf;
101 : size_t rp;
102 : const char *keytab;
103 : uint32_t validate;
104 : uint32_t send_pac;
105 : uint32_t use_enterprise_principal;
106 0 : size_t username_len = 0;
107 : errno_t ret;
108 :
109 0 : keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB);
110 0 : if (keytab == NULL) {
111 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing keytab option.\n");
112 0 : return EINVAL;
113 : }
114 :
115 0 : validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0;
116 :
117 : /* Always send PAC except for local IPA users and IPA server mode */
118 0 : switch (kr->krb5_ctx->config_type) {
119 : case K5C_IPA_CLIENT:
120 0 : send_pac = kr->upn_from_different_realm ? 1 : 0;
121 0 : break;
122 : case K5C_IPA_SERVER:
123 0 : send_pac = 0;
124 0 : break;
125 : default:
126 0 : send_pac = 1;
127 0 : break;
128 : }
129 :
130 0 : if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) {
131 0 : use_enterprise_principal = false;
132 : } else {
133 0 : use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts,
134 : KRB5_USE_ENTERPRISE_PRINCIPAL) ? 1 : 0;
135 : }
136 :
137 0 : buf = talloc(kr, struct io_buffer);
138 0 : if (buf == NULL) {
139 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
140 0 : return ENOMEM;
141 : }
142 :
143 0 : buf->size = 8*sizeof(uint32_t) + strlen(kr->upn);
144 :
145 0 : if (kr->pd->cmd == SSS_PAM_AUTHENTICATE ||
146 0 : kr->pd->cmd == SSS_CMD_RENEW ||
147 0 : kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
148 0 : kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
149 0 : buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
150 0 : sss_authtok_get_size(kr->pd->authtok);
151 :
152 0 : buf->size += sizeof(uint32_t);
153 0 : if (kr->old_ccname) {
154 0 : buf->size += strlen(kr->old_ccname);
155 : }
156 : }
157 :
158 0 : if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
159 0 : buf->size += 2*sizeof(uint32_t) +
160 0 : sss_authtok_get_size(kr->pd->newauthtok);
161 : }
162 :
163 0 : if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
164 0 : username_len = strlen(kr->pd->user);
165 0 : buf->size += sizeof(uint32_t) + username_len;
166 : }
167 :
168 0 : buf->data = talloc_size(kr, buf->size);
169 0 : if (buf->data == NULL) {
170 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
171 0 : talloc_free(buf);
172 0 : return ENOMEM;
173 : }
174 :
175 0 : rp = 0;
176 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->cmd, &rp);
177 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
178 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
179 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
180 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
181 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp);
182 0 : SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp);
183 :
184 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp);
185 0 : safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp);
186 :
187 0 : if (kr->pd->cmd == SSS_PAM_AUTHENTICATE ||
188 0 : kr->pd->cmd == SSS_CMD_RENEW ||
189 0 : kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
190 0 : kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
191 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
192 0 : safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
193 :
194 0 : if (kr->old_ccname) {
195 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->old_ccname), &rp);
196 0 : safealign_memcpy(&buf->data[rp], kr->old_ccname,
197 : strlen(kr->old_ccname), &rp);
198 : } else {
199 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
200 : }
201 :
202 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
203 0 : safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
204 :
205 0 : ret = pack_authtok(buf, &rp, kr->pd->authtok);
206 0 : if (ret) {
207 0 : return ret;
208 : }
209 : }
210 :
211 0 : if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
212 0 : ret = pack_authtok(buf, &rp, kr->pd->newauthtok);
213 0 : if (ret) {
214 0 : return ret;
215 : }
216 : }
217 :
218 0 : if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
219 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], username_len, &rp);
220 0 : safealign_memcpy(&buf->data[rp], kr->pd->user, username_len, &rp);
221 : }
222 :
223 0 : *io_buf = buf;
224 :
225 0 : return EOK;
226 : }
227 :
228 :
229 0 : static void krb5_child_timeout(struct tevent_context *ev,
230 : struct tevent_timer *te,
231 : struct timeval tv, void *pvt)
232 : {
233 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
234 0 : struct handle_child_state *state = tevent_req_data(req,
235 : struct handle_child_state);
236 : int ret;
237 :
238 0 : if (state->timeout_handler == NULL) {
239 0 : return;
240 : }
241 :
242 0 : DEBUG(SSSDBG_IMPORTANT_INFO,
243 : "Timeout for child [%d] reached. In case KDC is distant or network "
244 : "is slow you may consider increasing value of krb5_auth_timeout.\n",
245 : state->child_pid);
246 :
247 0 : ret = kill(state->child_pid, SIGKILL);
248 0 : if (ret == -1) {
249 0 : DEBUG(SSSDBG_CRIT_FAILURE,
250 : "kill failed [%d][%s].\n", errno, strerror(errno));
251 : }
252 :
253 0 : tevent_req_error(req, ETIMEDOUT);
254 : }
255 :
256 0 : static errno_t activate_child_timeout_handler(struct tevent_req *req,
257 : struct tevent_context *ev,
258 : const uint32_t timeout_seconds)
259 : {
260 : struct timeval tv;
261 0 : struct handle_child_state *state = tevent_req_data(req,
262 : struct handle_child_state);
263 :
264 0 : tv = tevent_timeval_current();
265 0 : tv = tevent_timeval_add(&tv, timeout_seconds, 0);
266 0 : state->timeout_handler = tevent_add_timer(ev, state, tv,
267 : krb5_child_timeout, req);
268 0 : if (state->timeout_handler == NULL) {
269 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
270 0 : return ENOMEM;
271 : }
272 :
273 0 : return EOK;
274 : }
275 :
276 0 : static errno_t fork_child(struct tevent_req *req)
277 : {
278 0 : int pipefd_to_child[2] = PIPE_INIT;
279 0 : int pipefd_from_child[2] = PIPE_INIT;
280 : pid_t pid;
281 : errno_t ret;
282 0 : struct handle_child_state *state = tevent_req_data(req,
283 : struct handle_child_state);
284 : const char *k5c_extra_args[3];
285 :
286 0 : k5c_extra_args[0] = talloc_asprintf(state, "--fast-ccache-uid=%"SPRIuid, getuid());
287 0 : k5c_extra_args[1] = talloc_asprintf(state, "--fast-ccache-gid=%"SPRIgid, getgid());
288 0 : k5c_extra_args[2] = NULL;
289 0 : if (k5c_extra_args[0] == NULL || k5c_extra_args[1] == NULL) {
290 0 : return ENOMEM;
291 : }
292 :
293 0 : ret = pipe(pipefd_from_child);
294 0 : if (ret == -1) {
295 0 : ret = errno;
296 0 : DEBUG(SSSDBG_CRIT_FAILURE,
297 : "pipe failed [%d][%s].\n", errno, strerror(errno));
298 0 : goto fail;
299 : }
300 0 : ret = pipe(pipefd_to_child);
301 0 : if (ret == -1) {
302 0 : ret = errno;
303 0 : DEBUG(SSSDBG_CRIT_FAILURE,
304 : "pipe failed [%d][%s].\n", errno, strerror(errno));
305 0 : goto fail;
306 : }
307 :
308 0 : pid = fork();
309 :
310 0 : if (pid == 0) { /* child */
311 0 : exec_child_ex(state,
312 : pipefd_to_child, pipefd_from_child,
313 0 : KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
314 : k5c_extra_args, false, STDIN_FILENO, STDOUT_FILENO);
315 :
316 : /* We should never get here */
317 0 : DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec KRB5 child\n");
318 0 : } else if (pid > 0) { /* parent */
319 0 : state->child_pid = pid;
320 0 : state->io->read_from_child_fd = pipefd_from_child[0];
321 0 : PIPE_FD_CLOSE(pipefd_from_child[1]);
322 0 : state->io->write_to_child_fd = pipefd_to_child[1];
323 0 : PIPE_FD_CLOSE(pipefd_to_child[0]);
324 0 : sss_fd_nonblocking(state->io->read_from_child_fd);
325 0 : sss_fd_nonblocking(state->io->write_to_child_fd);
326 :
327 0 : ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
328 0 : if (ret != EOK) {
329 0 : DEBUG(SSSDBG_CRIT_FAILURE,
330 : "Could not set up child signal handler\n");
331 0 : goto fail;
332 : }
333 :
334 0 : ret = activate_child_timeout_handler(req, state->ev,
335 0 : dp_opt_get_int(state->kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT));
336 0 : if (ret != EOK) {
337 0 : DEBUG(SSSDBG_CRIT_FAILURE,
338 : "activate_child_timeout_handler failed.\n");
339 : }
340 :
341 : } else { /* error */
342 0 : ret = errno;
343 0 : DEBUG(SSSDBG_CRIT_FAILURE,
344 : "fork failed [%d][%s].\n", errno, strerror(ret));
345 0 : goto fail;
346 : }
347 :
348 0 : return EOK;
349 :
350 : fail:
351 0 : PIPE_CLOSE(pipefd_from_child);
352 0 : PIPE_CLOSE(pipefd_to_child);
353 0 : return ret;
354 : }
355 :
356 : static void handle_child_step(struct tevent_req *subreq);
357 : static void handle_child_done(struct tevent_req *subreq);
358 :
359 0 : struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
360 : struct tevent_context *ev,
361 : struct krb5child_req *kr)
362 : {
363 : struct tevent_req *req, *subreq;
364 : struct handle_child_state *state;
365 : int ret;
366 0 : struct io_buffer *buf = NULL;
367 :
368 0 : req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
369 0 : if (req == NULL) {
370 0 : return NULL;
371 : }
372 :
373 0 : state->ev = ev;
374 0 : state->kr = kr;
375 0 : state->buf = NULL;
376 0 : state->len = 0;
377 0 : state->child_pid = -1;
378 0 : state->timeout_handler = NULL;
379 :
380 0 : state->io = talloc(state, struct child_io_fds);
381 0 : if (state->io == NULL) {
382 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
383 0 : ret = ENOMEM;
384 0 : goto fail;
385 : }
386 0 : state->io->write_to_child_fd = -1;
387 0 : state->io->read_from_child_fd = -1;
388 0 : talloc_set_destructor((void *) state->io, child_io_destructor);
389 :
390 0 : ret = create_send_buffer(kr, &buf);
391 0 : if (ret != EOK) {
392 0 : DEBUG(SSSDBG_CRIT_FAILURE, "create_send_buffer failed.\n");
393 0 : goto fail;
394 : }
395 :
396 0 : ret = fork_child(req);
397 0 : if (ret != EOK) {
398 0 : DEBUG(SSSDBG_CRIT_FAILURE, "fork_child failed.\n");
399 0 : goto fail;
400 : }
401 :
402 0 : subreq = write_pipe_send(state, ev, buf->data, buf->size,
403 0 : state->io->write_to_child_fd);
404 0 : if (!subreq) {
405 0 : ret = ENOMEM;
406 0 : goto fail;
407 : }
408 0 : tevent_req_set_callback(subreq, handle_child_step, req);
409 :
410 0 : return req;
411 :
412 : fail:
413 0 : tevent_req_error(req, ret);
414 0 : tevent_req_post(req, ev);
415 0 : return req;
416 : }
417 :
418 0 : static void handle_child_step(struct tevent_req *subreq)
419 : {
420 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
421 : struct tevent_req);
422 0 : struct handle_child_state *state = tevent_req_data(req,
423 : struct handle_child_state);
424 : int ret;
425 :
426 0 : ret = write_pipe_recv(subreq);
427 0 : talloc_zfree(subreq);
428 0 : if (ret != EOK) {
429 0 : tevent_req_error(req, ret);
430 0 : return;
431 : }
432 :
433 0 : PIPE_FD_CLOSE(state->io->write_to_child_fd);
434 :
435 0 : subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
436 0 : if (!subreq) {
437 0 : tevent_req_error(req, ENOMEM);
438 0 : return;
439 : }
440 0 : tevent_req_set_callback(subreq, handle_child_done, req);
441 : }
442 :
443 0 : static void handle_child_done(struct tevent_req *subreq)
444 : {
445 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
446 : struct tevent_req);
447 0 : struct handle_child_state *state = tevent_req_data(req,
448 : struct handle_child_state);
449 : int ret;
450 :
451 0 : talloc_zfree(state->timeout_handler);
452 :
453 0 : ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
454 0 : talloc_zfree(subreq);
455 0 : if (ret != EOK) {
456 0 : tevent_req_error(req, ret);
457 0 : return;
458 : }
459 :
460 0 : PIPE_FD_CLOSE(state->io->read_from_child_fd);
461 :
462 0 : tevent_req_done(req);
463 0 : return;
464 : }
465 :
466 0 : int handle_child_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
467 : uint8_t **buf, ssize_t *len)
468 : {
469 0 : struct handle_child_state *state = tevent_req_data(req,
470 : struct handle_child_state);
471 :
472 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
473 :
474 0 : *buf = talloc_move(mem_ctx, &state->buf);
475 0 : *len = state->len;
476 :
477 0 : return EOK;
478 : }
479 :
480 : errno_t
481 0 : parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
482 : struct pam_data *pd, int pwd_exp_warning,
483 : struct krb5_child_response **_res)
484 : {
485 : ssize_t pref_len;
486 : size_t p;
487 : errno_t ret;
488 : bool skip;
489 0 : char *ccname = NULL;
490 0 : size_t ccname_len = 0;
491 : int32_t msg_status;
492 : int32_t msg_type;
493 : int32_t msg_len;
494 : int64_t time_data;
495 : struct tgt_times tgtt;
496 : uint32_t expiration;
497 : uint32_t msg_subtype;
498 : struct krb5_child_response *res;
499 0 : const char *upn = NULL;
500 0 : size_t upn_len = 0;
501 0 : bool otp = false;
502 :
503 0 : if ((size_t) len < sizeof(int32_t)) {
504 0 : DEBUG(SSSDBG_CRIT_FAILURE, "message too short.\n");
505 0 : return EINVAL;
506 : }
507 :
508 0 : memset(&tgtt, 0, sizeof(struct tgt_times));
509 :
510 0 : if (pwd_exp_warning < 0) {
511 0 : pwd_exp_warning = KERBEROS_PWEXPIRE_WARNING_TIME;
512 : }
513 :
514 : /* A buffer with the following structure is expected.
515 : * int32_t status of the request (required)
516 : * message (zero or more)
517 : *
518 : * A message consists of:
519 : * int32_t type of the message
520 : * int32_t length of the following data
521 : * uint8_t[len] data
522 : */
523 :
524 0 : p=0;
525 0 : SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
526 :
527 0 : while (p < len) {
528 0 : skip = false;
529 0 : SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p);
530 0 : SAFEALIGN_COPY_INT32(&msg_len, buf+p, &p);
531 :
532 0 : DEBUG(SSSDBG_TRACE_LIBS, "child response [%d][%d][%d].\n",
533 : msg_status, msg_type, msg_len);
534 :
535 0 : if (msg_len > len - p) {
536 0 : DEBUG(SSSDBG_CRIT_FAILURE, "message format error [%d] > [%zu].\n",
537 : msg_len, len - p);
538 0 : return EINVAL;
539 : }
540 :
541 : /* We need to save the name of the credential cache file. To find it
542 : * we check if the data part of a message starts with
543 : * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
544 : * sizeof() counts the trailing '\0' of a string. */
545 0 : pref_len = sizeof(CCACHE_ENV_NAME);
546 0 : if ((msg_type == SSS_PAM_ENV_ITEM) &&
547 0 : (msg_len > pref_len) &&
548 0 : (strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0)) {
549 0 : ccname = (char *) &buf[p+pref_len];
550 0 : ccname_len = msg_len-pref_len;
551 : }
552 :
553 0 : if (msg_type == SSS_KRB5_INFO_TGT_LIFETIME &&
554 0 : msg_len == 4*sizeof(int64_t)) {
555 0 : SAFEALIGN_COPY_INT64(&time_data, buf+p, NULL);
556 0 : tgtt.authtime = int64_to_time_t(time_data);
557 0 : SAFEALIGN_COPY_INT64(&time_data, buf+p+sizeof(int64_t), NULL);
558 0 : tgtt.starttime = int64_to_time_t(time_data);
559 0 : SAFEALIGN_COPY_INT64(&time_data, buf+p+2*sizeof(int64_t), NULL);
560 0 : tgtt.endtime = int64_to_time_t(time_data);
561 0 : SAFEALIGN_COPY_INT64(&time_data, buf+p+3*sizeof(int64_t), NULL);
562 0 : tgtt.renew_till = int64_to_time_t(time_data);
563 0 : DEBUG(SSSDBG_TRACE_LIBS, "TGT times are [%ld][%ld][%ld][%ld].\n",
564 : tgtt.authtime, tgtt.starttime, tgtt.endtime, tgtt.renew_till);
565 : }
566 :
567 0 : if (msg_type == SSS_KRB5_INFO_UPN) {
568 0 : upn = (char *) buf + p;
569 0 : upn_len = msg_len;
570 : }
571 :
572 0 : if (msg_type == SSS_PAM_USER_INFO) {
573 0 : SAFEALIGN_COPY_UINT32(&msg_subtype, buf + p, NULL);
574 0 : if (msg_subtype == SSS_PAM_USER_INFO_EXPIRE_WARN) {
575 0 : SAFEALIGN_COPY_UINT32(&expiration,
576 : buf + p + sizeof(uint32_t), NULL);
577 0 : if (pwd_exp_warning > 0 &&
578 0 : difftime(pwd_exp_warning, expiration) < 0.0) {
579 0 : skip = true;
580 : }
581 : }
582 : }
583 :
584 0 : if (msg_type == SSS_OTP) {
585 0 : otp = true;
586 0 : skip = true;
587 : }
588 :
589 0 : if (!skip) {
590 0 : ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);
591 0 : if (ret != EOK) {
592 : /* This is not a fatal error */
593 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
594 : }
595 : }
596 :
597 0 : p += msg_len;
598 :
599 0 : if ((p < len) && (p + 2*sizeof(int32_t) > len)) {
600 0 : DEBUG(SSSDBG_CRIT_FAILURE,
601 : "The remainder of the message is too short.\n");
602 0 : return EINVAL;
603 : }
604 : }
605 :
606 0 : res = talloc_zero(mem_ctx, struct krb5_child_response);
607 0 : if (!res) return ENOMEM;
608 :
609 0 : res->otp = otp;
610 0 : res->msg_status = msg_status;
611 0 : memcpy(&res->tgtt, &tgtt, sizeof(tgtt));
612 :
613 0 : if (ccname) {
614 0 : res->ccname = talloc_strndup(res, ccname, ccname_len);
615 0 : if (res->ccname == NULL) {
616 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
617 0 : talloc_free(res);
618 0 : return ENOMEM;
619 : }
620 : }
621 :
622 0 : if (upn != NULL) {
623 0 : res->correct_upn = talloc_strndup(res, upn, upn_len);
624 0 : if (res->correct_upn == NULL) {
625 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
626 0 : talloc_free(res);
627 0 : return ENOMEM;
628 : }
629 : }
630 :
631 0 : *_res = res;
632 0 : return EOK;
633 : }
|