1 /*
2 SSSD
3
4 Proxy Module
5
6 Copyright (C) Simo Sorce <ssorce@redhat.com> 2008-2009
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 <nss.h>
23 #include <errno.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <dlfcn.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29
30 #include <security/pam_appl.h>
31 #include <security/pam_modules.h>
32
33 #include "util/util.h"
34 #include "providers/dp_backend.h"
35 #include "db/sysdb.h"
36 #include "proxy.h"
37 #include <dhash.h>
38
39 struct proxy_nss_ops {
40 enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
41 char *buffer, size_t buflen, int *errnop);
42 enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
43 char *buffer, size_t buflen, int *errnop);
44 enum nss_status (*setpwent)(void);
45 enum nss_status (*getpwent_r)(struct passwd *result,
46 char *buffer, size_t buflen, int *errnop);
47 enum nss_status (*endpwent)(void);
48
49 enum nss_status (*getgrnam_r)(const char *name, struct group *result,
50 char *buffer, size_t buflen, int *errnop);
51 enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
52 char *buffer, size_t buflen, int *errnop);
53 enum nss_status (*setgrent)(void);
54 enum nss_status (*getgrent_r)(struct group *result,
55 char *buffer, size_t buflen, int *errnop);
56 enum nss_status (*endgrent)(void);
57 enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
58 long int *start, long int *size,
59 gid_t **groups, long int limit,
60 int *errnop);
61 };
62
63 struct proxy_ctx {
64 struct be_ctx *be;
65 int entry_cache_timeout;
66 struct proxy_nss_ops ops;
67 };
68
69 struct proxy_auth_ctx {
70 struct be_ctx *be;
71 char *pam_target;
72
73 uint32_t max_children;
74 uint32_t running;
75 uint32_t next_id;
76 hash_table_t *request_table;
77 struct sbus_connection *sbus_srv;
78 int timeout_ms;
79 };
80
81 static int client_registration(DBusMessage *message,
82 struct sbus_connection *conn);
83
84 static struct sbus_method proxy_methods[] = {
85 { DP_METHOD_REGISTER, client_registration },
86 { NULL, NULL }
87 };
88
89 struct sbus_interface proxy_interface = {
90 DP_INTERFACE,
91 DP_PATH,
92 SBUS_DEFAULT_VTABLE,
93 proxy_methods,
94 NULL
95 };
96
97 struct authtok_conv {
98 uint32_t authtok_size;
99 uint8_t *authtok;
100 };
101
102 struct proxy_client_ctx {
103 struct be_req *be_req;
104 struct proxy_auth_ctx *auth_ctx;
105 };
106
107 static void proxy_pam_handler_cache_done(struct tevent_req *treq);
108 static void proxy_reply(struct be_req *req, int dp_err,
109 int error, const char *errstr);
110
111 static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
112 struct proxy_auth_ctx *ctx,
113 struct be_req *be_req);
114 static void proxy_child_done(struct tevent_req *child_req);
115 static void proxy_pam_handler(struct be_req *req) {
116 struct pam_data *pd;
117 struct proxy_auth_ctx *ctx;
118 struct tevent_req *child_req = NULL;
119 struct proxy_client_ctx *client_ctx;
120
121 pd = talloc_get_type(req->req_data, struct pam_data);
122
123 switch (pd->cmd) {
124 case SSS_PAM_AUTHENTICATE:
125 ctx = talloc_get_type(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
126 struct proxy_auth_ctx);
127 break;
128 case SSS_PAM_CHAUTHTOK:
129 case SSS_PAM_CHAUTHTOK_PRELIM:
130 ctx = talloc_get_type(req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
131 struct proxy_auth_ctx);
132 break;
133 case SSS_PAM_ACCT_MGMT:
134 ctx = talloc_get_type(req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
135 struct proxy_auth_ctx);
136 break;
137 case SSS_PAM_SETCRED:
138 case SSS_PAM_OPEN_SESSION:
139 case SSS_PAM_CLOSE_SESSION:
140 pd->pam_status = PAM_SUCCESS;
141 proxy_reply(req, DP_ERR_OK, EOK, NULL);
142 return;
143 default:
144 DEBUG(1, ("Unsupported PAM task.\n"));
145 pd->pam_status = PAM_MODULE_UNKNOWN;
146 proxy_reply(req, DP_ERR_OK, EINVAL, "Unsupported PAM task");
147 return;
148 }
149
150 client_ctx = talloc(req, struct proxy_client_ctx);
151 if (client_ctx == NULL) {
152 proxy_reply(req, DP_ERR_FATAL, ENOMEM, NULL);
153 return;
154 }
155 client_ctx->auth_ctx = ctx;
156 client_ctx->be_req = req;
157
158 /* Queue the request and spawn a child if there
159 * is an available slot.
160 */
161 child_req = proxy_child_send(req, ctx, req);
162 if (child_req == NULL) {
163 /* Could not queue request
164 * Return an error
165 */
166 proxy_reply(req, DP_ERR_FATAL, EINVAL, "Could not queue request\n");
167 return;
168 }
169 tevent_req_set_callback(child_req, proxy_child_done, client_ctx);
170 return;
171 }
172
173 struct pc_init_ctx;
174 struct proxy_child_ctx {
175 struct proxy_auth_ctx *auth_ctx;
176 struct be_req *be_req;
177 struct pam_data *pd;
178
179 uint32_t id;
180 pid_t pid;
181 bool running;
182
183 struct sbus_connection *conn;
184 struct tevent_timer *timer;
185
186 struct tevent_req *init_req;
187 };
188
189 static int proxy_child_destructor(TALLOC_CTX *ctx)
190 {
191 struct proxy_child_ctx *child_ctx =
192 talloc_get_type(ctx, struct proxy_child_ctx);
193 hash_key_t key;
194
195 DEBUG(8, ("Removing proxy child id [%d]\n", child_ctx->id));
196 key.type = HASH_KEY_ULONG;
197 key.ul = child_ctx->id;
198 hash_delete(child_ctx->auth_ctx->request_table, &key);
199 return 0;
200 }
201
202 static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
203 struct proxy_child_ctx *child_ctx,
204 struct proxy_auth_ctx *auth_ctx);
205 static void proxy_child_init_done(struct tevent_req *subreq);
206 static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
207 struct proxy_auth_ctx *auth_ctx,
208 struct be_req *be_req)
209 {
210 struct tevent_req *req;
211 struct tevent_req *subreq;
212 struct proxy_child_ctx *state;
213 int hret;
214 hash_key_t key;
215 hash_value_t value;
216 uint32_t first;
217
218 req = tevent_req_create(mem_ctx, &state, struct proxy_child_ctx);
219 if (req == NULL) {
220 DEBUG(1, ("Could not send PAM request to child\n"));
221 return NULL;
222 }
223
224 state->be_req = be_req;
225 state->auth_ctx = auth_ctx;
226 state->pd = talloc_get_type(be_req->req_data, struct pam_data);
227
228 /* Find an available key */
229 key.type = HASH_KEY_ULONG;
230 key.ul = auth_ctx->next_id;
231
232 first = auth_ctx->next_id;
233 while (auth_ctx->next_id == 0 ||
234 hash_has_key(auth_ctx->request_table, &key)) {
235 /* Handle overflow, zero is a reserved value
236 * Also handle the unlikely case where the next ID
237 * is still awaiting being run
238 */
239 auth_ctx->next_id++;
240 key.ul = auth_ctx->next_id;
241
242 if (auth_ctx->next_id == first) {
243 /* We've looped through all possible integers! */
244 DEBUG(0, ("Serious error: queue is too long!\n"));
245 talloc_zfree(req);
246 return NULL;
247 }
248 }
249
250 state->id = auth_ctx->next_id;
251 auth_ctx->next_id++;
252
253 value.type = HASH_VALUE_PTR;
254 value.ptr = req;
255 DEBUG(8, ("Queueing request [%d]\n", key.ul));
256 hret = hash_enter(auth_ctx->request_table,
257 &key, &value);
258 if (hret != HASH_SUCCESS) {
259 DEBUG(1, ("Could not add request to the queue\n"));
260 talloc_zfree(req);
261 return NULL;
262 }
263
264 talloc_set_destructor((TALLOC_CTX *) state,
265 proxy_child_destructor);
266
267 if (auth_ctx->running < auth_ctx->max_children) {
268 /* There's an available slot; start a child
269 * to handle the request
270 */
271
272 auth_ctx->running++;
273 subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
274 if (!subreq) {
275 DEBUG(1, ("Could not fork child process\n"));
276 auth_ctx->running--;
277 talloc_zfree(req);
278 return NULL;
279 }
280 tevent_req_set_callback(subreq, proxy_child_init_done, req);
281
282 state->running = true;
283 }
284 else {
285 /* If there was no available slot, it will be queued
286 * until a slot is available
287 */
288 DEBUG(8, ("All available child slots are full, queuing request\n"));
289 }
290 return req;
291 }
292
293 struct pc_init_ctx {
294 char *command;
295 pid_t pid;
296 struct tevent_timer *timeout;
297 struct tevent_signal *sige;
298 struct proxy_child_ctx *child_ctx;
299 struct sbus_connection *conn;
300 };
301
302 static int pc_init_destructor (TALLOC_CTX *ctx)
303 {
304 struct pc_init_ctx *init_ctx =
305 talloc_get_type(ctx, struct pc_init_ctx);
306
307 /* If the init request has died, forcibly kill the child */
308 kill(init_ctx->pid, SIGKILL);
309 return 0;
310 }
311
312 static void pc_init_sig_handler(struct tevent_context *ev,
313 struct tevent_signal *sige, int signum,
314 int count, void *__siginfo, void *pvt);
315 static void pc_init_timeout(struct tevent_context *ev,
316 struct tevent_timer *te,
317 struct timeval t, void *ptr);
318 static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
319 struct proxy_child_ctx *child_ctx,
320 struct proxy_auth_ctx *auth_ctx)
321 {
322 struct tevent_req *req;
323 struct pc_init_ctx *state;
324 char **proxy_child_args;
325 struct timeval tv;
326 errno_t ret;
327 pid_t pid;
328
329 req = tevent_req_create(mem_ctx, &state, struct pc_init_ctx);
330 if (req == NULL) {
331 DEBUG(1, ("Could not create tevent_req\n"));
332 return NULL;
333 }
334
335 state->child_ctx = child_ctx;
336
337 state->command = talloc_asprintf(req,
338 "%s/proxy_child -d %d%s%s --domain %s --id %d",
339 SSSD_LIBEXEC_PATH, debug_level,
340 (debug_timestamps ? "" : " --debug-timestamps=0"),
341 (debug_to_file ? " --debug-to-files" : ""),
342 auth_ctx->be->domain->name,
343 child_ctx->id);
344 if (state->command == NULL) {
345 DEBUG(1, ("talloc_asprintf failed.\n"));
346 return NULL;
347 }
348
349 DEBUG(7, ("Starting proxy child with args [%s]\n", state->command));
350
351 pid = fork();
352 if (pid < 0) {
353 ret = errno;
354 DEBUG(1, ("fork failed [%d][%s].\n", ret, strerror(ret)));
355 talloc_zfree(req);
356 return NULL;
357 }
358
359 if (pid == 0) { /* child */
360 proxy_child_args = parse_args(state->command);
361 execvp(proxy_child_args[0], proxy_child_args);
362
363 ret = errno;
364 DEBUG(0, ("Could not start proxy child [%s]: [%d][%s].\n",
365 state->command, ret, strerror(ret)));
366
367 _exit(1);
368 }
369
370 else { /* parent */
371 state->pid = pid;
372 /* Make sure to kill the child process if we abort */
373 talloc_set_destructor((TALLOC_CTX *)state, pc_init_destructor);
374
375 state->sige = tevent_add_signal(auth_ctx->be->ev, req,
376 SIGCHLD, SA_SIGINFO,
377 pc_init_sig_handler, req);
378 if (state->sige == NULL) {
379 DEBUG(1, ("tevent_add_signal failed.\n"));
380 talloc_zfree(req);
381 return NULL;
382 }
383
384 /* Save the init request to the child context.
385 * This is technically a layering violation,
386 * but it's the only sane way to be able to
387 * identify which client is which when it
388 * connects to the backend in
389 * client_registration()
390 */
391 child_ctx->init_req = req;
392
393 /* Wait six seconds for the child to connect
394 * This is because the connection handler will add
395 * its own five-second timeout, and we don't want to
396 * be faster here.
397 */
398 tv = tevent_timeval_current_ofs(6, 0);
399 state->timeout = tevent_add_timer(auth_ctx->be->ev, req,
400 tv, pc_init_timeout, req);
401
402 /* processing will continue once the connection is received
403 * in proxy_client_init()
404 */
405 return req;
406 }
407 }
408
409 static void pc_init_sig_handler(struct tevent_context *ev,
410 struct tevent_signal *sige, int signum,
411 int count, void *__siginfo, void *pvt)
412 {
413 int ret;
414 int child_status;
415 struct tevent_req *req;
416 struct pc_init_ctx *init_ctx;
417
418 if (count <= 0) {
419 DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));
420 return;
421 }
422
423 req = talloc_get_type(pvt, struct tevent_req);
424 init_ctx = tevent_req_data(req, struct pc_init_ctx);
425
426 DEBUG(7, ("Waiting for child [%d].\n", init_ctx->pid));
427
428 errno = 0;
429 ret = waitpid(init_ctx->pid, &child_status, WNOHANG);
430
431 if (ret == -1) {
432 ret = errno;
433 DEBUG(1, ("waitpid failed [%d][%s].\n", ret, strerror(ret)));
434 } else if (ret == 0) {
435 DEBUG(1, ("waitpid did not find a child with changed status.\n"));
436 } else {
437 if (WIFEXITED(child_status)) {
438 DEBUG(4, ("child [%d] exited with status [%d].\n", ret,
439 WEXITSTATUS(child_status)));
440 tevent_req_error(req, EIO);
441 } else if (WIFSIGNALED(child_status)) {
442 DEBUG(4, ("child [%d] was terminate by signal [%d].\n", ret,
443 WTERMSIG(child_status)));
444 tevent_req_error(req, EIO);
445 } else {
446 if (WIFSTOPPED(child_status)) {
447 DEBUG(1, ("child [%d] was stopped by signal [%d].\n", ret,
448 WSTOPSIG(child_status)));
449 }
450 if (WIFCONTINUED(child_status)) {
451 DEBUG(1, ("child [%d] was resumed by delivery of SIGCONT.\n",
452 ret));
453 }
454 DEBUG(1, ("Child is still running, no new child is started.\n"));
455 return;
456 }
457 }
458 }
459
460 static void pc_init_timeout(struct tevent_context *ev,
461 struct tevent_timer *te,
462 struct timeval t, void *ptr)
463 {
464 struct tevent_req *req;
465 struct pc_init_ctx *state;
466
467 DEBUG(2, ("Client timed out before Identification!\n"));
468
469 req = talloc_get_type(ptr, struct tevent_req);
470 state = tevent_req_data(req, struct pc_init_ctx);
471
472 tevent_req_error(req, ETIMEDOUT);
473 }
474
475 static errno_t proxy_child_init_recv(struct tevent_req *req,
476 pid_t *pid,
477 struct sbus_connection **conn)
478 {
479 struct pc_init_ctx *state;
480
481 TEVENT_REQ_RETURN_ON_ERROR(req);
482
483 state = tevent_req_data(req, struct pc_init_ctx);
484
485 /* Unset the destructor since we initialized successfully.
486 * We don't want to kill the child now that it's properly
487 * set up.
488 */
489 talloc_set_destructor((TALLOC_CTX *)state, NULL);
490
491 *pid = state->pid;
492 *conn = state->conn;
493
494 return EOK;
495 }
496
497 struct proxy_child_sig_ctx {
498 struct proxy_auth_ctx *auth_ctx;
499 pid_t pid;
500 };
501 static void proxy_child_sig_handler(struct tevent_context *ev,
502 struct tevent_signal *sige, int signum,
503 int count, void *__siginfo, void *pvt);
504 static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
505 struct proxy_auth_ctx *auth_ctx,
506 struct sbus_connection *conn,
507 struct pam_data *pd,
508 pid_t pid);
509 static void proxy_pam_conv_done(struct tevent_req *subreq);
510 static void proxy_child_init_done(struct tevent_req *subreq) {
511 int ret;
512 struct tevent_signal *sige;
513 struct tevent_req *req =
514 tevent_req_callback_data(subreq, struct tevent_req);
515 struct proxy_child_ctx *child_ctx =
516 tevent_req_data(req, struct proxy_child_ctx);
517 struct proxy_child_sig_ctx *sig_ctx;
518
519 ret = proxy_child_init_recv(subreq, &child_ctx->pid, &child_ctx->conn);
520 talloc_zfree(subreq);
521 if (ret != EOK) {
522 DEBUG(6, ("Proxy child init failed [%d]\n", ret));
523 tevent_req_error(req, ret);
524 return;
525 }
526
527 /* An initialized child is available, awaiting the PAM command */
528 subreq = proxy_pam_conv_send(req, child_ctx->auth_ctx,
529 child_ctx->conn, child_ctx->pd,
530 child_ctx->pid);
531 if (!subreq) {
532 DEBUG(1,("Could not start PAM conversation\n"));
533 tevent_req_error(req, EIO);
534 return;
535 }
536 tevent_req_set_callback(subreq, proxy_pam_conv_done, req);
537
538 /* Add a signal handler for the child under the auth_ctx,
539 * that way if the child exits after completion of the
540 * request, it will still be handled.
541 */
542 sig_ctx = talloc_zero(child_ctx->auth_ctx, struct proxy_child_sig_ctx);
543 if(sig_ctx == NULL) {
544 DEBUG(1, ("tevent_add_signal failed.\n"));
545 tevent_req_error(req, ENOMEM);
546 return;
547 }
548 sig_ctx->auth_ctx = child_ctx->auth_ctx;
549 sig_ctx->pid = child_ctx->pid;
550
551 sige = tevent_add_signal(child_ctx->auth_ctx->be->ev,
552 child_ctx->auth_ctx,
553 SIGCHLD, SA_SIGINFO,
554 proxy_child_sig_handler,
555 sig_ctx);
556 if (sige == NULL) {
557 DEBUG(1, ("tevent_add_signal failed.\n"));
558 tevent_req_error(req, ENOMEM);
559 return;
560 }
561
562 /* Steal the signal context onto the signal event
563 * so that when the signal is freed, the context
564 * will go with it.
565 */
566 talloc_steal(sige, sig_ctx);
567 }
568
569 static void remove_sige(struct tevent_context *ev,
570 struct tevent_immediate *imm,
571 void *pvt);
572 static void run_proxy_child_queue(struct tevent_context *ev,
573 struct tevent_immediate *imm,
574 void *pvt);
575 static void proxy_child_sig_handler(struct tevent_context *ev,
576 struct tevent_signal *sige, int signum,
577 int count, void *__siginfo, void *pvt)
578 {
579 int ret;
580 int child_status;
581 struct proxy_child_sig_ctx *sig_ctx;
582 struct tevent_immediate *imm;
583 struct tevent_immediate *imm2;
584
585 if (count <= 0) {
586 DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));
587 return;
588 }
589
590 sig_ctx = talloc_get_type(pvt, struct proxy_child_sig_ctx);
591 DEBUG(7, ("Waiting for child [%d].\n", sig_ctx->pid));
592
593 errno = 0;
594 ret = waitpid(sig_ctx->pid, &child_status, WNOHANG);
595
596 if (ret == -1) {
597 ret = errno;
598 DEBUG(1, ("waitpid failed [%d][%s].\n", ret, strerror(ret)));
599 } else if (ret == 0) {
600 DEBUG(1, ("waitpid did not found a child with changed status.\n"));
601 } else {
602 if (WIFEXITED(child_status)) {
603 DEBUG(4, ("child [%d] exited with status [%d].\n", ret,
604 WEXITSTATUS(child_status)));
605 } else if (WIFSIGNALED(child_status)) {
606 DEBUG(4, ("child [%d] was terminated by signal [%d].\n", ret,
607 WTERMSIG(child_status)));
608 } else {
609 if (WIFSTOPPED(child_status)) {
610 DEBUG(1, ("child [%d] was stopped by signal [%d].\n", ret,
611 WSTOPSIG(child_status)));
612 }
613 if (WIFCONTINUED(child_status)) {
614 DEBUG(1, ("child [%d] was resumed by delivery of SIGCONT.\n",
615 ret));
616 }
617 DEBUG(1, ("Child is still running, no new child is started.\n"));
618 return;
619 }
620
621 imm = tevent_create_immediate(ev);
622 if (imm == NULL) {
623 DEBUG(1, ("tevent_create_immediate failed.\n"));
624 return;
625 }
626
627 tevent_schedule_immediate(imm, ev, run_proxy_child_queue,
628 sig_ctx->auth_ctx);
629
630 /* schedule another immediate timer to delete the sigchld handler */
631 imm2 = tevent_create_immediate(ev);
632 if (imm == NULL) {
633 DEBUG(1, ("tevent_create_immediate failed.\n"));
634 return;
635 }
636
637 tevent_schedule_immediate(imm2, ev, remove_sige, sige);
638 }
639
640 return;
641 }
642
643 static void remove_sige(struct tevent_context *ev,
644 struct tevent_immediate *imm,
645 void *pvt)
646 {
647 talloc_free(pvt);
648 }
649
650 struct proxy_conv_ctx {
651 struct proxy_auth_ctx *auth_ctx;
652 struct sbus_connection *conn;
653 struct pam_data *pd;
654 pid_t pid;
655 };
656 static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr);
657 static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
658 struct proxy_auth_ctx *auth_ctx,
659 struct sbus_connection *conn,
660 struct pam_data *pd,
661 pid_t pid)
662 {
663 errno_t ret;
664 bool dp_ret;
665 DBusMessage *msg;
666 struct tevent_req *req;
667 struct proxy_conv_ctx *state;
668
669 req = tevent_req_create(mem_ctx, &state, struct proxy_conv_ctx);
670 if (req == NULL) {
671 return NULL;
672 }
673
674 state->auth_ctx = auth_ctx;
675 state->conn = conn;
676 state->pd = pd;
677 state->pid = pid;
678
679 msg = dbus_message_new_method_call(NULL,
680 DP_PATH,
681 DP_INTERFACE,
682 DP_METHOD_PAMHANDLER);
683 if (msg == NULL) {
684 DEBUG(1, ("dbus_message_new_method_call failed.\n"));
685 talloc_zfree(req);
686 return NULL;
687 }
688
689 DEBUG(4, ("Sending request with the following data:\n"));
690 DEBUG_PAM_DATA(4, pd);
691
692 dp_ret = dp_pack_pam_request(msg, pd);
693 if (!dp_ret) {
694 DEBUG(1, ("Failed to build message\n"));
695 dbus_message_unref(msg);
696 talloc_zfree(req);
697 return NULL;
698 }
699
700 ret = sbus_conn_send(state->conn, msg, state->auth_ctx->timeout_ms,
701 proxy_pam_conv_reply, req, NULL);
702 if (ret != EOK) {
703 dbus_message_unref(msg);
704 talloc_zfree(req);
705 return NULL;
706 }
707
708 dbus_message_unref(msg);
709 return req;
710 }
711
712 static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr)
713 {
714 struct tevent_req *req;
715 struct proxy_conv_ctx *state;
716 DBusError dbus_error;
717 DBusMessage *reply;
718 int type;
719 int ret;
720
721 DEBUG(8, ("Handling pam conversation reply\n"));
722
723 req = talloc_get_type(ptr, struct tevent_req);
724 state = tevent_req_data(req, struct proxy_conv_ctx);
725
726 dbus_error_init(&dbus_error);
727
728 reply = dbus_pending_call_steal_reply(pending);
729 dbus_pending_call_unref(pending);
730 if (reply == NULL) {
731 DEBUG(0, ("Severe error. A reply callback was called but no reply was"
732 "received and no timeout occurred\n"));
733 state->pd->pam_status = PAM_SYSTEM_ERR;
734 tevent_req_error(req, EIO);
735 }
736
737 type = dbus_message_get_type(reply);
738 switch (type) {
739 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
740 ret = dp_unpack_pam_response(reply, state->pd, &dbus_error);
741 if (!ret) {
742 DEBUG(0, ("Failed to parse reply.\n"));
743 state->pd->pam_status = PAM_SYSTEM_ERR;
744 dbus_message_unref(reply);
745 tevent_req_error(req, EIO);
746 return;
747 }
748 DEBUG(4, ("received: [%d][%s]\n",
749 state->pd->pam_status,
750 state->pd->domain));
751 break;
752 case DBUS_MESSAGE_TYPE_ERROR:
753 DEBUG(0, ("Reply error [%s].\n",
754 dbus_message_get_error_name(reply)));
755 state->pd->pam_status = PAM_SYSTEM_ERR;
756 break;
757 default:
758 DEBUG(0, ("Default... what now?.\n"));
759 state->pd->pam_status = PAM_SYSTEM_ERR;
760 }
761 dbus_message_unref(reply);
762
763 /* Kill the child */
764 kill(state->pid, SIGKILL);
765
766 /* Conversation is finished */
767 tevent_req_done(req);
768 }
769
770 static errno_t proxy_pam_conv_recv(struct tevent_req *req)
771 {
772 TEVENT_REQ_RETURN_ON_ERROR(req);
773
774 return EOK;
775 }
776
777 static void proxy_pam_conv_done(struct tevent_req *subreq)
778 {
779 struct tevent_req *req;
780 int ret;
781
782 req = tevent_req_callback_data(subreq, struct tevent_req);
783
784 ret = proxy_pam_conv_recv(subreq);
785 talloc_zfree(subreq);
786 if (ret != EOK) {
787 DEBUG(6, ("Proxy PAM conversation failed [%d]\n", ret));
788 tevent_req_error(req, ret);
789 return;
790 }
791
792 tevent_req_done(req);
793 }
794
795 static int proxy_child_recv(struct tevent_req *req,
796 TALLOC_CTX *mem_ctx,
797 struct pam_data **pd)
798 {
799 struct proxy_child_ctx *ctx;
800
801 TEVENT_REQ_RETURN_ON_ERROR(req);
802
803 ctx = tevent_req_data(req, struct proxy_child_ctx);
804 *pd = talloc_steal(mem_ctx, ctx->pd);
805
806 return EOK;
807 }
808
809 static void proxy_child_done(struct tevent_req *req)
810 {
811 struct proxy_client_ctx *client_ctx =
812 tevent_req_callback_data(req, struct proxy_client_ctx);
813 struct pam_data *pd;
814 char *password;
815 int ret;
816 struct tevent_immediate *imm;
817
818 ret = proxy_child_recv(req, client_ctx, &pd);
819 talloc_zfree(req);
820 if (ret != EOK) {
821 /* Pam child failed */
822 client_ctx->auth_ctx->running--;
823 proxy_reply(client_ctx->be_req, DP_ERR_FATAL, ret,
824 "PAM child failed");
825
826 /* Start the next auth in the queue, if any */
827 imm = tevent_create_immediate(client_ctx->be_req->be_ctx->ev);
828 if (imm == NULL) {
829 DEBUG(1, ("tevent_create_immediate failed.\n"));
830 return;
831 }
832
833 tevent_schedule_immediate(imm,
834 client_ctx->be_req->be_ctx->ev,
835 run_proxy_child_queue,
836 client_ctx->auth_ctx);
837 return;
838 }
839
840 /* Check if we need to save the cached credentials */
841 if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) &&
842 pd->pam_status == PAM_SUCCESS &&
843 client_ctx->be_req->be_ctx->domain->cache_credentials) {
844 password = talloc_strndup(client_ctx->be_req,
845 (char *) pd->authtok,
846 pd->authtok_size);
847 if (!password) {
848 /* password caching failures are not fatal errors */
849 DEBUG(2, ("Failed to cache password\n"));
850 goto done;
851 }
852 talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
853
854 DEBUG(6, ("Caching the password\n"));
855 req = sysdb_cache_password_send(client_ctx,
856 client_ctx->be_req->be_ctx->ev,
857 client_ctx->be_req->be_ctx->sysdb,
858 NULL,
859 client_ctx->be_req->be_ctx->domain,
860 pd->user, password);
861 if (!req) {
862 /* password caching failures are not fatal errors */
863 DEBUG(2, ("Failed to cache password\n"));
864 goto done;
865 }
866 tevent_req_set_callback(req, proxy_pam_handler_cache_done,
867 client_ctx->be_req);
868 return;
869 }
870
871 done:
872 proxy_reply(client_ctx->be_req, DP_ERR_OK, EOK, NULL);
873 }
874
875 static void run_proxy_child_queue(struct tevent_context *ev,
876 struct tevent_immediate *imm,
877 void *pvt)
878 {
879 struct proxy_auth_ctx *auth_ctx;
880 struct hash_iter_context_t *iter;
881 struct hash_entry_t *entry;
882 struct tevent_req *req;
883 struct tevent_req *subreq;
884 struct proxy_child_ctx *state;
885
886 auth_ctx = talloc_get_type(pvt, struct proxy_auth_ctx);
887
888 /* Launch next queued request */
889 iter = new_hash_iter_context(auth_ctx->request_table);
890 while ((entry = iter->next(iter)) != NULL) {
891 req = talloc_get_type(entry->value.ptr, struct tevent_req);
892 state = tevent_req_data(req, struct proxy_child_ctx);
893 if (!state->running) {
894 break;
895 }
896 }
897
898 if (!entry) {
899 /* Nothing pending on the queue */
900 return;
901 }
902
903 if (auth_ctx->running < auth_ctx->max_children) {
904 /* There's an available slot; start a child
905 * to handle the request
906 */
907 auth_ctx->running++;
908 subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
909 if (!subreq) {
910 DEBUG(1, ("Could not fork child process\n"));
911 auth_ctx->running--;
912 talloc_zfree(req);
913 return;
914 }
915 tevent_req_set_callback(subreq, proxy_child_init_done, req);
916
917 state->running = true;
918 }
919 }
920
921 static void proxy_pam_handler_cache_done(struct tevent_req *subreq)
922 {
923 struct be_req *be_req = tevent_req_callback_data(subreq, struct be_req);
924 int ret;
925
926 /* password caching failures are not fatal errors */
927 ret = sysdb_cache_password_recv(subreq);
928 talloc_zfree(subreq);
929
930 /* so we just log it and return */
931 if (ret) {
932 DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",
933 ret, strerror(ret)));
934 }
935
936 proxy_reply(be_req, DP_ERR_OK, EOK, NULL);
937
938 return;
939 }
940
941 static void proxy_reply(struct be_req *req, int dp_err,
942 int error, const char *errstr)
943 {
944 if (!req->be_ctx->offstat.offline) {
945 /* This action took place online.
946 * Fire any online callbacks if necessary.
947 * Note: we're checking the offline value directly,
948 * because if the activity took a long time to
949 * complete, calling be_is_offline() might report false
950 * incorrectly.
951 */
952 be_run_online_cb(req->be_ctx);
953 }
954 return req->fn(req, dp_err, error, errstr);
955 }
956
957 /* =Common-proxy-tevent_req-utils=========================================*/
958
959 #define DEFAULT_BUFSIZE 4096
960 #define MAX_BUF_SIZE 1024*1024 /* max 1MiB */
961
962 struct proxy_state {
963 struct tevent_context *ev;
964 struct proxy_ctx *ctx;
965 struct sysdb_ctx *sysdb;
966 struct sss_domain_info *domain;
967 const char *name;
968
969 struct sysdb_handle *handle;
970 struct passwd *pwd;
971 struct group *grp;
972 uid_t uid;
973 gid_t gid;
974 };
975
976 static void proxy_default_done(struct tevent_req *subreq)
977 {
978 struct tevent_req *req = tevent_req_callback_data(subreq,
979 struct tevent_req);
980 int ret;
981
982 ret = sysdb_transaction_commit_recv(subreq);
983 talloc_zfree(subreq);
984 if (ret) {
985 tevent_req_error(req, ret);
986 return;
987 }
988
989 tevent_req_done(req);
990 }
991
992 static int proxy_default_recv(struct tevent_req *req)
993 {
994 TEVENT_REQ_RETURN_ON_ERROR(req);
995
996 return EOK;
997 }
998
999
1000 /* =Getpwnam-wrapper======================================================*/
1001
1002 static void get_pw_name_process(struct tevent_req *subreq);
1003 static void get_pw_name_remove_done(struct tevent_req *subreq);
1004 static void get_pw_name_add_done(struct tevent_req *subreq);
1005
1006 static struct tevent_req *get_pw_name_send(TALLOC_CTX *mem_ctx,
1007 struct tevent_context *ev,
1008 struct proxy_ctx *ctx,
1009 struct sysdb_ctx *sysdb,
1010 struct sss_domain_info *domain,
1011 const char *name)
1012 {
1013 struct tevent_req *req, *subreq;
1014 struct proxy_state *state;
1015
1016 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1017 if (!req) return NULL;
1018
1019 memset(state, 0, sizeof(struct proxy_state));
1020
1021 state->ev = ev;
1022 state->ctx = ctx;
1023 state->sysdb = sysdb;
1024 state->domain = domain;
1025 state->name = name;
1026
1027 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1028 if (!subreq) {
1029 talloc_zfree(req);
1030 return NULL;
1031 }
1032 tevent_req_set_callback(subreq, get_pw_name_process, req);
1033
1034 return req;
1035 }
1036
1037 static void get_pw_name_process(struct tevent_req *subreq)
1038 {
1039 struct tevent_req *req = tevent_req_callback_data(subreq,
1040 struct tevent_req);
1041 struct proxy_state *state = tevent_req_data(req,
1042 struct proxy_state);
1043 struct proxy_ctx *ctx = state->ctx;
1044 struct sss_domain_info *dom = ctx->be->domain;
1045 enum nss_status status;
1046 char *buffer;
1047 size_t buflen;
1048 bool delete_user = false;
1049 int ret;
1050
1051 DEBUG(7, ("Searching user by name (%s)\n", state->name));
1052
1053 ret = sysdb_transaction_recv(subreq, state, &state->handle);
1054 if (ret) {
1055 tevent_req_error(req, ret);
1056 return;
1057 }
1058 talloc_zfree(subreq);
1059
1060 state->pwd = talloc(state, struct passwd);
1061 if (!state->pwd) {
1062 tevent_req_error(req, ENOMEM);
1063 return;
1064 }
1065
1066 buflen = DEFAULT_BUFSIZE;
1067 buffer = talloc_size(state, buflen);
1068 if (!buffer) {
1069 tevent_req_error(req, ENOMEM);
1070 return;
1071 }
1072
1073 /* FIXME: should we move this call outside the transaction to keep the
1074 * transaction as short as possible ? */
1075 status = ctx->ops.getpwnam_r(state->name, state->pwd,
1076 buffer, buflen, &ret);
1077
1078 switch (status) {
1079 case NSS_STATUS_NOTFOUND:
1080
1081 DEBUG(7, ("User %s not found.\n", state->name));
1082 delete_user = true;
1083 break;
1084
1085 case NSS_STATUS_SUCCESS:
1086
1087 DEBUG(7, ("User %s found: (%s, %d, %d)\n",
1088 state->name, state->pwd->pw_name,
1089 state->pwd->pw_uid, state->pwd->pw_gid));
1090
1091 /* uid=0 or gid=0 are invalid values */
1092 /* also check that the id is in the valid range for this domain */
1093 if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
1094 OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
1095
1096 DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
1097 state->name));
1098 delete_user = true;
1099 break;
1100 }
1101
1102 subreq = sysdb_store_user_send(state, state->ev, state->handle,
1103 state->domain,
1104 state->pwd->pw_name,
1105 state->pwd->pw_passwd,
1106 state->pwd->pw_uid,
1107 state->pwd->pw_gid,
1108 state->pwd->pw_gecos,
1109 state->pwd->pw_dir,
1110 state->pwd->pw_shell,
1111 NULL, ctx->entry_cache_timeout);
1112 if (!subreq) {
1113 tevent_req_error(req, ENOMEM);
1114 return;
1115 }
1116 tevent_req_set_callback(subreq, get_pw_name_add_done, req);
1117 return;
1118
1119 case NSS_STATUS_UNAVAIL:
1120 /* "remote" backend unavailable. Enter offline mode */
1121 tevent_req_error(req, ENXIO);
1122 return;
1123
1124 default:
1125 DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
1126 state->name, status));
1127 tevent_req_error(req, EIO);
1128 return;
1129 }
1130
1131 if (delete_user) {
1132 struct ldb_dn *dn;
1133
1134 DEBUG(7, ("User %s does not exist (or is invalid) on remote server,"
1135 " deleting!\n", state->name));
1136
1137 dn = sysdb_user_dn(state->sysdb, state,
1138 state->domain->name, state->name);
1139 if (!dn) {
1140 tevent_req_error(req, ENOMEM);
1141 return;
1142 }
1143
1144 subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1145 if (!subreq) {
1146 tevent_req_error(req, ENOMEM);
1147 return;
1148 }
1149 tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
1150 }
1151 }
1152
1153 static void get_pw_name_add_done(struct tevent_req *subreq)
1154 {
1155 struct tevent_req *req = tevent_req_callback_data(subreq,
1156 struct tevent_req);
1157 struct proxy_state *state = tevent_req_data(req,
1158 struct proxy_state);
1159 int ret;
1160
1161 ret = sysdb_store_user_recv(subreq);
1162 talloc_zfree(subreq);
1163 if (ret) {
1164 tevent_req_error(req, ret);
1165 return;
1166 }
1167
1168 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1169 if (!subreq) {
1170 tevent_req_error(req, ENOMEM);
1171 return;
1172 }
1173 tevent_req_set_callback(subreq, proxy_default_done, req);
1174 }
1175
1176 static void get_pw_name_remove_done(struct tevent_req *subreq)
1177 {
1178 struct tevent_req *req = tevent_req_callback_data(subreq,
1179 struct tevent_req);
1180 struct proxy_state *state = tevent_req_data(req,
1181 struct proxy_state);
1182 int ret;
1183
1184 ret = sysdb_delete_entry_recv(subreq);
1185 talloc_zfree(subreq);
1186 if (ret) {
1187 tevent_req_error(req, ret);
1188 return;
1189 }
1190
1191 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1192 if (!subreq) {
1193 tevent_req_error(req, ENOMEM);
1194 return;
1195 }
1196 tevent_req_set_callback(subreq, proxy_default_done, req);
1197 }
1198
1199 /* =Getpwuid-wrapper======================================================*/
1200
1201 static void get_pw_uid_process(struct tevent_req *subreq);
1202 static void get_pw_uid_remove_done(struct tevent_req *subreq);
1203
1204 static struct tevent_req *get_pw_uid_send(TALLOC_CTX *mem_ctx,
1205 struct tevent_context *ev,
1206 struct proxy_ctx *ctx,
1207 struct sysdb_ctx *sysdb,
1208 struct sss_domain_info *domain,
1209 uid_t uid)
1210 {
1211 struct tevent_req *req, *subreq;
1212 struct proxy_state *state;
1213
1214 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1215 if (!req) return NULL;
1216
1217 memset(state, 0, sizeof(struct proxy_state));
1218
1219 state->ev = ev;
1220 state->ctx = ctx;
1221 state->sysdb = sysdb;
1222 state->domain = domain;
1223 state->uid = uid;
1224
1225 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1226 if (!subreq) {
1227 talloc_zfree(req);
1228 return NULL;
1229 }
1230 tevent_req_set_callback(subreq, get_pw_uid_process, req);
1231
1232 return req;
1233 }
1234
1235 static void get_pw_uid_process(struct tevent_req *subreq)
1236 {
1237 struct tevent_req *req = tevent_req_callback_data(subreq,
1238 struct tevent_req);
1239 struct proxy_state *state = tevent_req_data(req,
1240 struct proxy_state);
1241 struct proxy_ctx *ctx = state->ctx;
1242 struct sss_domain_info *dom = ctx->be->domain;
1243 enum nss_status status;
1244 char *buffer;
1245 size_t buflen;
1246 bool delete_user = false;
1247 int ret;
1248
1249 DEBUG(7, ("Searching user by uid (%d)\n", state->uid));
1250
1251 ret = sysdb_transaction_recv(subreq, state, &state->handle);
1252 if (ret) {
1253 tevent_req_error(req, ret);
1254 return;
1255 }
1256 talloc_zfree(subreq);
1257
1258 state->pwd = talloc(state, struct passwd);
1259 if (!state->pwd) {
1260 tevent_req_error(req, ENOMEM);
1261 return;
1262 }
1263
1264 buflen = DEFAULT_BUFSIZE;
1265 buffer = talloc_size(state, buflen);
1266 if (!buffer) {
1267 tevent_req_error(req, ENOMEM);
1268 return;
1269 }
1270
1271 /* always zero out the pwd structure */
1272 memset(state->pwd, 0, sizeof(struct passwd));
1273
1274 status = ctx->ops.getpwuid_r(state->uid, state->pwd,
1275 buffer, buflen, &ret);
1276
1277 switch (status) {
1278 case NSS_STATUS_NOTFOUND:
1279
1280 DEBUG(7, ("User %d not found.\n", state->uid));
1281 delete_user = true;
1282 break;
1283
1284 case NSS_STATUS_SUCCESS:
1285
1286 DEBUG(7, ("User %d found (%s, %d, %d)\n",
1287 state->uid, state->pwd->pw_name,
1288 state->pwd->pw_uid, state->pwd->pw_gid));
1289
1290 /* uid=0 or gid=0 are invalid values */
1291 /* also check that the id is in the valid range for this domain */
1292 if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
1293 OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
1294
1295 DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
1296 state->name));
1297 delete_user = true;
1298 break;
1299 }
1300
1301 subreq = sysdb_store_user_send(state, state->ev, state->handle,
1302 state->domain,
1303 state->pwd->pw_name,
1304 state->pwd->pw_passwd,
1305 state->pwd->pw_uid,
1306 state->pwd->pw_gid,
1307 state->pwd->pw_gecos,
1308 state->pwd->pw_dir,
1309 state->pwd->pw_shell,
1310 NULL, ctx->entry_cache_timeout);
1311 if (!subreq) {
1312 tevent_req_error(req, ENOMEM);
1313 return;
1314 }
1315 tevent_req_set_callback(subreq, get_pw_name_add_done, req);
1316 return;
1317
1318 case NSS_STATUS_UNAVAIL:
1319 /* "remote" backend unavailable. Enter offline mode */
1320 tevent_req_error(req, ENXIO);
1321 return;
1322
1323 default:
1324 DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
1325 state->name, status));
1326 tevent_req_error(req, EIO);
1327 return;
1328 }
1329
1330 if (delete_user) {
1331 DEBUG(7, ("User %d does not exist (or is invalid) on remote server,"
1332 " deleting!\n", state->uid));
1333
1334 subreq = sysdb_delete_user_send(state, state->ev,
1335 NULL, state->handle,
1336 state->domain,
1337 NULL, state->uid);
1338 if (!subreq) {
1339 tevent_req_error(req, ENOMEM);
1340 return;
1341 }
1342 tevent_req_set_callback(subreq, get_pw_uid_remove_done, req);
1343 }
1344 }
1345
1346 static void get_pw_uid_remove_done(struct tevent_req *subreq)
1347 {
1348 struct tevent_req *req = tevent_req_callback_data(subreq,
1349 struct tevent_req);
1350 struct proxy_state *state = tevent_req_data(req,
1351 struct proxy_state);
1352 int ret;
1353
1354 ret = sysdb_delete_user_recv(subreq);
1355 talloc_zfree(subreq);
1356 if (ret && ret != ENOENT) {
1357 tevent_req_error(req, ret);
1358 return;
1359 }
1360
1361 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1362 if (!subreq) {
1363 tevent_req_error(req, ENOMEM);
1364 return;
1365 }
1366 tevent_req_set_callback(subreq, proxy_default_done, req);
1367 }
1368
1369 /* =Getpwent-wrapper======================================================*/
1370
1371 struct enum_users_state {
1372 struct tevent_context *ev;
1373 struct proxy_ctx *ctx;
1374 struct sysdb_ctx *sysdb;
1375 struct sss_domain_info *domain;
1376 struct sysdb_handle *handle;
1377
1378 struct passwd *pwd;
1379
1380 size_t buflen;
1381 char *buffer;
1382
1383 bool in_transaction;
1384 };
1385
1386 static void enum_users_process(struct tevent_req *subreq);
1387
1388 static struct tevent_req *enum_users_send(TALLOC_CTX *mem_ctx,
1389 struct tevent_context *ev,
1390 struct proxy_ctx *ctx,
1391 struct sysdb_ctx *sysdb,
1392 struct sss_domain_info *domain)
1393 {
1394 struct tevent_req *req, *subreq;
1395 struct enum_users_state *state;
1396 enum nss_status status;
1397
1398 DEBUG(7, ("Enumerating users\n"));
1399
1400 req = tevent_req_create(mem_ctx, &state, struct enum_users_state);
1401 if (!req) return NULL;
1402
1403 state->ev = ev;
1404 state->ctx = ctx;
1405 state->sysdb = sysdb;
1406 state->domain = domain;
1407 state->handle = NULL;
1408
1409 state->pwd = talloc(state, struct passwd);
1410 if (!state->pwd) {
1411 tevent_req_error(req, ENOMEM);
1412 goto fail;
1413 }
1414
1415 state->buflen = DEFAULT_BUFSIZE;
1416 state->buffer = talloc_size(state, state->buflen);
1417 if (!state->buffer) {
1418 tevent_req_error(req, ENOMEM);
1419 goto fail;
1420 }
1421
1422 state->in_transaction = false;
1423
1424 status = ctx->ops.setpwent();
1425 if (status != NSS_STATUS_SUCCESS) {
1426 tevent_req_error(req, EIO);
1427 goto fail;
1428 }
1429
1430 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1431 if (!subreq) {
1432 tevent_req_error(req, ENOMEM);
1433 goto fail;
1434 }
1435 tevent_req_set_callback(subreq, enum_users_process, req);
1436
1437 return req;
1438
1439 fail:
1440 tevent_req_post(req, ev);
1441 return req;
1442 }
1443
1444 static void enum_users_process(struct tevent_req *subreq)
1445 {
1446 struct tevent_req *req = tevent_req_callback_data(subreq,
1447 struct tevent_req);
1448 struct enum_users_state *state = tevent_req_data(req,
1449 struct enum_users_state);
1450 struct proxy_ctx *ctx = state->ctx;
1451 struct sss_domain_info *dom = ctx->be->domain;
1452 enum nss_status status;
1453 char *newbuf;
1454 int ret;
1455
1456 if (!state->in_transaction) {
1457 ret = sysdb_transaction_recv(subreq, state, &state->handle);
1458 if (ret) {
1459 goto fail;
1460 }
1461 talloc_zfree(subreq);
1462
1463 state->in_transaction = true;
1464 } else {
1465 ret = sysdb_store_user_recv(subreq);
1466 if (ret) {
1467 /* Do not fail completely on errors.
1468 * Just report the failure to save and go on */
1469 DEBUG(2, ("Failed to store user. Ignoring.\n"));
1470 }
1471 talloc_zfree(subreq);
1472 }
1473
1474 again:
1475 /* always zero out the pwd structure */
1476 memset(state->pwd, 0, sizeof(struct passwd));
1477
1478 /* get entry */
1479 status = ctx->ops.getpwent_r(state->pwd,
1480 state->buffer, state->buflen, &ret);
1481
1482 switch (status) {
1483 case NSS_STATUS_TRYAGAIN:
1484 /* buffer too small ? */
1485 if (state->buflen < MAX_BUF_SIZE) {
1486 state->buflen *= 2;
1487 }
1488 if (state->buflen > MAX_BUF_SIZE) {
1489 state->buflen = MAX_BUF_SIZE;
1490 }
1491 newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
1492 if (!newbuf) {
1493 ret = ENOMEM;
1494 goto fail;
1495 }
1496 state->buffer = newbuf;
1497 goto again;
1498
1499 case NSS_STATUS_NOTFOUND:
1500
1501 /* we are done here */
1502 DEBUG(7, ("Enumeration completed.\n"));
1503
1504 ctx->ops.endpwent();
1505 subreq = sysdb_transaction_commit_send(state, state->ev,
1506 state->handle);
1507 if (!subreq) {
1508 tevent_req_error(req, ENOMEM);
1509 return;
1510 }
1511 tevent_req_set_callback(subreq, proxy_default_done, req);
1512 return;
1513
1514 case NSS_STATUS_SUCCESS:
1515
1516 DEBUG(7, ("User found (%s, %d, %d)\n", state->pwd->pw_name,
1517 state->pwd->pw_uid, state->pwd->pw_gid));
1518
1519 /* uid=0 or gid=0 are invalid values */
1520 /* also check that the id is in the valid range for this domain */
1521 if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
1522 OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
1523
1524 DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
1525 state->pwd->pw_name));
1526
1527 goto again; /* skip */
1528 }
1529
1530 subreq = sysdb_store_user_send(state, state->ev, state->handle,
1531 state->domain,
1532 state->pwd->pw_name,
1533 state->pwd->pw_passwd,
1534 state->pwd->pw_uid,
1535 state->pwd->pw_gid,
1536 state->pwd->pw_gecos,
1537 state->pwd->pw_dir,
1538 state->pwd->pw_shell,
1539 NULL, ctx->entry_cache_timeout);
1540 if (!subreq) {
1541 tevent_req_error(req, ENOMEM);
1542 return;
1543 }
1544 tevent_req_set_callback(subreq, enum_users_process, req);
1545 return;
1546
1547 case NSS_STATUS_UNAVAIL:
1548 /* "remote" backend unavailable. Enter offline mode */
1549 ret = ENXIO;
1550 goto fail;
1551
1552 default:
1553 DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n",
1554 ret, strerror(ret)));
1555 goto fail;
1556 }
1557
1558 fail:
1559 ctx->ops.endpwent();
1560 tevent_req_error(req, ret);
1561 }
1562
1563 /* =Getgrnam-wrapper======================================================*/
1564
1565 #define DEBUG_GR_MEM(level, state) \
1566 do { \
1567 if (debug_level >= level) { \
1568 if (!state->grp->gr_mem || !state->grp->gr_mem[0]) { \
1569 DEBUG(level, ("Group %s has no members!\n", \
1570 state->grp->gr_name)); \
1571 } else { \
1572 int i = 0; \
1573 while (state->grp->gr_mem[i]) { \
1574 /* count */ \
1575 i++; \
1576 } \
1577 DEBUG(level, ("Group %s has %d members!\n", \
1578 state->grp->gr_name, i)); \
1579 } \
1580 } \
1581 } while(0)
1582
1583 static void get_gr_name_process(struct tevent_req *subreq);
1584 static void get_gr_name_remove_done(struct tevent_req *subreq);
1585 static void get_gr_name_add_done(struct tevent_req *subreq);
1586
1587 static struct tevent_req *get_gr_name_send(TALLOC_CTX *mem_ctx,
1588 struct tevent_context *ev,
1589 struct proxy_ctx *ctx,
1590 struct sysdb_ctx *sysdb,
1591 struct sss_domain_info *domain,
1592 const char *name)
1593 {
1594 struct tevent_req *req, *subreq;
1595 struct proxy_state *state;
1596
1597 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1598 if (!req) return NULL;
1599
1600 memset(state, 0, sizeof(struct proxy_state));
1601
1602 state->ev = ev;
1603 state->ctx = ctx;
1604 state->sysdb = sysdb;
1605 state->domain = domain;
1606 state->name = name;
1607
1608 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1609 if (!subreq) {
1610 talloc_zfree(req);
1611 return NULL;
1612 }
1613 tevent_req_set_callback(subreq, get_gr_name_process, req);
1614
1615 return req;
1616 }
1617
1618 static void get_gr_name_process(struct tevent_req *subreq)
1619 {
1620 struct tevent_req *req = tevent_req_callback_data(subreq,
1621 struct tevent_req);
1622 struct proxy_state *state = tevent_req_data(req,
1623 struct proxy_state);
1624 struct proxy_ctx *ctx = state->ctx;
1625 struct sss_domain_info *dom = ctx->be->domain;
1626 enum nss_status status;
1627 char *buffer;
1628 char *newbuf;
1629 size_t buflen;
1630 bool delete_group = false;
1631 struct sysdb_attrs *members;
1632 int ret;
1633
1634 DEBUG(7, ("Searching group by name (%s)\n", state->name));
1635
1636 ret = sysdb_transaction_recv(subreq, state, &state->handle);
1637 if (ret) {
1638 tevent_req_error(req, ret);
1639 return;
1640 }
1641 talloc_zfree(subreq);
1642
1643 state->grp = talloc(state, struct group);
1644 if (!state->grp) {
1645 tevent_req_error(req, ENOMEM);
1646 return;
1647 }
1648
1649 buflen = DEFAULT_BUFSIZE;
1650 buffer = talloc_size(state, buflen);
1651 if (!buffer) {
1652 tevent_req_error(req, ENOMEM);
1653 return;
1654 }
1655
1656 /* FIXME: should we move this call outside the transaction to keep the
1657 * transaction as short as possible ? */
1658 again:
1659 /* always zero out the grp structure */
1660 memset(state->grp, 0, sizeof(struct group));
1661
1662 status = ctx->ops.getgrnam_r(state->name, state->grp,
1663 buffer, buflen, &ret);
1664
1665 switch (status) {
1666 case NSS_STATUS_TRYAGAIN:
1667 /* buffer too small ? */
1668 if (buflen < MAX_BUF_SIZE) {
1669 buflen *= 2;
1670 }
1671 if (buflen > MAX_BUF_SIZE) {
1672 buflen = MAX_BUF_SIZE;
1673 }
1674 newbuf = talloc_realloc_size(state, buffer, buflen);
1675 if (!newbuf) {
1676 tevent_req_error(req, ENOMEM);
1677 return;
1678 }
1679 buffer = newbuf;
1680 goto again;
1681
1682 case NSS_STATUS_NOTFOUND:
1683
1684 DEBUG(7, ("Group %s not found.\n", state->name));
1685 delete_group = true;
1686 break;
1687
1688 case NSS_STATUS_SUCCESS:
1689
1690 DEBUG(7, ("Group %s found: (%s, %d)\n", state->name,
1691 state->grp->gr_name, state->grp->gr_gid));
1692
1693 /* gid=0 is an invalid value */
1694 /* also check that the id is in the valid range for this domain */
1695 if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1696
1697 DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1698 state->name));
1699 delete_group = true;
1700 break;
1701 }
1702
1703 DEBUG_GR_MEM(7, state);
1704
1705 if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1706 members = sysdb_new_attrs(state);
1707 if (!members) {
1708 tevent_req_error(req, ENOMEM);
1709 return;
1710 }
1711 ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1712 state->domain->name,
1713 (const char **)state->grp->gr_mem);
1714 if (ret) {
1715 tevent_req_error(req, ret);
1716 return;
1717 }
1718 } else {
1719 members = NULL;
1720 }
1721
1722 subreq = sysdb_store_group_send(state, state->ev, state->handle,
1723 state->domain,
1724 state->grp->gr_name,
1725 state->grp->gr_gid,
1726 members,
1727 ctx->entry_cache_timeout);
1728 if (!subreq) {
1729 tevent_req_error(req, ENOMEM);
1730 return;
1731 }
1732 tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1733 return;
1734
1735 case NSS_STATUS_UNAVAIL:
1736 /* "remote" backend unavailable. Enter offline mode */
1737 tevent_req_error(req, ENXIO);
1738 return;
1739
1740 default:
1741 DEBUG(2, ("proxy -> getgrnam_r failed for '%s' <%d>\n",
1742 state->name, status));
1743 tevent_req_error(req, EIO);
1744 return;
1745 }
1746
1747 if (delete_group) {
1748 struct ldb_dn *dn;
1749
1750 DEBUG(7, ("Group %s does not exist (or is invalid) on remote server,"
1751 " deleting!\n", state->name));
1752
1753 dn = sysdb_group_dn(state->sysdb, state,
1754 state->domain->name, state->name);
1755 if (!dn) {
1756 tevent_req_error(req, ENOMEM);
1757 return;
1758 }
1759
1760 subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1761 if (!subreq) {
1762 tevent_req_error(req, ENOMEM);
1763 return;
1764 }
1765 tevent_req_set_callback(subreq, get_gr_name_remove_done, req);
1766 }
1767 }
1768
1769 static void get_gr_name_add_done(struct tevent_req *subreq)
1770 {
1771 struct tevent_req *req = tevent_req_callback_data(subreq,
1772 struct tevent_req);
1773 struct proxy_state *state = tevent_req_data(req,
1774 struct proxy_state);
1775 int ret;
1776
1777 ret = sysdb_store_group_recv(subreq);
1778 talloc_zfree(subreq);
1779 if (ret) {
1780 tevent_req_error(req, ret);
1781 return;
1782 }
1783
1784 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1785 if (!subreq) {
1786 tevent_req_error(req, ENOMEM);
1787 return;
1788 }
1789 tevent_req_set_callback(subreq, proxy_default_done, req);
1790 }
1791
1792 static void get_gr_name_remove_done(struct tevent_req *subreq)
1793 {
1794 struct tevent_req *req = tevent_req_callback_data(subreq,
1795 struct tevent_req);
1796 struct proxy_state *state = tevent_req_data(req,
1797 struct proxy_state);
1798 int ret;
1799
1800 ret = sysdb_delete_entry_recv(subreq);
1801 talloc_zfree(subreq);
1802 if (ret) {
1803 tevent_req_error(req, ret);
1804 return;
1805 }
1806
1807 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1808 if (!subreq) {
1809 tevent_req_error(req, ENOMEM);
1810 return;
1811 }
1812 tevent_req_set_callback(subreq, proxy_default_done, req);
1813 }
1814
1815 /* =Getgrgid-wrapper======================================================*/
1816
1817 static void get_gr_gid_process(struct tevent_req *subreq);
1818 static void get_gr_gid_remove_done(struct tevent_req *subreq);
1819
1820 static struct tevent_req *get_gr_gid_send(TALLOC_CTX *mem_ctx,
1821 struct tevent_context *ev,
1822 struct proxy_ctx *ctx,
1823 struct sysdb_ctx *sysdb,
1824 struct sss_domain_info *domain,
1825 gid_t gid)
1826 {
1827 struct tevent_req *req, *subreq;
1828 struct proxy_state *state;
1829
1830 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1831 if (!req) return NULL;
1832
1833 memset(state, 0, sizeof(struct proxy_state));
1834
1835 state->ev = ev;
1836 state->ctx = ctx;
1837 state->sysdb = sysdb;
1838 state->domain = domain;
1839 state->gid = gid;
1840
1841 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1842 if (!subreq) {
1843 talloc_zfree(req);
1844 return NULL;
1845 }
1846 tevent_req_set_callback(subreq, get_gr_gid_process, req);
1847
1848 return req;
1849 }
1850
1851 static void get_gr_gid_process(struct tevent_req *subreq)
1852 {
1853 struct tevent_req *req = tevent_req_callback_data(subreq,
1854 struct tevent_req);
1855 struct proxy_state *state = tevent_req_data(req,
1856 struct proxy_state);
1857 struct proxy_ctx *ctx = state->ctx;
1858 struct sss_domain_info *dom = ctx->be->domain;
1859 enum nss_status status;
1860 char *buffer;
1861 char *newbuf;
1862 size_t buflen;
1863 bool delete_group = false;
1864 struct sysdb_attrs *members;
1865 int ret;
1866
1867 DEBUG(7, ("Searching group by gid (%d)\n", state->gid));
1868
1869 ret = sysdb_transaction_recv(subreq, state, &state->handle);
1870 if (ret) {
1871 tevent_req_error(req, ret);
1872 return;
1873 }
1874 talloc_zfree(subreq);
1875
1876 state->grp = talloc(state, struct group);
1877 if (!state->grp) {
1878 tevent_req_error(req, ENOMEM);
1879 return;
1880 }
1881
1882 buflen = DEFAULT_BUFSIZE;
1883 buffer = talloc_size(state, buflen);
1884 if (!buffer) {
1885 tevent_req_error(req, ENOMEM);
1886 return;
1887 }
1888
1889 again:
1890 /* always zero out the group structure */
1891 memset(state->grp, 0, sizeof(struct group));
1892
1893 status = ctx->ops.getgrgid_r(state->gid, state->grp,
1894 buffer, buflen, &ret);
1895
1896 switch (status) {
1897 case NSS_STATUS_TRYAGAIN:
1898 /* buffer too small ? */
1899 if (buflen < MAX_BUF_SIZE) {
1900 buflen *= 2;
1901 }
1902 if (buflen > MAX_BUF_SIZE) {
1903 buflen = MAX_BUF_SIZE;
1904 }
1905 newbuf = talloc_realloc_size(state, buffer, buflen);
1906 if (!newbuf) {
1907 tevent_req_error(req, ENOMEM);
1908 return;
1909 }
1910 buffer = newbuf;
1911 goto again;
1912
1913 case NSS_STATUS_NOTFOUND:
1914
1915 DEBUG(7, ("Group %d not found.\n", state->gid));
1916 delete_group = true;
1917 break;
1918
1919 case NSS_STATUS_SUCCESS:
1920
1921 DEBUG(7, ("Group %d found (%s, %d)\n", state->gid,
1922 state->grp->gr_name, state->grp->gr_gid));
1923
1924 /* gid=0 is an invalid value */
1925 /* also check that the id is in the valid range for this domain */
1926 if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1927
1928 DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1929 state->grp->gr_name));
1930 delete_group = true;
1931 break;
1932 }
1933
1934 DEBUG_GR_MEM(7, state);
1935
1936 if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1937 members = sysdb_new_attrs(state);
1938 if (!members) {
1939 tevent_req_error(req, ENOMEM);
1940 return;
1941 }
1942 ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1943 state->domain->name,
1944 (const char **)state->grp->gr_mem);
1945 if (ret) {
1946 tevent_req_error(req, ret);
1947 return;
1948 }
1949 } else {
1950 members = NULL;
1951 }
1952
1953 subreq = sysdb_store_group_send(state, state->ev, state->handle,
1954 state->domain,
1955 state->grp->gr_name,
1956 state->grp->gr_gid,
1957 members,
1958 ctx->entry_cache_timeout);
1959 if (!subreq) {
1960 tevent_req_error(req, ENOMEM);
1961 return;
1962 }
1963 tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1964 return;
1965
1966 case NSS_STATUS_UNAVAIL:
1967 /* "remote" backend unavailable. Enter offline mode */
1968 tevent_req_error(req, ENXIO);
1969 return;
1970
1971 default:
1972 DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
1973 state->gid, status));
1974 tevent_req_error(req, EIO);
1975 return;
1976 }
1977
1978 if (delete_group) {
1979
1980 DEBUG(7, ("Group %d does not exist (or is invalid) on remote server,"
1981 " deleting!\n", state->gid));
1982
1983 subreq = sysdb_delete_group_send(state, state->ev,
1984 NULL, state->handle,
1985 state->domain,
1986 NULL, state->gid);
1987 if (!subreq) {
1988 tevent_req_error(req, ENOMEM);
1989 return;
1990 }
1991 tevent_req_set_callback(subreq, get_gr_gid_remove_done, req);
1992 }
1993 }
1994
1995 static void get_gr_gid_remove_done(struct tevent_req *subreq)
1996 {
1997 struct tevent_req *req = tevent_req_callback_data(subreq,
1998 struct tevent_req);
1999 struct proxy_state *state = tevent_req_data(req,
2000 struct proxy_state);
2001 int ret;
2002
2003 ret = sysdb_delete_group_recv(subreq);
2004 talloc_zfree(subreq);
2005 if (ret && ret != ENOENT) {
2006 tevent_req_error(req, ret);
2007 return;
2008 }
2009
2010 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
2011 if (!subreq) {
2012 tevent_req_error(req, ENOMEM);
2013 return;
2014 }
2015 tevent_req_set_callback(subreq, proxy_default_done, req);
2016 }
2017
2018 /* =Getgrent-wrapper======================================================*/
2019
2020 struct enum_groups_state {
2021 struct tevent_context *ev;
2022 struct proxy_ctx *ctx;
2023 struct sysdb_ctx *sysdb;
2024 struct sss_domain_info *domain;
2025 struct sysdb_handle *handle;
2026
2027 struct group *grp;
2028
2029 size_t buflen;
2030 char *buffer;
2031
2032 bool in_transaction;
2033 };
2034
2035 static void enum_groups_process(struct tevent_req *subreq);
2036
2037 static struct tevent_req *enum_groups_send(TALLOC_CTX *mem_ctx,
2038 struct tevent_context *ev,
2039 struct proxy_ctx *ctx,
2040 struct sysdb_ctx *sysdb,
2041 struct sss_domain_info *domain)
2042 {
2043 struct tevent_req *req, *subreq;
2044 struct enum_groups_state *state;
2045 enum nss_status status;
2046
2047 DEBUG(7, ("Enumerating groups\n"));
2048
2049 req = tevent_req_create(mem_ctx, &state, struct enum_groups_state);
2050 if (!req) return NULL;
2051
2052 state->ev = ev;
2053 state->ctx = ctx;
2054 state->sysdb = sysdb;
2055 state->domain = domain;
2056 state->handle = NULL;
2057
2058 state->grp = talloc(state, struct group);
2059 if (!state->grp) {
2060 tevent_req_error(req, ENOMEM);
2061 goto fail;
2062 }
2063
2064 state->buflen = DEFAULT_BUFSIZE;
2065 state->buffer = talloc_size(state, state->buflen);
2066 if (!state->buffer) {
2067 tevent_req_error(req, ENOMEM);
2068 goto fail;
2069 }
2070
2071 state->in_transaction = false;
2072
2073 status = ctx->ops.setgrent();
2074 if (status != NSS_STATUS_SUCCESS) {
2075 tevent_req_error(req, EIO);
2076 goto fail;
2077 }
2078
2079 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
2080 if (!subreq) {
2081 tevent_req_error(req, ENOMEM);
2082 goto fail;
2083 }
2084 tevent_req_set_callback(subreq, enum_groups_process, req);
2085
2086 return req;
2087
2088 fail:
2089 tevent_req_post(req, ev);
2090 return req;
2091 }
2092
2093 static void enum_groups_process(struct tevent_req *subreq)
2094 {
2095 struct tevent_req *req = tevent_req_callback_data(subreq,
2096 struct tevent_req);
2097 struct enum_groups_state *state = tevent_req_data(req,
2098 struct enum_groups_state);
2099 struct proxy_ctx *ctx = state->ctx;
2100 struct sss_domain_info *dom = ctx->be->domain;
2101 enum nss_status status;
2102 struct sysdb_attrs *members;
2103 char *newbuf;
2104 int ret;
2105
2106 if (!state->in_transaction) {
2107 ret = sysdb_transaction_recv(subreq, state, &state->handle);
2108 if (ret) {
2109 tevent_req_error(req, ret);
2110 return;
2111 }
2112 talloc_zfree(subreq);
2113
2114 state->in_transaction = true;
2115 } else {
2116 ret = sysdb_store_group_recv(subreq);
2117 if (ret) {
2118 /* Do not fail completely on errors.
2119 * Just report the failure to save and go on */
2120 DEBUG(2, ("Failed to store group. Ignoring.\n"));
2121 }
2122 talloc_zfree(subreq);
2123 }
2124
2125 again:
2126 /* always zero out the grp structure */
2127 memset(state->grp, 0, sizeof(struct group));
2128
2129 /* get entry */
2130 status = ctx->ops.getgrent_r(state->grp,
2131 state->buffer, state->buflen, &ret);
2132
2133 switch (status) {
2134 case NSS_STATUS_TRYAGAIN:
2135 /* buffer too small ? */
2136 if (state->buflen < MAX_BUF_SIZE) {
2137 state->buflen *= 2;
2138 }
2139 if (state->buflen > MAX_BUF_SIZE) {
2140 state->buflen = MAX_BUF_SIZE;
2141 }
2142 newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
2143 if (!newbuf) {
2144 ret = ENOMEM;
2145 goto fail;
2146 }
2147 state->buffer = newbuf;
2148 goto again;
2149
2150 case NSS_STATUS_NOTFOUND:
2151
2152 /* we are done here */
2153 DEBUG(7, ("Enumeration completed.\n"));
2154
2155 ctx->ops.endgrent();
2156 subreq = sysdb_transaction_commit_send(state, state->ev,
2157 state->handle);
2158 if (!subreq) {
2159 tevent_req_error(req, ENOMEM);
2160 return;
2161 }
2162 tevent_req_set_callback(subreq, proxy_default_done, req);
2163 return;
2164
2165 case NSS_STATUS_SUCCESS:
2166
2167 DEBUG(7, ("Group found (%s, %d)\n",
2168 state->grp->gr_name, state->grp->gr_gid));
2169
2170 /* gid=0 is an invalid value */
2171 /* also check that the id is in the valid range for this domain */
2172 if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
2173
2174 DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
2175 state->grp->gr_name));
2176
2177 goto again; /* skip */
2178 }
2179
2180 DEBUG_GR_MEM(7, state);
2181
2182 if (state->grp->gr_mem && state->grp->gr_mem[0]) {
2183 members = sysdb_new_attrs(state);
2184 if (!members) {
2185 tevent_req_error(req, ENOMEM);
2186 return;
2187 }
2188 ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
2189 state->domain->name,
2190 (const char **)state->grp->gr_mem);
2191 if (ret) {
2192 tevent_req_error(req, ret);
2193 return;
2194 }
2195 } else {
2196 members = NULL;
2197 }
2198
2199 subreq = sysdb_store_group_send(state, state->ev, state->handle,
2200 state->domain,
2201 state->grp->gr_name,
2202 state->grp->gr_gid,
2203 members,
2204 ctx->entry_cache_timeout);
2205 if (!subreq) {
2206 tevent_req_error(req, ENOMEM);
2207 return;
2208 }
2209 tevent_req_set_callback(subreq, enum_groups_process, req);
2210 return;
2211
2212 case NSS_STATUS_UNAVAIL:
2213 /* "remote" backend unavailable. Enter offline mode */
2214 ret = ENXIO;
2215 goto fail;
2216
2217 default:
2218 DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n",
2219 ret, strerror(ret)));
2220 goto fail;
2221 }
2222
2223 fail:
2224 ctx->ops.endgrent();
2225 tevent_req_error(req, ret);
2226 }
2227
2228
2229 /* =Initgroups-wrapper====================================================*/
2230
2231 static void get_initgr_process(struct tevent_req *subreq);
2232 static void get_initgr_groups_process(struct tevent_req *subreq);
2233 static void get_initgr_groups_done(struct tevent_req *subreq);
2234 static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
2235 struct tevent_context *ev,
2236 struct sysdb_handle *handle,
2237 struct proxy_ctx *ctx,
2238 struct sss_domain_info *domain,
2239 gid_t *gids, int num_gids);
2240 static int get_groups_by_gid_recv(struct tevent_req *req);
2241 static void get_groups_by_gid_process(struct tevent_req *subreq);
2242 static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
2243 struct tevent_context *ev,
2244 struct sysdb_handle *handle,
2245 struct proxy_ctx *ctx,
2246 struct sss_domain_info *domain,
2247 gid_t gid);
2248 static int get_group_from_gid_recv(struct tevent_req *req);
2249 static void get_group_from_gid_send_del_done(struct tevent_req *subreq);
2250 static void get_group_from_gid_send_add_done(struct tevent_req *subreq);
2251
2252
2253 static struct tevent_req *get_initgr_send(TALLOC_CTX *mem_ctx,
2254 struct tevent_context *ev,
2255 struct proxy_ctx *ctx,
2256 struct sysdb_ctx *sysdb,
2257 struct sss_domain_info *domain,
2258 const char *name)
2259 {
2260 struct tevent_req *req, *subreq;
2261 struct proxy_state *state;
2262
2263 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
2264 if (!req) return NULL;
2265
2266 memset(state, 0, sizeof(struct proxy_state));
2267
2268 state->ev = ev;
2269 state->ctx = ctx;
2270 state->sysdb = sysdb;
2271 state->domain = domain;
2272 state->name = name;
2273
2274 subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
2275 if (!subreq) {
2276 talloc_zfree(req);
2277 return NULL;
2278 }
2279 tevent_req_set_callback(subreq, get_initgr_process, req);
2280
2281 return req;
2282 }
2283
2284 static void get_initgr_process(struct tevent_req *subreq)
2285 {
2286 struct tevent_req *req = tevent_req_callback_data(subreq,
2287 struct tevent_req);
2288 struct proxy_state *state = tevent_req_data(req,
2289 struct proxy_state);
2290 struct proxy_ctx *ctx = state->ctx;
2291 struct sss_domain_info *dom = ctx->be->domain;
2292 enum nss_status status;
2293 char *buffer;
2294 size_t buflen;
2295 bool delete_user = false;
2296 int ret;
2297
2298 ret = sysdb_transaction_recv(subreq, state, &state->handle);
2299 if (ret) {
2300 tevent_req_error(req, ret);
2301 return;
2302 }
2303 talloc_zfree(subreq);
2304
2305 state->pwd = talloc(state, struct passwd);
2306 if (!state->pwd) {
2307 tevent_req_error(req, ENOMEM);
2308 return;
2309 }
2310
2311 buflen = DEFAULT_BUFSIZE;
2312 buffer = talloc_size(state, buflen);
2313 if (!buffer) {
2314 tevent_req_error(req, ENOMEM);
2315 return;
2316 }
2317
2318 /* FIXME: should we move this call outside the transaction to keep the
2319 * transaction as short as possible ? */
2320 status = ctx->ops.getpwnam_r(state->name, state->pwd,
2321 buffer, buflen, &ret);
2322
2323 switch (status) {
2324 case NSS_STATUS_NOTFOUND:
2325
2326 delete_user = true;
2327 break;
2328
2329 case NSS_STATUS_SUCCESS:
2330
2331 /* uid=0 or gid=0 are invalid values */
2332 /* also check that the id is in the valid range for this domain */
2333 if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
2334 OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
2335
2336 DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
2337 state->name));
2338 delete_user = true;
2339 break;
2340 }
2341
2342 subreq = sysdb_store_user_send(state, state->ev, state->handle,
2343 state->domain,
2344 state->pwd->pw_name,
2345 state->pwd->pw_passwd,
2346 state->pwd->pw_uid,
2347 state->pwd->pw_gid,
2348 state->pwd->pw_gecos,
2349 state->pwd->pw_dir,
2350 state->pwd->pw_shell,
2351 NULL, ctx->entry_cache_timeout);
2352 if (!subreq) {
2353 tevent_req_error(req, ENOMEM);
2354 return;
2355 }
2356 tevent_req_set_callback(subreq, get_initgr_groups_process, req);
2357 return;
2358
2359 case NSS_STATUS_UNAVAIL:
2360 /* "remote" backend unavailable. Enter offline mode */
2361 tevent_req_error(req, ENXIO);
2362 return;
2363
2364 default:
2365 DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
2366 state->name, status));
2367 tevent_req_error(req, EIO);
2368 return;
2369 }
2370
2371 if (delete_user) {
2372 struct ldb_dn *dn;
2373
2374 dn = sysdb_user_dn(state->sysdb, state,
2375 state->domain->name, state->name);
2376 if (!dn) {
2377 tevent_req_error(req, ENOMEM);
2378 return;
2379 }
2380
2381 subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
2382 if (!subreq) {
2383 tevent_req_error(req, ENOMEM);
2384 return;
2385 }
2386 tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
2387 }
2388 }
2389
2390 static void get_initgr_groups_process(struct tevent_req *subreq)
2391 {
2392 struct tevent_req *req = tevent_req_callback_data(subreq,
2393 struct tevent_req);
2394 struct proxy_state *state = tevent_req_data(req,
2395 struct proxy_state);
2396 struct proxy_ctx *ctx = state->ctx;
2397 enum nss_status status;
2398 long int limit;
2399 long int size;
2400 long int num;
2401 long int num_gids;
2402 gid_t *gids;
2403 int ret;
2404
2405 ret = sysdb_store_user_recv(subreq);
2406 if (ret) {
2407 tevent_req_error(req, ret);
2408 return;
2409 }
2410 talloc_zfree(subreq);
2411
2412 num_gids = 0;
2413 limit = 4096;
2414 num = 4096;
2415 size = num*sizeof(gid_t);
2416 gids = talloc_size(state, size);
2417 if (!gids) {
2418 tevent_req_error(req, ENOMEM);
2419 return;
2420 }
2421
2422 state->gid = state->pwd->pw_gid;
2423
2424 again:
2425 /* FIXME: should we move this call outside the transaction to keep the
2426 * transaction as short as possible ? */
2427 status = ctx->ops.initgroups_dyn(state->name, state->gid, &num_gids,
2428 &num, &gids, limit, &ret);
2429 switch (status) {
2430 case NSS_STATUS_TRYAGAIN:
2431 /* buffer too small ? */
2432 if (size < MAX_BUF_SIZE) {
2433 num *= 2;
2434 size = num*sizeof(gid_t);
2435 }
2436 if (size > MAX_BUF_SIZE) {
2437 size = MAX_BUF_SIZE;
2438 num = size/sizeof(gid_t);
2439 }
2440 limit = num;
2441 gids = talloc_realloc_size(state, gids, size);
2442 if (!gids) {
2443 tevent_req_error(req, ENOMEM);
2444 return;
2445 }
2446 goto again; /* retry with more memory */
2447
2448 case NSS_STATUS_SUCCESS:
2449 DEBUG(4, ("User [%s] appears to be member of %lu groups\n",
2450 state->name, num_gids));
2451
2452 subreq = get_groups_by_gid_send(state, state->ev, state->handle,
2453 state->ctx, state->domain,
2454 gids, num_gids);
2455 if (!subreq) {
2456 tevent_req_error(req, ENOMEM);
2457 return;
2458 }
2459 tevent_req_set_callback(subreq, get_initgr_groups_done, req);
2460 break;
2461
2462 default:
2463 DEBUG(2, ("proxy -> initgroups_dyn failed (%d)[%s]\n",
2464 ret, strerror(ret)));
2465 tevent_req_error(req, EIO);
2466 return;
2467 }
2468 }
2469
2470 static void get_initgr_groups_done(struct tevent_req *subreq)
2471 {
2472 struct tevent_req *req = tevent_req_callback_data(subreq,
2473 struct tevent_req);
2474 struct proxy_state *state = tevent_req_data(req,
2475 struct proxy_state);
2476 int ret;
2477
2478 ret = get_groups_by_gid_recv(subreq);
2479 talloc_zfree(subreq);
2480 if (ret) {
2481 tevent_req_error(req, ret);
2482 return;
2483 }
2484
2485 subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
2486 if (!subreq) {
2487 tevent_req_error(req, ENOMEM);
2488 return;
2489 }
2490 tevent_req_set_callback(subreq, proxy_default_done, req);
2491 }
2492
2493 struct get_groups_state {
2494 struct tevent_context *ev;
2495 struct sysdb_handle *handle;
2496 struct proxy_ctx *ctx;
2497 struct sss_domain_info *domain;
2498
2499 gid_t *gids;
2500 int num_gids;
2501 int cur_gid;
2502 };
2503
2504 static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
2505 struct tevent_context *ev,
2506 struct sysdb_handle *handle,
2507 struct proxy_ctx *ctx,
2508 struct sss_domain_info *domain,
2509 gid_t *gids, int num_gids)
2510 {
2511 struct tevent_req *req, *subreq;
2512 struct get_groups_state *state;
2513
2514 req = tevent_req_create(mem_ctx, &state, struct get_groups_state);
2515 if (!req) return NULL;
2516
2517 state->ev = ev;
2518 state->handle = handle;
2519 state->ctx = ctx;
2520 state->domain = domain;
2521 state->gids = gids;
2522 state->num_gids = num_gids;
2523 state->cur_gid = 0;
2524
2525 subreq = get_group_from_gid_send(state, ev, handle, ctx, domain, gids[0]);
2526 if (!subreq) {
2527 talloc_zfree(req);
2528 return NULL;
2529 }
2530 tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
2531
2532 return req;
2533 }
2534
2535 static void get_groups_by_gid_process(struct tevent_req *subreq)
2536 {
2537 struct tevent_req *req = tevent_req_callback_data(subreq,
2538 struct tevent_req);
2539 struct get_groups_state *state = tevent_req_data(req,
2540 struct get_groups_state);
2541 int ret;
2542
2543 ret = get_group_from_gid_recv(subreq);
2544 talloc_zfree(subreq);
2545 if (ret) {
2546 tevent_req_error(req, ret);
2547 return;
2548 }
2549
2550 state->cur_gid++;
2551 if (state->cur_gid >= state->num_gids) {
2552 tevent_req_done(req);
2553 return;
2554 }
2555
2556 subreq = get_group_from_gid_send(state,
2557 state->ev, state->handle,
2558 state->ctx, state->domain,
2559 state->gids[state->cur_gid]);
2560 if (!subreq) {
2561 tevent_req_error(req, ENOMEM);
2562 return;
2563 }
2564 tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
2565 }
2566
2567 static int get_groups_by_gid_recv(struct tevent_req *req)
2568 {
2569 TEVENT_REQ_RETURN_ON_ERROR(req);
2570
2571 return EOK;
2572 }
2573
2574 static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
2575 struct tevent_context *ev,
2576 struct sysdb_handle *handle,
2577 struct proxy_ctx *ctx,
2578 struct sss_domain_info *domain,
2579 gid_t gid)
2580 {
2581 struct tevent_req *req, *subreq;
2582 struct proxy_state *state;
2583 struct sss_domain_info *dom = ctx->be->domain;
2584 enum nss_status status;
2585 char *buffer;
2586 char *newbuf;
2587 size_t buflen;
2588 bool delete_group = false;
2589 struct sysdb_attrs *members;
2590 int ret;
2591
2592 req = tevent_req_create(mem_ctx, &state, struct proxy_state);
2593 if (!req) return NULL;
2594
2595 memset(state, 0, sizeof(struct proxy_state));
2596
2597 state->ev = ev;
2598 state->handle = handle;
2599 state->ctx = ctx;
2600 state->domain = domain;
2601 state->gid = gid;
2602
2603 state->grp = talloc(state, struct group);
2604 if (!state->grp) {
2605 ret = ENOMEM;
2606 goto fail;
2607 }
2608
2609 buflen = DEFAULT_BUFSIZE;
2610 buffer = talloc_size(state, buflen);
2611 if (!buffer) {
2612 ret = ENOMEM;
2613 goto fail;
2614 }
2615
2616 again:
2617 /* always zero out the grp structure */
2618 memset(state->grp, 0, sizeof(struct group));
2619
2620 status = ctx->ops.getgrgid_r(state->gid, state->grp,
2621 buffer, buflen, &ret);
2622
2623 switch (status) {
2624 case NSS_STATUS_TRYAGAIN:
2625 /* buffer too small ? */
2626 if (buflen < MAX_BUF_SIZE) {
2627 buflen *= 2;
2628 }
2629 if (buflen > MAX_BUF_SIZE) {
2630 buflen = MAX_BUF_SIZE;
2631 }
2632 newbuf = talloc_realloc_size(state, buffer, buflen);
2633 if (!newbuf) {
2634 ret = ENOMEM;
2635 goto fail;
2636 }
2637 buffer = newbuf;
2638 goto again;
2639
2640 case NSS_STATUS_NOTFOUND:
2641
2642 delete_group = true;
2643 break;
2644
2645 case NSS_STATUS_SUCCESS:
2646
2647 /* gid=0 is an invalid value */
2648 /* also check that the id is in the valid range for this domain */
2649 if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
2650
2651 DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
2652 state->grp->gr_name));
2653 delete_group = true;
2654 break;
2655 }
2656
2657 if (state->grp->gr_mem && state->grp->gr_mem[0]) {
2658 members = sysdb_new_attrs(state);
2659 if (!members) {
2660 ret = ENOMEM;
2661 goto fail;
2662 }
2663 ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
2664 state->domain->name,
2665 (const char **)state->grp->gr_mem);
2666 if (ret) {
2667 goto fail;
2668 }
2669 } else {
2670 members = NULL;
2671 }
2672
2673 subreq = sysdb_store_group_send(state, state->ev, state->handle,
2674 state->domain,
2675 state->grp->gr_name,
2676 state->grp->gr_gid,
2677 members,
2678 ctx->entry_cache_timeout);
2679 if (!subreq) {
2680 ret = ENOMEM;
2681 goto fail;
2682 }
2683 tevent_req_set_callback(subreq, get_group_from_gid_send_add_done, req);
2684 break;
2685
2686 case NSS_STATUS_UNAVAIL:
2687 /* "remote" backend unavailable. Enter offline mode */
2688 ret = ENXIO;
2689 goto fail;
2690
2691 default:
2692 DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
2693 state->gid, status));
2694 ret = EIO;
2695 goto fail;
2696 }
2697
2698 if (delete_group) {
2699 subreq = sysdb_delete_group_send(state, state->ev,
2700 NULL, state->handle,
2701 state->domain,
2702 NULL, state->gid);
2703 if (!subreq) {
2704 ret = ENOMEM;
2705 goto fail;
2706 }
2707 tevent_req_set_callback(subreq, get_group_from_gid_send_del_done, req);
2708 }
2709
2710 return req;
2711
2712 fail:
2713 tevent_req_error(req, ret);
2714 tevent_req_post(req, ev);
2715 return req;
2716 }
2717
2718 static void get_group_from_gid_send_add_done(struct tevent_req *subreq)
2719 {
2720 struct tevent_req *req = tevent_req_callback_data(subreq,
2721 struct tevent_req);
2722 int ret;
2723
2724 ret = sysdb_store_group_recv(subreq);
2725 talloc_zfree(subreq);
2726 if (ret) {
2727 tevent_req_error(req, ret);
2728 return;
2729 }
2730
2731 tevent_req_done(req);
2732 }
2733
2734 static void get_group_from_gid_send_del_done(struct tevent_req *subreq)
2735 {
2736 struct tevent_req *req = tevent_req_callback_data(subreq,
2737 struct tevent_req);
2738 int ret;
2739
2740 ret = sysdb_delete_group_recv(subreq);
2741 talloc_zfree(subreq);
2742 if (ret && ret != ENOENT) {
2743 tevent_req_error(req, ret);
2744 return;
2745 }
2746
2747 tevent_req_done(req);
2748 }
2749
2750 static int get_group_from_gid_recv(struct tevent_req *req)
2751 {
2752 TEVENT_REQ_RETURN_ON_ERROR(req);
2753
2754 return EOK;
2755 }
2756
2757
2758 /* =Proxy_Id-Functions====================================================*/
2759
2760 static void proxy_get_account_info_done(struct tevent_req *subreq);
2761
2762 /* TODO: See if we can use async_req code */
2763 static void proxy_get_account_info(struct be_req *breq)
2764 {
2765 struct tevent_req *subreq;
2766 struct be_acct_req *ar;
2767 struct proxy_ctx *ctx;
2768 struct tevent_context *ev;
2769 struct sysdb_ctx *sysdb;
2770 struct sss_domain_info *domain;
2771 uid_t uid;
2772 gid_t gid;
2773
2774 ar = talloc_get_type(breq->req_data, struct be_acct_req);
2775 ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct proxy_ctx);
2776 ev = breq->be_ctx->ev;
2777 sysdb = breq->be_ctx->sysdb;
2778 domain = breq->be_ctx->domain;
2779
2780 if (be_is_offline(breq->be_ctx)) {
2781 return proxy_reply(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
2782 }
2783
2784 /* for now we support only core attrs */
2785 if (ar->attr_type != BE_ATTR_CORE) {
2786 return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
2787 }
2788
2789 switch (ar->entry_type & 0xFFF) {
2790 case BE_REQ_USER: /* user */
2791 switch (ar->filter_type) {
2792 case BE_FILTER_NAME:
2793 if (strchr(ar->filter_value, '*')) {
2794 subreq = enum_users_send(breq, ev, ctx,
2795 sysdb, domain);
2796 if (!subreq) {
2797 return proxy_reply(breq, DP_ERR_FATAL,
2798 ENOMEM, "Out of memory");
2799 }
2800 tevent_req_set_callback(subreq,
2801 proxy_get_account_info_done, breq);
2802 return;
2803 } else {
2804 subreq = get_pw_name_send(breq, ev, ctx,
2805 sysdb, domain,
2806 ar->filter_value);
2807 if (!subreq) {
2808 return proxy_reply(breq, DP_ERR_FATAL,
2809 ENOMEM, "Out of memory");
2810 }
2811 tevent_req_set_callback(subreq,
2812 proxy_get_account_info_done, breq);
2813 return;
2814 }
2815 break;
2816
2817 case BE_FILTER_IDNUM:
2818 if (strchr(ar->filter_value, '*')) {
2819 return proxy_reply(breq, DP_ERR_FATAL,
2820 EINVAL, "Invalid attr type");
2821 } else {
2822 char *endptr;
2823 errno = 0;
2824 uid = (uid_t)strtol(ar->filter_value, &endptr, 0);
2825 if (errno || *endptr || (ar->filter_value == endptr)) {
2826 return proxy_reply(breq, DP_ERR_FATAL,
2827 EINVAL, "Invalid attr type");
2828 }
2829 subreq = get_pw_uid_send(breq, ev, ctx,
2830 sysdb, domain, uid);
2831 if (!subreq) {
2832 return proxy_reply(breq, DP_ERR_FATAL,
2833 ENOMEM, "Out of memory");
2834 }
2835 tevent_req_set_callback(subreq,
2836 proxy_get_account_info_done, breq);
2837 return;
2838 }
2839 break;
2840 default:
2841 return proxy_reply(breq, DP_ERR_FATAL,
2842 EINVAL, "Invalid filter type");
2843 }
2844 break;
2845
2846 case BE_REQ_GROUP: /* group */
2847 switch (ar->filter_type) {
2848 case BE_FILTER_NAME:
2849 if (strchr(ar->filter_value, '*')) {
2850 subreq = enum_groups_send(breq, ev, ctx,
2851 sysdb, domain);
2852 if (!subreq) {
2853 return proxy_reply(breq, DP_ERR_FATAL,
2854 ENOMEM, "Out of memory");
2855 }
2856 tevent_req_set_callback(subreq,
2857 proxy_get_account_info_done, breq);
2858 return;
2859 } else {
2860 subreq = get_gr_name_send(breq, ev, ctx,
2861 sysdb, domain,
2862 ar->filter_value);
2863 if (!subreq) {
2864 return proxy_reply(breq, DP_ERR_FATAL,
2865 ENOMEM, "Out of memory");
2866 }
2867 tevent_req_set_callback(subreq,
2868 proxy_get_account_info_done, breq);
2869 return;
2870 }
2871 break;
2872 case BE_FILTER_IDNUM:
2873 if (strchr(ar->filter_value, '*')) {
2874 return proxy_reply(breq, DP_ERR_FATAL,
2875 EINVAL, "Invalid attr type");
2876 } else {
2877 char *endptr;
2878 errno = 0;
2879 gid = (gid_t)strtol(ar->filter_value, &endptr, 0);
2880 if (errno || *endptr || (ar->filter_value == endptr)) {
2881 return proxy_reply(breq, DP_ERR_FATAL,
2882 EINVAL, "Invalid attr type");
2883 }
2884 subreq = get_gr_gid_send(breq, ev, ctx,
2885 sysdb, domain, gid);
2886 if (!subreq) {
2887 return proxy_reply(breq, DP_ERR_FATAL,
2888 ENOMEM, "Out of memory");
2889 }
2890 tevent_req_set_callback(subreq,
2891 proxy_get_account_info_done, breq);
2892 return;
2893 }
2894 break;
2895 default:
2896 return proxy_reply(breq, DP_ERR_FATAL,
2897 EINVAL, "Invalid filter type");
2898 }
2899 break;
2900
2901 case BE_REQ_INITGROUPS: /* init groups for user */
2902 if (ar->filter_type != BE_FILTER_NAME) {
2903 return proxy_reply(breq, DP_ERR_FATAL,
2904 EINVAL, "Invalid filter type");
2905 }
2906 if (strchr(ar->filter_value, '*')) {
2907 return proxy_reply(breq, DP_ERR_FATAL,
2908 EINVAL, "Invalid filter value");
2909 }
2910 if (ctx->ops.initgroups_dyn == NULL) {
2911 return proxy_reply(breq, DP_ERR_FATAL,
2912 ENODEV, "Initgroups call not supported");
2913 }
2914 subreq = get_initgr_send(breq, ev, ctx, sysdb,
2915 domain, ar->filter_value);
2916 if (!subreq) {
2917 return proxy_reply(breq, DP_ERR_FATAL,
2918 ENOMEM, "Out of memory");
2919 }
2920 tevent_req_set_callback(subreq,
2921 proxy_get_account_info_done, breq);
2922 return;
2923
2924 default: /*fail*/
2925 break;
2926 }
2927
2928 return proxy_reply(breq, DP_ERR_FATAL,
2929 EINVAL, "Invalid request type");
2930 }
2931
2932 static void proxy_get_account_info_done(struct tevent_req *subreq)
2933 {
2934 struct be_req *breq = tevent_req_callback_data(subreq,
2935 struct be_req);
2936 int ret;
2937 ret = proxy_default_recv(subreq);
2938 talloc_zfree(subreq);
2939 if (ret) {
2940 if (ret == ENXIO) {
2941 DEBUG(2, ("proxy returned UNAVAIL error, going offline!\n"));
2942 be_mark_offline(breq->be_ctx);
2943 }
2944 proxy_reply(breq, DP_ERR_FATAL, ret, NULL);
2945 return;
2946 }
2947 proxy_reply(breq, DP_ERR_OK, EOK, NULL);
2948 }
2949
2950 static void proxy_shutdown(struct be_req *req)
2951 {
2952 /* TODO: Clean up any internal data */
2953 req->fn(req, DP_ERR_OK, EOK, NULL);
2954 }
2955
2956 static void proxy_auth_shutdown(struct be_req *req)
2957 {
2958 talloc_free(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data);
2959 req->fn(req, DP_ERR_OK, EOK, NULL);
2960 }
2961
2962 struct bet_ops proxy_id_ops = {
2963 .handler = proxy_get_account_info,
2964 .finalize = proxy_shutdown
2965 };
2966
2967 struct bet_ops proxy_auth_ops = {
2968 .handler = proxy_pam_handler,
2969 .finalize = proxy_auth_shutdown
2970 };
2971
2972 struct bet_ops proxy_access_ops = {
2973 .handler = proxy_pam_handler,
2974 .finalize = proxy_auth_shutdown
2975 };
2976
2977 struct bet_ops proxy_chpass_ops = {
2978 .handler = proxy_pam_handler,
2979 .finalize = proxy_auth_shutdown
2980 };
2981
Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle". Event noescape: "proxy_dlsym" does not free or save its pointer parameter "handle".
|
2982 static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
2983 {
2984 char *funcname;
2985 void *funcptr;
2986
2987 funcname = talloc_asprintf(NULL, functemp, libname);
2988 if (funcname == NULL) return NULL;
2989
2990 funcptr = dlsym(handle, funcname);
2991 talloc_free(funcname);
2992
2993 return funcptr;
2994 }
2995
2996 int sssm_proxy_id_init(struct be_ctx *bectx,
2997 struct bet_ops **ops, void **pvt_data)
2998 {
2999 struct proxy_ctx *ctx;
3000 char *libname;
3001 char *libpath;
3002 void *handle;
3003 int ret;
3004
3005 ctx = talloc_zero(bectx, struct proxy_ctx);
3006 if (!ctx) {
3007 return ENOMEM;
3008 }
3009 ctx->be = bectx;
3010
3011 ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path,
3012 CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT, 600,
3013 &ctx->entry_cache_timeout);
3014 if (ret != EOK) goto done;
3015
3016 ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
3017 CONFDB_PROXY_LIBNAME, NULL, &libname);
3018 if (ret != EOK) goto done;
3019 if (libname == NULL) {
3020 ret = ENOENT;
3021 goto done;
3022 }
3023
3024 libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname);
3025 if (!libpath) {
3026 ret = ENOMEM;
3027 goto done;
3028 }
3029
3030 handle = dlopen(libpath, RTLD_NOW);
At conditional (1): "!handle": Taking false branch.
|
3031 if (!handle) {
3032 DEBUG(0, ("Unable to load %s module with path, error: %s\n",
3033 libpath, dlerror()));
3034 ret = ELIBACC;
3035 goto done;
3036 }
3037
3038 ctx->ops.getpwnam_r = proxy_dlsym(handle, "_nss_%s_getpwnam_r", libname);
At conditional (2): "!ctx->ops.getpwnam_r": Taking true branch.
|
3039 if (!ctx->ops.getpwnam_r) {
At conditional (3): "0 <= debug_level": Taking true branch.
At conditional (4): "debug_timestamps": Taking true branch.
| |
3040 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3041 ret = ELIBBAD;
3042 goto done;
3043 }
3044
3045 ctx->ops.getpwuid_r = proxy_dlsym(handle, "_nss_%s_getpwuid_r", libname);
3046 if (!ctx->ops.getpwuid_r) {
3047 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3048 ret = ELIBBAD;
3049 goto done;
3050 }
3051
3052 ctx->ops.setpwent = proxy_dlsym(handle, "_nss_%s_setpwent", libname);
3053 if (!ctx->ops.setpwent) {
3054 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3055 ret = ELIBBAD;
3056 goto done;
3057 }
3058
3059 ctx->ops.getpwent_r = proxy_dlsym(handle, "_nss_%s_getpwent_r", libname);
3060 if (!ctx->ops.getpwent_r) {
3061 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3062 ret = ELIBBAD;
3063 goto done;
3064 }
3065
3066 ctx->ops.endpwent = proxy_dlsym(handle, "_nss_%s_endpwent", libname);
3067 if (!ctx->ops.endpwent) {
3068 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3069 ret = ELIBBAD;
3070 goto done;
3071 }
3072
3073 ctx->ops.getgrnam_r = proxy_dlsym(handle, "_nss_%s_getgrnam_r", libname);
3074 if (!ctx->ops.getgrnam_r) {
3075 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3076 ret = ELIBBAD;
3077 goto done;
3078 }
3079
3080 ctx->ops.getgrgid_r = proxy_dlsym(handle, "_nss_%s_getgrgid_r", libname);
3081 if (!ctx->ops.getgrgid_r) {
3082 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3083 ret = ELIBBAD;
3084 goto done;
3085 }
3086
3087 ctx->ops.setgrent = proxy_dlsym(handle, "_nss_%s_setgrent", libname);
3088 if (!ctx->ops.setgrent) {
3089 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3090 ret = ELIBBAD;
3091 goto done;
3092 }
3093
3094 ctx->ops.getgrent_r = proxy_dlsym(handle, "_nss_%s_getgrent_r", libname);
3095 if (!ctx->ops.getgrent_r) {
3096 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3097 ret = ELIBBAD;
3098 goto done;
3099 }
3100
3101 ctx->ops.endgrent = proxy_dlsym(handle, "_nss_%s_endgrent", libname);
3102 if (!ctx->ops.endgrent) {
3103 DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
3104 ret = ELIBBAD;
3105 goto done;
3106 }
3107
3108 ctx->ops.initgroups_dyn = proxy_dlsym(handle, "_nss_%s_initgroups_dyn",
3109 libname);
3110 if (!ctx->ops.initgroups_dyn) {
3111 DEBUG(1, ("The '%s' library does not provides the "
3112 "_nss_XXX_initgroups_dyn function!\n"
3113 "initgroups will be slow as it will require "
3114 "full groups enumeration!\n", libname));
3115 }
3116
3117 *ops = &proxy_id_ops;
3118 *pvt_data = ctx;
3119 ret = EOK;
3120
3121 done:
At conditional (5): "ret != 0": Taking true branch.
|
3122 if (ret != EOK) {
3123 talloc_free(ctx);
3124 }
3125 return ret;
3126 }
3127
3128 struct proxy_client {
3129 struct proxy_auth_ctx *proxy_auth_ctx;
3130 struct sbus_connection *conn;
3131 struct tevent_timer *timeout;
3132 bool initialized;
3133 };
3134
3135 static void init_timeout(struct tevent_context *ev,
3136 struct tevent_timer *te,
3137 struct timeval t, void *ptr);
3138 static int proxy_client_init(struct sbus_connection *conn, void *data)
3139 {
3140 struct proxy_auth_ctx *proxy_auth_ctx;
3141 struct proxy_client *proxy_cli;
3142 struct timeval tv;
3143
3144 proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
3145
3146 /* hang off this memory to the connection so that when the connection
3147 * is freed we can potentially call a destructor */
3148
3149 proxy_cli = talloc_zero(conn, struct proxy_client);
3150 if (!proxy_cli) {
3151 DEBUG(0,("Out of memory?!\n"));
3152 talloc_zfree(conn);
3153 return ENOMEM;
3154 }
3155 proxy_cli->proxy_auth_ctx = proxy_auth_ctx;
3156 proxy_cli->conn = conn;
3157 proxy_cli->initialized = false;
3158
3159 /* 5 seconds should be plenty */
3160 tv = tevent_timeval_current_ofs(5, 0);
3161
3162 proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,
3163 tv, init_timeout, proxy_cli);
3164 if (!proxy_cli->timeout) {
3165 DEBUG(0,("Out of memory?!\n"));
3166 talloc_zfree(conn);
3167 return ENOMEM;
3168 }
3169 DEBUG(4, ("Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout));
3170
3171 /* Attach the client context to the connection context, so that it is
3172 * always available when we need to manage the connection. */
3173 sbus_conn_set_private_data(conn, proxy_cli);
3174
3175 return EOK;
3176 }
3177
3178 static void init_timeout(struct tevent_context *ev,
3179 struct tevent_timer *te,
3180 struct timeval t, void *ptr)
3181 {
3182 struct proxy_client *proxy_cli;
3183
3184 DEBUG(2, ("Client timed out before Identification [%p]!\n", te));
3185
3186 proxy_cli = talloc_get_type(ptr, struct proxy_client);
3187
3188 sbus_disconnect(proxy_cli->conn);
3189 talloc_zfree(proxy_cli);
3190
3191 /* If we time out here, we will also time out to
3192 * pc_init_timeout(), so we'll finish the request
3193 * there.
3194 */
3195 }
3196
3197 static int client_registration(DBusMessage *message,
3198 struct sbus_connection *conn)
3199 {
3200 dbus_uint16_t version = DATA_PROVIDER_VERSION;
3201 struct proxy_client *proxy_cli;
3202 DBusMessage *reply;
3203 DBusError dbus_error;
3204 dbus_uint16_t cli_ver;
3205 uint32_t cli_id;
3206 dbus_bool_t dbret;
3207 void *data;
3208 int hret;
3209 hash_key_t key;
3210 hash_value_t value;
3211 struct tevent_req *req;
3212 struct proxy_child_ctx *child_ctx;
3213 struct pc_init_ctx *init_ctx;
3214
3215 data = sbus_conn_get_private_data(conn);
3216 proxy_cli = talloc_get_type(data, struct proxy_client);
3217 if (!proxy_cli) {
3218 DEBUG(0, ("Connection holds no valid init data\n"));
3219 return EINVAL;
3220 }
3221
3222 /* First thing, cancel the timeout */
3223 DEBUG(4, ("Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout));
3224 talloc_zfree(proxy_cli->timeout);
3225
3226 dbus_error_init(&dbus_error);
3227
3228 dbret = dbus_message_get_args(message, &dbus_error,
3229 DBUS_TYPE_UINT16, &cli_ver,
3230 DBUS_TYPE_UINT32, &cli_id,
3231 DBUS_TYPE_INVALID);
3232 if (!dbret) {
3233 DEBUG(1, ("Failed to parse message, killing connection\n"));
3234 if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
3235 sbus_disconnect(conn);
3236 /* FIXME: should we just talloc_zfree(conn) ? */
3237 return EIO;
3238 }
3239
3240 DEBUG(4, ("Proxy client [%ld] connected\n", cli_id));
3241
3242 /* Check the hash table */
3243 key.type = HASH_KEY_ULONG;
3244 key.ul = cli_id;
3245 if (!hash_has_key(proxy_cli->proxy_auth_ctx->request_table, &key)) {
3246 DEBUG(1, ("Unknown child ID. Killing the connection\n"));
3247 sbus_disconnect(proxy_cli->conn);
3248 return EIO;
3249 }
3250
3251 /* reply that all is ok */
3252 reply = dbus_message_new_method_return(message);
3253 if (!reply) {
3254 DEBUG(0, ("Dbus Out of memory!\n"));
3255 return ENOMEM;
3256 }
3257
3258 dbret = dbus_message_append_args(reply,
3259 DBUS_TYPE_UINT16, &version,
3260 DBUS_TYPE_INVALID);
3261 if (!dbret) {
3262 DEBUG(0, ("Failed to build dbus reply\n"));
3263 dbus_message_unref(reply);
3264 sbus_disconnect(conn);
3265 return EIO;
3266 }
3267
3268 /* send reply back */
3269 sbus_conn_send_reply(conn, reply);
3270 dbus_message_unref(reply);
3271
3272 hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
3273 if (hret != HASH_SUCCESS) {
3274 DEBUG(1, ("Hash error [%d][%s]\n", hret, hash_error_string(hret)));
3275 sbus_disconnect(conn);
3276 }
3277
3278 /* Signal that the child is up and ready to receive the request */
3279 req = talloc_get_type(value.ptr, struct tevent_req);
3280 child_ctx = tevent_req_data(req, struct proxy_child_ctx);
3281
3282 if (!child_ctx->running) {
3283 /* This should hopefully be impossible, but protect
3284 * against it anyway. If we're not marked running, then
3285 * the init_req will be NULL below and things will
3286 * break.
3287 */
3288 DEBUG(1, ("Client connection from a request "
3289 "that's not marked as running\n"));
3290 return EIO;
3291 }
3292
3293 init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);
3294 init_ctx->conn = conn;
3295 tevent_req_done(child_ctx->init_req);
3296 child_ctx->init_req = NULL;
3297
3298 return EOK;
3299 }
3300
3301 int sssm_proxy_auth_init(struct be_ctx *bectx,
3302 struct bet_ops **ops, void **pvt_data)
3303 {
3304 struct proxy_auth_ctx *ctx;
3305 int ret;
3306 int hret;
3307 char *sbus_address;
3308
3309 /* If we're already set up, just return that */
3310 if(bectx->bet_info[BET_AUTH].mod_name &&
3311 strcmp("proxy", bectx->bet_info[BET_AUTH].mod_name) == 0) {
3312 DEBUG(8, ("Re-using proxy_auth_ctx for this provider\n"));
3313 *ops = bectx->bet_info[BET_AUTH].bet_ops;
3314 *pvt_data = bectx->bet_info[BET_AUTH].pvt_bet_data;
3315 return EOK;
3316 }
3317
3318 ctx = talloc_zero(bectx, struct proxy_auth_ctx);
3319 if (!ctx) {
3320 return ENOMEM;
3321 }
3322 ctx->be = bectx;
3323 ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT/4;
3324 ctx->next_id = 1;
3325
3326 ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
3327 CONFDB_PROXY_PAM_TARGET, NULL,
3328 &ctx->pam_target);
3329 if (ret != EOK) goto done;
3330 if (!ctx->pam_target) {
3331 DEBUG(1, ("Missing option proxy_pam_target.\n"));
3332 ret = EINVAL;
3333 goto done;
3334 }
3335
3336 sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s", PIPE_PATH,
3337 PROXY_CHILD_PIPE, bectx->domain->name);
3338 if (sbus_address == NULL) {
3339 DEBUG(1, ("talloc_asprintf failed.\n"));
3340 ret = ENOMEM;
3341 goto done;
3342 }
3343
3344 ret = sbus_new_server(ctx, bectx->ev, sbus_address, &proxy_interface,
3345 &ctx->sbus_srv, proxy_client_init, ctx);
3346 if (ret != EOK) {
3347 DEBUG(0, ("Could not set up sbus server.\n"));
3348 goto done;
3349 }
3350
3351 /* Set up request hash table */
3352 /* FIXME: get max_children from configuration file */
3353 ctx->max_children = 10;
3354
3355 hret = hash_create(ctx->max_children * 2, &ctx->request_table,
3356 NULL, NULL);
3357 if (hret != HASH_SUCCESS) {
3358 DEBUG(0, ("Could not initialize request table\n"));
3359 ret = EIO;
3360 goto done;
3361 }
3362
3363 *ops = &proxy_auth_ops;
3364 *pvt_data = ctx;
3365
3366 done:
3367 if (ret != EOK) {
3368 talloc_free(ctx);
3369 }
3370 return ret;
3371 }
3372
3373 int sssm_proxy_access_init(struct be_ctx *bectx,
3374 struct bet_ops **ops, void **pvt_data)
3375 {
3376 int ret;
3377 ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
3378 *ops = &proxy_access_ops;
3379 return ret;
3380 }
3381
3382 int sssm_proxy_chpass_init(struct be_ctx *bectx,
3383 struct bet_ops **ops, void **pvt_data)
3384 {
3385 int ret;
3386 ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
3387 *ops = &proxy_chpass_ops;
3388 return ret;
3389 }