1    	/*
2    	   SSSD
3    	
4    	   Data Provider, auth utils
5    	
6    	   Copyright (C) Sumit Bose <sbose@redhat.com>	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 "data_provider.h"
23   	
24   	bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd)
25   	{
26   	    dbus_bool_t db_ret;
27   	
28   	    if (pd->user == NULL) return false;
29   	    if (pd->service == NULL) pd->service = talloc_strdup(pd, "");
30   	    if (pd->tty == NULL) pd->tty = talloc_strdup(pd, "");
31   	    if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, "");
32   	    if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, "");
33   	
34   	
35   	    db_ret = dbus_message_append_args(msg,
36   	                                      DBUS_TYPE_INT32,  &(pd->cmd),
37   	                                      DBUS_TYPE_STRING, &(pd->user),
38   	                                      DBUS_TYPE_STRING, &(pd->service),
39   	                                      DBUS_TYPE_STRING, &(pd->tty),
40   	                                      DBUS_TYPE_STRING, &(pd->ruser),
41   	                                      DBUS_TYPE_STRING, &(pd->rhost),
42   	                                      DBUS_TYPE_UINT32, &(pd->authtok_type),
43   	                                      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
44   	                                          &(pd->authtok),
45   	                                          (pd->authtok_size),
46   	                                      DBUS_TYPE_UINT32, &(pd->newauthtok_type),
47   	                                      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
48   	                                          &(pd->newauthtok),
49   	                                          pd->newauthtok_size,
50   	                                      DBUS_TYPE_INT32, &(pd->priv),
51   	                                      DBUS_TYPE_UINT32, &(pd->cli_pid),
52   	                                      DBUS_TYPE_INVALID);
53   	
54   	    return db_ret;
55   	}
56   	
57   	bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx,
58   	                           struct pam_data **new_pd, DBusError *dbus_error)
59   	{
60   	    dbus_bool_t db_ret;
61   	    int ret;
62   	    struct pam_data pd;
63   	
64   	    memset(&pd, 0, sizeof(pd));
65   	
66   	    db_ret = dbus_message_get_args(msg, dbus_error,
67   	                                   DBUS_TYPE_INT32,  &(pd.cmd),
68   	                                   DBUS_TYPE_STRING, &(pd.user),
69   	                                   DBUS_TYPE_STRING, &(pd.service),
70   	                                   DBUS_TYPE_STRING, &(pd.tty),
71   	                                   DBUS_TYPE_STRING, &(pd.ruser),
72   	                                   DBUS_TYPE_STRING, &(pd.rhost),
73   	                                   DBUS_TYPE_UINT32, &(pd.authtok_type),
74   	                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
75   	                                       &(pd.authtok),
76   	                                       &(pd.authtok_size),
77   	                                   DBUS_TYPE_UINT32, &(pd.newauthtok_type),
78   	                                   DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
79   	                                       &(pd.newauthtok),
80   	                                       &(pd.newauthtok_size),
81   	                                   DBUS_TYPE_INT32, &(pd.priv),
82   	                                   DBUS_TYPE_UINT32, &(pd.cli_pid),
83   	                                   DBUS_TYPE_INVALID);
84   	
85   	    if (!db_ret) {
86   	        DEBUG(1, ("dbus_message_get_args failed.\n"));
87   	        return false;
88   	    }
89   	
90   	    ret = copy_pam_data(mem_ctx, &pd, new_pd);
91   	    if (ret != EOK) {
92   	        DEBUG(1, ("copy_pam_data failed.\n"));
93   	        return false;
94   	    }
95   	
96   	    if (pd.authtok_size != 0 && pd.authtok != NULL) {
97   	        memset(pd.authtok, 0, pd.authtok_size);
98   	        pd.authtok_size = 0;
99   	    }
100  	
101  	    if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) {
102  	        memset(pd.newauthtok, 0, pd.newauthtok_size);
103  	        pd.newauthtok_size = 0;
104  	    }
105  	
106  	    return true;
107  	}
108  	
109  	bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd)
110  	{
111  	    dbus_bool_t dbret;
112  	    struct response_data *resp;
113  	    DBusMessageIter iter;
114  	    DBusMessageIter array_iter;
115  	    DBusMessageIter struct_iter;
116  	    DBusMessageIter data_iter;
117  	
118  	    dbus_message_iter_init_append(msg, &iter);
119  	
120  	    /* Append the PAM status */
121  	    dbret = dbus_message_iter_append_basic(&iter,
122  	                                   DBUS_TYPE_UINT32, &(pd->pam_status));
At conditional (1): "!dbret": Taking false branch.
123  	    if (!dbret) {
124  	        return false;
125  	    }
126  	
127  	    /* Create an array of response structures */
128  	    dbret = dbus_message_iter_open_container(&iter,
129  	                                             DBUS_TYPE_ARRAY, "(uay)",
130  	                                             &array_iter);
At conditional (2): "!dbret": Taking false branch.
131  	    if (!dbret) {
132  	        return false;
133  	    }
134  	
Event deref_parm: Directly dereferencing parameter "pd".
135  	    resp = pd->resp_list;
136  	    while (resp != NULL) {
137  	        /* Create a DBUS struct */
138  	        dbret = dbus_message_iter_open_container(&array_iter,
139  	                                                 DBUS_TYPE_STRUCT, NULL,
140  	                                                 &struct_iter);
141  	        if (!dbret) {
142  	            return false;
143  	        }
144  	
145  	        /* Add the response type */
146  	        dbret = dbus_message_iter_append_basic(&struct_iter,
147  	                                               DBUS_TYPE_UINT32,
148  	                                               &(resp->type));
149  	        if (!dbret) {
150  	            return false;
151  	        }
152  	
153  	        /* Add the response message */
154  	        dbret = dbus_message_iter_open_container(&struct_iter,
155  	                                                 DBUS_TYPE_ARRAY, "y",
156  	                                                 &data_iter);
157  	        if (!dbret) {
158  	            return false;
159  	        }
160  	        dbret = dbus_message_iter_append_fixed_array(&data_iter,
161  	                       DBUS_TYPE_BYTE, &(resp->data), resp->len);
162  	        if (!dbret) {
163  	            return false;
164  	        }
165  	        dbret = dbus_message_iter_close_container(&struct_iter, &data_iter);
166  	        if (!dbret) {
167  	            return false;
168  	        }
169  	
170  	        resp = resp->next;
171  	        dbret = dbus_message_iter_close_container(&array_iter, &struct_iter);
172  	        if (!dbret) {
173  	            return false;
174  	        }
175  	    }
176  	
177  	    /* Close the struct array */
178  	    dbret = dbus_message_iter_close_container(&iter, &array_iter);
179  	    if (!dbret) {
180  	        return false;
181  	    }
182  	
183  	    return true;
184  	}
185  	
186  	bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, DBusError *dbus_error)
187  	{
188  	    DBusMessageIter iter;
189  	    DBusMessageIter array_iter;
190  	    DBusMessageIter struct_iter;
191  	    DBusMessageIter sub_iter;
192  	    int type;
193  	    int len;
194  	    const uint8_t *data;
195  	
196  	    if (!dbus_message_iter_init(msg, &iter)) {
197  	        DEBUG(1, ("pam response has no arguments.\n"));
198  	        return false;
199  	    }
200  	
201  	    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
202  	        DEBUG(1, ("pam response format error.\n"));
203  	        return false;
204  	    }
205  	    dbus_message_iter_get_basic(&iter, &(pd->pam_status));
206  	
207  	    if (!dbus_message_iter_next(&iter)) {
208  	        DEBUG(1, ("pam response has too few arguments.\n"));
209  	        return false;
210  	    }
211  	
212  	    /* After this point will be an array of pam data */
213  	    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
214  	        DEBUG(1, ("pam response format error.\n"));
215  	        DEBUG(1, ("Type was %c\n", (char)dbus_message_iter_get_arg_type(&iter)));
216  	        return false;
217  	    }
218  	
219  	    if (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
220  	        DEBUG(1, ("pam response format error.\n"));
221  	        return false;
222  	    }
223  	
224  	    dbus_message_iter_recurse(&iter, &array_iter);
225  	    while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID) {
226  	        /* Read in a pam data struct */
227  	        if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
228  	            DEBUG(1, ("pam response format error.\n"));
229  	            return false;
230  	        }
231  	
232  	        dbus_message_iter_recurse(&array_iter,  &struct_iter);
233  	
234  	        /* PAM data struct contains a type and a byte-array of data */
235  	
236  	        /* Get the pam data type */
237  	        if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_UINT32) {
238  	            DEBUG(1, ("pam response format error.\n"));
239  	            return false;
240  	        }
241  	        dbus_message_iter_get_basic(&struct_iter, &type);
242  	
243  	        if (!dbus_message_iter_next(&struct_iter)) {
244  	            DEBUG(1, ("pam response format error.\n"));
245  	            return false;
246  	        }
247  	
248  	        /* Get the byte array */
249  	        if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_ARRAY ||
250  	            dbus_message_iter_get_element_type(&struct_iter) != DBUS_TYPE_BYTE) {
251  	            DEBUG(1, ("pam response format error.\n"));
252  	            return false;
253  	        }
254  	
255  	        dbus_message_iter_recurse(&struct_iter, &sub_iter);
256  	        dbus_message_iter_get_fixed_array(&sub_iter, &data, &len);
257  	
258  	        pam_add_response(pd, type, len, data);
259  	        dbus_message_iter_next(&array_iter);
260  	    }
261  	
262  	    return true;
263  	}
264  	
265  	void dp_id_callback(DBusPendingCall *pending, void *ptr)
266  	{
267  	    DBusMessage *reply;
268  	    DBusError dbus_error;
269  	    dbus_bool_t ret;
270  	    dbus_uint16_t dp_ver;
271  	    int type;
272  	
273  	    dbus_error_init(&dbus_error);
274  	
275  	    reply = dbus_pending_call_steal_reply(pending);
276  	    if (!reply) {
277  	        /* reply should never be null. This function shouldn't be called
278  	         * until reply is valid or timeout has occurred. If reply is NULL
279  	         * here, something is seriously wrong and we should bail out.
280  	         */
281  	        DEBUG(0, ("Severe error. A reply callback was called but no"
282  	                  " reply was received and no timeout occurred\n"));
283  	
284  	        /* FIXME: Destroy this connection ? */
285  	        goto done;
286  	    }
287  	
288  	    type = dbus_message_get_type(reply);
289  	    switch (type) {
290  	    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
291  	        ret = dbus_message_get_args(reply, &dbus_error,
292  	                                    DBUS_TYPE_UINT16, &dp_ver,
293  	                                    DBUS_TYPE_INVALID);
294  	        if (!ret) {
295  	            DEBUG(1, ("Failed to parse message\n"));
296  	            if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
297  	            /* FIXME: Destroy this connection ? */
298  	            goto done;
299  	        }
300  	
301  	        DEBUG(4, ("Got id ack and version (%d) from DP\n", dp_ver));
302  	
303  	        break;
304  	
305  	    case DBUS_MESSAGE_TYPE_ERROR:
306  	        DEBUG(0,("The Monitor returned an error [%s]\n",
307  	                 dbus_message_get_error_name(reply)));
308  	        /* Falling through to default intentionally*/
309  	    default:
310  	        /*
311  	         * Timeout or other error occurred or something
312  	         * unexpected happened.
313  	         * It doesn't matter which, because either way we
314  	         * know that this connection isn't trustworthy.
315  	         * We'll destroy it now.
316  	         */
317  	
318  	        /* FIXME: Destroy this connection ? */
319  	        break;
320  	    }
321  	
322  	done:
323  	    dbus_pending_call_unref(pending);
324  	    dbus_message_unref(reply);
325  	}
326  	
327  	int dp_common_send_id(struct sbus_connection *conn, uint16_t version,
328  	                      const char *name)
329  	{
330  	    DBusMessage *msg;
331  	    dbus_bool_t ret;
332  	    int retval;
333  	
334  	    /* create the message */
335  	    msg = dbus_message_new_method_call(NULL,
336  	                                       DP_PATH,
337  	                                       DP_INTERFACE,
338  	                                       DP_METHOD_REGISTER);
339  	    if (msg == NULL) {
340  	        DEBUG(0, ("Out of memory?!\n"));
341  	        return ENOMEM;
342  	    }
343  	
344  	    DEBUG(4, ("Sending ID to DP: (%d,%s)\n",
345  	              version, name));
346  	
347  	    ret = dbus_message_append_args(msg,
348  	                                   DBUS_TYPE_UINT16, &version,
349  	                                   DBUS_TYPE_STRING, &name,
350  	                                   DBUS_TYPE_INVALID);
351  	    if (!ret) {
352  	        DEBUG(1, ("Failed to build message\n"));
353  	        return EIO;
354  	    }
355  	
356  	    retval = sbus_conn_send(conn, msg, 30000, dp_id_callback, NULL, NULL);
357  	
358  	    dbus_message_unref(msg);
359  	    return retval;
360  	}
361