Line data Source code
1 : /*
2 : SSSD
3 :
4 : Simple access control
5 :
6 : Copyright (C) Sumit Bose <sbose@redhat.com> 2010
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 "providers/dp_backend.h"
23 : #include "providers/simple/simple_access.h"
24 : #include "util/sss_utf8.h"
25 : #include "db/sysdb.h"
26 :
27 : #define NON_EXIST_USR_ALLOW "The user %s does not exist. Possible typo in simple_allow_users.\n"
28 : #define NON_EXIST_USR_DENY "The user %s does not exist. Possible typo in simple_deny_users.\n"
29 : #define NON_EXIST_GRP_ALLOW "The group %s does not exist. Possible typo in simple_allow_groups.\n"
30 : #define NON_EXIST_GRP_DENY "The group %s does not exist. Possible typo in simple_deny_groups.\n"
31 :
32 : static bool
33 13 : is_posix(const struct ldb_message *group)
34 : {
35 : const char *val;
36 :
37 13 : val = ldb_msg_find_attr_as_string(group, SYSDB_POSIX, NULL);
38 26 : if (!val || /* Groups are posix by default */
39 13 : strcasecmp(val, "TRUE") == 0) {
40 13 : return true;
41 : }
42 :
43 0 : return false;
44 : }
45 :
46 : /* Returns EOK if the result is definitive, EAGAIN if only partial result
47 : */
48 : static errno_t
49 18 : simple_check_users(struct simple_ctx *ctx, const char *username,
50 : bool *access_granted)
51 : {
52 18 : struct sss_domain_info *domain = NULL;
53 : int i;
54 :
55 : /* First, check whether the user is in the allowed users list */
56 18 : if (ctx->allow_users != NULL) {
57 15 : for(i = 0; ctx->allow_users[i] != NULL; i++) {
58 11 : domain = find_domain_by_object_name(ctx->domain,
59 11 : ctx->allow_users[i]);
60 11 : if (domain == NULL) {
61 0 : DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_ALLOW,
62 : ctx->allow_users[i]);
63 0 : sss_log(SSS_LOG_CRIT, NON_EXIST_USR_ALLOW,
64 0 : ctx->allow_users[i]);
65 0 : continue;
66 : }
67 :
68 11 : if (sss_string_equal(domain->case_sensitive, username,
69 11 : ctx->allow_users[i])) {
70 3 : DEBUG(SSSDBG_TRACE_LIBS,
71 : "User [%s] found in allow list, access granted.\n",
72 : username);
73 :
74 : /* Do not return immediately on explicit allow
75 : * We need to make sure none of the user's groups
76 : * are denied. But there's no need to check username
77 : * matches any more.
78 : */
79 3 : *access_granted = true;
80 3 : break;
81 : }
82 : }
83 11 : } else if (!ctx->allow_groups) {
84 : /* If neither allow rule is in place, we'll assume allowed
85 : * unless a deny rule disables us below.
86 : */
87 5 : DEBUG(SSSDBG_TRACE_LIBS,
88 : "No allow rule, assumuing allow unless explicitly denied\n");
89 5 : *access_granted = true;
90 : }
91 :
92 : /* Next check whether this user has been specifically denied */
93 18 : if (ctx->deny_users != NULL) {
94 8 : for(i = 0; ctx->deny_users[i] != NULL; i++) {
95 6 : domain = find_domain_by_object_name(ctx->domain,
96 6 : ctx->deny_users[i]);
97 6 : if (domain == NULL) {
98 0 : DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_USR_DENY,
99 : ctx->deny_users[i]);
100 0 : sss_log(SSS_LOG_CRIT, NON_EXIST_USR_DENY,
101 0 : ctx->deny_users[i]);
102 0 : return EINVAL;
103 : }
104 :
105 6 : if (sss_string_equal(domain->case_sensitive, username,
106 6 : ctx->deny_users[i])) {
107 2 : DEBUG(SSSDBG_TRACE_LIBS,
108 : "User [%s] found in deny list, access denied.\n",
109 : ctx->deny_users[i]);
110 :
111 : /* Return immediately on explicit denial */
112 2 : *access_granted = false;
113 2 : return EOK;
114 : }
115 : }
116 : }
117 :
118 16 : return EAGAIN;
119 : }
120 :
121 : static errno_t
122 8 : simple_check_groups(struct simple_ctx *ctx, const char **group_names,
123 : bool *access_granted)
124 : {
125 8 : struct sss_domain_info *domain = NULL;
126 : bool matched;
127 : int i, j;
128 :
129 : /* Now process allow and deny group rules
130 : * If access was already granted above, we'll skip
131 : * this redundant rule check
132 : */
133 8 : if (ctx->allow_groups && !*access_granted) {
134 6 : matched = false;
135 14 : for (i = 0; ctx->allow_groups[i]; i++) {
136 10 : domain = find_domain_by_object_name(ctx->domain,
137 10 : ctx->allow_groups[i]);
138 10 : if (domain == NULL) {
139 0 : DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_ALLOW,
140 : ctx->allow_groups[i]);
141 0 : sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_ALLOW,
142 0 : ctx->allow_groups[i]);
143 :
144 0 : continue;
145 : }
146 :
147 22 : for(j = 0; group_names[j]; j++) {
148 28 : if (sss_string_equal(domain->case_sensitive,
149 28 : group_names[j], ctx->allow_groups[i])) {
150 2 : matched = true;
151 2 : break;
152 : }
153 : }
154 :
155 : /* If any group has matched, we can skip out on the
156 : * processing early
157 : */
158 10 : if (matched) {
159 2 : DEBUG(SSSDBG_TRACE_LIBS,
160 : "Group [%s] found in allow list, access granted.\n",
161 : group_names[j]);
162 2 : *access_granted = true;
163 2 : break;
164 : }
165 : }
166 : }
167 :
168 : /* Finally, process the deny group rules */
169 8 : if (ctx->deny_groups) {
170 4 : matched = false;
171 10 : for (i = 0; ctx->deny_groups[i]; i++) {
172 7 : domain = find_domain_by_object_name(ctx->domain,
173 7 : ctx->deny_groups[i]);
174 7 : if (domain == NULL) {
175 0 : DEBUG(SSSDBG_CRIT_FAILURE, NON_EXIST_GRP_DENY,
176 : ctx->deny_groups[i]);
177 0 : sss_log(SSS_LOG_CRIT, NON_EXIST_GRP_DENY,
178 0 : ctx->deny_groups[i]);
179 :
180 0 : return EINVAL;
181 : }
182 :
183 15 : for(j = 0; group_names[j]; j++) {
184 18 : if (sss_string_equal(domain->case_sensitive,
185 18 : group_names[j], ctx->deny_groups[i])) {
186 1 : matched = true;
187 1 : break;
188 : }
189 : }
190 :
191 : /* If any group has matched, we can skip out on the
192 : * processing early
193 : */
194 7 : if (matched) {
195 1 : DEBUG(SSSDBG_TRACE_LIBS,
196 : "Group [%s] found in deny list, access denied.\n",
197 : group_names[j]);
198 1 : *access_granted = false;
199 1 : break;
200 : }
201 : }
202 : }
203 :
204 8 : return EOK;
205 : }
206 :
207 : struct simple_resolve_group_state {
208 : struct sss_domain_info *domain;
209 : gid_t gid;
210 : struct simple_ctx *ctx;
211 :
212 : const char *name;
213 : };
214 :
215 : static errno_t
216 : simple_resolve_group_check(struct simple_resolve_group_state *state);
217 : static void simple_resolve_group_done(struct tevent_req *subreq);
218 :
219 : static struct tevent_req *
220 0 : simple_resolve_group_send(TALLOC_CTX *mem_ctx,
221 : struct tevent_context *ev,
222 : struct simple_ctx *ctx,
223 : struct sss_domain_info *domain,
224 : gid_t gid)
225 : {
226 : errno_t ret;
227 : struct tevent_req *req;
228 : struct tevent_req *subreq;
229 : struct simple_resolve_group_state *state;
230 : struct be_acct_req *ar;
231 :
232 0 : req = tevent_req_create(mem_ctx, &state,
233 : struct simple_resolve_group_state);
234 0 : if (!req) return NULL;
235 :
236 0 : state->domain = domain;
237 0 : state->gid = gid;
238 0 : state->ctx = ctx;
239 :
240 : /* First check if the group was updated already. If it was (maybe its
241 : * parent was updated first), then just shortcut */
242 0 : ret = simple_resolve_group_check(state);
243 0 : if (ret == EOK) {
244 0 : DEBUG(SSSDBG_TRACE_LIBS, "Group already updated\n");
245 0 : ret = EOK;
246 0 : goto done;
247 0 : } else if (ret != EAGAIN) {
248 0 : DEBUG(SSSDBG_OP_FAILURE,
249 : "Cannot check if group was already updated [%d]: %s\n",
250 : ret, sss_strerror(ret));
251 0 : goto done;
252 : }
253 : /* EAGAIN - still needs update */
254 :
255 0 : ar = talloc(state, struct be_acct_req);
256 0 : if (!ar) {
257 0 : ret = ENOMEM;
258 0 : goto done;
259 : }
260 :
261 0 : ar->entry_type = BE_REQ_GROUP;
262 0 : ar->attr_type = BE_ATTR_CORE;
263 0 : ar->filter_type = BE_FILTER_IDNUM;
264 0 : ar->filter_value = talloc_asprintf(ar, "%llu", (unsigned long long) gid);
265 0 : ar->domain = talloc_strdup(ar, state->domain->name);
266 0 : if (!ar->domain || !ar->filter_value) {
267 0 : ret = ENOMEM;
268 0 : goto done;
269 : }
270 :
271 0 : subreq = be_get_account_info_send(state, ev, NULL, ctx->be_ctx, ar);
272 0 : if (!subreq) {
273 0 : ret = ENOMEM;
274 0 : goto done;
275 : }
276 0 : tevent_req_set_callback(subreq, simple_resolve_group_done, req);
277 :
278 0 : return req;
279 :
280 : done:
281 0 : if (ret == EOK) {
282 0 : tevent_req_done(req);
283 : } else {
284 0 : tevent_req_error(req, ret);
285 : }
286 0 : tevent_req_post(req, ev);
287 0 : return req;
288 : }
289 :
290 : static errno_t
291 0 : simple_resolve_group_check(struct simple_resolve_group_state *state)
292 : {
293 : errno_t ret;
294 : struct ldb_message *group;
295 0 : const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
296 : SYSDB_GIDNUM, NULL };
297 :
298 : /* Check the cache by GID again and fetch the name */
299 0 : ret = sysdb_search_group_by_gid(state, state->domain, state->gid,
300 : group_attrs, &group);
301 0 : if (ret == ENOENT) {
302 : /* The group is missing, we will try to update it. */
303 0 : return EAGAIN;
304 0 : } else if (ret != EOK) {
305 0 : DEBUG(SSSDBG_OP_FAILURE,
306 : "Could not look up group by gid [%"SPRIgid"]: [%d][%s]\n",
307 : state->gid, ret, sss_strerror(ret));
308 0 : return ret;
309 : }
310 :
311 0 : state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
312 0 : if (!state->name) {
313 0 : DEBUG(SSSDBG_OP_FAILURE, "No group name\n");
314 0 : return ERR_ACCOUNT_UNKNOWN;
315 : }
316 :
317 0 : if (is_posix(group) == false) {
318 0 : DEBUG(SSSDBG_TRACE_LIBS,
319 : "The group is still non-POSIX\n");
320 0 : return EAGAIN;
321 : }
322 :
323 0 : DEBUG(SSSDBG_TRACE_LIBS, "Got POSIX group\n");
324 0 : return EOK;
325 : }
326 :
327 0 : static void simple_resolve_group_done(struct tevent_req *subreq)
328 : {
329 : struct tevent_req *req;
330 : struct simple_resolve_group_state *state;
331 : int err_maj;
332 : int err_min;
333 : errno_t ret;
334 : const char *err_msg;
335 :
336 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
337 0 : state = tevent_req_data(req, struct simple_resolve_group_state);
338 :
339 0 : ret = be_get_account_info_recv(subreq, state,
340 : &err_maj, &err_min, &err_msg);
341 0 : talloc_zfree(subreq);
342 0 : if (ret) {
343 0 : DEBUG(SSSDBG_OP_FAILURE, "be_get_account_info_recv failed\n");
344 0 : tevent_req_error(req, ret);
345 0 : return;
346 : }
347 :
348 0 : if (err_maj) {
349 0 : DEBUG(SSSDBG_MINOR_FAILURE,
350 : "Cannot refresh data from DP: %u,%u: %s\n",
351 : err_maj, err_min, err_msg);
352 0 : tevent_req_error(req, EIO);
353 0 : return;
354 : }
355 :
356 : /* Check the cache by GID again and fetch the name */
357 0 : ret = simple_resolve_group_check(state);
358 0 : if (ret != EOK) {
359 0 : DEBUG(SSSDBG_OP_FAILURE, "Refresh failed\n");
360 0 : tevent_req_error(req, ret);
361 0 : return;
362 : }
363 :
364 0 : tevent_req_done(req);
365 : }
366 :
367 : static errno_t
368 0 : simple_resolve_group_recv(struct tevent_req *req,
369 : TALLOC_CTX *mem_ctx,
370 : const char **name)
371 : {
372 : struct simple_resolve_group_state *state;
373 :
374 0 : state = tevent_req_data(req, struct simple_resolve_group_state);
375 :
376 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
377 :
378 0 : *name = talloc_strdup(mem_ctx, state->name);
379 0 : return EOK;
380 : }
381 :
382 : struct simple_group {
383 : struct sss_domain_info *domain;
384 : gid_t gid;
385 : };
386 :
387 : struct simple_check_groups_state {
388 : struct tevent_context *ev;
389 : struct simple_ctx *ctx;
390 : struct sss_domain_info *domain;
391 :
392 : struct simple_group *lookup_groups;
393 : size_t num_groups;
394 : size_t giter;
395 :
396 : const char **group_names;
397 : size_t num_names;
398 :
399 : bool failed_to_resolve_groups;
400 : };
401 :
402 : static void simple_check_get_groups_next(struct tevent_req *subreq);
403 :
404 : static errno_t
405 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
406 : gid_t gid);
407 : static errno_t
408 : simple_check_process_group(struct simple_check_groups_state *state,
409 : struct ldb_message *group);
410 :
411 : static struct tevent_req *
412 8 : simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
413 : struct tevent_context *ev,
414 : struct simple_ctx *ctx,
415 : const char *username)
416 : {
417 : errno_t ret;
418 : struct tevent_req *req;
419 : struct tevent_req *subreq;
420 : struct simple_check_groups_state *state;
421 8 : const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM,
422 : SYSDB_SID_STR, NULL };
423 : size_t group_count;
424 : struct ldb_message *user;
425 : struct ldb_message **groups;
426 : int i;
427 : gid_t gid;
428 :
429 8 : req = tevent_req_create(mem_ctx, &state,
430 : struct simple_check_groups_state);
431 8 : if (!req) return NULL;
432 :
433 8 : state->ev = ev;
434 8 : state->ctx = ctx;
435 8 : state->failed_to_resolve_groups = false;
436 :
437 8 : DEBUG(SSSDBG_TRACE_LIBS, "Looking up groups for user %s\n", username);
438 :
439 : /* get domain from username */
440 8 : state->domain = find_domain_by_object_name(ctx->domain, username);
441 8 : if (state->domain == NULL) {
442 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n", username);
443 0 : ret = EINVAL;
444 0 : goto done;
445 : }
446 :
447 8 : ret = sysdb_search_user_by_name(state, state->domain, username, attrs,
448 : &user);
449 8 : if (ret == ENOENT) {
450 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No such user %s\n", username);
451 0 : ret = ERR_ACCOUNT_UNKNOWN;
452 0 : goto done;
453 8 : } else if (ret != EOK) {
454 0 : DEBUG(SSSDBG_OP_FAILURE,
455 : "Could not look up username [%s]: [%d][%s]\n",
456 : username, ret, sss_strerror(ret));
457 0 : goto done;
458 : }
459 :
460 8 : ret = sysdb_asq_search(state, state->domain,
461 8 : user->dn, NULL, SYSDB_MEMBEROF,
462 : attrs, &group_count, &groups);
463 8 : if (ret != EOK) {
464 0 : goto done;
465 : }
466 :
467 8 : DEBUG(SSSDBG_TRACE_FUNC,
468 : "User %s is a member of %zu supplemental groups\n",
469 : username, group_count);
470 :
471 : /* One extra space for terminator, one extra space for private group */
472 8 : state->group_names = talloc_zero_array(state, const char *, group_count + 2);
473 8 : state->lookup_groups = talloc_zero_array(state, struct simple_group,
474 : group_count + 2);
475 8 : if (!state->group_names || !state->lookup_groups) {
476 0 : ret = ENOMEM;
477 0 : goto done;
478 : }
479 :
480 13 : for (i=0; i < group_count; i++) {
481 : /* Some providers (like the AD provider) might perform initgroups
482 : * without resolving the group names. In order for the simple access
483 : * provider to work correctly, we need to resolve the groups before
484 : * performing the access check. In AD provider, the situation is
485 : * even more tricky b/c the groups HAVE name, but their name
486 : * attribute is set to SID and they are set as non-POSIX
487 : */
488 5 : ret = simple_check_process_group(state, groups[i]);
489 5 : if (ret != EOK) {
490 0 : goto done;
491 : }
492 : }
493 :
494 8 : gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
495 8 : if (!gid) {
496 0 : DEBUG(SSSDBG_MINOR_FAILURE, "User %s has no gid?\n", username);
497 0 : ret = EINVAL;
498 0 : goto done;
499 : }
500 :
501 8 : ret = simple_check_get_groups_primary(state, gid);
502 8 : if (ret != EOK) {
503 0 : goto done;
504 : }
505 :
506 8 : if (state->num_groups == 0) {
507 : /* If all groups could have been resolved by name, we are
508 : * done
509 : */
510 8 : DEBUG(SSSDBG_TRACE_FUNC, "All groups had name attribute\n");
511 8 : ret = EOK;
512 8 : goto done;
513 : }
514 :
515 0 : DEBUG(SSSDBG_TRACE_FUNC, "Need to resolve %zu groups\n",
516 : state->num_groups);
517 0 : state->giter = 0;
518 0 : subreq = simple_resolve_group_send(req, state->ev, state->ctx,
519 0 : state->lookup_groups[state->giter].domain,
520 0 : state->lookup_groups[state->giter].gid);
521 0 : if (!subreq) {
522 0 : ret = ENOMEM;
523 0 : goto done;
524 : }
525 0 : tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
526 :
527 0 : return req;
528 :
529 : done:
530 8 : if (ret == EOK) {
531 8 : tevent_req_done(req);
532 : } else {
533 0 : tevent_req_error(req, ret);
534 : }
535 8 : tevent_req_post(req, ev);
536 8 : return req;
537 : }
538 :
539 0 : static void simple_check_get_groups_next(struct tevent_req *subreq)
540 : {
541 0 : struct tevent_req *req =
542 0 : tevent_req_callback_data(subreq, struct tevent_req);
543 0 : struct simple_check_groups_state *state =
544 0 : tevent_req_data(req, struct simple_check_groups_state);
545 : errno_t ret;
546 :
547 0 : ret = simple_resolve_group_recv(subreq, state->group_names,
548 0 : &state->group_names[state->num_names]);
549 0 : talloc_zfree(subreq);
550 0 : if (ret != EOK) {
551 0 : DEBUG(SSSDBG_OP_FAILURE,
552 : "Could not resolve name of group with GID %"SPRIgid"\n",
553 : state->lookup_groups[state->giter].gid);
554 0 : state->failed_to_resolve_groups = true;
555 : } else {
556 0 : state->num_names++;
557 : }
558 0 : state->giter++;
559 :
560 0 : if (state->giter < state->num_groups) {
561 0 : subreq = simple_resolve_group_send(req, state->ev, state->ctx,
562 0 : state->lookup_groups[state->giter].domain,
563 0 : state->lookup_groups[state->giter].gid);
564 0 : if (!subreq) {
565 0 : tevent_req_error(req, ENOMEM);
566 0 : return;
567 : }
568 0 : tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
569 0 : return;
570 : }
571 :
572 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "All groups resolved. Done.\n");
573 0 : tevent_req_done(req);
574 : }
575 :
576 : static errno_t
577 13 : simple_check_process_group(struct simple_check_groups_state *state,
578 : struct ldb_message *group)
579 : {
580 : const char *name;
581 : const char *group_sid;
582 : struct sss_domain_info *domain;
583 : gid_t gid;
584 : bool posix;
585 :
586 13 : posix = is_posix(group);
587 13 : name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
588 13 : gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
589 :
590 : /* With the current sysdb layout, every group has a name */
591 13 : if (name == NULL) {
592 0 : return EINVAL;
593 : }
594 :
595 13 : if (gid == 0) {
596 0 : if (posix == true) {
597 0 : DEBUG(SSSDBG_CRIT_FAILURE, "POSIX group without GID\n");
598 0 : return EINVAL;
599 : }
600 :
601 : /* Non-posix group with a name. Still can be used for access
602 : * control as the name should point to the real name, no SID
603 : */
604 0 : state->group_names[state->num_names] = talloc_strdup(state->group_names,
605 : name);
606 0 : if (!state->group_names[state->num_names]) {
607 0 : return ENOMEM;
608 : }
609 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
610 0 : state->num_names++;
611 0 : return EOK;
612 : }
613 :
614 : /* Here are only groups with a name and gid. POSIX group can already
615 : * be used, non-POSIX groups can be resolved */
616 13 : if (posix) {
617 13 : state->group_names[state->num_names] = talloc_strdup(state->group_names,
618 : name);
619 13 : if (!state->group_names[state->num_names]) {
620 0 : return ENOMEM;
621 : }
622 13 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
623 13 : state->num_names++;
624 13 : return EOK;
625 : }
626 :
627 : /* Try to get group SID and assign it a domain */
628 0 : group_sid = ldb_msg_find_attr_as_string(group, SYSDB_SID_STR, NULL);
629 0 : if (group_sid == NULL) {
630 : /* We will look it up in main domain. */
631 0 : domain = state->ctx->domain;
632 : } else {
633 0 : domain = find_domain_by_sid(state->ctx->domain, group_sid);
634 0 : if (domain == NULL) {
635 0 : DEBUG(SSSDBG_CRIT_FAILURE, "There is no domain information for "
636 : "SID %s\n", group_sid);
637 0 : return ENOENT;
638 : }
639 : }
640 :
641 : /* It is a non-posix group with a GID. Needs resolving */
642 0 : state->lookup_groups[state->num_groups].domain = domain;
643 0 : state->lookup_groups[state->num_groups].gid = gid;
644 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding GID %"SPRIgid"\n", gid);
645 0 : state->num_groups++;
646 0 : return EOK;
647 : }
648 :
649 : static errno_t
650 8 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
651 : gid_t gid)
652 : {
653 : errno_t ret;
654 8 : const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
655 : SYSDB_GIDNUM, SYSDB_SID_STR, NULL };
656 : struct ldb_message *msg;
657 :
658 8 : ret = sysdb_search_group_by_gid(state, state->domain, gid, group_attrs,
659 : &msg);
660 8 : if (ret != EOK) {
661 0 : DEBUG(SSSDBG_OP_FAILURE,
662 : "Could not look up primary group [%"SPRIgid"]: [%d][%s]\n",
663 : gid, ret, sss_strerror(ret));
664 : /* We have to treat this as non-fatal, because the primary
665 : * group may be local to the machine and not available in
666 : * our ID provider.
667 : */
668 : } else {
669 8 : ret = simple_check_process_group(state, msg);
670 8 : if (ret != EOK) {
671 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot process primary group\n");
672 0 : return ret;
673 : }
674 : }
675 :
676 8 : return EOK;
677 : }
678 :
679 : static errno_t
680 8 : simple_check_get_groups_recv(struct tevent_req *req,
681 : TALLOC_CTX *mem_ctx,
682 : const char ***_group_names)
683 : {
684 : struct simple_check_groups_state *state;
685 :
686 8 : state = tevent_req_data(req, struct simple_check_groups_state);
687 :
688 8 : TEVENT_REQ_RETURN_ON_ERROR(req);
689 :
690 8 : *_group_names = talloc_steal(mem_ctx, state->group_names);
691 8 : if (state->failed_to_resolve_groups) {
692 0 : return ERR_SIMPLE_GROUPS_MISSING;
693 : }
694 8 : return EOK;
695 : }
696 :
697 : struct simple_access_check_state {
698 : bool access_granted;
699 : struct simple_ctx *ctx;
700 : const char *username;
701 :
702 : const char **group_names;
703 : };
704 :
705 : static void simple_access_check_done(struct tevent_req *subreq);
706 :
707 18 : struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
708 : struct tevent_context *ev,
709 : struct simple_ctx *ctx,
710 : const char *username)
711 : {
712 : errno_t ret;
713 : struct tevent_req *req;
714 : struct tevent_req *subreq;
715 : struct simple_access_check_state *state;
716 :
717 18 : req = tevent_req_create(mem_ctx, &state,
718 : struct simple_access_check_state);
719 18 : if (!req) return NULL;
720 :
721 18 : state->access_granted = false;
722 18 : state->ctx = ctx;
723 18 : state->username = talloc_strdup(state, username);
724 18 : if (!state->username) {
725 0 : ret = ENOMEM;
726 0 : goto immediate;
727 : }
728 :
729 18 : DEBUG(SSSDBG_FUNC_DATA, "Simple access check for %s\n", username);
730 :
731 18 : ret = simple_check_users(ctx, username, &state->access_granted);
732 18 : if (ret == EOK) {
733 2 : goto immediate;
734 16 : } else if (ret != EAGAIN) {
735 0 : ret = ERR_INTERNAL;
736 0 : goto immediate;
737 : }
738 :
739 : /* EAGAIN -- check groups */
740 :
741 16 : if (!ctx->allow_groups && !ctx->deny_groups) {
742 : /* There are no group restrictions, so just return
743 : * here with whatever we've decided.
744 : */
745 8 : DEBUG(SSSDBG_TRACE_LIBS, "No group restrictions, end request\n");
746 8 : ret = EOK;
747 8 : goto immediate;
748 : }
749 :
750 : /* The group names might not be available. Fire a request to
751 : * gather them. In most cases, the request will just shortcut
752 : */
753 8 : subreq = simple_check_get_groups_send(state, ev, ctx, username);
754 8 : if (!subreq) {
755 0 : ret = ENOMEM;
756 0 : goto immediate;
757 : }
758 8 : tevent_req_set_callback(subreq, simple_access_check_done, req);
759 :
760 8 : return req;
761 :
762 : immediate:
763 10 : if (ret == EOK) {
764 10 : tevent_req_done(req);
765 : } else {
766 0 : tevent_req_error(req, ret);
767 : }
768 10 : tevent_req_post(req, ev);
769 10 : return req;
770 : }
771 :
772 :
773 8 : static void simple_access_check_done(struct tevent_req *subreq)
774 : {
775 8 : struct tevent_req *req =
776 8 : tevent_req_callback_data(subreq, struct tevent_req);
777 8 : struct simple_access_check_state *state =
778 8 : tevent_req_data(req, struct simple_access_check_state);
779 : errno_t ret;
780 :
781 : /* We know the names now. Run the check. */
782 8 : ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
783 :
784 8 : talloc_zfree(subreq);
785 8 : if (ret == ENOENT) {
786 : /* If the user wasn't found, just shortcut */
787 0 : state->access_granted = false;
788 0 : tevent_req_done(req);
789 0 : return;
790 8 : } else if (ret == ERR_SIMPLE_GROUPS_MISSING) {
791 0 : DEBUG(SSSDBG_OP_FAILURE,
792 : "Could not collect groups of user %s\n", state->username);
793 0 : if (state->ctx->deny_groups == NULL) {
794 0 : DEBUG(SSSDBG_TRACE_FUNC,
795 : "But no deny groups were defined so we can continue.\n");
796 : } else {
797 0 : DEBUG(SSSDBG_OP_FAILURE,
798 : "Some deny groups were defined, we can't continue\n");
799 0 : tevent_req_error(req, ret);
800 0 : return;
801 : }
802 8 : } else if (ret != EOK) {
803 0 : DEBUG(SSSDBG_OP_FAILURE,
804 : "Could not collect groups of user %s\n", state->username);
805 0 : tevent_req_error(req, ret);
806 0 : return;
807 : }
808 :
809 8 : ret = simple_check_groups(state->ctx, state->group_names,
810 : &state->access_granted);
811 8 : if (ret != EOK) {
812 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not check group access [%d]: %s\n",
813 : ret, sss_strerror(ret));
814 0 : tevent_req_error(req, ERR_INTERNAL);
815 0 : return;
816 : }
817 :
818 : /* Now just return whatever we decided */
819 8 : DEBUG(SSSDBG_TRACE_INTERNAL, "Group check done\n");
820 8 : tevent_req_done(req);
821 : }
822 :
823 18 : errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
824 : {
825 18 : struct simple_access_check_state *state =
826 18 : tevent_req_data(req, struct simple_access_check_state);
827 :
828 18 : TEVENT_REQ_RETURN_ON_ERROR(req);
829 :
830 36 : DEBUG(SSSDBG_TRACE_LIBS,
831 : "Access %sgranted\n", state->access_granted ? "" : "not ");
832 18 : if (access_granted) {
833 18 : *access_granted = state->access_granted;
834 : }
835 :
836 18 : return EOK;
837 : }
|