Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2015 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 : #include <string.h>
24 :
25 : #include "db/sysdb.h"
26 : #include "util/util.h"
27 : #include "util/strtonum.h"
28 : #include "util/cert.h"
29 : #include "sbus/sssd_dbus_errors.h"
30 : #include "responder/common/responder.h"
31 : #include "responder/common/responder_cache_req.h"
32 : #include "responder/ifp/ifp_users.h"
33 : #include "responder/ifp/ifp_groups.h"
34 : #include "responder/ifp/ifp_cache.h"
35 :
36 0 : char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx,
37 : struct sss_domain_info *domain,
38 : struct ldb_message *msg)
39 : {
40 : const char *uid;
41 :
42 0 : uid = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL);
43 :
44 0 : if (uid == NULL) {
45 0 : return NULL;
46 : }
47 :
48 0 : return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, uid);
49 : }
50 :
51 0 : static errno_t ifp_users_decompose_path(struct sss_domain_info *domains,
52 : const char *path,
53 : struct sss_domain_info **_domain,
54 : uid_t *_uid)
55 : {
56 0 : char **parts = NULL;
57 : struct sss_domain_info *domain;
58 : uid_t uid;
59 : errno_t ret;
60 :
61 0 : ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_USERS, 2, &parts);
62 0 : if (ret != EOK) {
63 0 : return ret;
64 : }
65 :
66 0 : domain = find_domain_by_name(domains, parts[0], false);
67 0 : if (domain == NULL) {
68 0 : ret = ERR_DOMAIN_NOT_FOUND;
69 0 : goto done;
70 : }
71 :
72 0 : uid = strtouint32(parts[1], NULL, 10);
73 0 : ret = errno;
74 0 : if (ret != EOK) {
75 0 : goto done;
76 : }
77 :
78 0 : *_domain = domain;
79 0 : *_uid = uid;
80 :
81 : done:
82 0 : talloc_free(parts);
83 0 : return ret;
84 : }
85 :
86 : static void ifp_users_find_by_name_done(struct tevent_req *req);
87 :
88 0 : int ifp_users_find_by_name(struct sbus_request *sbus_req,
89 : void *data,
90 : const char *name)
91 : {
92 : struct ifp_ctx *ctx;
93 : struct tevent_req *req;
94 :
95 0 : ctx = talloc_get_type(data, struct ifp_ctx);
96 0 : if (ctx == NULL) {
97 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
98 0 : return ERR_INTERNAL;
99 : }
100 :
101 0 : req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
102 : ctx->ncache, ctx->neg_timeout, 0,
103 : NULL, name);
104 0 : if (req == NULL) {
105 0 : return ENOMEM;
106 : }
107 :
108 0 : tevent_req_set_callback(req, ifp_users_find_by_name_done, sbus_req);
109 :
110 0 : return EOK;
111 : }
112 :
113 : static void
114 0 : ifp_users_find_by_name_done(struct tevent_req *req)
115 : {
116 : DBusError *error;
117 : struct sbus_request *sbus_req;
118 : struct sss_domain_info *domain;
119 : struct ldb_result *result;
120 : char *object_path;
121 : errno_t ret;
122 :
123 0 : sbus_req = tevent_req_callback_data(req, struct sbus_request);
124 :
125 0 : ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
126 0 : talloc_zfree(req);
127 0 : if (ret == ENOENT) {
128 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
129 : "User not found");
130 0 : goto done;
131 0 : } else if (ret != EOK) {
132 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
133 : "user [%d]: %s\n", ret, sss_strerror(ret));
134 0 : goto done;
135 : }
136 :
137 0 : object_path = ifp_users_build_path_from_msg(sbus_req, domain,
138 0 : result->msgs[0]);
139 0 : if (object_path == NULL) {
140 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
141 : "Failed to compose object path");
142 0 : goto done;
143 : }
144 :
145 0 : ret = EOK;
146 :
147 : done:
148 0 : if (ret != EOK) {
149 0 : sbus_request_fail_and_finish(sbus_req, error);
150 0 : return;
151 : }
152 :
153 0 : iface_ifp_users_FindByName_finish(sbus_req, object_path);
154 0 : return;
155 : }
156 :
157 : static void ifp_users_find_by_id_done(struct tevent_req *req);
158 :
159 0 : int ifp_users_find_by_id(struct sbus_request *sbus_req,
160 : void *data,
161 : uint32_t id)
162 : {
163 : struct ifp_ctx *ctx;
164 : struct tevent_req *req;
165 :
166 0 : ctx = talloc_get_type(data, struct ifp_ctx);
167 0 : if (ctx == NULL) {
168 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
169 0 : return ERR_INTERNAL;
170 : }
171 :
172 0 : req = cache_req_user_by_id_send(sbus_req, ctx->rctx->ev, ctx->rctx,
173 : ctx->ncache, ctx->neg_timeout, 0,
174 : NULL, id);
175 0 : if (req == NULL) {
176 0 : return ENOMEM;
177 : }
178 :
179 0 : tevent_req_set_callback(req, ifp_users_find_by_id_done, sbus_req);
180 :
181 0 : return EOK;
182 : }
183 :
184 : static void
185 0 : ifp_users_find_by_id_done(struct tevent_req *req)
186 : {
187 : DBusError *error;
188 : struct sbus_request *sbus_req;
189 : struct sss_domain_info *domain;
190 : struct ldb_result *result;
191 : char *object_path;
192 : errno_t ret;
193 :
194 0 : sbus_req = tevent_req_callback_data(req, struct sbus_request);
195 :
196 0 : ret = cache_req_user_by_id_recv(sbus_req, req, &result, &domain);
197 0 : talloc_zfree(req);
198 0 : if (ret == ENOENT) {
199 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
200 : "User not found");
201 0 : goto done;
202 0 : } else if (ret != EOK) {
203 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
204 : "user [%d]: %s\n", ret, sss_strerror(ret));
205 0 : goto done;
206 : }
207 :
208 0 : object_path = ifp_users_build_path_from_msg(sbus_req, domain,
209 0 : result->msgs[0]);
210 0 : if (object_path == NULL) {
211 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
212 : "Failed to compose object path");
213 0 : goto done;
214 : }
215 :
216 : done:
217 0 : if (ret != EOK) {
218 0 : sbus_request_fail_and_finish(sbus_req, error);
219 0 : return;
220 : }
221 :
222 0 : iface_ifp_users_FindByID_finish(sbus_req, object_path);
223 0 : return;
224 : }
225 :
226 : static void ifp_users_find_by_cert_done(struct tevent_req *req);
227 :
228 0 : int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data,
229 : const char *pem_cert)
230 : {
231 : struct ifp_ctx *ctx;
232 : struct tevent_req *req;
233 : int ret;
234 : char *derb64;
235 : DBusError *error;
236 :
237 0 : ctx = talloc_get_type(data, struct ifp_ctx);
238 0 : if (ctx == NULL) {
239 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
240 0 : return ERR_INTERNAL;
241 : }
242 :
243 0 : ret = sss_cert_pem_to_derb64(sbus_req, pem_cert, &derb64);
244 0 : if (ret != EOK) {
245 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_cert_pem_to_derb64 failed.\n");
246 :
247 0 : if (ret == ENOMEM) {
248 0 : return ret;
249 : }
250 :
251 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_INVALID_ARGS,
252 : "Invalid certificate format");
253 0 : sbus_request_fail_and_finish(sbus_req, error);
254 : /* the connection is already terminated with an error message, hence
255 : * we have to return EOK to not terminate the connection twice. */
256 0 : return EOK;
257 : }
258 :
259 0 : req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx,
260 : ctx->ncache, ctx->neg_timeout, 0,
261 : NULL, derb64);
262 0 : if (req == NULL) {
263 0 : return ENOMEM;
264 : }
265 :
266 0 : tevent_req_set_callback(req, ifp_users_find_by_cert_done, sbus_req);
267 :
268 0 : return EOK;
269 : }
270 :
271 0 : static void ifp_users_find_by_cert_done(struct tevent_req *req)
272 : {
273 : DBusError *error;
274 : struct sbus_request *sbus_req;
275 : struct sss_domain_info *domain;
276 : struct ldb_result *result;
277 : char *object_path;
278 : errno_t ret;
279 :
280 0 : sbus_req = tevent_req_callback_data(req, struct sbus_request);
281 :
282 0 : ret = cache_req_user_by_cert_recv(sbus_req, req, &result, &domain, NULL);
283 0 : talloc_zfree(req);
284 0 : if (ret == ENOENT) {
285 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
286 : "User not found");
287 0 : goto done;
288 0 : } else if (ret != EOK) {
289 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
290 : "user [%d]: %s\n", ret, sss_strerror(ret));
291 0 : goto done;
292 : }
293 :
294 0 : object_path = ifp_users_build_path_from_msg(sbus_req, domain,
295 0 : result->msgs[0]);
296 0 : if (object_path == NULL) {
297 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
298 : "Failed to compose object path");
299 0 : goto done;
300 : }
301 :
302 : done:
303 0 : if (ret != EOK) {
304 0 : sbus_request_fail_and_finish(sbus_req, error);
305 0 : return;
306 : }
307 :
308 0 : iface_ifp_users_FindByCertificate_finish(sbus_req, object_path);
309 0 : return;
310 : }
311 :
312 0 : static int ifp_users_list_copy(struct ifp_list_ctx *list_ctx,
313 : struct ldb_result *result)
314 : {
315 : size_t copy_count, i;
316 :
317 0 : copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
318 :
319 0 : for (i = 0; i < copy_count; i++) {
320 0 : list_ctx->paths[list_ctx->path_count + i] = \
321 0 : ifp_users_build_path_from_msg(list_ctx->paths,
322 : list_ctx->dom,
323 0 : result->msgs[i]);
324 0 : if (list_ctx->paths[list_ctx->path_count + i] == NULL) {
325 0 : return ENOMEM;
326 : }
327 : }
328 :
329 0 : list_ctx->path_count += copy_count;
330 0 : return EOK;
331 : }
332 :
333 : static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx);
334 : static void ifp_users_list_by_name_done(struct tevent_req *req);
335 : static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx);
336 :
337 0 : int ifp_users_list_by_name(struct sbus_request *sbus_req,
338 : void *data,
339 : const char *filter,
340 : uint32_t limit)
341 : {
342 : struct ifp_ctx *ctx;
343 : struct ifp_list_ctx *list_ctx;
344 :
345 0 : ctx = talloc_get_type(data, struct ifp_ctx);
346 0 : if (ctx == NULL) {
347 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
348 0 : return ERR_INTERNAL;
349 : }
350 :
351 0 : list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
352 0 : if (list_ctx == NULL) {
353 0 : return ENOMEM;
354 : }
355 :
356 0 : return ifp_users_list_by_name_step(list_ctx);
357 : }
358 :
359 0 : static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx)
360 : {
361 : struct tevent_req *req;
362 :
363 0 : req = cache_req_user_by_filter_send(list_ctx,
364 0 : list_ctx->ctx->rctx->ev,
365 0 : list_ctx->ctx->rctx,
366 0 : list_ctx->dom->name,
367 : list_ctx->filter);
368 0 : if (req == NULL) {
369 0 : return ENOMEM;
370 : }
371 0 : tevent_req_set_callback(req,
372 : ifp_users_list_by_name_done, list_ctx);
373 :
374 0 : return EOK;
375 : }
376 :
377 0 : static void ifp_users_list_by_name_done(struct tevent_req *req)
378 : {
379 : DBusError *error;
380 : struct ifp_list_ctx *list_ctx;
381 : struct sbus_request *sbus_req;
382 : struct ldb_result *result;
383 : struct sss_domain_info *domain;
384 : errno_t ret;
385 :
386 0 : list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
387 0 : sbus_req = list_ctx->sbus_req;
388 :
389 0 : ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
390 0 : talloc_zfree(req);
391 0 : if (ret != EOK && ret != ENOENT) {
392 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
393 : "users by filter [%d]: %s\n", ret, sss_strerror(ret));
394 0 : sbus_request_fail_and_finish(sbus_req, error);
395 0 : return;
396 : }
397 :
398 0 : ret = ifp_users_list_copy(list_ctx, result);
399 0 : if (ret != EOK) {
400 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
401 : "Failed to copy domain result");
402 0 : sbus_request_fail_and_finish(sbus_req, error);
403 0 : return;
404 : }
405 :
406 0 : list_ctx->dom = get_next_domain(list_ctx->dom, true);
407 0 : if (list_ctx->dom == NULL) {
408 0 : return ifp_users_list_by_name_reply(list_ctx);
409 : }
410 :
411 0 : ret = ifp_users_list_by_name_step(list_ctx);
412 0 : if (ret != EOK) {
413 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
414 : "Failed to start next-domain search");
415 0 : sbus_request_fail_and_finish(sbus_req, error);
416 0 : return;
417 : }
418 : }
419 :
420 0 : static void ifp_users_list_by_name_reply(struct ifp_list_ctx *list_ctx)
421 : {
422 0 : iface_ifp_users_ListByName_finish(list_ctx->sbus_req,
423 : list_ctx->paths,
424 0 : list_ctx->path_count);
425 0 : }
426 :
427 : static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req);
428 :
429 0 : int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req,
430 : void *data,
431 : const char *domain,
432 : const char *filter,
433 : uint32_t limit)
434 : {
435 : struct tevent_req *req;
436 : struct ifp_ctx *ctx;
437 : struct ifp_list_ctx *list_ctx;
438 :
439 0 : ctx = talloc_get_type(data, struct ifp_ctx);
440 0 : if (ctx == NULL) {
441 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
442 0 : return ERR_INTERNAL;
443 : }
444 :
445 0 : list_ctx = ifp_list_ctx_new(sbus_req, ctx, filter, limit);
446 0 : if (list_ctx == NULL) {
447 0 : return ENOMEM;
448 : }
449 :
450 0 : req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx,
451 : domain, filter);
452 0 : if (req == NULL) {
453 0 : return ENOMEM;
454 : }
455 0 : tevent_req_set_callback(req,
456 : ifp_users_list_by_domain_and_name_done, list_ctx);
457 :
458 0 : return EOK;
459 : }
460 :
461 0 : static void ifp_users_list_by_domain_and_name_done(struct tevent_req *req)
462 : {
463 : DBusError *error;
464 : struct ifp_list_ctx *list_ctx;
465 : struct sbus_request *sbus_req;
466 : struct ldb_result *result;
467 : struct sss_domain_info *domain;
468 : errno_t ret;
469 : size_t copy_count, i;
470 :
471 0 : list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx);
472 0 : sbus_req = list_ctx->sbus_req;
473 :
474 0 : ret = cache_req_user_by_name_recv(sbus_req, req, &result, &domain, NULL);
475 0 : talloc_zfree(req);
476 0 : if (ret == ENOENT) {
477 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
478 : "User not found by filter");
479 0 : goto done;
480 0 : } else if (ret != EOK) {
481 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
482 : "users by filter [%d]: %s\n", ret, sss_strerror(ret));
483 0 : goto done;
484 : }
485 :
486 0 : copy_count = ifp_list_ctx_remaining_capacity(list_ctx, result->count);
487 :
488 0 : for (i = 0; i < copy_count; i++) {
489 0 : list_ctx->paths[i] = ifp_users_build_path_from_msg(list_ctx->paths,
490 : list_ctx->dom,
491 0 : result->msgs[i]);
492 0 : if (list_ctx->paths[i] == NULL) {
493 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL,
494 : "Failed to compose object path");
495 0 : goto done;
496 : }
497 : }
498 :
499 0 : list_ctx->path_count += copy_count;
500 :
501 : done:
502 0 : if (ret != EOK) {
503 0 : sbus_request_fail_and_finish(sbus_req, error);
504 0 : return;
505 : }
506 :
507 0 : iface_ifp_users_ListByDomainAndName_finish(sbus_req,
508 : list_ctx->paths,
509 0 : list_ctx->path_count);
510 0 : return;
511 : }
512 :
513 : static errno_t
514 0 : ifp_users_user_get(struct sbus_request *sbus_req,
515 : struct ifp_ctx *ifp_ctx,
516 : uid_t *_uid,
517 : struct sss_domain_info **_domain,
518 : struct ldb_message **_user)
519 : {
520 : struct sss_domain_info *domain;
521 : struct ldb_result *res;
522 : uid_t uid;
523 : errno_t ret;
524 :
525 0 : ret = ifp_users_decompose_path(ifp_ctx->rctx->domains, sbus_req->path,
526 : &domain, &uid);
527 0 : if (ret != EOK) {
528 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path"
529 : "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret));
530 0 : return ret;
531 : }
532 :
533 0 : if (_user != NULL) {
534 0 : ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &res);
535 0 : if (ret == EOK && res->count == 0) {
536 0 : *_user = NULL;
537 0 : ret = ENOENT;
538 : }
539 :
540 0 : if (ret != EOK) {
541 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n",
542 : uid, domain->name, ret, sss_strerror(ret));
543 : } else {
544 0 : *_user = res->msgs[0];
545 : }
546 : }
547 :
548 0 : if (ret == EOK || ret == ENOENT) {
549 0 : if (_uid != NULL) {
550 0 : *_uid = uid;
551 : }
552 :
553 0 : if (_domain != NULL) {
554 0 : *_domain = domain;
555 : }
556 : }
557 :
558 0 : return ret;
559 : }
560 :
561 0 : static void ifp_users_get_as_string(struct sbus_request *sbus_req,
562 : void *data,
563 : const char *attr,
564 : const char **_out)
565 : {
566 : struct ifp_ctx *ifp_ctx;
567 : struct ldb_message *msg;
568 : struct sss_domain_info *domain;
569 : errno_t ret;
570 :
571 0 : *_out = NULL;
572 :
573 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
574 0 : if (ifp_ctx == NULL) {
575 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
576 0 : return;
577 : }
578 :
579 0 : if (!ifp_is_user_attr_allowed(ifp_ctx, attr)) {
580 0 : DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n", attr);
581 0 : return;
582 : }
583 :
584 0 : ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg);
585 0 : if (ret != EOK) {
586 0 : return;
587 : }
588 :
589 0 : *_out = sss_view_ldb_msg_find_attr_as_string(domain, msg, attr, NULL);
590 :
591 0 : return;
592 : }
593 :
594 0 : static void ifp_users_get_as_uint32(struct sbus_request *sbus_req,
595 : void *data,
596 : const char *attr,
597 : uint32_t *_out)
598 : {
599 : struct ifp_ctx *ifp_ctx;
600 : struct ldb_message *msg;
601 : struct sss_domain_info *domain;
602 : errno_t ret;
603 :
604 0 : *_out = 0;
605 :
606 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
607 0 : if (ifp_ctx == NULL) {
608 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
609 0 : return;
610 : }
611 :
612 0 : if (!ifp_is_user_attr_allowed(ifp_ctx, attr)) {
613 0 : DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n", attr);
614 0 : return;
615 : }
616 :
617 0 : ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg);
618 0 : if (ret != EOK) {
619 0 : return;
620 : }
621 :
622 0 : *_out = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, attr, 0);
623 :
624 0 : return;
625 : }
626 :
627 : static void ifp_users_user_update_groups_list_done(struct tevent_req *req);
628 :
629 0 : int ifp_users_user_update_groups_list(struct sbus_request *sbus_req,
630 : void *data)
631 : {
632 : struct tevent_req *req;
633 : struct ifp_ctx *ctx;
634 : struct sss_domain_info *domain;
635 : const char *username;
636 : struct ldb_message *user;
637 : errno_t ret;
638 :
639 0 : ctx = talloc_get_type(data, struct ifp_ctx);
640 0 : if (ctx == NULL) {
641 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
642 0 : return ERR_INTERNAL;
643 : }
644 :
645 0 : ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
646 0 : if (ret != EOK) {
647 0 : return ret;
648 : }
649 :
650 0 : username = ldb_msg_find_attr_as_string(user, SYSDB_NAME, NULL);
651 0 : if (username == NULL) {
652 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User name is empty!\n");
653 0 : return ERR_INTERNAL;
654 : }
655 :
656 0 : req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx,
657 : ctx->ncache, ctx->neg_timeout, 0,
658 0 : domain->name, username);
659 0 : if (req == NULL) {
660 0 : return ENOMEM;
661 : }
662 :
663 0 : tevent_req_set_callback(req, ifp_users_user_update_groups_list_done,
664 : sbus_req);
665 :
666 0 : return EOK;
667 : }
668 :
669 0 : static void ifp_users_user_update_groups_list_done(struct tevent_req *req)
670 : {
671 : DBusError *error;
672 : struct sbus_request *sbus_req;
673 : errno_t ret;
674 :
675 0 : sbus_req = tevent_req_callback_data(req, struct sbus_request);
676 :
677 0 : ret = cache_req_initgr_by_name_recv(sbus_req, req, NULL, NULL, NULL);
678 0 : talloc_zfree(req);
679 0 : if (ret == ENOENT) {
680 0 : error = sbus_error_new(sbus_req, SBUS_ERROR_NOT_FOUND,
681 : "User not found");
682 0 : goto done;
683 0 : } else if (ret != EOK) {
684 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
685 : "user [%d]: %s\n", ret, sss_strerror(ret));
686 0 : goto done;
687 : }
688 :
689 : done:
690 0 : if (ret != EOK) {
691 0 : sbus_request_fail_and_finish(sbus_req, error);
692 0 : return;
693 : }
694 :
695 0 : iface_ifp_users_user_UpdateGroupsList_finish(sbus_req);
696 0 : return;
697 : }
698 :
699 0 : void ifp_users_user_get_name(struct sbus_request *sbus_req,
700 : void *data,
701 : const char **_out)
702 : {
703 0 : ifp_users_get_as_string(sbus_req, data, SYSDB_NAME, _out);
704 0 : }
705 :
706 0 : void ifp_users_user_get_uid_number(struct sbus_request *sbus_req,
707 : void *data,
708 : uint32_t *_out)
709 : {
710 0 : ifp_users_get_as_uint32(sbus_req, data, SYSDB_UIDNUM, _out);
711 0 : }
712 :
713 0 : void ifp_users_user_get_gid_number(struct sbus_request *sbus_req,
714 : void *data,
715 : uint32_t *_out)
716 : {
717 0 : ifp_users_get_as_uint32(sbus_req, data, SYSDB_GIDNUM, _out);
718 0 : }
719 :
720 0 : void ifp_users_user_get_gecos(struct sbus_request *sbus_req,
721 : void *data,
722 : const char **_out)
723 : {
724 0 : ifp_users_get_as_string(sbus_req, data, SYSDB_GECOS, _out);
725 0 : }
726 :
727 0 : void ifp_users_user_get_home_directory(struct sbus_request *sbus_req,
728 : void *data,
729 : const char **_out)
730 : {
731 0 : ifp_users_get_as_string(sbus_req, data, SYSDB_HOMEDIR, _out);
732 0 : }
733 :
734 0 : void ifp_users_user_get_login_shell(struct sbus_request *sbus_req,
735 : void *data,
736 : const char **_out)
737 : {
738 0 : ifp_users_get_as_string(sbus_req, data, SYSDB_SHELL, _out);
739 0 : }
740 :
741 0 : void ifp_users_user_get_groups(struct sbus_request *sbus_req,
742 : void *data,
743 : const char ***_out,
744 : int *_size)
745 : {
746 : struct ifp_ctx *ifp_ctx;
747 : struct sss_domain_info *domain;
748 : const char *username;
749 : struct ldb_message *user;
750 : struct ldb_result *res;
751 : const char **out;
752 : int num_groups;
753 : gid_t gid;
754 : errno_t ret;
755 : int i;
756 :
757 0 : *_out = NULL;
758 0 : *_size = 0;
759 :
760 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
761 0 : if (ifp_ctx == NULL) {
762 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
763 0 : return;
764 : }
765 :
766 0 : if (!ifp_is_user_attr_allowed(ifp_ctx, "groups")) {
767 0 : DEBUG(SSSDBG_TRACE_ALL, "Attribute %s is not allowed\n",
768 : SYSDB_MEMBEROF);
769 0 : return;
770 : }
771 :
772 0 : ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &user);
773 0 : if (ret != EOK) {
774 0 : return;
775 : }
776 :
777 0 : username = ldb_msg_find_attr_as_string(user, SYSDB_NAME, NULL);
778 0 : if (username == NULL) {
779 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User name is empty!\n");
780 0 : return;
781 : }
782 :
783 : /* Run initgroups. */
784 0 : ret = sysdb_initgroups_with_views(sbus_req, domain, username, &res);
785 0 : if (ret != EOK) {
786 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get groups for %s@%s [%d]: %s\n",
787 : username, domain->name, ret, sss_strerror(ret));
788 0 : return;
789 : }
790 :
791 0 : if (res->count == 0) {
792 0 : return;
793 : }
794 :
795 0 : out = talloc_zero_array(sbus_req, const char *, res->count);
796 0 : if (out == NULL) {
797 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
798 0 : return;
799 : }
800 :
801 0 : num_groups = 0;
802 0 : for (i = 0; i < res->count; i++) {
803 0 : gid = sss_view_ldb_msg_find_attr_as_uint64(domain, res->msgs[i],
804 : SYSDB_GIDNUM, 0);
805 0 : if (gid == 0) {
806 0 : continue;
807 : }
808 :
809 0 : out[i] = ifp_groups_build_path_from_msg(out, domain, res->msgs[i]);
810 0 : if (out[i] == NULL) {
811 0 : DEBUG(SSSDBG_CRIT_FAILURE, "ifp_groups_build_path() failed\n");
812 0 : return;
813 : }
814 :
815 0 : num_groups++;
816 : }
817 :
818 0 : *_out = out;
819 0 : *_size = num_groups;
820 : }
821 :
822 0 : void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
823 : void *data,
824 : hash_table_t **_out)
825 : {
826 : struct ifp_ctx *ifp_ctx;
827 : struct sss_domain_info *domain;
828 : struct ldb_message **user;
829 : struct ldb_message_element *el;
830 : struct ldb_dn *basedn;
831 : size_t count;
832 : uid_t uid;
833 : const char *filter;
834 : const char **extra;
835 : hash_table_t *table;
836 : hash_key_t key;
837 : hash_value_t value;
838 : const char **values;
839 : errno_t ret;
840 : int hret;
841 : int i;
842 :
843 0 : *_out = NULL;
844 :
845 0 : ifp_ctx = talloc_get_type(data, struct ifp_ctx);
846 0 : if (ifp_ctx == NULL) {
847 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n");
848 0 : return;
849 : }
850 :
851 0 : extra = ifp_get_user_extra_attributes(sbus_req, ifp_ctx);
852 0 : if (extra == NULL || extra[0] == NULL) {
853 0 : DEBUG(SSSDBG_TRACE_ALL, "No extra attributes to return\n");
854 0 : return;
855 : }
856 :
857 0 : ret = ifp_users_user_get(sbus_req, data, &uid, &domain, NULL);
858 0 : if (ret != EOK) {
859 0 : return;
860 : }
861 :
862 0 : basedn = sysdb_user_base_dn(sbus_req, domain);
863 0 : if (basedn == NULL) {
864 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_user_base_dn() failed\n");
865 0 : return;
866 : }
867 :
868 0 : filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%u))",
869 : SYSDB_OBJECTCLASS, SYSDB_USER_CLASS,
870 : SYSDB_UIDNUM, uid);
871 0 : if (filter == NULL) {
872 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
873 0 : return;
874 : }
875 :
876 0 : ret = sysdb_search_entry(sbus_req, domain->sysdb, basedn,
877 : LDB_SCOPE_ONELEVEL, filter,
878 : extra, &count, &user);
879 0 : if (ret != EOK) {
880 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user [%d]: %s\n",
881 : ret, sss_strerror(ret));
882 0 : return;
883 : }
884 :
885 0 : if (count == 0) {
886 0 : DEBUG(SSSDBG_TRACE_FUNC, "User %u not found!\n", uid);
887 0 : return;
888 0 : } else if (count > 1) {
889 0 : DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry found!\n");
890 0 : return;
891 : }
892 :
893 0 : ret = sss_hash_create(sbus_req, 10, &table);
894 0 : if (ret != EOK) {
895 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table!\n");
896 0 : return;
897 : }
898 :
899 : /* Read each extra attribute. */
900 0 : for (i = 0; extra[i] != NULL; i++) {
901 0 : el = ldb_msg_find_element(user[0], extra[i]);
902 0 : if (el == NULL) {
903 0 : DEBUG(SSSDBG_TRACE_ALL, "Attribute %s not found, skipping...\n",
904 : extra[i]);
905 0 : continue;
906 : }
907 :
908 0 : values = sss_ldb_el_to_string_list(table, el);
909 0 : if (values == NULL) {
910 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldb_el_to_string_list() failed\n");
911 0 : return;
912 : }
913 :
914 0 : key.type = HASH_KEY_STRING;
915 0 : key.str = talloc_strdup(table, extra[i]);
916 0 : if (key.str == NULL) {
917 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
918 0 : return;
919 : }
920 :
921 0 : value.type = HASH_VALUE_PTR;
922 0 : value.ptr = values;
923 :
924 0 : hret = hash_enter(table, &key, &value);
925 0 : if (hret != HASH_SUCCESS) {
926 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to insert entry "
927 : "into hash table: %d\n", hret);
928 0 : return;
929 : }
930 : }
931 :
932 0 : *_out = table;
933 : }
934 :
935 0 : int ifp_cache_list_user(struct sbus_request *sbus_req,
936 : void *data)
937 : {
938 0 : return ifp_cache_list(sbus_req, data, IFP_CACHE_USER);
939 : }
940 :
941 0 : int ifp_cache_list_by_domain_user(struct sbus_request *sbus_req,
942 : void *data,
943 : const char *domain)
944 : {
945 0 : return ifp_cache_list_by_domain(sbus_req, data, domain, IFP_CACHE_USER);
946 : }
947 :
948 0 : int ifp_cache_object_store_user(struct sbus_request *sbus_req,
949 : void *data)
950 : {
951 : DBusError *error;
952 : struct sss_domain_info *domain;
953 : struct ldb_message *user;
954 : errno_t ret;
955 :
956 0 : ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
957 0 : if (ret != EOK) {
958 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
959 : "user [%d]: %s\n", ret, sss_strerror(ret));
960 0 : return sbus_request_fail_and_finish(sbus_req, error);
961 : }
962 :
963 : /* The request is finished inside. */
964 0 : return ifp_cache_object_store(sbus_req, domain, user->dn);
965 : }
966 :
967 0 : int ifp_cache_object_remove_user(struct sbus_request *sbus_req,
968 : void *data)
969 : {
970 : DBusError *error;
971 : struct sss_domain_info *domain;
972 : struct ldb_message *user;
973 : errno_t ret;
974 :
975 0 : ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user);
976 0 : if (ret != EOK) {
977 0 : error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch "
978 : "user [%d]: %s\n", ret, sss_strerror(ret));
979 0 : return sbus_request_fail_and_finish(sbus_req, error);
980 : }
981 :
982 : /* The request is finished inside. */
983 0 : return ifp_cache_object_remove(sbus_req, domain, user->dn);
984 : }
|