Line data Source code
1 : /*
2 : SSSD
3 :
4 : PAM Responder - certificate realted requests
5 :
6 : Copyright (C) Sumit Bose <sbose@redhat.com> 2015
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <time.h>
23 :
24 : #include "util/util.h"
25 : #include "providers/data_provider.h"
26 : #include "util/child_common.h"
27 : #include "util/strtonum.h"
28 : #include "responder/pam/pamsrv.h"
29 :
30 :
31 : #ifndef SSSD_LIBEXEC_PATH
32 : #error "SSSD_LIBEXEC_PATH not defined"
33 : #endif /* SSSD_LIBEXEC_PATH */
34 :
35 : #define P11_CHILD_LOG_FILE "p11_child"
36 : #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
37 :
38 0 : errno_t p11_child_init(struct pam_ctx *pctx)
39 : {
40 0 : return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
41 : }
42 :
43 77 : bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd)
44 : {
45 : size_t c;
46 77 : const char *sc_services[] = { "login", "su", "su-l", "gdm-smartcard",
47 : "gdm-password", "kdm", "sudo", "sudo-i",
48 : "gnome-screensaver", NULL };
49 77 : if (!pctx->cert_auth) {
50 59 : return false;
51 : }
52 :
53 18 : if (pd->cmd != SSS_PAM_PREAUTH && pd->cmd != SSS_PAM_AUTHENTICATE) {
54 0 : return false;
55 : }
56 :
57 18 : if (pd->cmd == SSS_PAM_AUTHENTICATE
58 4 : && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
59 0 : && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
60 0 : return false;
61 : }
62 :
63 : /* TODO: make services configurable */
64 18 : if (pd->service == NULL || *pd->service == '\0') {
65 0 : return false;
66 : }
67 18 : for (c = 0; sc_services[c] != NULL; c++) {
68 18 : if (strcmp(pd->service, sc_services[c]) == 0) {
69 18 : break;
70 : }
71 : }
72 18 : if (sc_services[c] == NULL) {
73 0 : DEBUG(SSSDBG_CRIT_FAILURE,
74 : "Smartcard authentication for service [%s] not supported.\n",
75 : pd->service);
76 0 : return false;
77 : }
78 :
79 18 : return true;
80 : }
81 :
82 2 : static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
83 : struct pam_data *pd,
84 : uint8_t **_buf, size_t *_len)
85 : {
86 : int ret;
87 : uint8_t *buf;
88 : size_t len;
89 2 : const char *pin = NULL;
90 :
91 2 : if (pd == NULL || pd->authtok == NULL) {
92 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing authtok.\n");
93 0 : return EINVAL;
94 : }
95 :
96 2 : switch (sss_authtok_get_type(pd->authtok)) {
97 : case SSS_AUTHTOK_TYPE_SC_PIN:
98 2 : ret = sss_authtok_get_sc_pin(pd->authtok, &pin, &len);
99 2 : if (ret != EOK) {
100 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc_pin failed.\n");
101 0 : return ret;
102 : }
103 2 : if (pin == NULL || len == 0) {
104 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
105 0 : return EINVAL;
106 : }
107 :
108 2 : buf = talloc_size(mem_ctx, len);
109 2 : if (buf == NULL) {
110 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
111 0 : return ENOMEM;
112 : }
113 :
114 2 : safealign_memcpy(buf, pin, len, NULL);
115 :
116 2 : break;
117 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
118 : /* Nothing to send */
119 0 : len = 0;
120 0 : buf = NULL;
121 0 : break;
122 : default:
123 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type [%d].\n",
124 : sss_authtok_get_type(pd->authtok));
125 0 : return EINVAL;
126 : }
127 :
128 2 : *_len = len;
129 2 : *_buf = buf;
130 :
131 2 : return EOK;
132 : }
133 :
134 9 : static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
135 : ssize_t buf_len, char **_cert,
136 : char **_token_name)
137 : {
138 : int ret;
139 9 : TALLOC_CTX *tmp_ctx = NULL;
140 : uint8_t *p;
141 : uint8_t *pn;
142 9 : char *cert = NULL;
143 9 : char *token_name = NULL;
144 :
145 9 : if (buf_len < 0) {
146 0 : DEBUG(SSSDBG_CRIT_FAILURE,
147 : "Error occurred while reading data from p11_child.\n");
148 0 : return EIO;
149 : }
150 :
151 9 : if (buf_len == 0) {
152 2 : DEBUG(SSSDBG_TRACE_LIBS, "No certificate found.\n");
153 2 : ret = EOK;
154 2 : goto done;
155 : }
156 :
157 7 : p = memchr(buf, '\n', buf_len);
158 7 : if (p == NULL) {
159 0 : DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n");
160 0 : return EINVAL;
161 : }
162 7 : if (p == buf) {
163 0 : DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
164 0 : return EINVAL;
165 : }
166 :
167 7 : tmp_ctx = talloc_new(NULL);
168 7 : if (tmp_ctx == NULL) {
169 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
170 0 : return ENOMEM;
171 : }
172 :
173 7 : token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
174 7 : if (token_name == NULL) {
175 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
176 0 : ret = ENOMEM;
177 0 : goto done;
178 : }
179 :
180 7 : p++;
181 7 : pn = memchr(p, '\n', buf_len - (p - buf));
182 7 : if (pn == NULL) {
183 0 : DEBUG(SSSDBG_OP_FAILURE,
184 : "Missing new-line in p11_child response.\n");
185 0 : ret = EINVAL;
186 0 : goto done;
187 : }
188 :
189 7 : if (pn == p) {
190 0 : DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
191 0 : ret = EINVAL;
192 0 : goto done;
193 : }
194 :
195 7 : cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
196 7 : if(cert == NULL) {
197 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
198 0 : ret = ENOMEM;
199 0 : goto done;
200 : }
201 7 : DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
202 :
203 7 : ret = EOK;
204 :
205 : done:
206 9 : if (ret == EOK) {
207 9 : *_token_name = talloc_steal(mem_ctx, token_name);
208 9 : *_cert = talloc_steal(mem_ctx, cert);
209 : }
210 :
211 9 : talloc_free(tmp_ctx);
212 :
213 9 : return ret;
214 : }
215 :
216 : struct pam_check_cert_state {
217 : int child_status;
218 : struct sss_child_ctx_old *child_ctx;
219 : struct tevent_timer *timeout_handler;
220 : struct tevent_context *ev;
221 :
222 : struct child_io_fds *io;
223 : char *cert;
224 : char *token_name;
225 : };
226 :
227 : static void p11_child_write_done(struct tevent_req *subreq);
228 : static void p11_child_done(struct tevent_req *subreq);
229 : static void p11_child_timeout(struct tevent_context *ev,
230 : struct tevent_timer *te,
231 : struct timeval tv, void *pvt);
232 :
233 9 : struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
234 : struct tevent_context *ev,
235 : int child_debug_fd,
236 : const char *nss_db,
237 : time_t timeout,
238 : const char *verify_opts,
239 : struct pam_data *pd)
240 : {
241 : errno_t ret;
242 : struct tevent_req *req;
243 : struct tevent_req *subreq;
244 : struct pam_check_cert_state *state;
245 : pid_t child_pid;
246 : struct timeval tv;
247 9 : int pipefd_to_child[2] = PIPE_INIT;
248 9 : int pipefd_from_child[2] = PIPE_INIT;
249 9 : const char *extra_args[7] = { NULL };
250 9 : uint8_t *write_buf = NULL;
251 9 : size_t write_buf_len = 0;
252 : size_t arg_c;
253 :
254 9 : req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state);
255 9 : if (req == NULL) {
256 0 : return NULL;
257 : }
258 :
259 9 : if (nss_db == NULL) {
260 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing NSS DB.\n");
261 0 : ret = EINVAL;
262 0 : goto done;
263 : }
264 :
265 : /* extra_args are added in revers order */
266 9 : arg_c = 0;
267 9 : extra_args[arg_c++] = nss_db;
268 9 : extra_args[arg_c++] = "--nssdb";
269 9 : if (verify_opts != NULL) {
270 9 : extra_args[arg_c++] = verify_opts;
271 9 : extra_args[arg_c++] = "--verify";
272 : }
273 9 : if (pd->cmd == SSS_PAM_AUTHENTICATE) {
274 2 : extra_args[arg_c++] = "--auth";
275 2 : switch (sss_authtok_get_type(pd->authtok)) {
276 : case SSS_AUTHTOK_TYPE_SC_PIN:
277 2 : extra_args[arg_c++] = "--pin";
278 2 : break;
279 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
280 0 : extra_args[arg_c++] = "--keypad";
281 0 : break;
282 : default:
283 0 : DEBUG(SSSDBG_OP_FAILURE, "Unsupported authtok type.\n");
284 0 : ret = EINVAL;
285 0 : goto done;
286 : }
287 7 : } else if (pd->cmd == SSS_PAM_PREAUTH) {
288 7 : extra_args[arg_c++] = "--pre";
289 : } else {
290 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd);
291 0 : ret = EINVAL;
292 0 : goto done;
293 : }
294 :
295 9 : state->ev = ev;
296 9 : state->child_status = EFAULT;
297 9 : state->cert = NULL;
298 9 : state->token_name = NULL;
299 9 : state->io = talloc(state, struct child_io_fds);
300 9 : if (state->io == NULL) {
301 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
302 0 : ret = ENOMEM;
303 0 : goto done;
304 : }
305 9 : state->io->write_to_child_fd = -1;
306 9 : state->io->read_from_child_fd = -1;
307 9 : talloc_set_destructor((void *) state->io, child_io_destructor);
308 :
309 9 : ret = pipe(pipefd_from_child);
310 9 : if (ret == -1) {
311 0 : ret = errno;
312 0 : DEBUG(SSSDBG_CRIT_FAILURE,
313 : "pipe failed [%d][%s].\n", ret, strerror(ret));
314 0 : goto done;
315 : }
316 9 : ret = pipe(pipefd_to_child);
317 9 : if (ret == -1) {
318 0 : ret = errno;
319 0 : DEBUG(SSSDBG_CRIT_FAILURE,
320 : "pipe failed [%d][%s].\n", ret, strerror(ret));
321 0 : goto done;
322 : }
323 :
324 9 : if (child_debug_fd == -1) {
325 0 : child_debug_fd = STDERR_FILENO;
326 : }
327 :
328 9 : child_pid = fork();
329 9 : if (child_pid == 0) { /* child */
330 0 : exec_child_ex(state, pipefd_to_child, pipefd_from_child,
331 : P11_CHILD_PATH, child_debug_fd, extra_args, false,
332 : STDIN_FILENO, STDOUT_FILENO);
333 :
334 : /* We should never get here */
335 0 : DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec p11 child\n");
336 9 : } else if (child_pid > 0) { /* parent */
337 :
338 9 : state->io->read_from_child_fd = pipefd_from_child[0];
339 9 : PIPE_FD_CLOSE(pipefd_from_child[1]);
340 9 : sss_fd_nonblocking(state->io->read_from_child_fd);
341 :
342 9 : state->io->write_to_child_fd = pipefd_to_child[1];
343 9 : PIPE_FD_CLOSE(pipefd_to_child[0]);
344 9 : sss_fd_nonblocking(state->io->write_to_child_fd);
345 :
346 : /* Set up SIGCHLD handler */
347 9 : ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
348 9 : if (ret != EOK) {
349 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
350 : ret, sss_strerror(ret));
351 0 : ret = ERR_P11_CHILD;
352 0 : goto done;
353 : }
354 :
355 : /* Set up timeout handler */
356 9 : tv = tevent_timeval_current_ofs(timeout, 0);
357 9 : state->timeout_handler = tevent_add_timer(ev, req, tv,
358 : p11_child_timeout, req);
359 9 : if(state->timeout_handler == NULL) {
360 0 : ret = ERR_P11_CHILD;
361 0 : goto done;
362 : }
363 :
364 9 : if (pd->cmd == SSS_PAM_AUTHENTICATE) {
365 2 : ret = get_p11_child_write_buffer(state, pd, &write_buf,
366 : &write_buf_len);
367 2 : if (ret != EOK) {
368 0 : DEBUG(SSSDBG_OP_FAILURE,
369 : "get_p11_child_write_buffer failed.\n");
370 0 : goto done;
371 : }
372 : }
373 :
374 9 : if (write_buf_len != 0) {
375 2 : subreq = write_pipe_send(state, ev, write_buf, write_buf_len,
376 2 : state->io->write_to_child_fd);
377 2 : if (subreq == NULL) {
378 0 : DEBUG(SSSDBG_OP_FAILURE, "write_pipe_send failed.\n");
379 0 : ret = ERR_P11_CHILD;
380 0 : goto done;
381 : }
382 2 : tevent_req_set_callback(subreq, p11_child_write_done, req);
383 : } else {
384 7 : subreq = read_pipe_send(state, ev, state->io->read_from_child_fd);
385 7 : if (subreq == NULL) {
386 0 : DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
387 0 : ret = ERR_P11_CHILD;
388 0 : goto done;
389 : }
390 7 : tevent_req_set_callback(subreq, p11_child_done, req);
391 : }
392 :
393 : /* Now either wait for the timeout to fire or the child
394 : * to finish
395 : */
396 : } else { /* error */
397 0 : ret = errno;
398 0 : DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
399 : ret, sss_strerror(ret));
400 0 : goto done;
401 : }
402 :
403 9 : ret = EOK;
404 :
405 : done:
406 9 : if (ret != EOK) {
407 0 : PIPE_CLOSE(pipefd_from_child);
408 0 : PIPE_CLOSE(pipefd_to_child);
409 0 : tevent_req_error(req, ret);
410 0 : tevent_req_post(req, ev);
411 : }
412 9 : return req;
413 : }
414 :
415 2 : static void p11_child_write_done(struct tevent_req *subreq)
416 : {
417 2 : struct tevent_req *req = tevent_req_callback_data(subreq,
418 : struct tevent_req);
419 2 : struct pam_check_cert_state *state = tevent_req_data(req,
420 : struct pam_check_cert_state);
421 : int ret;
422 :
423 2 : ret = write_pipe_recv(subreq);
424 2 : talloc_zfree(subreq);
425 2 : if (ret != EOK) {
426 0 : tevent_req_error(req, ret);
427 0 : return;
428 : }
429 :
430 2 : PIPE_FD_CLOSE(state->io->write_to_child_fd);
431 :
432 2 : subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
433 2 : if (subreq == NULL) {
434 0 : tevent_req_error(req, ENOMEM);
435 0 : return;
436 : }
437 2 : tevent_req_set_callback(subreq, p11_child_done, req);
438 : }
439 :
440 9 : static void p11_child_done(struct tevent_req *subreq)
441 : {
442 : uint8_t *buf;
443 : ssize_t buf_len;
444 9 : struct tevent_req *req = tevent_req_callback_data(subreq,
445 : struct tevent_req);
446 9 : struct pam_check_cert_state *state = tevent_req_data(req,
447 : struct pam_check_cert_state);
448 : int ret;
449 :
450 9 : talloc_zfree(state->timeout_handler);
451 :
452 9 : ret = read_pipe_recv(subreq, state, &buf, &buf_len);
453 9 : talloc_zfree(subreq);
454 9 : if (ret != EOK) {
455 0 : tevent_req_error(req, ret);
456 0 : return;
457 : }
458 :
459 9 : PIPE_FD_CLOSE(state->io->read_from_child_fd);
460 :
461 9 : ret = parse_p11_child_response(state, buf, buf_len, &state->cert,
462 : &state->token_name);
463 9 : if (ret != EOK) {
464 0 : DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n");
465 0 : tevent_req_error(req, ret);
466 0 : return;
467 : }
468 :
469 9 : tevent_req_done(req);
470 9 : return;
471 : }
472 :
473 0 : static void p11_child_timeout(struct tevent_context *ev,
474 : struct tevent_timer *te,
475 : struct timeval tv, void *pvt)
476 : {
477 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
478 0 : struct pam_check_cert_state *state =
479 0 : tevent_req_data(req, struct pam_check_cert_state);
480 :
481 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for p11_child.\n");
482 0 : child_handler_destroy(state->child_ctx);
483 0 : state->child_ctx = NULL;
484 0 : state->child_status = ETIMEDOUT;
485 0 : tevent_req_error(req, ERR_P11_CHILD);
486 0 : }
487 :
488 9 : errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
489 : char **cert, char **token_name)
490 : {
491 9 : struct pam_check_cert_state *state =
492 9 : tevent_req_data(req, struct pam_check_cert_state);
493 :
494 9 : TEVENT_REQ_RETURN_ON_ERROR(req);
495 :
496 9 : if (cert != NULL) {
497 9 : *cert = talloc_steal(mem_ctx, state->cert);
498 : }
499 :
500 9 : if (token_name != NULL) {
501 9 : *token_name = talloc_steal(mem_ctx, state->token_name);
502 : }
503 :
504 9 : return EOK;
505 : }
506 :
507 : /* The PKCS11_LOGIN_TOKEN_NAME environment variable is e.g. used by the Gnome
508 : * Settings Daemon to determine the name of the token used for login */
509 : #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
510 :
511 2 : errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
512 : const char *token_name)
513 : {
514 2 : uint8_t *msg = NULL;
515 2 : char *env = NULL;
516 : size_t user_len;
517 : size_t msg_len;
518 : size_t slot_len;
519 : int ret;
520 :
521 2 : if (user == NULL || token_name == NULL) {
522 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
523 0 : return EINVAL;
524 : }
525 :
526 2 : user_len = strlen(user) + 1;
527 2 : slot_len = strlen(token_name) + 1;
528 2 : msg_len = user_len + slot_len;
529 :
530 2 : msg = talloc_zero_size(pd, msg_len);
531 2 : if (msg == NULL) {
532 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
533 0 : return ENOMEM;
534 : }
535 :
536 2 : memcpy(msg, user, user_len);
537 2 : memcpy(msg + user_len, token_name, slot_len);
538 :
539 2 : ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg);
540 2 : talloc_free(msg);
541 2 : if (ret != EOK) {
542 0 : DEBUG(SSSDBG_OP_FAILURE,
543 : "pam_add_response failed to add certificate info.\n");
544 0 : return ret;
545 : }
546 :
547 2 : env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, token_name);
548 2 : if (env == NULL) {
549 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
550 0 : return ENOMEM;
551 : }
552 :
553 2 : ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1,
554 : (uint8_t *)env);
555 2 : talloc_free(env);
556 2 : if (ret != EOK) {
557 0 : DEBUG(SSSDBG_OP_FAILURE,
558 : "pam_add_response failed to add environment variable.\n");
559 0 : return ret;
560 : }
561 :
562 2 : return ret;
563 : }
|