Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2016 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 :
24 : #include "responder/common/data_provider/rdp.h"
25 : #include "sbus/sssd_dbus.h"
26 : #include "sbus/sssd_dbus_errors.h"
27 : #include "util/util.h"
28 :
29 0 : static errno_t rdp_error_to_errno(DBusError *error)
30 : {
31 : static struct {
32 : const char *name;
33 : errno_t ret;
34 : } list[] = {{SBUS_ERROR_INTERNAL, ERR_INTERNAL},
35 : {SBUS_ERROR_NOT_FOUND, ENOENT},
36 : {SBUS_ERROR_DP_FATAL, ERR_TERMINATED},
37 : {SBUS_ERROR_DP_OFFLINE, ERR_OFFLINE},
38 : {SBUS_ERROR_DP_NOTSUP, ENOTSUP},
39 : {NULL, ERR_INTERNAL}
40 : };
41 : int i;
42 :
43 0 : if (!dbus_error_is_set(error)) {
44 0 : return EOK;
45 : }
46 :
47 0 : for (i = 0; list[i].name != NULL; i ++) {
48 0 : if (dbus_error_has_name(error, list[i].name)) {
49 0 : return list[i].ret;
50 : }
51 : }
52 :
53 0 : return EIO;
54 : }
55 :
56 : struct rdp_message_state {
57 : struct DBusMessage *reply;
58 : };
59 :
60 0 : static int rdp_message_state_destructor(struct rdp_message_state *state)
61 : {
62 0 : if (state->reply != NULL) {
63 0 : dbus_message_unref(state->reply);
64 : }
65 :
66 0 : return 0;
67 : }
68 :
69 : static void rdp_message_done(DBusPendingCall *pending, void *ptr);
70 :
71 0 : struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx,
72 : struct resp_ctx *rctx,
73 : struct sss_domain_info *domain,
74 : const char *path,
75 : const char *iface,
76 : const char *method,
77 : int first_arg_type,
78 : ...)
79 : {
80 : struct rdp_message_state *state;
81 : struct be_conn *be_conn;
82 : struct tevent_req *req;
83 : DBusMessage *msg;
84 : dbus_bool_t bret;
85 : errno_t ret;
86 : va_list va;
87 :
88 0 : req = tevent_req_create(mem_ctx, &state, struct rdp_message_state);
89 0 : if (req == NULL) {
90 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
91 0 : return NULL;
92 : }
93 :
94 0 : talloc_set_destructor(state, rdp_message_state_destructor);
95 :
96 0 : ret = sss_dp_get_domain_conn(rctx, domain->conn_name, &be_conn);
97 0 : if (ret != EOK) {
98 0 : DEBUG(SSSDBG_CRIT_FAILURE, "BUG: The Data Provider connection for "
99 : "%s is not available!\n", domain->name);
100 0 : ret = ERR_INTERNAL;
101 0 : goto immediately;
102 : }
103 :
104 0 : msg = dbus_message_new_method_call(NULL, path, iface, method);
105 0 : if (msg == NULL) {
106 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n");
107 0 : ret = ENOMEM;
108 0 : goto immediately;
109 : }
110 :
111 0 : va_start(va, first_arg_type);
112 0 : bret = dbus_message_append_args_valist(msg, first_arg_type, va);
113 0 : va_end(va);
114 0 : if (!bret) {
115 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
116 0 : ret = EIO;
117 0 : goto immediately;
118 : }
119 :
120 0 : DEBUG(SSSDBG_TRACE_FUNC, "DP Request: %s %s.%s\n", path, iface, method);
121 :
122 0 : ret = sbus_conn_send(be_conn->conn, msg, 30000,
123 : rdp_message_done, req, NULL);
124 0 : if (ret != EOK) {
125 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider "
126 : "[%d]: %s\n", ret, sss_strerror(ret));
127 0 : goto immediately;
128 : }
129 :
130 0 : return req;
131 :
132 : immediately:
133 0 : if (ret == EOK) {
134 0 : tevent_req_done(req);
135 : } else {
136 0 : tevent_req_error(req, ret);
137 : }
138 0 : tevent_req_post(req, rctx->ev);
139 :
140 0 : return req;
141 : }
142 :
143 0 : static void rdp_message_done(DBusPendingCall *pending, void *ptr)
144 : {
145 : struct rdp_message_state *state;
146 0 : DBusMessage *reply = NULL;
147 : struct tevent_req *req;
148 : DBusError error;
149 : dbus_bool_t bret;
150 : errno_t ret;
151 :
152 0 : req = talloc_get_type(ptr, struct tevent_req);
153 0 : state = tevent_req_data(req, struct rdp_message_state);
154 :
155 0 : dbus_error_init(&error);
156 :
157 0 : reply = dbus_pending_call_steal_reply(pending);
158 0 : if (reply == NULL) {
159 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Severe error. A reply callback was "
160 : "called but no reply was received and no timeout occurred\n");
161 0 : ret = EFAULT;
162 0 : goto done;
163 : }
164 :
165 0 : switch (dbus_message_get_type(reply)) {
166 : case DBUS_MESSAGE_TYPE_METHOD_RETURN:
167 0 : DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n");
168 0 : state->reply = reply;
169 0 : ret = EOK;
170 0 : goto done;
171 :
172 : case DBUS_MESSAGE_TYPE_ERROR:
173 0 : bret = dbus_set_error_from_message(&error, reply);
174 0 : if (bret == false) {
175 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read error from message\n");
176 0 : ret = EIO;
177 0 : goto done;
178 : }
179 :
180 0 : DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n",
181 : error.name, (error.message == NULL ? "(null)" : error.message));
182 0 : ret = rdp_error_to_errno(&error);
183 0 : goto done;
184 : default:
185 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n");
186 0 : ret = ERR_INTERNAL;
187 0 : goto done;
188 : }
189 :
190 : ret = ERR_INTERNAL;
191 :
192 : done:
193 0 : dbus_pending_call_unref(pending);
194 0 : dbus_error_free(&error);
195 :
196 0 : if (ret == EOK) {
197 0 : tevent_req_done(req);
198 0 : return;
199 : }
200 :
201 0 : if (reply != NULL) {
202 0 : dbus_message_unref(reply);
203 : }
204 0 : tevent_req_error(req, ret);
205 : }
206 :
207 0 : errno_t _rdp_message_recv(struct tevent_req *req,
208 : int first_arg_type,
209 : ...)
210 : {
211 : struct rdp_message_state *state;
212 : DBusError error;
213 : dbus_bool_t bret;
214 : errno_t ret;
215 : va_list va;
216 :
217 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
218 :
219 0 : state = tevent_req_data(req, struct rdp_message_state);
220 0 : dbus_error_init(&error);
221 :
222 0 : va_start(va, first_arg_type);
223 0 : bret = dbus_message_get_args_valist(state->reply, &error, first_arg_type, va);
224 0 : va_end(va);
225 :
226 0 : if (bret == false) {
227 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse reply\n");
228 0 : ret = EIO;
229 0 : goto done;
230 : }
231 :
232 0 : ret = rdp_error_to_errno(&error);
233 0 : if (ret != EOK) {
234 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse message [%s]: %s\n",
235 : error.name, error.message);
236 0 : goto done;
237 : }
238 :
239 : done:
240 0 : dbus_error_free(&error);
241 0 : return ret;
242 : }
243 :
|