1    	/*
2    	   SSSD
3    	
4    	   Data Provider Process
5    	
6    	   Copyright (C) Simo Sorce <ssorce@redhat.com>	2008
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 <stdio.h>
23   	#include <unistd.h>
24   	#include <fcntl.h>
25   	#include <sys/types.h>
26   	#include <sys/stat.h>
27   	#include <sys/socket.h>
28   	#include <sys/un.h>
29   	#include <string.h>
30   	#include <sys/time.h>
31   	#include <errno.h>
32   	#include <dlfcn.h>
33   	
34   	#include <security/pam_appl.h>
35   	#include <security/pam_modules.h>
36   	
37   	#include "popt.h"
38   	#include "util/util.h"
39   	#include "confdb/confdb.h"
40   	#include "db/sysdb.h"
41   	#include "dbus/dbus.h"
42   	#include "sbus/sssd_dbus.h"
43   	#include "providers/dp_backend.h"
44   	#include "providers/fail_over.h"
45   	#include "resolv/async_resolv.h"
46   	#include "monitor/monitor_interfaces.h"
47   	
48   	#define MSG_TARGET_NO_CONFIGURED "sssd_be: The requested target is not configured"
49   	
50   	#define ACCESS_PERMIT "permit"
51   	#define ACCESS_DENY "deny"
52   	#define NO_PROVIDER "none"
53   	
54   	static int data_provider_res_init(DBusMessage *message,
55   	                                  struct sbus_connection *conn);
56   	static int data_provider_go_offline(DBusMessage *message,
57   	                                    struct sbus_connection *conn);
58   	
59   	struct sbus_method monitor_be_methods[] = {
60   	    { MON_CLI_METHOD_PING, monitor_common_pong },
61   	    { MON_CLI_METHOD_RES_INIT, data_provider_res_init },
62   	    { MON_CLI_METHOD_OFFLINE, data_provider_go_offline },
63   	    { MON_CLI_METHOD_ROTATE, monitor_common_rotate_logs },
64   	    { NULL, NULL }
65   	};
66   	
67   	struct sbus_interface monitor_be_interface = {
68   	    MONITOR_INTERFACE,
69   	    MONITOR_PATH,
70   	    SBUS_DEFAULT_VTABLE,
71   	    monitor_be_methods,
72   	    NULL
73   	};
74   	
75   	static int client_registration(DBusMessage *message, struct sbus_connection *conn);
76   	static int be_check_online(DBusMessage *message, struct sbus_connection *conn);
77   	static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn);
78   	static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn);
79   	
80   	struct sbus_method be_methods[] = {
81   	    { DP_METHOD_REGISTER, client_registration },
82   	    { DP_METHOD_ONLINE, be_check_online },
83   	    { DP_METHOD_GETACCTINFO, be_get_account_info },
84   	    { DP_METHOD_PAMHANDLER, be_pam_handler },
85   	    { NULL, NULL }
86   	};
87   	
88   	struct sbus_interface be_interface = {
89   	    DP_INTERFACE,
90   	    DP_PATH,
91   	    SBUS_DEFAULT_VTABLE,
92   	    be_methods,
93   	    NULL
94   	};
95   	
96   	static struct bet_data bet_data[] = {
97   	    {BET_NULL, NULL, NULL},
98   	    {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_id_init"},
99   	    {BET_AUTH, CONFDB_DOMAIN_AUTH_PROVIDER, "sssm_%s_auth_init"},
100  	    {BET_ACCESS, CONFDB_DOMAIN_ACCESS_PROVIDER, "sssm_%s_access_init"},
101  	    {BET_CHPASS, CONFDB_DOMAIN_CHPASS_PROVIDER, "sssm_%s_chpass_init"},
102  	    {BET_MAX, NULL, NULL}
103  	};
104  	
105  	struct be_async_req {
106  	    be_req_fn_t fn;
107  	    struct be_req *req;
108  	};
109  	
110  	static void be_async_req_handler(struct tevent_context *ev,
111  	                                 struct tevent_timer *te,
112  	                                 struct timeval tv, void *pvt)
113  	{
114  	    struct be_async_req *async_req;
115  	
116  	    async_req = talloc_get_type(pvt, struct be_async_req);
117  	
118  	    async_req->fn(async_req->req);
119  	}
120  	
121  	static int be_file_request(struct be_ctx *ctx,
122  	                           be_req_fn_t fn,
123  	                           struct be_req *req)
124  	{
125  	    struct be_async_req *areq;
126  	    struct tevent_timer *te;
127  	    struct timeval tv;
128  	
129  	    if (!fn || !req) return EINVAL;
130  	
131  	    areq = talloc(req, struct be_async_req);
132  	    if (!areq) {
133  	        return ENOMEM;
134  	    }
135  	    areq->fn = fn;
136  	    areq->req = req;
137  	
138  	    /* fire immediately */
139  	    tv.tv_sec = 0;
140  	    tv.tv_usec = 0;
141  	
142  	    te = tevent_add_timer(ctx->ev, req, tv, be_async_req_handler, areq);
143  	    if (te == NULL) {
144  	        return EIO;
145  	    }
146  	
147  	    return EOK;
148  	}
149  	
150  	bool be_is_offline(struct be_ctx *ctx)
151  	{
152  	    time_t now = time(NULL);
153  	
154  	    /* check if we are past the offline blackout timeout */
155  	    /* FIXME: get offline_timeout from configuration */
156  	    if (ctx->offstat.went_offline + 60 < now) {
157  	        ctx->offstat.offline = false;
158  	    }
159  	
160  	    return ctx->offstat.offline;
161  	}
162  	
163  	void be_mark_offline(struct be_ctx *ctx)
164  	{
165  	    DEBUG(8, ("Going offline!\n"));
166  	
167  	    ctx->offstat.went_offline = time(NULL);
168  	    ctx->offstat.offline = true;
169  	    ctx->run_online_cb = true;
170  	    be_run_offline_cb(ctx);
171  	}
172  	
173  	static int be_check_online(DBusMessage *message, struct sbus_connection *conn)
174  	{
175  	    struct be_client *becli;
176  	    DBusMessage *reply;
177  	    DBusConnection *dbus_conn;
178  	    dbus_bool_t dbret;
179  	    void *user_data;
180  	    dbus_uint16_t online;
181  	    dbus_uint16_t err_maj = 0;
182  	    dbus_uint32_t err_min = 0;
183  	    static const char *err_msg = "Success";
184  	
185  	    user_data = sbus_conn_get_private_data(conn);
186  	    if (!user_data) return EINVAL;
187  	    becli = talloc_get_type(user_data, struct be_client);
188  	    if (!becli) return EINVAL;
189  	
190  	    reply = dbus_message_new_method_return(message);
191  	    if (!reply) return ENOMEM;
192  	
193  	    if (be_is_offline(becli->bectx)) {
194  	        online = MOD_OFFLINE;
195  	    } else {
196  	        online = MOD_ONLINE;
197  	    }
198  	
199  	    dbret = dbus_message_append_args(reply,
200  	                                     DBUS_TYPE_UINT16, &online,
201  	                                     DBUS_TYPE_UINT16, &err_maj,
202  	                                     DBUS_TYPE_UINT32, &err_min,
203  	                                     DBUS_TYPE_STRING, &err_msg,
204  	                                     DBUS_TYPE_INVALID);
205  	    if (!dbret) {
206  	        DEBUG(1, ("Failed to generate dbus reply\n"));
207  	        return EIO;
208  	    }
209  	
210  	    dbus_conn = sbus_get_connection(becli->conn);
211  	    dbus_connection_send(dbus_conn, reply, NULL);
212  	    dbus_message_unref(reply);
213  	
214  	    DEBUG(4, ("Request processed. Returned %d,%d,%s\n",
215  	              err_maj, err_min, err_msg));
216  	
217  	    return EOK;
218  	}
219  	
220  	static char *dp_err_to_string(TALLOC_CTX *memctx, int dp_err_type, int errnum)
221  	{
222  	    switch (dp_err_type) {
223  	    case DP_ERR_OK:
224  	        return talloc_strdup(memctx, "Success");
225  	        break;
226  	
227  	    case DP_ERR_OFFLINE:
228  	        return talloc_asprintf(memctx,
229  	                               "Provider is Offline (%s)",
230  	                               strerror(errnum));
231  	        break;
232  	
233  	    case DP_ERR_TIMEOUT:
234  	        return talloc_asprintf(memctx,
235  	                               "Request timed out (%s)",
236  	                               strerror(errnum));
237  	        break;
238  	
239  	    case DP_ERR_FATAL:
240  	    default:
241  	        return talloc_asprintf(memctx,
242  	                               "Internal Error (%s)",
243  	                               strerror(errnum));
244  	        break;
245  	    }
246  	
247  	    return NULL;
248  	}
249  	
250  	
251  	static void acctinfo_callback(struct be_req *req,
252  	                              int dp_err_type,
253  	                              int errnum,
254  	                              const char *errstr)
255  	{
256  	    DBusMessage *reply;
257  	    DBusConnection *dbus_conn;
258  	    dbus_bool_t dbret;
259  	    dbus_uint16_t err_maj = 0;
260  	    dbus_uint32_t err_min = 0;
261  	    const char *err_msg = NULL;
262  	
263  	    reply = (DBusMessage *)req->pvt;
264  	
265  	    if (reply) {
266  	        /* Return a reply if one was requested
267  	         * There may not be one if this request began
268  	         * while we were offline
269  	         */
270  	
271  	        err_maj = dp_err_type;
272  	        err_min = errnum;
273  	        if (errstr) {
274  	            err_msg = errstr;
275  	        } else {
276  	            err_msg = dp_err_to_string(req, dp_err_type, errnum);
277  	        }
278  	        if (!err_msg) {
279  	            DEBUG(1, ("Failed to set err_msg, Out of memory?\n"));
280  	            err_msg = "OOM";
281  	        }
282  	
283  	        dbret = dbus_message_append_args(reply,
284  	                                         DBUS_TYPE_UINT16, &err_maj,
285  	                                         DBUS_TYPE_UINT32, &err_min,
286  	                                         DBUS_TYPE_STRING, &err_msg,
287  	                                         DBUS_TYPE_INVALID);
288  	        if (!dbret) {
289  	            DEBUG(1, ("Failed to generate dbus reply\n"));
290  	            return;
291  	        }
292  	
293  	        dbus_conn = sbus_get_connection(req->becli->conn);
294  	        dbus_connection_send(dbus_conn, reply, NULL);
295  	        dbus_message_unref(reply);
296  	
297  	        DEBUG(4, ("Request processed. Returned %d,%d,%s\n",
298  	                  err_maj, err_min, err_msg));
299  	    }
300  	
301  	    /* finally free the request */
302  	    talloc_free(req);
303  	}
304  	
305  	static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn)
306  	{
307  	    struct be_acct_req *req;
308  	    struct be_req *be_req;
309  	    struct be_client *becli;
310  	    DBusMessage *reply;
311  	    DBusError dbus_error;
312  	    dbus_bool_t dbret;
313  	    void *user_data;
314  	    uint32_t type;
315  	    char *filter;
316  	    int filter_type;
317  	    uint32_t attr_type;
318  	    char *filter_val;
319  	    int ret;
320  	    dbus_uint16_t err_maj;
321  	    dbus_uint32_t err_min;
322  	    const char *err_msg;
323  	
324  	    be_req = NULL;
325  	
326  	    user_data = sbus_conn_get_private_data(conn);
327  	    if (!user_data) return EINVAL;
328  	    becli = talloc_get_type(user_data, struct be_client);
329  	    if (!becli) return EINVAL;
330  	
331  	    dbus_error_init(&dbus_error);
332  	
333  	    ret = dbus_message_get_args(message, &dbus_error,
334  	                                DBUS_TYPE_UINT32, &type,
335  	                                DBUS_TYPE_UINT32, &attr_type,
336  	                                DBUS_TYPE_STRING, &filter,
337  	                                DBUS_TYPE_INVALID);
338  	    if (!ret) {
339  	        DEBUG(1,("Failed, to parse message!\n"));
340  	        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
341  	        return EIO;
342  	    }
343  	
344  	    DEBUG(4, ("Got request for [%u][%d][%s]\n", type, attr_type, filter));
345  	
346  	    reply = dbus_message_new_method_return(message);
347  	    if (!reply) return ENOMEM;
348  	
349  	    /* If we are offline and fast reply was requested
350  	     * return offline immediately
351  	     */
352  	    if ((type & BE_REQ_FAST) && becli->bectx->offstat.offline) {
353  	        /* Send back an immediate reply */
354  	        err_maj = DP_ERR_OFFLINE;
355  	        err_min = EAGAIN;
356  	        err_msg = "Fast reply - offline";
357  	
358  	        dbret = dbus_message_append_args(reply,
359  	                                         DBUS_TYPE_UINT16, &err_maj,
360  	                                         DBUS_TYPE_UINT32, &err_min,
361  	                                         DBUS_TYPE_STRING, &err_msg,
362  	                                         DBUS_TYPE_INVALID);
363  	        if (!dbret) return EIO;
364  	
365  	        DEBUG(4, ("Request processed. Returned %d,%d,%s\n",
366  	                  err_maj, err_min, err_msg));
367  	
368  	        sbus_conn_send_reply(conn, reply);
369  	        dbus_message_unref(reply);
370  	        reply = NULL;
371  	        /* This reply will be queued and sent
372  	         * when we reenter the mainloop.
373  	         *
374  	         * Continue processing in case we are
375  	         * going back online.
376  	         */
377  	    }
378  	
379  	    if ((attr_type != BE_ATTR_CORE) &&
380  	        (attr_type != BE_ATTR_MEM) &&
381  	        (attr_type != BE_ATTR_ALL)) {
382  	        /* Unrecognized attr type */
383  	        err_maj = DP_ERR_FATAL;
384  	        err_min = EINVAL;
385  	        err_msg = "Invalid Attrs Parameter";
386  	        goto done;
387  	    }
388  	
389  	    if (filter) {
390  	        if (strncmp(filter, "name=", 5) == 0) {
391  	            filter_type = BE_FILTER_NAME;
392  	            filter_val = &filter[5];
393  	        } else if (strncmp(filter, "idnumber=", 9) == 0) {
394  	            filter_type = BE_FILTER_IDNUM;
395  	            filter_val = &filter[9];
396  	        } else {
397  	            err_maj = DP_ERR_FATAL;
398  	            err_min = EINVAL;
399  	            err_msg = "Invalid Filter";
400  	            goto done;
401  	        }
402  	    } else {
403  	        err_maj = DP_ERR_FATAL;
404  	        err_min = EINVAL;
405  	        err_msg = "Missing Filter Parameter";
406  	        goto done;
407  	    }
408  	
409  	    /* process request */
410  	    be_req = talloc_zero(becli, struct be_req);
411  	    if (!be_req) {
412  	        err_maj = DP_ERR_FATAL;
413  	        err_min = ENOMEM;
414  	        err_msg = "Out of memory";
415  	        goto done;
416  	    }
417  	    be_req->becli = becli;
418  	    be_req->be_ctx = becli->bectx;
419  	    be_req->fn = acctinfo_callback;
420  	    be_req->pvt = reply;
421  	
422  	    req = talloc(be_req, struct be_acct_req);
423  	    if (!req) {
424  	        err_maj = DP_ERR_FATAL;
425  	        err_min = ENOMEM;
426  	        err_msg = "Out of memory";
427  	        goto done;
428  	    }
429  	    req->entry_type = type;
430  	    req->attr_type = (int)attr_type;
431  	    req->filter_type = filter_type;
432  	    req->filter_value = talloc_strdup(req, filter_val);
433  	
434  	    be_req->req_data = req;
435  	
436  	    ret = be_file_request(becli->bectx,
437  	                          becli->bectx->bet_info[BET_ID].bet_ops->handler,
438  	                          be_req);
439  	    if (ret != EOK) {
440  	        err_maj = DP_ERR_FATAL;
441  	        err_min = ret;
442  	        err_msg = "Failed to file request";
443  	        goto done;
444  	    }
445  	
446  	    return EOK;
447  	
448  	done:
449  	    if (be_req) {
450  	        talloc_free(be_req);
451  	    }
452  	
453  	    if (reply) {
454  	        dbret = dbus_message_append_args(reply,
455  	                                         DBUS_TYPE_UINT16, &err_maj,
456  	                                         DBUS_TYPE_UINT32, &err_min,
457  	                                         DBUS_TYPE_STRING, &err_msg,
458  	                                         DBUS_TYPE_INVALID);
459  	        if (!dbret) return EIO;
460  	
461  	        DEBUG(4, ("Request processed. Returned %d,%d,%s\n",
462  	                  err_maj, err_min, err_msg));
463  	
464  	        /* send reply back */
465  	        sbus_conn_send_reply(conn, reply);
466  	        dbus_message_unref(reply);
467  	    }
468  	
469  	    return EOK;
470  	}
471  	
472  	static void be_pam_handler_callback(struct be_req *req,
473  	                                    int dp_err_type,
474  	                                    int errnum,
475  	                                    const char *errstr)
476  	{
477  	    struct pam_data *pd;
478  	    DBusMessage *reply;
479  	    DBusConnection *dbus_conn;
480  	    dbus_bool_t dbret;
481  	
482  	    DEBUG(4, ("Backend returned: (%d, %d, %s) [%s]\n",
483  	              dp_err_type, errnum, errstr?errstr:"<NULL>",
484  	              dp_err_to_string(req, dp_err_type, errnum)));
485  	
486  	    pd = talloc_get_type(req->req_data, struct pam_data);
487  	
488  	    DEBUG(4, ("Sending result [%d][%s]\n", pd->pam_status, pd->domain));
489  	    reply = (DBusMessage *)req->pvt;
490  	    dbret = dp_pack_pam_response(reply, pd);
491  	    if (!dbret) {
492  	        DEBUG(1, ("Failed to generate dbus reply\n"));
493  	        dbus_message_unref(reply);
494  	        return;
495  	    }
496  	
497  	    dbus_conn = sbus_get_connection(req->becli->conn);
498  	    dbus_connection_send(dbus_conn, reply, NULL);
499  	    dbus_message_unref(reply);
500  	
501  	    DEBUG(4, ("Sent result [%d][%s]\n", pd->pam_status, pd->domain));
502  	
503  	    talloc_free(req);
504  	}
505  	
506  	static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn)
507  	{
508  	    DBusError dbus_error;
509  	    DBusMessage *reply;
510  	    struct be_client *becli;
511  	    dbus_bool_t ret;
512  	    void *user_data;
Event assign_zero: Assigning: "pd" = 0.
Also see events: [var_deref_op][var_deref_model]
513  	    struct pam_data *pd = NULL;
514  	    struct be_req *be_req = NULL;
515  	    enum bet_type target = BET_NULL;
516  	
517  	    user_data = sbus_conn_get_private_data(conn);
At conditional (1): "!user_data": Taking false branch.
518  	    if (!user_data) return EINVAL;
519  	    becli = talloc_get_type(user_data, struct be_client);
At conditional (2): "!becli": Taking false branch.
520  	    if (!becli) return EINVAL;
521  	
522  	    reply = dbus_message_new_method_return(message);
At conditional (3): "!reply": Taking false branch.
523  	    if (!reply) {
524  	        DEBUG(1, ("dbus_message_new_method_return failed, cannot send reply.\n"));
525  	        return ENOMEM;
526  	    }
527  	
528  	    be_req = talloc_zero(becli, struct be_req);
At conditional (4): "!be_req": Taking true branch.
529  	    if (!be_req) {
At conditional (5): "7 <= debug_level": Taking true branch.
At conditional (6): "debug_timestamps": Taking true branch.
530  	        DEBUG(7, ("talloc_zero failed.\n"));
531  	        goto done;
532  	    }
533  	
534  	    be_req->becli = becli;
535  	    be_req->be_ctx = becli->bectx;
536  	    be_req->fn = be_pam_handler_callback;
537  	    be_req->pvt = reply;
538  	
539  	    dbus_error_init(&dbus_error);
540  	
541  	    ret = dp_unpack_pam_request(message, be_req, &pd, &dbus_error);
542  	    if (!ret) {
543  	        DEBUG(1,("Failed, to parse message!\n"));
544  	        talloc_free(be_req);
545  	        return EIO;
546  	    }
547  	
548  	    pd->pam_status = PAM_SYSTEM_ERR;
549  	    pd->domain = talloc_strdup(pd, becli->bectx->domain->name);
550  	    if (pd->domain == NULL) {
551  	        talloc_free(be_req);
552  	        return ENOMEM;
553  	    }
554  	
555  	
556  	    DEBUG(4, ("Got request with the following data\n"));
557  	    DEBUG_PAM_DATA(4, pd);
558  	
559  	    switch (pd->cmd) {
560  	        case SSS_PAM_AUTHENTICATE:
561  	            target = BET_AUTH;
562  	            break;
563  	        case SSS_PAM_ACCT_MGMT:
564  	            target = BET_ACCESS;
565  	            break;
566  	        case SSS_PAM_CHAUTHTOK:
567  	        case SSS_PAM_CHAUTHTOK_PRELIM:
568  	            target = BET_CHPASS;
569  	            break;
570  	        case SSS_PAM_SETCRED:
571  	        case SSS_PAM_OPEN_SESSION:
572  	        case SSS_PAM_CLOSE_SESSION:
573  	            pd->pam_status = PAM_SUCCESS;
574  	            goto done;
575  	            break;
576  	        default:
577  	            DEBUG(7, ("Unsupported PAM command [%d].\n", pd->cmd));
578  	            pd->pam_status = PAM_MODULE_UNKNOWN;
579  	            goto done;
580  	    }
581  	
582  	    /* return an error if corresponding backend target is not configured */
583  	    if (!becli->bectx->bet_info[target].bet_ops) {
584  	        DEBUG(7, ("Undefined backend target.\n"));
585  	        pd->pam_status = PAM_MODULE_UNKNOWN;
586  	        ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
587  	                               sizeof(MSG_TARGET_NO_CONFIGURED),
588  	                               (const uint8_t *) MSG_TARGET_NO_CONFIGURED);
589  	        if (ret != EOK) {
590  	            DEBUG(1, ("pam_add_response failed.\n"));
591  	        }
592  	        goto done;
593  	    }
594  	
595  	    be_req->req_data = pd;
596  	
597  	    ret = be_file_request(becli->bectx,
598  	                          becli->bectx->bet_info[target].bet_ops->handler,
599  	                          be_req);
600  	    if (ret != EOK) {
601  	        DEBUG(7, ("be_file_request failed.\n"));
602  	        goto done;
603  	    }
604  	
605  	    return EOK;
606  	
607  	done:
608  	
Event var_deref_op: Dereferencing null variable "pd".
Also see events: [assign_zero][var_deref_model]
At conditional (7): "4 <= debug_level": Taking true branch.
At conditional (8): "debug_timestamps": Taking true branch.
609  	    DEBUG(4, ("Sending result [%d][%s]\n",
610  	              pd->pam_status, pd->domain));
611  	
Event var_deref_model: Passing null variable "pd" to function "dp_pack_pam_response", which dereferences it. [model]
Also see events: [assign_zero][var_deref_op]
612  	    ret = dp_pack_pam_response(reply, pd);
613  	    if (!ret) {
614  	        DEBUG(1, ("Failed to generate dbus reply\n"));
615  	        talloc_free(be_req);
616  	        dbus_message_unref(reply);
617  	        return EIO;
618  	    }
619  	
620  	    /* send reply back immediately */
621  	    sbus_conn_send_reply(conn, reply);
622  	    dbus_message_unref(reply);
623  	
624  	    talloc_free(be_req);
625  	
626  	    return EOK;
627  	}
628  	
629  	static int be_client_destructor(void *ctx)
630  	{
631  	    struct be_client *becli = talloc_get_type(ctx, struct be_client);
632  	    if (becli->bectx) {
633  	        if (becli->bectx->nss_cli == becli) {
634  	            DEBUG(4, ("Removed NSS client\n"));
635  	            becli->bectx->nss_cli = NULL;
636  	        } else if (becli->bectx->pam_cli == becli) {
637  	            DEBUG(4, ("Removed PAM client\n"));
638  	            becli->bectx->pam_cli = NULL;
639  	        } else {
640  	            DEBUG(2, ("Unknown client removed ...\n"));
641  	        }
642  	    }
643  	    return 0;
644  	}
645  	
646  	static int client_registration(DBusMessage *message,
647  	                               struct sbus_connection *conn)
648  	{
649  	    dbus_uint16_t version = DATA_PROVIDER_VERSION;
650  	    struct be_client *becli;
651  	    DBusMessage *reply;
652  	    DBusError dbus_error;
653  	    dbus_uint16_t cli_ver;
654  	    char *cli_name;
655  	    dbus_bool_t dbret;
656  	    void *data;
657  	
658  	    data = sbus_conn_get_private_data(conn);
659  	    becli = talloc_get_type(data, struct be_client);
660  	    if (!becli) {
661  	        DEBUG(0, ("Connection holds no valid init data\n"));
662  	        return EINVAL;
663  	    }
664  	
665  	    /* First thing, cancel the timeout */
666  	    DEBUG(4, ("Cancel DP ID timeout [%p]\n", becli->timeout));
667  	    talloc_zfree(becli->timeout);
668  	
669  	    dbus_error_init(&dbus_error);
670  	
671  	    dbret = dbus_message_get_args(message, &dbus_error,
672  	                                  DBUS_TYPE_UINT16, &cli_ver,
673  	                                  DBUS_TYPE_STRING, &cli_name,
674  	                                  DBUS_TYPE_INVALID);
675  	    if (!dbret) {
676  	        DEBUG(1, ("Failed to parse message, killing connection\n"));
677  	        if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
678  	        sbus_disconnect(conn);
679  	        /* FIXME: should we just talloc_zfree(conn) ? */
680  	        return EIO;
681  	    }
682  	
683  	    if (strcasecmp(cli_name, "NSS") == 0) {
684  	        becli->bectx->nss_cli = becli;
685  	    } else if (strcasecmp(cli_name, "PAM") == 0) {
686  	        becli->bectx->pam_cli = becli;
687  	    } else {
688  	        DEBUG(1, ("Unknown client! [%s]\n", cli_name));
689  	    }
690  	    talloc_set_destructor((TALLOC_CTX *)becli, be_client_destructor);
691  	
692  	    DEBUG(4, ("Added Frontend client [%s]\n", cli_name));
693  	
694  	    /* reply that all is ok */
695  	    reply = dbus_message_new_method_return(message);
696  	    if (!reply) {
697  	        DEBUG(0, ("Dbus Out of memory!\n"));
698  	        return ENOMEM;
699  	    }
700  	
701  	    dbret = dbus_message_append_args(reply,
702  	                                     DBUS_TYPE_UINT16, &version,
703  	                                     DBUS_TYPE_INVALID);
704  	    if (!dbret) {
705  	        DEBUG(0, ("Failed to build dbus reply\n"));
706  	        dbus_message_unref(reply);
707  	        sbus_disconnect(conn);
708  	        return EIO;
709  	    }
710  	
711  	    /* send reply back */
712  	    sbus_conn_send_reply(conn, reply);
713  	    dbus_message_unref(reply);
714  	
715  	    becli->initialized = true;
716  	    return EOK;
717  	}
718  	
719  	static void init_timeout(struct tevent_context *ev,
720  	                         struct tevent_timer *te,
721  	                         struct timeval t, void *ptr)
722  	{
723  	    struct be_client *becli;
724  	
725  	    DEBUG(2, ("Client timed out before Identification [%p]!\n", te));
726  	
727  	    becli = talloc_get_type(ptr, struct be_client);
728  	
729  	    sbus_disconnect(becli->conn);
730  	    talloc_zfree(becli);
731  	}
732  	
733  	static int be_client_init(struct sbus_connection *conn, void *data)
734  	{
735  	    struct be_ctx *bectx;
736  	    struct be_client *becli;
737  	    struct timeval tv;
738  	
739  	    bectx = talloc_get_type(data, struct be_ctx);
740  	
741  	    /* hang off this memory to the connection so that when the connection
742  	     * is freed we can potentially call a destructor */
743  	
744  	    becli = talloc(conn, struct be_client);
745  	    if (!becli) {
746  	        DEBUG(0,("Out of memory?!\n"));
747  	        talloc_zfree(conn);
748  	        return ENOMEM;
749  	    }
750  	    becli->bectx = bectx;
751  	    becli->conn = conn;
752  	    becli->initialized = false;
753  	
754  	    /* 5 seconds should be plenty */
755  	    tv = tevent_timeval_current_ofs(5, 0);
756  	
757  	    becli->timeout = tevent_add_timer(bectx->ev, becli,
758  	                                      tv, init_timeout, becli);
759  	    if (!becli->timeout) {
760  	        DEBUG(0,("Out of memory?!\n"));
761  	        talloc_zfree(conn);
762  	        return ENOMEM;
763  	    }
764  	    DEBUG(4, ("Set-up Backend ID timeout [%p]\n", becli->timeout));
765  	
766  	    /* Attach the client context to the connection context, so that it is
767  	     * always available when we need to manage the connection. */
768  	    sbus_conn_set_private_data(conn, becli);
769  	
770  	    return EOK;
771  	}
772  	
773  	/* be_srv_init
774  	 * set up per-domain sbus channel */
775  	static int be_srv_init(struct be_ctx *ctx)
776  	{
777  	    char *sbus_address;
778  	    int ret;
779  	
780  	    /* Set up SBUS connection to the monitor */
781  	    ret = dp_get_sbus_address(ctx, &sbus_address, ctx->domain->name);
782  	    if (ret != EOK) {
783  	        DEBUG(0, ("Could not get sbus backend address.\n"));
784  	        return ret;
785  	    }
786  	
787  	    ret = sbus_new_server(ctx, ctx->ev, sbus_address,
788  	                          &be_interface, &ctx->sbus_srv,
789  	                          be_client_init, ctx);
790  	    if (ret != EOK) {
791  	        DEBUG(0, ("Could not set up sbus server.\n"));
792  	        return ret;
793  	    }
794  	
795  	    return EOK;
796  	}
797  	
798  	/* mon_cli_init
799  	 * sbus channel to the monitor daemon */
800  	static int mon_cli_init(struct be_ctx *ctx)
801  	{
802  	    char *sbus_address;
803  	    int ret;
804  	
805  	    /* Set up SBUS connection to the monitor */
806  	    ret = monitor_get_sbus_address(ctx, &sbus_address);
807  	    if (ret != EOK) {
808  	        DEBUG(0, ("Could not locate monitor address.\n"));
809  	        return ret;
810  	    }
811  	
812  	    ret = sbus_client_init(ctx, ctx->ev, sbus_address,
813  	                           &monitor_be_interface, &ctx->mon_conn,
814  	                           NULL, ctx);
815  	    if (ret != EOK) {
816  	        DEBUG(0, ("Failed to connect to monitor services.\n"));
817  	        return ret;
818  	    }
819  	
820  	    /* Identify ourselves to the monitor */
821  	    ret = monitor_common_send_id(ctx->mon_conn,
822  	                                 ctx->identity,
823  	                                 DATA_PROVIDER_VERSION);
824  	    if (ret != EOK) {
825  	        DEBUG(0, ("Failed to identify to the monitor!\n"));
826  	        return ret;
827  	    }
828  	
829  	    return EOK;
830  	}
831  	
832  	static void be_target_access_permit(struct be_req *be_req)
833  	{
834  	    struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data);
835  	    DEBUG(9, ("be_target_access_permit called, returning PAM_SUCCESS.\n"));
836  	
837  	    pd->pam_status = PAM_SUCCESS;
838  	    be_req->fn(be_req, DP_ERR_OK, PAM_SUCCESS, NULL);
839  	}
840  	
841  	static struct bet_ops be_target_access_permit_ops = {
842  	    .check_online = NULL,
843  	    .handler = be_target_access_permit,
844  	    .finalize = NULL
845  	};
846  	
847  	static void be_target_access_deny(struct be_req *be_req)
848  	{
849  	    struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data);
850  	    DEBUG(9, ("be_target_access_deny called, returning PAM_PERM_DENIED.\n"));
851  	
852  	    pd->pam_status = PAM_PERM_DENIED;
853  	    be_req->fn(be_req, DP_ERR_OK, PAM_PERM_DENIED, NULL);
854  	}
855  	
856  	static struct bet_ops be_target_access_deny_ops = {
857  	    .check_online = NULL,
858  	    .handler = be_target_access_deny,
859  	    .finalize = NULL
860  	};
861  	
862  	static int load_backend_module(struct be_ctx *ctx,
863  	                               enum bet_type bet_type,
864  	                               struct bet_info *bet_info,
865  	                               const char *default_mod_name)
866  	{
867  	    TALLOC_CTX *tmp_ctx;
868  	    int ret = EINVAL;
869  	    bool already_loaded = false;
870  	    int lb=0;
871  	    char *mod_name = NULL;
872  	    char *path = NULL;
873  	    void *handle;
874  	    char *mod_init_fn_name = NULL;
875  	    bet_init_fn_t mod_init_fn = NULL;
876  	
877  	    (*bet_info).mod_name = NULL;
878  	    (*bet_info).bet_ops = NULL;
879  	    (*bet_info).pvt_bet_data = NULL;
880  	
881  	    if (bet_type <= BET_NULL || bet_type >= BET_MAX ||
882  	        bet_type != bet_data[bet_type].bet_type) {
883  	        DEBUG(2, ("invalid bet_type or bet_data corrupted.\n"));
884  	        return EINVAL;
885  	    }
886  	
887  	    tmp_ctx = talloc_new(ctx);
888  	    if (!tmp_ctx) {
889  	        DEBUG(7, ("talloc_new failed.\n"));
890  	        return ENOMEM;
891  	    }
892  	
893  	    ret = confdb_get_string(ctx->cdb, tmp_ctx, ctx->conf_path,
894  	                            bet_data[bet_type].option_name, NULL,
895  	                            &mod_name);
896  	    if (ret != EOK) {
897  	        ret = EFAULT;
898  	        goto done;
899  	    }
900  	    if (!mod_name) {
901  	        if (default_mod_name != NULL) {
902  	            DEBUG(5, ("no module name found in confdb, using [%s].\n",
903  	                      default_mod_name));
904  	            mod_name = talloc_strdup(ctx, default_mod_name);
905  	        } else {
906  	            ret = ENOENT;
907  	            goto done;
908  	        }
909  	    }
910  	
911  	    if (strcasecmp(mod_name, NO_PROVIDER) == 0) {
912  	        ret = ENOENT;
913  	        goto done;
914  	    }
915  	
916  	    if (bet_type == BET_ACCESS) {
917  	        if (strcmp(mod_name, ACCESS_PERMIT) == 0) {
918  	            (*bet_info).bet_ops = &be_target_access_permit_ops;
919  	            (*bet_info).pvt_bet_data = NULL;
920  	            (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_PERMIT);
921  	
922  	            ret = EOK;
923  	            goto done;
924  	        }
925  	        if (strcmp(mod_name, ACCESS_DENY) == 0) {
926  	            (*bet_info).bet_ops = &be_target_access_deny_ops;
927  	            (*bet_info).pvt_bet_data = NULL;
928  	            (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_DENY);
929  	
930  	            ret = EOK;
931  	            goto done;
932  	        }
933  	    }
934  	
935  	    mod_init_fn_name = talloc_asprintf(tmp_ctx,
936  	                                       bet_data[bet_type].mod_init_fn_name_fmt,
937  	                                       mod_name);
938  	    if (mod_init_fn_name == NULL) {
939  	        DEBUG(7, ("talloc_asprintf failed\n"));
940  	        ret = ENOMEM;
941  	        goto done;
942  	    }
943  	
944  	
945  	    lb = 0;
946  	    while(ctx->loaded_be[lb].be_name != NULL) {
947  	        if (strncmp(ctx->loaded_be[lb].be_name, mod_name,
948  	                    strlen(mod_name)) == 0) {
949  	            DEBUG(7, ("Backend [%s] already loaded.\n", mod_name));
950  	            already_loaded = true;
951  	            break;
952  	        }
953  	
954  	        ++lb;
955  	        if (lb >= BET_MAX) {
956  	            DEBUG(2, ("Backend context corrupted.\n"));
957  	            ret = EINVAL;
958  	            goto done;
959  	        }
960  	    }
961  	
962  	    if (!already_loaded) {
963  	        path = talloc_asprintf(tmp_ctx, "%s/libsss_%s.so",
964  	                               DATA_PROVIDER_PLUGINS_PATH, mod_name);
965  	        if (!path) {
966  	            ret = ENOMEM;
967  	            goto done;
968  	        }
969  	
970  	        DEBUG(7, ("Loading backend [%s] with path [%s].\n", mod_name, path));
971  	        handle = dlopen(path, RTLD_NOW);
972  	        if (!handle) {
973  	            DEBUG(0, ("Unable to load %s module with path (%s), error: %s\n",
974  	                      mod_name, path, dlerror()));
975  	            ret = ELIBACC;
976  	            goto done;
977  	        }
978  	
979  	        ctx->loaded_be[lb].be_name = talloc_strdup(ctx, mod_name);
980  	        ctx->loaded_be[lb].handle = handle;
981  	    }
982  	
983  	    mod_init_fn = (bet_init_fn_t)dlsym(ctx->loaded_be[lb].handle,
984  	                                           mod_init_fn_name);
985  	    if (mod_init_fn == NULL) {
986  	        if (default_mod_name != NULL &&
987  	            strcmp(default_mod_name, mod_name) == 0 ) {
988  	            /* If the default is used and fails we indicate this to the caller
989  	             * by returning ENOENT. Ths way the caller can decide how to
990  	             * handle the different types of error conditions. */
991  	            ret = ENOENT;
992  	        } else {
993  	            DEBUG(0, ("Unable to load init fn %s from module %s, error: %s\n",
994  	                      mod_init_fn_name, mod_name, dlerror()));
995  	            ret = ELIBBAD;
996  	        }
997  	        goto done;
998  	    }
999  	
1000 	    ret = mod_init_fn(ctx, &(*bet_info).bet_ops, &(*bet_info).pvt_bet_data);
1001 	    if (ret != EOK) {
1002 	        DEBUG(0, ("Error (%d) in module (%s) initialization (%s)!\n",
1003 	                  ret, mod_name, mod_init_fn_name));
1004 	        goto done;
1005 	    }
1006 	
1007 	    (*bet_info).mod_name = talloc_strdup(ctx, mod_name);
1008 	
1009 	    ret = EOK;
1010 	
1011 	done:
1012 	    talloc_free(tmp_ctx);
1013 	    return ret;
1014 	}
1015 	
1016 	static void signal_be_offline(struct tevent_context *ev,
1017 	                              struct tevent_signal *se,
1018 	                              int signum,
1019 	                              int count,
1020 	                              void *siginfo,
1021 	                              void *private_data)
1022 	{
1023 	    struct be_ctx *ctx = talloc_get_type(private_data, struct be_ctx);
1024 	    be_mark_offline(ctx);
1025 	}
1026 	
1027 	int be_process_init(TALLOC_CTX *mem_ctx,
1028 	                    const char *be_domain,
1029 	                    struct tevent_context *ev,
1030 	                    struct confdb_ctx *cdb)
1031 	{
1032 	    struct be_ctx *ctx;
1033 	    struct tevent_signal *tes;
1034 	    int ret;
1035 	
1036 	    ctx = talloc_zero(mem_ctx, struct be_ctx);
1037 	    if (!ctx) {
1038 	        DEBUG(0, ("fatal error initializing be_ctx\n"));
1039 	        return ENOMEM;
1040 	    }
1041 	    ctx->ev = ev;
1042 	    ctx->cdb = cdb;
1043 	    ctx->identity = talloc_asprintf(ctx, "%%BE_%s", be_domain);
1044 	    ctx->conf_path = talloc_asprintf(ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain);
1045 	    if (!ctx->identity || !ctx->conf_path) {
1046 	        DEBUG(0, ("Out of memory!?\n"));
1047 	        return ENOMEM;
1048 	    }
1049 	
1050 	    ret = be_init_failover(ctx);
1051 	    if (ret != EOK) {
1052 	        DEBUG(0, ("fatal error initializing failover context\n"));
1053 	        return ret;
1054 	    }
1055 	
1056 	    ret = confdb_get_domain(cdb, be_domain, &ctx->domain);
1057 	    if (ret != EOK) {
1058 	        DEBUG(0, ("fatal error retrieving domain configuration\n"));
1059 	        return ret;
1060 	    }
1061 	
1062 	    ret = sysdb_domain_init(ctx, ev, ctx->domain, DB_PATH, &ctx->sysdb);
1063 	    if (ret != EOK) {
1064 	        DEBUG(0, ("fatal error opening cache database\n"));
1065 	        return ret;
1066 	    }
1067 	
1068 	    ret = mon_cli_init(ctx);
1069 	    if (ret != EOK) {
1070 	        DEBUG(0, ("fatal error setting up monitor bus\n"));
1071 	        return ret;
1072 	    }
1073 	
1074 	    ret = be_srv_init(ctx);
1075 	    if (ret != EOK) {
1076 	        DEBUG(0, ("fatal error setting up server bus\n"));
1077 	        return ret;
1078 	    }
1079 	
1080 	    ret = load_backend_module(ctx, BET_ID,
1081 	                              &ctx->bet_info[BET_ID], NULL);
1082 	    if (ret != EOK) {
1083 	        DEBUG(0, ("fatal error initializing data providers\n"));
1084 	        return ret;
1085 	    }
1086 	    DEBUG(9, ("ID backend target successfully loaded from provider [%s].\n",
1087 	              ctx->bet_info[BET_ID].mod_name));
1088 	
1089 	    ret = load_backend_module(ctx, BET_AUTH,
1090 	                              &ctx->bet_info[BET_AUTH],
1091 	                              ctx->bet_info[BET_ID].mod_name);
1092 	    if (ret != EOK) {
1093 	        if (ret != ENOENT) {
1094 	            DEBUG(0, ("fatal error initializing data providers\n"));
1095 	            return ret;
1096 	        }
1097 	        DEBUG(1, ("No authentication module provided for [%s] !!\n",
1098 	                  be_domain));
1099 	    } else {
1100 	        DEBUG(9, ("AUTH backend target successfully loaded "
1101 	                  "from provider [%s].\n", ctx->bet_info[BET_AUTH].mod_name));
1102 	    }
1103 	
1104 	    ret = load_backend_module(ctx, BET_ACCESS, &ctx->bet_info[BET_ACCESS],
1105 	                              ACCESS_PERMIT);
1106 	    if (ret != EOK) {
1107 	        DEBUG(0, ("Failed to setup ACCESS backend.\n"));
1108 	        return ret;
1109 	    }
1110 	    DEBUG(9, ("ACCESS backend target successfully loaded "
1111 	              "from provider [%s].\n", ctx->bet_info[BET_ACCESS].mod_name));
1112 	
1113 	    ret = load_backend_module(ctx, BET_CHPASS,
1114 	                              &ctx->bet_info[BET_CHPASS],
1115 	                              ctx->bet_info[BET_AUTH].mod_name);
1116 	    if (ret != EOK) {
1117 	        if (ret != ENOENT) {
1118 	            DEBUG(0, ("fatal error initializing data providers\n"));
1119 	            return ret;
1120 	        }
1121 	        DEBUG(1, ("No change password module provided for [%s] !!\n",
1122 	                  be_domain));
1123 	    } else {
1124 	        DEBUG(9, ("CHPASS backend target successfully loaded "
1125 	                  "from provider [%s].\n", ctx->bet_info[BET_CHPASS].mod_name));
1126 	    }
1127 	
1128 	    /* Handle SIGUSR1 to force offline behavior */
1129 	    BlockSignals(false, SIGUSR1);
1130 	    tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,
1131 	                            signal_be_offline, ctx);
1132 	    if (tes == NULL) {
1133 	        return EIO;
1134 	    }
1135 	
1136 	    return EOK;
1137 	}
1138 	
1139 	int main(int argc, const char *argv[])
1140 	{
1141 	    int opt;
1142 	    poptContext pc;
1143 	    char *be_domain = NULL;
1144 	    char *srv_name = NULL;
1145 	    char *conf_entry = NULL;
1146 	    struct main_context *main_ctx;
1147 	    int ret;
1148 	
1149 	    struct poptOption long_options[] = {
1150 	        POPT_AUTOHELP
1151 	        SSSD_MAIN_OPTS
1152 	        {"domain", 0, POPT_ARG_STRING, &be_domain, 0,
1153 	         _("Domain of the information provider (mandatory)"), NULL },
1154 	        POPT_TABLEEND
1155 	    };
1156 	
1157 	    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
1158 	    while((opt = poptGetNextOpt(pc)) != -1) {
1159 	        switch(opt) {
1160 	        default:
1161 	        fprintf(stderr, "\nInvalid option %s: %s\n\n",
1162 	                  poptBadOption(pc, 0), poptStrerror(opt));
1163 	            poptPrintUsage(pc, stderr, 0);
1164 	            return 1;
1165 	        }
1166 	    }
1167 	
1168 	    if (be_domain == NULL) {
1169 	        fprintf(stderr, "\nMissing option, --domain is a mandatory option.\n\n");
1170 	            poptPrintUsage(pc, stderr, 0);
1171 	            return 1;
1172 	    }
1173 	
1174 	    poptFreeContext(pc);
1175 	
1176 	
1177 	    /* set up things like debug , signals, daemonization, etc... */
1178 	    debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain);
1179 	    if (!debug_log_file) return 2;
1180 	
1181 	    srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain);
1182 	    if (!srv_name) return 2;
1183 	
1184 	    conf_entry = talloc_asprintf(NULL, CONFDB_DOMAIN_PATH_TMPL, be_domain);
1185 	    if (!conf_entry) return 2;
1186 	
1187 	    ret = server_setup(srv_name, 0, conf_entry, &main_ctx);
1188 	    if (ret != EOK) {
1189 	        DEBUG(0, ("Could not set up mainloop [%d]\n", ret));
1190 	        return 2;
1191 	    }
1192 	
1193 	    ret = die_if_parent_died();
1194 	    if (ret != EOK) {
1195 	        /* This is not fatal, don't return */
1196 	        DEBUG(2, ("Could not set up to exit when parent process does\n"));
1197 	    }
1198 	
1199 	    ret = be_process_init(main_ctx,
1200 	                          be_domain,
1201 	                          main_ctx->event_ctx,
1202 	                          main_ctx->confdb_ctx);
1203 	    if (ret != EOK) {
1204 	        DEBUG(0, ("Could not initialize backend [%d]\n", ret));
1205 	        return 3;
1206 	    }
1207 	
1208 	    DEBUG(1, ("Backend provider (%s) started!\n", be_domain));
1209 	
1210 	    /* loop on main */
1211 	    server_loop(main_ctx);
1212 	
1213 	    return 0;
1214 	}
1215 	
1216 	static int data_provider_res_init(DBusMessage *message,
1217 	                                  struct sbus_connection *conn)
1218 	{
1219 	    resolv_reread_configuration();
1220 	
1221 	    return monitor_common_res_init(message, conn);
1222 	}
1223 	
1224 	static int data_provider_go_offline(DBusMessage *message,
1225 	                                    struct sbus_connection *conn)
1226 	{
1227 	    struct be_ctx *be_ctx;
1228 	    be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx);
1229 	    be_mark_offline(be_ctx);
1230 	    return monitor_common_pong(message, conn);
1231 	}