Line data Source code
1 : /*
2 : SSSD
3 :
4 : proxy_auth.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@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 "providers/proxy/proxy.h"
26 :
27 : struct pc_init_ctx;
28 :
29 0 : static int proxy_child_destructor(TALLOC_CTX *ctx)
30 : {
31 0 : struct proxy_child_ctx *child_ctx =
32 : talloc_get_type(ctx, struct proxy_child_ctx);
33 : hash_key_t key;
34 : int hret;
35 :
36 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
37 : "Removing proxy child id [%d]\n", child_ctx->id);
38 0 : key.type = HASH_KEY_ULONG;
39 0 : key.ul = child_ctx->id;
40 0 : hret = hash_delete(child_ctx->auth_ctx->request_table, &key);
41 0 : if (!(hret == HASH_SUCCESS ||
42 : hret == HASH_ERROR_KEY_NOT_FOUND)) {
43 0 : DEBUG(SSSDBG_CRIT_FAILURE,
44 : "Hash error [%d][%s]\n", hret, hash_error_string(hret));
45 : /* Nothing we can do about this, so just continue */
46 : }
47 0 : return 0;
48 : }
49 :
50 : static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
51 : struct proxy_child_ctx *child_ctx,
52 : struct proxy_auth_ctx *auth_ctx);
53 : static void proxy_child_init_done(struct tevent_req *subreq);
54 0 : static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
55 : struct proxy_auth_ctx *auth_ctx,
56 : struct pam_data *pd)
57 : {
58 : struct tevent_req *req;
59 : struct tevent_req *subreq;
60 : struct proxy_child_ctx *state;
61 : int hret;
62 : hash_key_t key;
63 : hash_value_t value;
64 : uint32_t first;
65 :
66 0 : req = tevent_req_create(mem_ctx, &state, struct proxy_child_ctx);
67 0 : if (req == NULL) {
68 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not send PAM request to child\n");
69 0 : return NULL;
70 : }
71 :
72 0 : state->auth_ctx = auth_ctx;
73 0 : state->pd = pd;
74 :
75 : /* Find an available key */
76 0 : key.type = HASH_KEY_ULONG;
77 0 : key.ul = auth_ctx->next_id;
78 :
79 0 : first = auth_ctx->next_id;
80 0 : while (auth_ctx->next_id == 0 ||
81 0 : hash_has_key(auth_ctx->request_table, &key)) {
82 : /* Handle overflow, zero is a reserved value
83 : * Also handle the unlikely case where the next ID
84 : * is still awaiting being run
85 : */
86 0 : auth_ctx->next_id++;
87 0 : key.ul = auth_ctx->next_id;
88 :
89 0 : if (auth_ctx->next_id == first) {
90 : /* We've looped through all possible integers! */
91 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Serious error: queue is too long!\n");
92 0 : talloc_zfree(req);
93 0 : return NULL;
94 : }
95 : }
96 :
97 0 : state->id = auth_ctx->next_id;
98 0 : auth_ctx->next_id++;
99 :
100 0 : value.type = HASH_VALUE_PTR;
101 0 : value.ptr = req;
102 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Queueing request [%lu]\n", key.ul);
103 0 : hret = hash_enter(auth_ctx->request_table,
104 : &key, &value);
105 0 : if (hret != HASH_SUCCESS) {
106 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not add request to the queue\n");
107 0 : talloc_zfree(req);
108 0 : return NULL;
109 : }
110 :
111 0 : talloc_set_destructor((TALLOC_CTX *) state,
112 : proxy_child_destructor);
113 :
114 0 : if (auth_ctx->running < auth_ctx->max_children) {
115 : /* There's an available slot; start a child
116 : * to handle the request
117 : */
118 :
119 0 : auth_ctx->running++;
120 0 : subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
121 0 : if (!subreq) {
122 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not fork child process\n");
123 0 : auth_ctx->running--;
124 0 : talloc_zfree(req);
125 0 : return NULL;
126 : }
127 0 : tevent_req_set_callback(subreq, proxy_child_init_done, req);
128 :
129 0 : state->running = true;
130 : }
131 : else {
132 : /* If there was no available slot, it will be queued
133 : * until a slot is available
134 : */
135 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
136 : "All available child slots are full, queuing request\n");
137 : }
138 0 : return req;
139 : }
140 :
141 0 : static int pc_init_destructor (TALLOC_CTX *ctx)
142 : {
143 0 : struct pc_init_ctx *init_ctx =
144 : talloc_get_type(ctx, struct pc_init_ctx);
145 :
146 : /* If the init request has died, forcibly kill the child */
147 0 : kill(init_ctx->pid, SIGKILL);
148 0 : return 0;
149 : }
150 :
151 : static void pc_init_sig_handler(struct tevent_context *ev,
152 : struct tevent_signal *sige, int signum,
153 : int count, void *__siginfo, void *pvt);
154 : static void pc_init_timeout(struct tevent_context *ev,
155 : struct tevent_timer *te,
156 : struct timeval t, void *ptr);
157 0 : static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
158 : struct proxy_child_ctx *child_ctx,
159 : struct proxy_auth_ctx *auth_ctx)
160 : {
161 : struct tevent_req *req;
162 : struct pc_init_ctx *state;
163 : char **proxy_child_args;
164 : struct timeval tv;
165 : errno_t ret;
166 : pid_t pid;
167 :
168 0 : req = tevent_req_create(mem_ctx, &state, struct pc_init_ctx);
169 0 : if (req == NULL) {
170 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not create tevent_req\n");
171 0 : return NULL;
172 : }
173 :
174 0 : state->child_ctx = child_ctx;
175 :
176 0 : state->command = talloc_asprintf(req,
177 : "%s/proxy_child -d %#.4x --debug-timestamps=%d "
178 : "--debug-microseconds=%d%s --domain %s --id %d",
179 : SSSD_LIBEXEC_PATH, debug_level, debug_timestamps,
180 0 : debug_microseconds, (debug_to_file ? " --debug-to-files" : ""),
181 0 : auth_ctx->be->domain->name,
182 : child_ctx->id);
183 0 : if (state->command == NULL) {
184 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
185 0 : return NULL;
186 : }
187 :
188 0 : DEBUG(SSSDBG_TRACE_LIBS,
189 : "Starting proxy child with args [%s]\n", state->command);
190 :
191 0 : pid = fork();
192 0 : if (pid < 0) {
193 0 : ret = errno;
194 0 : DEBUG(SSSDBG_CRIT_FAILURE,
195 : "fork failed [%d][%s].\n", ret, strerror(ret));
196 0 : talloc_zfree(req);
197 0 : return NULL;
198 : }
199 :
200 0 : if (pid == 0) { /* child */
201 0 : proxy_child_args = parse_args(state->command);
202 0 : execvp(proxy_child_args[0], proxy_child_args);
203 :
204 0 : ret = errno;
205 0 : DEBUG(SSSDBG_FATAL_FAILURE,
206 : "Could not start proxy child [%s]: [%d][%s].\n",
207 : state->command, ret, strerror(ret));
208 :
209 0 : _exit(1);
210 : }
211 :
212 : else { /* parent */
213 0 : state->pid = pid;
214 : /* Make sure to kill the child process if we abort */
215 0 : talloc_set_destructor((TALLOC_CTX *)state, pc_init_destructor);
216 :
217 0 : state->sige = tevent_add_signal(auth_ctx->be->ev, req,
218 : SIGCHLD, 0,
219 : pc_init_sig_handler, req);
220 0 : if (state->sige == NULL) {
221 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
222 0 : talloc_zfree(req);
223 0 : return NULL;
224 : }
225 :
226 : /* Save the init request to the child context.
227 : * This is technically a layering violation,
228 : * but it's the only sane way to be able to
229 : * identify which client is which when it
230 : * connects to the backend in
231 : * client_registration()
232 : */
233 0 : child_ctx->init_req = req;
234 :
235 : /* Wait six seconds for the child to connect
236 : * This is because the connection handler will add
237 : * its own five-second timeout, and we don't want to
238 : * be faster here.
239 : */
240 0 : tv = tevent_timeval_current_ofs(6, 0);
241 0 : state->timeout = tevent_add_timer(auth_ctx->be->ev, req,
242 : tv, pc_init_timeout, req);
243 :
244 : /* processing will continue once the connection is received
245 : * in proxy_client_init()
246 : */
247 0 : return req;
248 : }
249 : }
250 :
251 0 : static void pc_init_sig_handler(struct tevent_context *ev,
252 : struct tevent_signal *sige, int signum,
253 : int count, void *__siginfo, void *pvt)
254 : {
255 : int ret;
256 : int child_status;
257 : struct tevent_req *req;
258 : struct pc_init_ctx *init_ctx;
259 :
260 0 : if (count <= 0) {
261 0 : DEBUG(SSSDBG_FATAL_FAILURE,
262 : "SIGCHLD handler called with invalid child count\n");
263 0 : return;
264 : }
265 :
266 0 : req = talloc_get_type(pvt, struct tevent_req);
267 0 : init_ctx = tevent_req_data(req, struct pc_init_ctx);
268 :
269 0 : DEBUG(SSSDBG_TRACE_LIBS, "Waiting for child [%d].\n", init_ctx->pid);
270 :
271 0 : errno = 0;
272 0 : ret = waitpid(init_ctx->pid, &child_status, WNOHANG);
273 :
274 0 : if (ret == -1) {
275 0 : ret = errno;
276 0 : DEBUG(SSSDBG_CRIT_FAILURE,
277 : "waitpid failed [%d][%s].\n", ret, strerror(ret));
278 0 : } else if (ret == 0) {
279 0 : DEBUG(SSSDBG_CRIT_FAILURE,
280 : "waitpid did not find a child with changed status.\n");
281 : } else {
282 0 : if (WIFEXITED(child_status)) {
283 0 : DEBUG(SSSDBG_CONF_SETTINGS,
284 : "child [%d] exited with status [%d].\n", ret,
285 : WEXITSTATUS(child_status));
286 0 : tevent_req_error(req, EIO);
287 0 : } else if (WIFSIGNALED(child_status)) {
288 0 : DEBUG(SSSDBG_CONF_SETTINGS,
289 : "child [%d] was terminate by signal [%d].\n", ret,
290 : WTERMSIG(child_status));
291 0 : tevent_req_error(req, EIO);
292 : } else {
293 0 : if (WIFSTOPPED(child_status)) {
294 0 : DEBUG(SSSDBG_CRIT_FAILURE,
295 : "child [%d] was stopped by signal [%d].\n", ret,
296 : WSTOPSIG(child_status));
297 : }
298 0 : if (WIFCONTINUED(child_status) == true) {
299 0 : DEBUG(SSSDBG_CRIT_FAILURE,
300 : "child [%d] was resumed by delivery of SIGCONT.\n",
301 : ret);
302 : }
303 0 : DEBUG(SSSDBG_CRIT_FAILURE,
304 : "Child is still running, no new child is started.\n");
305 0 : return;
306 : }
307 : }
308 : }
309 :
310 0 : static void pc_init_timeout(struct tevent_context *ev,
311 : struct tevent_timer *te,
312 : struct timeval t, void *ptr)
313 : {
314 : struct tevent_req *req;
315 :
316 0 : DEBUG(SSSDBG_OP_FAILURE, "Client timed out before Identification!\n");
317 0 : req = talloc_get_type(ptr, struct tevent_req);
318 0 : tevent_req_error(req, ETIMEDOUT);
319 0 : }
320 :
321 0 : static errno_t proxy_child_init_recv(struct tevent_req *req,
322 : pid_t *pid,
323 : struct sbus_connection **conn)
324 : {
325 : struct pc_init_ctx *state;
326 :
327 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
328 :
329 0 : state = tevent_req_data(req, struct pc_init_ctx);
330 :
331 : /* Unset the destructor since we initialized successfully.
332 : * We don't want to kill the child now that it's properly
333 : * set up.
334 : */
335 0 : talloc_set_destructor((TALLOC_CTX *)state, NULL);
336 :
337 0 : *pid = state->pid;
338 0 : *conn = state->conn;
339 :
340 0 : return EOK;
341 : }
342 :
343 : struct proxy_child_sig_ctx {
344 : struct proxy_auth_ctx *auth_ctx;
345 : pid_t pid;
346 : };
347 : static void proxy_child_sig_handler(struct tevent_context *ev,
348 : struct tevent_signal *sige, int signum,
349 : int count, void *__siginfo, void *pvt);
350 : static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
351 : struct proxy_auth_ctx *auth_ctx,
352 : struct sbus_connection *conn,
353 : struct pam_data *pd,
354 : pid_t pid);
355 : static void proxy_pam_conv_done(struct tevent_req *subreq);
356 0 : static void proxy_child_init_done(struct tevent_req *subreq) {
357 : int ret;
358 : struct tevent_signal *sige;
359 0 : struct tevent_req *req =
360 0 : tevent_req_callback_data(subreq, struct tevent_req);
361 0 : struct proxy_child_ctx *child_ctx =
362 0 : tevent_req_data(req, struct proxy_child_ctx);
363 : struct proxy_child_sig_ctx *sig_ctx;
364 :
365 0 : ret = proxy_child_init_recv(subreq, &child_ctx->pid, &child_ctx->conn);
366 0 : talloc_zfree(subreq);
367 0 : if (ret != EOK) {
368 0 : DEBUG(SSSDBG_TRACE_FUNC, "Proxy child init failed [%d]\n", ret);
369 0 : tevent_req_error(req, ret);
370 0 : return;
371 : }
372 :
373 : /* An initialized child is available, awaiting the PAM command */
374 0 : subreq = proxy_pam_conv_send(req, child_ctx->auth_ctx,
375 : child_ctx->conn, child_ctx->pd,
376 : child_ctx->pid);
377 0 : if (!subreq) {
378 0 : DEBUG(SSSDBG_CRIT_FAILURE,"Could not start PAM conversation\n");
379 0 : tevent_req_error(req, EIO);
380 0 : return;
381 : }
382 0 : tevent_req_set_callback(subreq, proxy_pam_conv_done, req);
383 :
384 : /* Add a signal handler for the child under the auth_ctx,
385 : * that way if the child exits after completion of the
386 : * request, it will still be handled.
387 : */
388 0 : sig_ctx = talloc_zero(child_ctx->auth_ctx, struct proxy_child_sig_ctx);
389 0 : if(sig_ctx == NULL) {
390 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
391 0 : tevent_req_error(req, ENOMEM);
392 0 : return;
393 : }
394 0 : sig_ctx->auth_ctx = child_ctx->auth_ctx;
395 0 : sig_ctx->pid = child_ctx->pid;
396 :
397 0 : sige = tevent_add_signal(child_ctx->auth_ctx->be->ev,
398 : child_ctx->auth_ctx,
399 : SIGCHLD, 0,
400 : proxy_child_sig_handler,
401 : sig_ctx);
402 0 : if (sige == NULL) {
403 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
404 0 : tevent_req_error(req, ENOMEM);
405 0 : return;
406 : }
407 :
408 : /* Steal the signal context onto the signal event
409 : * so that when the signal is freed, the context
410 : * will go with it.
411 : */
412 0 : talloc_steal(sige, sig_ctx);
413 : }
414 :
415 : static void remove_sige(struct tevent_context *ev,
416 : struct tevent_immediate *imm,
417 : void *pvt);
418 : static void run_proxy_child_queue(struct tevent_context *ev,
419 : struct tevent_immediate *imm,
420 : void *pvt);
421 0 : static void proxy_child_sig_handler(struct tevent_context *ev,
422 : struct tevent_signal *sige, int signum,
423 : int count, void *__siginfo, void *pvt)
424 : {
425 : int ret;
426 : int child_status;
427 : struct proxy_child_sig_ctx *sig_ctx;
428 : struct tevent_immediate *imm;
429 : struct tevent_immediate *imm2;
430 :
431 0 : if (count <= 0) {
432 0 : DEBUG(SSSDBG_FATAL_FAILURE,
433 : "SIGCHLD handler called with invalid child count\n");
434 0 : return;
435 : }
436 :
437 0 : sig_ctx = talloc_get_type(pvt, struct proxy_child_sig_ctx);
438 0 : DEBUG(SSSDBG_TRACE_LIBS, "Waiting for child [%d].\n", sig_ctx->pid);
439 :
440 0 : errno = 0;
441 0 : ret = waitpid(sig_ctx->pid, &child_status, WNOHANG);
442 :
443 0 : if (ret == -1) {
444 0 : ret = errno;
445 0 : DEBUG(SSSDBG_CRIT_FAILURE,
446 : "waitpid failed [%d][%s].\n", ret, strerror(ret));
447 0 : } else if (ret == 0) {
448 0 : DEBUG(SSSDBG_CRIT_FAILURE,
449 : "waitpid did not found a child with changed status.\n");
450 : } else {
451 0 : if (WIFEXITED(child_status)) {
452 0 : DEBUG(SSSDBG_CONF_SETTINGS,
453 : "child [%d] exited with status [%d].\n", ret,
454 : WEXITSTATUS(child_status));
455 0 : } else if (WIFSIGNALED(child_status) == true) {
456 0 : DEBUG(SSSDBG_CONF_SETTINGS,
457 : "child [%d] was terminated by signal [%d].\n", ret,
458 : WTERMSIG(child_status));
459 : } else {
460 0 : if (WIFSTOPPED(child_status)) {
461 0 : DEBUG(SSSDBG_CRIT_FAILURE,
462 : "child [%d] was stopped by signal [%d].\n", ret,
463 : WSTOPSIG(child_status));
464 : }
465 0 : if (WIFCONTINUED(child_status) == true) {
466 0 : DEBUG(SSSDBG_CRIT_FAILURE,
467 : "child [%d] was resumed by delivery of SIGCONT.\n",
468 : ret);
469 : }
470 0 : DEBUG(SSSDBG_CRIT_FAILURE,
471 : "Child is still running, no new child is started.\n");
472 0 : return;
473 : }
474 :
475 0 : imm = tevent_create_immediate(ev);
476 0 : if (imm == NULL) {
477 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
478 0 : return;
479 : }
480 :
481 0 : tevent_schedule_immediate(imm, ev, run_proxy_child_queue,
482 : sig_ctx->auth_ctx);
483 :
484 : /* schedule another immediate timer to delete the sigchld handler */
485 0 : imm2 = tevent_create_immediate(ev);
486 0 : if (imm2 == NULL) {
487 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
488 0 : return;
489 : }
490 :
491 0 : tevent_schedule_immediate(imm2, ev, remove_sige, sige);
492 : }
493 :
494 0 : return;
495 : }
496 :
497 0 : static void remove_sige(struct tevent_context *ev,
498 : struct tevent_immediate *imm,
499 : void *pvt)
500 : {
501 0 : talloc_free(pvt);
502 0 : }
503 :
504 : struct proxy_conv_ctx {
505 : struct proxy_auth_ctx *auth_ctx;
506 : struct sbus_connection *conn;
507 : struct pam_data *pd;
508 : pid_t pid;
509 : };
510 : static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr);
511 0 : static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
512 : struct proxy_auth_ctx *auth_ctx,
513 : struct sbus_connection *conn,
514 : struct pam_data *pd,
515 : pid_t pid)
516 : {
517 : errno_t ret;
518 : bool dp_ret;
519 : DBusMessage *msg;
520 : struct tevent_req *req;
521 : struct proxy_conv_ctx *state;
522 :
523 0 : req = tevent_req_create(mem_ctx, &state, struct proxy_conv_ctx);
524 0 : if (req == NULL) {
525 0 : return NULL;
526 : }
527 :
528 0 : state->auth_ctx = auth_ctx;
529 0 : state->conn = conn;
530 0 : state->pd = pd;
531 0 : state->pid = pid;
532 :
533 0 : msg = dbus_message_new_method_call(NULL,
534 : DP_PATH,
535 : DATA_PROVIDER_IFACE,
536 : DATA_PROVIDER_IFACE_PAMHANDLER);
537 0 : if (msg == NULL) {
538 0 : DEBUG(SSSDBG_CRIT_FAILURE, "dbus_message_new_method_call failed.\n");
539 0 : talloc_zfree(req);
540 0 : return NULL;
541 : }
542 :
543 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Sending request with the following data:\n");
544 0 : DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
545 :
546 0 : dp_ret = dp_pack_pam_request(msg, pd);
547 0 : if (!dp_ret) {
548 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
549 0 : dbus_message_unref(msg);
550 0 : talloc_zfree(req);
551 0 : return NULL;
552 : }
553 :
554 0 : ret = sbus_conn_send(state->conn, msg, state->auth_ctx->timeout_ms,
555 : proxy_pam_conv_reply, req, NULL);
556 0 : if (ret != EOK) {
557 0 : dbus_message_unref(msg);
558 0 : talloc_zfree(req);
559 0 : return NULL;
560 : }
561 :
562 0 : dbus_message_unref(msg);
563 0 : return req;
564 : }
565 :
566 0 : static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr)
567 : {
568 : struct tevent_req *req;
569 : struct proxy_conv_ctx *state;
570 : DBusError dbus_error;
571 : DBusMessage *reply;
572 : int type;
573 : int ret;
574 :
575 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Handling pam conversation reply\n");
576 :
577 0 : req = talloc_get_type(ptr, struct tevent_req);
578 0 : state = tevent_req_data(req, struct proxy_conv_ctx);
579 :
580 0 : dbus_error_init(&dbus_error);
581 :
582 0 : reply = dbus_pending_call_steal_reply(pending);
583 0 : dbus_pending_call_unref(pending);
584 0 : if (reply == NULL) {
585 0 : DEBUG(SSSDBG_FATAL_FAILURE,
586 : "Severe error. A reply callback was called but no reply was"
587 : "received and no timeout occurred\n");
588 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
589 0 : tevent_req_error(req, EIO);
590 : }
591 :
592 0 : type = dbus_message_get_type(reply);
593 0 : switch (type) {
594 : case DBUS_MESSAGE_TYPE_METHOD_RETURN:
595 0 : ret = dp_unpack_pam_response(reply, state->pd, &dbus_error);
596 0 : if (!ret) {
597 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse reply.\n");
598 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
599 0 : dbus_message_unref(reply);
600 0 : tevent_req_error(req, EIO);
601 0 : return;
602 : }
603 0 : DEBUG(SSSDBG_CONF_SETTINGS, "received: [%d][%s]\n",
604 : state->pd->pam_status,
605 : state->pd->domain);
606 0 : break;
607 : case DBUS_MESSAGE_TYPE_ERROR:
608 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Reply error [%s].\n",
609 : dbus_message_get_error_name(reply));
610 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
611 0 : break;
612 : default:
613 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Default... what now?.\n");
614 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
615 : }
616 0 : dbus_message_unref(reply);
617 :
618 : /* Kill the child */
619 0 : kill(state->pid, SIGKILL);
620 :
621 : /* Conversation is finished */
622 0 : tevent_req_done(req);
623 : }
624 :
625 0 : static errno_t proxy_pam_conv_recv(struct tevent_req *req)
626 : {
627 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
628 :
629 0 : return EOK;
630 : }
631 :
632 0 : static void proxy_pam_conv_done(struct tevent_req *subreq)
633 : {
634 : struct tevent_req *req;
635 : int ret;
636 :
637 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
638 :
639 0 : ret = proxy_pam_conv_recv(subreq);
640 0 : talloc_zfree(subreq);
641 0 : if (ret != EOK) {
642 0 : DEBUG(SSSDBG_TRACE_FUNC, "Proxy PAM conversation failed [%d]\n", ret);
643 0 : tevent_req_error(req, ret);
644 0 : return;
645 : }
646 :
647 0 : tevent_req_done(req);
648 : }
649 :
650 0 : static int proxy_child_recv(struct tevent_req *req,
651 : TALLOC_CTX *mem_ctx,
652 : struct pam_data **pd)
653 : {
654 : struct proxy_child_ctx *ctx;
655 :
656 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
657 :
658 0 : ctx = tevent_req_data(req, struct proxy_child_ctx);
659 0 : *pd = talloc_steal(mem_ctx, ctx->pd);
660 :
661 0 : return EOK;
662 : }
663 :
664 0 : static void run_proxy_child_queue(struct tevent_context *ev,
665 : struct tevent_immediate *imm,
666 : void *pvt)
667 : {
668 : struct proxy_auth_ctx *auth_ctx;
669 : struct hash_iter_context_t *iter;
670 : struct hash_entry_t *entry;
671 : struct tevent_req *req;
672 : struct tevent_req *subreq;
673 : struct proxy_child_ctx *state;
674 :
675 0 : auth_ctx = talloc_get_type(pvt, struct proxy_auth_ctx);
676 :
677 : /* Launch next queued request */
678 0 : iter = new_hash_iter_context(auth_ctx->request_table);
679 0 : while ((entry = iter->next(iter)) != NULL) {
680 0 : req = talloc_get_type(entry->value.ptr, struct tevent_req);
681 0 : state = tevent_req_data(req, struct proxy_child_ctx);
682 0 : if (!state->running) {
683 0 : break;
684 : }
685 : }
686 0 : free(iter);
687 :
688 0 : if (!entry) {
689 : /* Nothing pending on the queue */
690 0 : return;
691 : }
692 :
693 0 : if (auth_ctx->running < auth_ctx->max_children) {
694 : /* There's an available slot; start a child
695 : * to handle the request
696 : */
697 0 : auth_ctx->running++;
698 0 : subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
699 0 : if (!subreq) {
700 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not fork child process\n");
701 0 : auth_ctx->running--;
702 0 : talloc_zfree(req);
703 0 : return;
704 : }
705 0 : tevent_req_set_callback(subreq, proxy_child_init_done, req);
706 :
707 0 : state->running = true;
708 : }
709 : }
710 :
711 : struct proxy_pam_handler_state {
712 : struct pam_data *pd;
713 : struct proxy_auth_ctx *auth_ctx;
714 : struct be_ctx *be_ctx;
715 : };
716 :
717 : static void proxy_pam_handler_done(struct tevent_req *subreq);
718 :
719 : struct tevent_req *
720 0 : proxy_pam_handler_send(TALLOC_CTX *mem_ctx,
721 : struct proxy_auth_ctx *proxy_auth_ctx,
722 : struct pam_data *pd,
723 : struct dp_req_params *params)
724 : {
725 : struct proxy_pam_handler_state *state;
726 : struct tevent_req *subreq;
727 : struct tevent_req *req;
728 :
729 0 : req = tevent_req_create(mem_ctx, &state, struct proxy_pam_handler_state);
730 0 : if (req == NULL) {
731 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
732 0 : return NULL;
733 : }
734 :
735 0 : state->pd = pd;
736 0 : state->auth_ctx = proxy_auth_ctx;
737 0 : state->be_ctx = params->be_ctx;
738 :
739 0 : switch (pd->cmd) {
740 : case SSS_PAM_AUTHENTICATE:
741 : case SSS_PAM_CHAUTHTOK:
742 : case SSS_PAM_CHAUTHTOK_PRELIM:
743 : case SSS_PAM_ACCT_MGMT:
744 : /* Queue the request and spawn a child if there is an available slot. */
745 0 : subreq = proxy_child_send(state, proxy_auth_ctx, state->pd);
746 0 : if (subreq == NULL) {
747 0 : pd->pam_status = PAM_SYSTEM_ERR;
748 0 : goto immediately;
749 : }
750 0 : tevent_req_set_callback(subreq, proxy_pam_handler_done, req);
751 0 : break;
752 : case SSS_PAM_SETCRED:
753 : case SSS_PAM_OPEN_SESSION:
754 : case SSS_PAM_CLOSE_SESSION:
755 0 : pd->pam_status = PAM_SUCCESS;
756 0 : goto immediately;
757 : default:
758 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
759 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
760 0 : goto immediately;
761 : }
762 :
763 0 : return req;
764 :
765 : immediately:
766 : /* TODO For backward compatibility we always return EOK to DP now. */
767 0 : tevent_req_done(req);
768 0 : tevent_req_post(req, params->ev);
769 :
770 0 : return req;
771 : }
772 :
773 0 : static void proxy_pam_handler_done(struct tevent_req *subreq)
774 : {
775 : struct proxy_pam_handler_state *state;
776 : struct tevent_immediate *imm;
777 : struct tevent_req *req;
778 : const char *password;
779 : errno_t ret;
780 :
781 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
782 0 : state = tevent_req_data(req, struct proxy_pam_handler_state);
783 :
784 0 : ret = proxy_child_recv(subreq, state, &state->pd);
785 0 : talloc_zfree(subreq);
786 0 : if (ret != EOK) {
787 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
788 0 : goto done;
789 : }
790 :
791 : /* Start the next auth in the queue, if any */
792 0 : state->auth_ctx->running--;
793 0 : imm = tevent_create_immediate(state->be_ctx->ev);
794 0 : if (imm == NULL) {
795 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
796 : /* We'll still finish the current request, but we're
797 : * likely to have problems if there are queued events
798 : * if we've gotten into this state.
799 : * Hopefully this is impossible, since freeing req
800 : * above should guarantee that we have enough memory
801 : * to create this immediate event.
802 : */
803 : } else {
804 0 : tevent_schedule_immediate(imm, state->be_ctx->ev,
805 : run_proxy_child_queue,
806 : state->auth_ctx);
807 : }
808 :
809 : /* Check if we need to save the cached credentials */
810 0 : if ((state->pd->cmd == SSS_PAM_AUTHENTICATE || state->pd->cmd == SSS_PAM_CHAUTHTOK)
811 0 : && (state->pd->pam_status == PAM_SUCCESS) && state->be_ctx->domain->cache_credentials) {
812 :
813 0 : ret = sss_authtok_get_password(state->pd->authtok, &password, NULL);
814 0 : if (ret) {
815 : /* password caching failures are not fatal errors */
816 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password\n");
817 0 : goto done;
818 : }
819 :
820 0 : ret = sysdb_cache_password(state->be_ctx->domain, state->pd->user, password);
821 :
822 : /* password caching failures are not fatal errors */
823 : /* so we just log it any return */
824 0 : if (ret != EOK) {
825 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password (%d)[%s]!?\n",
826 : ret, sss_strerror(ret));
827 : }
828 : }
829 :
830 : done:
831 : /* TODO For backward compatibility we always return EOK to DP now. */
832 0 : tevent_req_done(req);
833 0 : }
834 :
835 : errno_t
836 0 : proxy_pam_handler_recv(TALLOC_CTX *mem_ctx,
837 : struct tevent_req *req,
838 : struct pam_data **_data)
839 : {
840 0 : struct proxy_pam_handler_state *state = NULL;
841 :
842 0 : state = tevent_req_data(req, struct proxy_pam_handler_state);
843 :
844 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
845 :
846 0 : *_data = talloc_steal(mem_ctx, state->pd);
847 :
848 0 : return EOK;
849 : }
850 :
|