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/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 = dp_req_send(state, ctx->be_ctx->provider, NULL, ar->domain,
272 : "Simple Resolve Group", DPT_ID, DPM_ACCOUNT_HANDLER,
273 : 0, ar, NULL);
274 0 : if (!subreq) {
275 0 : ret = ENOMEM;
276 0 : goto done;
277 : }
278 0 : tevent_req_set_callback(subreq, simple_resolve_group_done, req);
279 :
280 0 : return req;
281 :
282 : done:
283 0 : if (ret == EOK) {
284 0 : tevent_req_done(req);
285 : } else {
286 0 : tevent_req_error(req, ret);
287 : }
288 0 : tevent_req_post(req, ev);
289 0 : return req;
290 : }
291 :
292 : static errno_t
293 0 : simple_resolve_group_check(struct simple_resolve_group_state *state)
294 : {
295 : errno_t ret;
296 : struct ldb_message *group;
297 0 : const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
298 : SYSDB_GIDNUM, NULL };
299 :
300 : /* Check the cache by GID again and fetch the name */
301 0 : ret = sysdb_search_group_by_gid(state, state->domain, state->gid,
302 : group_attrs, &group);
303 0 : if (ret == ENOENT) {
304 : /* The group is missing, we will try to update it. */
305 0 : return EAGAIN;
306 0 : } else if (ret != EOK) {
307 0 : DEBUG(SSSDBG_OP_FAILURE,
308 : "Could not look up group by gid [%"SPRIgid"]: [%d][%s]\n",
309 : state->gid, ret, sss_strerror(ret));
310 0 : return ret;
311 : }
312 :
313 0 : state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
314 0 : if (!state->name) {
315 0 : DEBUG(SSSDBG_OP_FAILURE, "No group name\n");
316 0 : return ERR_ACCOUNT_UNKNOWN;
317 : }
318 :
319 0 : if (is_posix(group) == false) {
320 0 : DEBUG(SSSDBG_TRACE_LIBS,
321 : "The group is still non-POSIX\n");
322 0 : return EAGAIN;
323 : }
324 :
325 0 : DEBUG(SSSDBG_TRACE_LIBS, "Got POSIX group\n");
326 0 : return EOK;
327 : }
328 :
329 0 : static void simple_resolve_group_done(struct tevent_req *subreq)
330 : {
331 : struct tevent_req *req;
332 : struct simple_resolve_group_state *state;
333 : struct dp_reply_std *reply;
334 : errno_t ret;
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 = dp_req_recv_ptr(state, subreq, struct dp_reply_std, &reply);
340 0 : talloc_zfree(subreq);
341 0 : if (ret) {
342 0 : DEBUG(SSSDBG_OP_FAILURE, "dp_req_recv failed\n");
343 0 : tevent_req_error(req, ret);
344 0 : return;
345 : }
346 :
347 0 : if (reply->dp_error != DP_ERR_OK) {
348 0 : DEBUG(SSSDBG_MINOR_FAILURE,
349 : "Cannot refresh data from DP: %u,%u: %s\n",
350 : reply->dp_error, reply->error, reply->message);
351 0 : tevent_req_error(req, EIO);
352 0 : return;
353 : }
354 :
355 : /* Check the cache by GID again and fetch the name */
356 0 : ret = simple_resolve_group_check(state);
357 0 : if (ret != EOK) {
358 0 : DEBUG(SSSDBG_OP_FAILURE, "Refresh failed\n");
359 0 : tevent_req_error(req, ret);
360 0 : return;
361 : }
362 :
363 0 : tevent_req_done(req);
364 : }
365 :
366 : static errno_t
367 0 : simple_resolve_group_recv(struct tevent_req *req,
368 : TALLOC_CTX *mem_ctx,
369 : const char **name)
370 : {
371 : struct simple_resolve_group_state *state;
372 :
373 0 : state = tevent_req_data(req, struct simple_resolve_group_state);
374 :
375 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
376 :
377 0 : *name = talloc_strdup(mem_ctx, state->name);
378 0 : return EOK;
379 : }
380 :
381 : struct simple_group {
382 : struct sss_domain_info *domain;
383 : gid_t gid;
384 : };
385 :
386 : struct simple_check_groups_state {
387 : struct tevent_context *ev;
388 : struct simple_ctx *ctx;
389 : struct sss_domain_info *domain;
390 :
391 : struct simple_group *lookup_groups;
392 : size_t num_groups;
393 : size_t giter;
394 :
395 : const char **group_names;
396 : size_t num_names;
397 :
398 : bool failed_to_resolve_groups;
399 : };
400 :
401 : static void simple_check_get_groups_next(struct tevent_req *subreq);
402 :
403 : static errno_t
404 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
405 : gid_t gid);
406 : static errno_t
407 : simple_check_process_group(struct simple_check_groups_state *state,
408 : struct ldb_message *group);
409 :
410 : static struct tevent_req *
411 8 : simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
412 : struct tevent_context *ev,
413 : struct simple_ctx *ctx,
414 : const char *username)
415 : {
416 : errno_t ret;
417 : struct tevent_req *req;
418 : struct tevent_req *subreq;
419 : struct simple_check_groups_state *state;
420 8 : const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM,
421 : SYSDB_SID_STR, NULL };
422 : size_t group_count;
423 : struct ldb_message *user;
424 : struct ldb_message **groups;
425 : int i;
426 : gid_t gid;
427 :
428 8 : req = tevent_req_create(mem_ctx, &state,
429 : struct simple_check_groups_state);
430 8 : if (!req) return NULL;
431 :
432 8 : state->ev = ev;
433 8 : state->ctx = ctx;
434 8 : state->failed_to_resolve_groups = false;
435 :
436 8 : DEBUG(SSSDBG_TRACE_LIBS, "Looking up groups for user %s\n", username);
437 :
438 : /* get domain from username */
439 8 : state->domain = find_domain_by_object_name(ctx->domain, username);
440 8 : if (state->domain == NULL) {
441 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid user %s!\n", username);
442 0 : ret = EINVAL;
443 0 : goto done;
444 : }
445 :
446 8 : ret = sysdb_search_user_by_name(state, state->domain, username, attrs,
447 : &user);
448 8 : if (ret == ENOENT) {
449 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No such user %s\n", username);
450 0 : ret = ERR_ACCOUNT_UNKNOWN;
451 0 : goto done;
452 8 : } else if (ret != EOK) {
453 0 : DEBUG(SSSDBG_OP_FAILURE,
454 : "Could not look up username [%s]: [%d][%s]\n",
455 : username, ret, sss_strerror(ret));
456 0 : goto done;
457 : }
458 :
459 8 : ret = sysdb_asq_search(state, state->domain,
460 8 : user->dn, NULL, SYSDB_MEMBEROF,
461 : attrs, &group_count, &groups);
462 8 : if (ret != EOK) {
463 0 : goto done;
464 : }
465 :
466 8 : DEBUG(SSSDBG_TRACE_FUNC,
467 : "User %s is a member of %zu supplemental groups\n",
468 : username, group_count);
469 :
470 : /* One extra space for terminator, one extra space for private group */
471 8 : state->group_names = talloc_zero_array(state, const char *, group_count + 2);
472 8 : state->lookup_groups = talloc_zero_array(state, struct simple_group,
473 : group_count + 2);
474 8 : if (!state->group_names || !state->lookup_groups) {
475 0 : ret = ENOMEM;
476 0 : goto done;
477 : }
478 :
479 13 : for (i=0; i < group_count; i++) {
480 : /* Some providers (like the AD provider) might perform initgroups
481 : * without resolving the group names. In order for the simple access
482 : * provider to work correctly, we need to resolve the groups before
483 : * performing the access check. In AD provider, the situation is
484 : * even more tricky b/c the groups HAVE name, but their name
485 : * attribute is set to SID and they are set as non-POSIX
486 : */
487 5 : ret = simple_check_process_group(state, groups[i]);
488 5 : if (ret != EOK) {
489 0 : goto done;
490 : }
491 : }
492 :
493 8 : gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
494 8 : if (!gid) {
495 0 : DEBUG(SSSDBG_MINOR_FAILURE, "User %s has no gid?\n", username);
496 0 : ret = EINVAL;
497 0 : goto done;
498 : }
499 :
500 8 : ret = simple_check_get_groups_primary(state, gid);
501 8 : if (ret != EOK) {
502 0 : goto done;
503 : }
504 :
505 8 : if (state->num_groups == 0) {
506 : /* If all groups could have been resolved by name, we are
507 : * done
508 : */
509 8 : DEBUG(SSSDBG_TRACE_FUNC, "All groups had name attribute\n");
510 8 : ret = EOK;
511 8 : goto done;
512 : }
513 :
514 0 : DEBUG(SSSDBG_TRACE_FUNC, "Need to resolve %zu groups\n",
515 : state->num_groups);
516 0 : state->giter = 0;
517 0 : subreq = simple_resolve_group_send(req, state->ev, state->ctx,
518 0 : state->lookup_groups[state->giter].domain,
519 0 : state->lookup_groups[state->giter].gid);
520 0 : if (!subreq) {
521 0 : ret = ENOMEM;
522 0 : goto done;
523 : }
524 0 : tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
525 :
526 0 : return req;
527 :
528 : done:
529 8 : if (ret == EOK) {
530 8 : tevent_req_done(req);
531 : } else {
532 0 : tevent_req_error(req, ret);
533 : }
534 8 : tevent_req_post(req, ev);
535 8 : return req;
536 : }
537 :
538 0 : static void simple_check_get_groups_next(struct tevent_req *subreq)
539 : {
540 0 : struct tevent_req *req =
541 0 : tevent_req_callback_data(subreq, struct tevent_req);
542 0 : struct simple_check_groups_state *state =
543 0 : tevent_req_data(req, struct simple_check_groups_state);
544 : errno_t ret;
545 :
546 0 : ret = simple_resolve_group_recv(subreq, state->group_names,
547 0 : &state->group_names[state->num_names]);
548 0 : talloc_zfree(subreq);
549 0 : if (ret != EOK) {
550 0 : DEBUG(SSSDBG_OP_FAILURE,
551 : "Could not resolve name of group with GID %"SPRIgid"\n",
552 : state->lookup_groups[state->giter].gid);
553 0 : state->failed_to_resolve_groups = true;
554 : } else {
555 0 : state->num_names++;
556 : }
557 0 : state->giter++;
558 :
559 0 : if (state->giter < state->num_groups) {
560 0 : subreq = simple_resolve_group_send(req, state->ev, state->ctx,
561 0 : state->lookup_groups[state->giter].domain,
562 0 : state->lookup_groups[state->giter].gid);
563 0 : if (!subreq) {
564 0 : tevent_req_error(req, ENOMEM);
565 0 : return;
566 : }
567 0 : tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
568 0 : return;
569 : }
570 :
571 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "All groups resolved. Done.\n");
572 0 : tevent_req_done(req);
573 : }
574 :
575 : static errno_t
576 13 : simple_check_process_group(struct simple_check_groups_state *state,
577 : struct ldb_message *group)
578 : {
579 : const char *name;
580 : const char *group_sid;
581 : struct sss_domain_info *domain;
582 : gid_t gid;
583 : bool posix;
584 :
585 13 : posix = is_posix(group);
586 13 : name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
587 13 : gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
588 :
589 : /* With the current sysdb layout, every group has a name */
590 13 : if (name == NULL) {
591 0 : return EINVAL;
592 : }
593 :
594 13 : if (gid == 0) {
595 0 : if (posix == true) {
596 0 : DEBUG(SSSDBG_CRIT_FAILURE, "POSIX group without GID\n");
597 0 : return EINVAL;
598 : }
599 :
600 : /* Non-posix group with a name. Still can be used for access
601 : * control as the name should point to the real name, no SID
602 : */
603 0 : state->group_names[state->num_names] = talloc_strdup(state->group_names,
604 : name);
605 0 : if (!state->group_names[state->num_names]) {
606 0 : return ENOMEM;
607 : }
608 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
609 0 : state->num_names++;
610 0 : return EOK;
611 : }
612 :
613 : /* Here are only groups with a name and gid. POSIX group can already
614 : * be used, non-POSIX groups can be resolved */
615 13 : if (posix) {
616 13 : state->group_names[state->num_names] = talloc_strdup(state->group_names,
617 : name);
618 13 : if (!state->group_names[state->num_names]) {
619 0 : return ENOMEM;
620 : }
621 13 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding group %s\n", name);
622 13 : state->num_names++;
623 13 : return EOK;
624 : }
625 :
626 : /* Try to get group SID and assign it a domain */
627 0 : group_sid = ldb_msg_find_attr_as_string(group, SYSDB_SID_STR, NULL);
628 0 : if (group_sid == NULL) {
629 : /* We will look it up in main domain. */
630 0 : domain = state->ctx->domain;
631 : } else {
632 0 : domain = find_domain_by_sid(state->ctx->domain, group_sid);
633 0 : if (domain == NULL) {
634 0 : DEBUG(SSSDBG_CRIT_FAILURE, "There is no domain information for "
635 : "SID %s\n", group_sid);
636 0 : return ENOENT;
637 : }
638 : }
639 :
640 : /* It is a non-posix group with a GID. Needs resolving */
641 0 : state->lookup_groups[state->num_groups].domain = domain;
642 0 : state->lookup_groups[state->num_groups].gid = gid;
643 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Adding GID %"SPRIgid"\n", gid);
644 0 : state->num_groups++;
645 0 : return EOK;
646 : }
647 :
648 : static errno_t
649 8 : simple_check_get_groups_primary(struct simple_check_groups_state *state,
650 : gid_t gid)
651 : {
652 : errno_t ret;
653 8 : const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
654 : SYSDB_GIDNUM, SYSDB_SID_STR, NULL };
655 : struct ldb_message *msg;
656 :
657 8 : ret = sysdb_search_group_by_gid(state, state->domain, gid, group_attrs,
658 : &msg);
659 8 : if (ret != EOK) {
660 0 : DEBUG(SSSDBG_OP_FAILURE,
661 : "Could not look up primary group [%"SPRIgid"]: [%d][%s]\n",
662 : gid, ret, sss_strerror(ret));
663 : /* We have to treat this as non-fatal, because the primary
664 : * group may be local to the machine and not available in
665 : * our ID provider.
666 : */
667 : } else {
668 8 : ret = simple_check_process_group(state, msg);
669 8 : if (ret != EOK) {
670 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot process primary group\n");
671 0 : return ret;
672 : }
673 : }
674 :
675 8 : return EOK;
676 : }
677 :
678 : static errno_t
679 8 : simple_check_get_groups_recv(struct tevent_req *req,
680 : TALLOC_CTX *mem_ctx,
681 : const char ***_group_names)
682 : {
683 : struct simple_check_groups_state *state;
684 :
685 8 : state = tevent_req_data(req, struct simple_check_groups_state);
686 :
687 8 : TEVENT_REQ_RETURN_ON_ERROR(req);
688 :
689 8 : *_group_names = talloc_steal(mem_ctx, state->group_names);
690 8 : if (state->failed_to_resolve_groups) {
691 0 : return ERR_SIMPLE_GROUPS_MISSING;
692 : }
693 8 : return EOK;
694 : }
695 :
696 : struct simple_access_check_state {
697 : bool access_granted;
698 : struct simple_ctx *ctx;
699 : const char *username;
700 :
701 : const char **group_names;
702 : };
703 :
704 : static void simple_access_check_done(struct tevent_req *subreq);
705 :
706 18 : struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
707 : struct tevent_context *ev,
708 : struct simple_ctx *ctx,
709 : const char *username)
710 : {
711 : errno_t ret;
712 : struct tevent_req *req;
713 : struct tevent_req *subreq;
714 : struct simple_access_check_state *state;
715 :
716 18 : req = tevent_req_create(mem_ctx, &state,
717 : struct simple_access_check_state);
718 18 : if (!req) return NULL;
719 :
720 18 : state->access_granted = false;
721 18 : state->ctx = ctx;
722 18 : state->username = talloc_strdup(state, username);
723 18 : if (!state->username) {
724 0 : ret = ENOMEM;
725 0 : goto immediate;
726 : }
727 :
728 18 : DEBUG(SSSDBG_FUNC_DATA, "Simple access check for %s\n", username);
729 :
730 18 : ret = simple_check_users(ctx, username, &state->access_granted);
731 18 : if (ret == EOK) {
732 2 : goto immediate;
733 16 : } else if (ret != EAGAIN) {
734 0 : ret = ERR_INTERNAL;
735 0 : goto immediate;
736 : }
737 :
738 : /* EAGAIN -- check groups */
739 :
740 16 : if (!ctx->allow_groups && !ctx->deny_groups) {
741 : /* There are no group restrictions, so just return
742 : * here with whatever we've decided.
743 : */
744 8 : DEBUG(SSSDBG_TRACE_LIBS, "No group restrictions, end request\n");
745 8 : ret = EOK;
746 8 : goto immediate;
747 : }
748 :
749 : /* The group names might not be available. Fire a request to
750 : * gather them. In most cases, the request will just shortcut
751 : */
752 8 : subreq = simple_check_get_groups_send(state, ev, ctx, username);
753 8 : if (!subreq) {
754 0 : ret = ENOMEM;
755 0 : goto immediate;
756 : }
757 8 : tevent_req_set_callback(subreq, simple_access_check_done, req);
758 :
759 8 : return req;
760 :
761 : immediate:
762 10 : if (ret == EOK) {
763 10 : tevent_req_done(req);
764 : } else {
765 0 : tevent_req_error(req, ret);
766 : }
767 10 : tevent_req_post(req, ev);
768 10 : return req;
769 : }
770 :
771 :
772 8 : static void simple_access_check_done(struct tevent_req *subreq)
773 : {
774 8 : struct tevent_req *req =
775 8 : tevent_req_callback_data(subreq, struct tevent_req);
776 8 : struct simple_access_check_state *state =
777 8 : tevent_req_data(req, struct simple_access_check_state);
778 : errno_t ret;
779 :
780 : /* We know the names now. Run the check. */
781 8 : ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
782 :
783 8 : talloc_zfree(subreq);
784 8 : if (ret == ENOENT) {
785 : /* If the user wasn't found, just shortcut */
786 0 : state->access_granted = false;
787 0 : tevent_req_done(req);
788 0 : return;
789 8 : } else if (ret == ERR_SIMPLE_GROUPS_MISSING) {
790 0 : DEBUG(SSSDBG_OP_FAILURE,
791 : "Could not collect groups of user %s\n", state->username);
792 0 : if (state->ctx->deny_groups == NULL) {
793 0 : DEBUG(SSSDBG_TRACE_FUNC,
794 : "But no deny groups were defined so we can continue.\n");
795 : } else {
796 0 : DEBUG(SSSDBG_OP_FAILURE,
797 : "Some deny groups were defined, we can't continue\n");
798 0 : tevent_req_error(req, ret);
799 0 : return;
800 : }
801 8 : } else if (ret != EOK) {
802 0 : DEBUG(SSSDBG_OP_FAILURE,
803 : "Could not collect groups of user %s\n", state->username);
804 0 : tevent_req_error(req, ret);
805 0 : return;
806 : }
807 :
808 8 : ret = simple_check_groups(state->ctx, state->group_names,
809 : &state->access_granted);
810 8 : if (ret != EOK) {
811 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not check group access [%d]: %s\n",
812 : ret, sss_strerror(ret));
813 0 : tevent_req_error(req, ERR_INTERNAL);
814 0 : return;
815 : }
816 :
817 : /* Now just return whatever we decided */
818 8 : DEBUG(SSSDBG_TRACE_INTERNAL, "Group check done\n");
819 8 : tevent_req_done(req);
820 : }
821 :
822 18 : errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
823 : {
824 18 : struct simple_access_check_state *state =
825 18 : tevent_req_data(req, struct simple_access_check_state);
826 :
827 18 : TEVENT_REQ_RETURN_ON_ERROR(req);
828 :
829 36 : DEBUG(SSSDBG_TRACE_LIBS,
830 : "Access %sgranted\n", state->access_granted ? "" : "not ");
831 18 : if (access_granted) {
832 18 : *access_granted = state->access_granted;
833 : }
834 :
835 18 : return EOK;
836 : }
|