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);
Event returned_pointer: Pointer "state" returned by "_talloc_get_type_abort(_tevent_req_data(req), &"struct pc_init_ctx", &"providers/proxy/proxy.c:470")" is never used.
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 	
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);
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);
3039 	    if (!ctx->ops.getpwnam_r) {
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:
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 	}