Line data Source code
1 : /*
2 : Authors:
3 : Stef Walter <stefw@redhat.com>
4 : Pavel Březina <pbrezina@redhat.com>
5 :
6 : Copyright (C) 2014 Red Hat
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 "config.h"
23 :
24 : #include "util/util.h"
25 : #include "sbus/sssd_dbus.h"
26 : #include "sbus/sssd_dbus_meta.h"
27 : #include "sbus/sssd_dbus_private.h"
28 : #include "sbus/sssd_dbus_invokers.h"
29 :
30 : #define CHECK_SIGNATURE_OR_FAIL(req, error, label, exp) do { \
31 : const char *__sig; \
32 : __sig = dbus_message_get_signature(req->message); \
33 : if (strcmp(__sig, exp) != 0) { \
34 : error = sbus_error_new(req, DBUS_ERROR_INVALID_ARGS, \
35 : "Invalid arguments: expected \"%s\", got \"%s\"", exp, __sig); \
36 : goto label; \
37 : } \
38 : } while (0)
39 :
40 : struct iface_properties {
41 : struct sbus_vtable vtable; /* derive from sbus_vtable */
42 : sbus_msg_handler_fn Get;
43 : sbus_msg_handler_fn Set;
44 : sbus_msg_handler_fn GetAll;
45 : };
46 :
47 : static int sbus_properties_get(struct sbus_request *sbus_req, void *pvt);
48 : static int sbus_properties_set(struct sbus_request *sbus_req, void *pvt);
49 : static int sbus_properties_get_all(struct sbus_request *sbus_req, void *pvt);
50 :
51 : struct sbus_vtable *
52 0 : sbus_properties_vtable(void)
53 : {
54 : /* Properties.Get */
55 : static const struct sbus_arg_meta get_args_in[] = {
56 : { "interface_name", "s" },
57 : { "property_name", "s" },
58 : { NULL, }
59 : };
60 :
61 : static const struct sbus_arg_meta get_args_out[] = {
62 : { "value", "v" },
63 : { NULL, }
64 : };
65 :
66 : /* Properties.Set */
67 : static const struct sbus_arg_meta set_args_in[] = {
68 : { "interface_name", "s" },
69 : { "property_name", "s" },
70 : { "value", "v" },
71 : { NULL, }
72 : };
73 :
74 : /* Properties.GetAll */
75 : static const struct sbus_arg_meta getall_args_in[] = {
76 : { "interface_name", "s" },
77 : { NULL, }
78 : };
79 :
80 : static const struct sbus_arg_meta getall_args_out[] = {
81 : { "props", "a{sv}" },
82 : { NULL, }
83 : };
84 :
85 : static const struct sbus_method_meta iface_methods[] = {
86 : {
87 : "Get", /* name */
88 : get_args_in,
89 : get_args_out,
90 : offsetof(struct iface_properties, Get),
91 : NULL, /* no invoker */
92 : },
93 : {
94 : "Set", /* name */
95 : set_args_in,
96 : NULL, /* no out_args */
97 : offsetof(struct iface_properties, Set),
98 : NULL, /* no invoker */
99 : },
100 : {
101 : "GetAll", /* name */
102 : getall_args_in,
103 : getall_args_out,
104 : offsetof(struct iface_properties, GetAll),
105 : NULL, /* no invoker */
106 : },
107 : { NULL, }
108 : };
109 :
110 : static const struct sbus_interface_meta iface_meta = {
111 : "org.freedesktop.DBus.Properties", /* name */
112 : iface_methods,
113 : NULL, /* no signals */
114 : NULL, /* no properties */
115 : NULL, /* no GetAll invoker */
116 : };
117 :
118 : static struct iface_properties iface = {
119 : { &iface_meta, 0 },
120 : .Get = sbus_properties_get,
121 : .Set = sbus_properties_set,
122 : .GetAll = sbus_properties_get_all,
123 : };
124 :
125 0 : return &iface.vtable;
126 : }
127 :
128 : static struct sbus_request *
129 0 : sbus_properties_subreq(struct sbus_request *sbus_req,
130 : struct sbus_interface *iface)
131 : {
132 : struct sbus_request *sbus_subreq;
133 :
134 : /* Create new sbus_request to so it contain given interface. The
135 : * old sbus_request talloc context will be attached to this new one
136 : * so it is freed together. */
137 0 : sbus_subreq = sbus_new_request(sbus_req->conn, iface, sbus_req->message);
138 0 : if (sbus_subreq == NULL) {
139 0 : return NULL;
140 : }
141 :
142 0 : talloc_steal(sbus_subreq, sbus_req);
143 :
144 0 : return sbus_subreq;
145 : }
146 :
147 0 : static int sbus_properties_get(struct sbus_request *sbus_req, void *pvt)
148 : {
149 : DBusError *error;
150 : struct sbus_request *sbus_subreq;
151 : struct sbus_connection *conn;
152 : struct sbus_interface *iface;
153 : const struct sbus_property_meta *prop;
154 : sbus_msg_handler_fn handler_fn;
155 : const char *interface_name;
156 : const char *property_name;
157 : bool bret;
158 :
159 0 : conn = talloc_get_type(pvt, struct sbus_connection);
160 :
161 0 : CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "ss");
162 :
163 0 : bret = sbus_request_parse_or_finish(sbus_req,
164 : DBUS_TYPE_STRING, &interface_name,
165 : DBUS_TYPE_STRING, &property_name,
166 : DBUS_TYPE_INVALID);
167 0 : if (!bret) {
168 : /* request was handled */
169 0 : return EOK;
170 : }
171 :
172 : /* find interface */
173 0 : iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
174 : interface_name);
175 0 : if (iface == NULL) {
176 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
177 : "Unknown interface");
178 0 : goto fail;
179 : }
180 :
181 : /* find property handler */
182 0 : prop = sbus_meta_find_property(iface->vtable->meta, property_name);
183 0 : if (prop == NULL) {
184 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_PROPERTY,
185 : "Unknown property");
186 0 : goto fail;
187 : }
188 :
189 0 : if (!(prop->flags & SBUS_PROPERTY_READABLE)) {
190 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_ACCESS_DENIED,
191 : "Property is not readable");
192 0 : goto fail;
193 : }
194 :
195 0 : handler_fn = VTABLE_FUNC(iface->vtable, prop->vtable_offset_get);
196 0 : if (handler_fn == NULL) {
197 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_NOT_SUPPORTED,
198 : "Getter is not implemented");
199 0 : goto fail;
200 : }
201 :
202 0 : sbus_subreq = sbus_properties_subreq(sbus_req, iface);
203 0 : if (sbus_subreq == NULL) {
204 0 : error = NULL;
205 0 : goto fail;
206 : }
207 :
208 0 : sbus_invoke_get(sbus_subreq, prop->type,
209 : prop->invoker_get, handler_fn);
210 0 : return EOK;
211 :
212 : fail:
213 0 : return sbus_request_fail_and_finish(sbus_req, error);
214 : }
215 :
216 : /*
217 : * We don't implement any handlers for setters yet. This code is for future
218 : * use and it is likely it will need some changes.
219 : */
220 0 : static int sbus_properties_set(struct sbus_request *sbus_req, void *pvt)
221 : {
222 : DBusError *error;
223 : DBusMessageIter iter;
224 : DBusMessageIter iter_variant;
225 : struct sbus_request *sbus_subreq;
226 : struct sbus_connection *conn;
227 : struct sbus_interface *iface;
228 : const struct sbus_property_meta *prop;
229 : const char *interface_name;
230 : const char *property_name;
231 : const char *variant_sig;
232 : sbus_msg_handler_fn handler_fn;
233 :
234 0 : conn = talloc_get_type(pvt, struct sbus_connection);
235 :
236 0 : CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "ssv");
237 :
238 : /* get interface and property */
239 0 : dbus_message_iter_init(sbus_req->message, &iter);
240 0 : dbus_message_iter_get_basic(&iter, &interface_name);
241 0 : dbus_message_iter_next(&iter);
242 0 : dbus_message_iter_get_basic(&iter, &property_name);
243 0 : dbus_message_iter_next(&iter);
244 :
245 : /* find interface */
246 0 : iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
247 : interface_name);
248 0 : if (iface == NULL) {
249 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
250 : "Unknown interface");
251 0 : goto fail;
252 : }
253 :
254 : /* find property handler */
255 0 : prop = sbus_meta_find_property(iface->vtable->meta, property_name);
256 0 : if (prop == NULL) {
257 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_PROPERTY,
258 : "Unknown property");
259 0 : goto fail;
260 : }
261 :
262 0 : if (!(prop->flags & SBUS_PROPERTY_WRITABLE)) {
263 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_ACCESS_DENIED,
264 : "Property is not writable");
265 0 : goto fail;
266 : }
267 :
268 0 : handler_fn = VTABLE_FUNC(iface->vtable, prop->vtable_offset_set);
269 0 : if (handler_fn == NULL) {
270 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_NOT_SUPPORTED,
271 : "Setter is not implemented");
272 0 : goto fail;
273 : }
274 :
275 : /* check variant type */
276 0 : dbus_message_iter_recurse(&iter, &iter_variant);
277 0 : variant_sig = dbus_message_iter_get_signature(&iter_variant);
278 0 : if (strcmp(prop->type, variant_sig) != 0) {
279 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_INVALID_ARGS,
280 : "Invalid data type for property");
281 0 : goto fail;
282 : }
283 :
284 0 : sbus_subreq = sbus_properties_subreq(sbus_req, iface);
285 0 : if (sbus_subreq == NULL) {
286 0 : error = NULL;
287 0 : goto fail;
288 : }
289 :
290 0 : sbus_request_invoke_or_finish(sbus_subreq, handler_fn,
291 : iface->handler_data, prop->invoker_set);
292 :
293 0 : return EOK;
294 :
295 : fail:
296 0 : return sbus_request_fail_and_finish(sbus_req, error);
297 : }
298 :
299 0 : static int sbus_properties_get_all(struct sbus_request *sbus_req, void *pvt)
300 : {
301 : DBusError *error;
302 : struct sbus_request *sbus_subreq;
303 : struct sbus_connection *conn;
304 : struct sbus_interface *iface;
305 : const char *interface_name;
306 : bool bret;
307 :
308 0 : conn = talloc_get_type(pvt, struct sbus_connection);
309 :
310 0 : CHECK_SIGNATURE_OR_FAIL(sbus_req, error, fail, "s");
311 :
312 0 : bret = sbus_request_parse_or_finish(sbus_req,
313 : DBUS_TYPE_STRING, &interface_name,
314 : DBUS_TYPE_INVALID);
315 0 : if (!bret) {
316 : /* request was handled */
317 0 : return EOK;
318 : }
319 :
320 : /* find interface */
321 0 : iface = sbus_opath_hash_lookup_iface(conn->managed_paths, sbus_req->path,
322 : interface_name);
323 0 : if (iface == NULL) {
324 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_UNKNOWN_INTERFACE,
325 : "Unknown interface");
326 0 : goto fail;
327 : }
328 :
329 0 : sbus_subreq = sbus_properties_subreq(sbus_req, iface);
330 0 : if (sbus_subreq == NULL) {
331 0 : error = NULL;
332 0 : goto fail;
333 : }
334 :
335 0 : if (iface->vtable->meta->invoker_get_all == NULL) {
336 0 : DEBUG(SSSDBG_TRACE_FUNC, "No get all invoker set,"
337 : "using the default one\n");
338 :
339 0 : sbus_invoke_get_all(sbus_req);
340 : } else {
341 0 : iface->vtable->meta->invoker_get_all(sbus_subreq);
342 : }
343 :
344 0 : return EOK;
345 :
346 : fail:
347 0 : return sbus_request_fail_and_finish(sbus_req, error);
348 : }
|