Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@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 <talloc.h>
23 : #include <tevent.h>
24 : #include <string.h>
25 :
26 : #include "db/sysdb.h"
27 : #include "util/util.h"
28 : #include "confdb/confdb.h"
29 : #include "responder/common/responder.h"
30 : #include "responder/ifp/ifp_domains.h"
31 :
32 : #define RETURN_DOM_PROP_AS_STRING(dbus_req, pvt_data, out, property) do { \
33 : struct sss_domain_info *__dom; \
34 : \
35 : *(out) = NULL; \
36 : \
37 : __dom = get_domain_info_from_req((dbus_req), (pvt_data)); \
38 : if (__dom == NULL) { \
39 : return; \
40 : } \
41 : \
42 : *(out) = __dom->property; \
43 : } while (0)
44 :
45 : static void ifp_list_domains_process(struct tevent_req *req);
46 :
47 0 : int ifp_list_domains(struct sbus_request *dbus_req,
48 : void *data)
49 : {
50 : struct ifp_ctx *ifp_ctx;
51 : struct ifp_req *ireq;
52 : struct tevent_req *req;
53 : DBusError *error;
54 : errno_t ret;
55 :
56 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
57 0 : if (ifp_ctx == NULL) {
58 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
59 0 : error = sbus_error_new(dbus_req, DBUS_ERROR_FAILED,
60 : "Invalid ifp context!");
61 0 : return sbus_request_fail_and_finish(dbus_req, error);
62 : }
63 :
64 0 : ret = ifp_req_create(dbus_req, ifp_ctx, &ireq);
65 0 : if (ret != EOK) {
66 0 : error = sbus_error_new(dbus_req, DBUS_ERROR_FAILED,
67 : "%s", sss_strerror(ret));
68 0 : return sbus_request_fail_and_finish(dbus_req, error);
69 : }
70 :
71 0 : req = sss_dp_get_domains_send(ireq, ifp_ctx->rctx, false, NULL);
72 0 : if (req == NULL) {
73 0 : return sbus_request_finish(ireq->dbus_req, NULL);
74 : }
75 :
76 0 : tevent_req_set_callback(req, ifp_list_domains_process, ireq);
77 :
78 0 : return EOK;
79 : }
80 :
81 0 : static void ifp_list_domains_process(struct tevent_req *req)
82 : {
83 : struct sss_domain_info *dom;
84 : struct ifp_req *ireq;
85 : const char **paths;
86 : char *p;
87 : DBusError *error;
88 : size_t num_domains;
89 : size_t pi;
90 : errno_t ret;
91 :
92 0 : ireq = tevent_req_callback_data(req, struct ifp_req);
93 :
94 0 : ret = sss_dp_get_domains_recv(req);
95 0 : talloc_free(req);
96 0 : if (ret != EOK) {
97 0 : error = sbus_error_new(ireq->dbus_req, DBUS_ERROR_FAILED,
98 : "Failed to refresh domain objects\n");
99 0 : sbus_request_fail_and_finish(ireq->dbus_req, error);
100 0 : return;
101 : }
102 :
103 0 : ret = sysdb_master_domain_update(ireq->ifp_ctx->rctx->domains);
104 0 : if (ret != EOK) {
105 0 : error = sbus_error_new(ireq->dbus_req, DBUS_ERROR_FAILED,
106 : "Failed to refresh subdomain list\n");
107 0 : sbus_request_fail_and_finish(ireq->dbus_req, error);
108 0 : return;
109 : }
110 :
111 0 : num_domains = 0;
112 0 : for (dom = ireq->ifp_ctx->rctx->domains;
113 : dom != NULL;
114 0 : dom = get_next_domain(dom, true)) {
115 0 : num_domains++;
116 : }
117 :
118 0 : paths = talloc_zero_array(ireq, const char *, num_domains);
119 0 : if (paths == NULL) {
120 0 : sbus_request_finish(ireq->dbus_req, NULL);
121 0 : return;
122 : }
123 :
124 0 : pi = 0;
125 0 : for (dom = ireq->ifp_ctx->rctx->domains;
126 : dom != NULL;
127 0 : dom = get_next_domain(dom, true)) {
128 0 : p = sbus_opath_compose(ireq, IFP_PATH_DOMAINS, dom->name);
129 0 : if (p == NULL) {
130 0 : DEBUG(SSSDBG_MINOR_FAILURE,
131 : "Could not create path for dom %s, skipping\n", dom->name);
132 0 : continue;
133 : }
134 0 : paths[pi] = p;
135 0 : pi++;
136 : }
137 :
138 0 : ret = iface_ifp_ListDomains_finish(ireq->dbus_req, paths, num_domains);
139 0 : if (ret != EOK) {
140 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not finish request!\n");
141 : }
142 : }
143 :
144 : struct ifp_get_domain_state {
145 : const char *name;
146 : struct ifp_req *ireq;
147 : };
148 :
149 : static void ifp_find_domain_by_name_process(struct tevent_req *req);
150 :
151 0 : int ifp_find_domain_by_name(struct sbus_request *dbus_req,
152 : void *data,
153 : const char *arg_name)
154 : {
155 : struct ifp_ctx *ifp_ctx;
156 : struct ifp_req *ireq;
157 : struct tevent_req *req;
158 : struct ifp_get_domain_state *state;
159 : DBusError *error;
160 : errno_t ret;
161 :
162 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
163 0 : if (ifp_ctx == NULL) {
164 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
165 0 : error = sbus_error_new(dbus_req, DBUS_ERROR_FAILED,
166 : "Invalid ifp context!");
167 0 : return sbus_request_fail_and_finish(dbus_req, error);
168 : }
169 :
170 0 : ret = ifp_req_create(dbus_req, ifp_ctx, &ireq);
171 0 : if (ret != EOK) {
172 0 : error = sbus_error_new(dbus_req, DBUS_ERROR_FAILED,
173 : "%s", sss_strerror(ret));
174 0 : return sbus_request_fail_and_finish(dbus_req, error);
175 : }
176 :
177 0 : state = talloc_zero(ireq, struct ifp_get_domain_state);
178 0 : if (state == NULL) {
179 0 : return sbus_request_finish(dbus_req, NULL);
180 : }
181 0 : state->name = arg_name;
182 0 : state->ireq = ireq;
183 :
184 0 : req = sss_dp_get_domains_send(ireq, ifp_ctx->rctx, false, NULL);
185 0 : if (req == NULL) {
186 0 : return sbus_request_finish(dbus_req, NULL);
187 : }
188 0 : tevent_req_set_callback(req, ifp_find_domain_by_name_process, state);
189 0 : return EOK;
190 : }
191 :
192 0 : static void ifp_find_domain_by_name_process(struct tevent_req *req)
193 : {
194 : errno_t ret;
195 : struct ifp_req *ireq;
196 : struct ifp_get_domain_state *state;
197 : struct sss_domain_info *iter;
198 : const char *path;
199 : DBusError *error;
200 :
201 0 : state = tevent_req_callback_data(req, struct ifp_get_domain_state);
202 0 : ireq = state->ireq;
203 :
204 0 : ret = sss_dp_get_domains_recv(req);
205 0 : talloc_free(req);
206 0 : if (ret != EOK) {
207 0 : error = sbus_error_new(ireq->dbus_req, DBUS_ERROR_FAILED,
208 : "Failed to refresh domain objects\n");
209 0 : sbus_request_fail_and_finish(ireq->dbus_req, error);
210 0 : return;
211 : }
212 :
213 0 : ret = sysdb_master_domain_update(ireq->ifp_ctx->rctx->domains);
214 0 : if (ret != EOK) {
215 0 : error = sbus_error_new(ireq->dbus_req, DBUS_ERROR_FAILED,
216 : "Failed to refresh subdomain list\n");
217 0 : sbus_request_fail_and_finish(ireq->dbus_req, error);
218 0 : return;
219 : }
220 :
221 : /* Reply with the domain that was asked for */
222 0 : for (iter = ireq->ifp_ctx->rctx->domains;
223 : iter != NULL;
224 0 : iter = get_next_domain(iter, true)) {
225 0 : if (strcasecmp(iter->name, state->name) == 0) {
226 0 : break;
227 : }
228 : }
229 :
230 0 : if (iter == NULL) {
231 0 : error = sbus_error_new(ireq->dbus_req, DBUS_ERROR_FAILED,
232 : "No such domain\n");
233 0 : sbus_request_fail_and_finish(ireq->dbus_req, error);
234 0 : return;
235 : }
236 :
237 0 : path = sbus_opath_compose(ireq, IFP_PATH_DOMAINS, iter->name);
238 0 : if (path == NULL) {
239 0 : DEBUG(SSSDBG_MINOR_FAILURE,
240 : "Could not create path for domain %s, skipping\n", iter->name);
241 0 : sbus_request_finish(ireq->dbus_req, NULL);
242 0 : return;
243 : }
244 :
245 0 : ret = iface_ifp_FindDomainByName_finish(ireq->dbus_req, path);
246 0 : if (ret != EOK) {
247 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not finish request!\n");
248 : }
249 : }
250 :
251 : static struct sss_domain_info *
252 0 : get_domain_info_from_req(struct sbus_request *dbus_req, void *data)
253 : {
254 0 : struct ifp_ctx *ctx = NULL;
255 0 : struct sss_domain_info *domains = NULL;
256 0 : struct sss_domain_info *iter = NULL;
257 0 : char *name = NULL;
258 :
259 0 : ctx = talloc_get_type(data, struct ifp_ctx);
260 0 : if (ctx == NULL) {
261 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
262 0 : return NULL;
263 : }
264 :
265 0 : name = sbus_opath_get_object_name(dbus_req, dbus_req->path,
266 : IFP_PATH_DOMAINS);
267 0 : if (name == NULL) {
268 0 : return NULL;
269 : }
270 :
271 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Looking for domain %s\n", name);
272 :
273 0 : domains = ctx->rctx->domains;
274 0 : for (iter = domains; iter != NULL; iter = get_next_domain(iter, true)) {
275 0 : if (strcasecmp(iter->name, name) == 0) {
276 0 : break;
277 : }
278 : }
279 :
280 0 : talloc_free(name);
281 0 : return iter;
282 : }
283 :
284 0 : static void get_server_list(struct sbus_request *dbus_req,
285 : void *data,
286 : const char ***_out,
287 : int *_out_len,
288 : bool backup)
289 : {
290 : static const char *srv[] = {"_srv_"};
291 0 : struct sss_domain_info *dom = NULL;
292 0 : struct ifp_ctx *ctx = NULL;
293 0 : const char *conf_path = NULL;
294 0 : const char *option = NULL;
295 0 : const char **out = NULL;
296 0 : char **servers = NULL;
297 : int num_servers;
298 : errno_t ret;
299 : int i;
300 :
301 0 : *_out = NULL;
302 0 : *_out_len = 0;
303 :
304 0 : dom = get_domain_info_from_req(dbus_req, data);
305 0 : if (dom == NULL) {
306 0 : return;
307 : }
308 :
309 0 : if (dom->parent != NULL) {
310 : /* subdomains are not present in configuration */
311 0 : ret = ENOENT;
312 0 : goto done;
313 : }
314 :
315 0 : ctx = talloc_get_type(data, struct ifp_ctx);
316 0 : if (ctx == NULL) {
317 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid ifp context!\n");
318 0 : ret = ENOMEM;
319 0 : goto done;
320 : }
321 :
322 0 : conf_path = talloc_asprintf(dbus_req, CONFDB_DOMAIN_PATH_TMPL, dom->name);
323 0 : if (conf_path == NULL) {
324 0 : ret = ENOMEM;
325 0 : goto done;
326 : }
327 :
328 : /* TODO: replace hardcoded values with option names from the provider */
329 0 : if (strcasecmp(dom->provider, "ldap") == 0) {
330 0 : option = backup == false ? "ldap_uri" : "ldap_backup_uri";
331 0 : } else if (strcasecmp(dom->provider, "ipa") == 0) {
332 0 : option = backup == false ? "ipa_server" : "ipa_backup_server";
333 0 : } else if (strcasecmp(dom->provider, "ad") == 0) {
334 0 : option = backup == false ? "ad_server" : "ad_backup_server";
335 : } else {
336 0 : ret = EINVAL;
337 0 : goto done;
338 : }
339 :
340 0 : ret = confdb_get_string_as_list(ctx->rctx->cdb, dbus_req, conf_path,
341 : option, &servers);
342 0 : if (ret != EOK) {
343 0 : goto done;
344 : }
345 :
346 0 : for (num_servers = 0; servers[num_servers] != NULL; num_servers++);
347 :
348 0 : if (num_servers == 0) {
349 0 : ret = ENOENT;
350 0 : goto done;
351 : }
352 :
353 0 : out = talloc_zero_array(dbus_req, const char*, num_servers);
354 0 : if (out == NULL) {
355 0 : ret = ENOMEM;
356 0 : goto done;
357 : }
358 :
359 0 : for (i = 0; i < num_servers; i++) {
360 0 : out[i] = talloc_steal(out, servers[i]);
361 : }
362 :
363 0 : *_out = out;
364 0 : *_out_len = num_servers;
365 :
366 0 : ret = EOK;
367 :
368 : done:
369 0 : if (ret == ENOENT) {
370 0 : *_out = srv;
371 0 : *_out_len = 1;
372 : }
373 :
374 0 : return;
375 : }
376 :
377 0 : void ifp_dom_get_name(struct sbus_request *dbus_req,
378 : void *data,
379 : const char **_out)
380 : {
381 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, name);
382 : }
383 :
384 0 : void ifp_dom_get_provider(struct sbus_request *dbus_req,
385 : void *data,
386 : const char **_out)
387 : {
388 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, provider);
389 : }
390 :
391 0 : void ifp_dom_get_primary_servers(struct sbus_request *dbus_req,
392 : void *data,
393 : const char ***_out,
394 : int *_out_len)
395 : {
396 0 : get_server_list(dbus_req, data, _out, _out_len, false);
397 0 : }
398 :
399 0 : void ifp_dom_get_backup_servers(struct sbus_request *dbus_req,
400 : void *data,
401 : const char ***_out,
402 : int *_out_len)
403 : {
404 0 : get_server_list(dbus_req, data, _out, _out_len, true);
405 0 : }
406 :
407 0 : void ifp_dom_get_min_id(struct sbus_request *dbus_req,
408 : void *data,
409 : uint32_t *_out)
410 : {
411 : struct sss_domain_info *dom;
412 :
413 0 : *_out = 1;
414 :
415 0 : dom = get_domain_info_from_req(dbus_req, data);
416 0 : if (dom == NULL) {
417 0 : return;
418 : }
419 :
420 0 : *_out = dom->id_min;
421 : }
422 :
423 0 : void ifp_dom_get_max_id(struct sbus_request *dbus_req,
424 : void *data,
425 : uint32_t *_out)
426 : {
427 : struct sss_domain_info *dom;
428 :
429 0 : *_out = 0;
430 :
431 0 : dom = get_domain_info_from_req(dbus_req, data);
432 0 : if (dom == NULL) {
433 0 : return;
434 : }
435 :
436 0 : *_out = dom->id_max;
437 : }
438 :
439 0 : void ifp_dom_get_realm(struct sbus_request *dbus_req,
440 : void *data,
441 : const char **_out)
442 : {
443 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, realm);
444 : }
445 :
446 0 : void ifp_dom_get_forest(struct sbus_request *dbus_req,
447 : void *data,
448 : const char **_out)
449 : {
450 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, forest);
451 : }
452 :
453 0 : void ifp_dom_get_login_format(struct sbus_request *dbus_req,
454 : void *data,
455 : const char **_out)
456 : {
457 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, names->re_pattern);
458 : }
459 :
460 0 : void ifp_dom_get_fqdn_format(struct sbus_request *dbus_req,
461 : void *data,
462 : const char **_out)
463 : {
464 0 : RETURN_DOM_PROP_AS_STRING(dbus_req, data, _out, names->fq_fmt);
465 : }
466 :
467 0 : void ifp_dom_get_enumerable(struct sbus_request *dbus_req,
468 : void *data,
469 : bool *_out)
470 : {
471 : struct sss_domain_info *dom;
472 :
473 0 : *_out = false;
474 :
475 0 : dom = get_domain_info_from_req(dbus_req, data);
476 0 : if (dom == NULL) {
477 0 : return;
478 : }
479 :
480 0 : *_out = dom->enumerate;
481 : }
482 :
483 0 : void ifp_dom_get_use_fqdn(struct sbus_request *dbus_req,
484 : void *data,
485 : bool *_out)
486 : {
487 : struct sss_domain_info *dom;
488 :
489 0 : *_out = false;
490 :
491 0 : dom = get_domain_info_from_req(dbus_req, data);
492 0 : if (dom == NULL) {
493 0 : return;
494 : }
495 :
496 0 : *_out = dom->fqnames;
497 : }
498 :
499 0 : void ifp_dom_get_subdomain(struct sbus_request *dbus_req,
500 : void *data,
501 : bool *_out)
502 : {
503 : struct sss_domain_info *dom;
504 :
505 0 : *_out = false;
506 :
507 0 : dom = get_domain_info_from_req(dbus_req, data);
508 0 : if (dom == NULL) {
509 0 : return;
510 : }
511 :
512 0 : *_out = dom->parent ? true : false;
513 : }
514 :
515 0 : void ifp_dom_get_parent_domain(struct sbus_request *dbus_req,
516 : void *data,
517 : const char **_out)
518 : {
519 : struct sss_domain_info *dom;
520 :
521 0 : *_out = NULL;
522 :
523 0 : dom = get_domain_info_from_req(dbus_req, data);
524 0 : if (dom == NULL) {
525 0 : return;
526 : }
527 :
528 0 : if (dom->parent == NULL) {
529 0 : *_out = "/";
530 0 : return;
531 : }
532 :
533 0 : *_out = sbus_opath_compose(dbus_req, IFP_PATH_DOMAINS,
534 : dom->parent->name);
535 : }
|