Branch data 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 <errno.h>
23 : :
24 : : #include <security/pam_modules.h>
25 : :
26 : : #include "util/util.h"
27 : : #include "util/sss_utf8.h"
28 : : #include "providers/dp_backend.h"
29 : : #include "db/sysdb.h"
30 : : #include "providers/simple/simple_access.h"
31 : :
32 : : #define CONFDB_SIMPLE_ALLOW_USERS "simple_allow_users"
33 : : #define CONFDB_SIMPLE_DENY_USERS "simple_deny_users"
34 : :
35 : : #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
36 : : #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
37 : :
38 : 9 : errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
39 : : bool *access_granted)
40 : : {
41 : : int i, j;
42 : : errno_t ret;
43 : 9 : TALLOC_CTX *tmp_ctx = NULL;
44 : 9 : const char *user_attrs[] = { SYSDB_MEMBEROF,
45 : : SYSDB_GIDNUM,
46 : : NULL };
47 : 9 : const char *group_attrs[] = { SYSDB_NAME,
48 : : NULL };
49 : : struct ldb_message *msg;
50 : : struct ldb_message_element *el;
51 : : char **groups;
52 : : const char *primary_group;
53 : : gid_t gid;
54 : : bool matched;
55 : 9 : bool cs = ctx->domain->case_sensitive;
56 : :
57 : 9 : *access_granted = false;
58 : :
59 : : /* First, check whether the user is in the allowed users list */
60 [ + + ]: 9 : if (ctx->allow_users != NULL) {
61 [ + + ]: 18 : for(i = 0; ctx->allow_users[i] != NULL; i++) {
62 [ + + ]: 12 : if (sss_string_equal(cs, username, ctx->allow_users[i])) {
63 [ + - ][ + - ]: 3 : DEBUG(9, ("User [%s] found in allow list, access granted.\n",
[ - + ][ # # ]
[ # # ]
64 : : username));
65 : :
66 : : /* Do not return immediately on explicit allow
67 : : * We need to make sure none of the user's groups
68 : : * are denied.
69 : : */
70 : 3 : *access_granted = true;
71 : : }
72 : : }
73 [ + - ]: 3 : } else if (!ctx->allow_groups) {
74 : : /* If neither allow rule is in place, we'll assume allowed
75 : : * unless a deny rule disables us below.
76 : : */
77 : 3 : *access_granted = true;
78 : : }
79 : :
80 : : /* Next check whether this user has been specifically denied */
81 [ + + ]: 9 : if (ctx->deny_users != NULL) {
82 [ + + ]: 8 : for(i = 0; ctx->deny_users[i] != NULL; i++) {
83 [ + + ]: 6 : if (sss_string_equal(cs, username, ctx->deny_users[i])) {
84 [ + - ][ + - ]: 2 : DEBUG(9, ("User [%s] found in deny list, access denied.\n",
[ - + ][ # # ]
[ # # ]
85 : : username));
86 : :
87 : : /* Return immediately on explicit denial */
88 : 2 : *access_granted = false;
89 : : return EOK;
90 : : }
91 : : }
92 : : }
93 : :
94 [ + - ][ - + ]: 7 : if (!ctx->allow_groups && !ctx->deny_groups) {
95 : : /* There are no group restrictions, so just return
96 : : * here with whatever we've decided.
97 : : */
98 : : return EOK;
99 : : }
100 : :
101 : : /* Now get a list of this user's groups and check those against the
102 : : * simple_allow_groups list.
103 : : */
104 : 0 : tmp_ctx = talloc_new(NULL);
105 [ # # ]: 0 : if (!tmp_ctx) {
106 : : ret = ENOMEM;
107 : : goto done;
108 : : }
109 : :
110 : 0 : ret = sysdb_search_user_by_name(tmp_ctx, ctx->sysdb,
111 : : username, user_attrs, &msg);
112 [ # # ]: 0 : if (ret != EOK) {
113 [ # # ][ # # ]: 0 : DEBUG(1, ("Could not look up username [%s]: [%d][%s]\n",
[ # # ][ # # ]
[ # # ]
114 : : username, ret, strerror(ret)));
115 : : goto done;
116 : : }
117 : :
118 : : /* Construct a list of the user's groups */
119 : 0 : el = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
120 [ # # ][ # # ]: 0 : if (el && el->num_values) {
121 : : /* Get the groups from the memberOf entries
122 : : * Allocate the array with room for both the NULL
123 : : * terminator and the primary group
124 : : */
125 : 0 : groups = talloc_array(tmp_ctx, char *, el->num_values + 2);
126 [ # # ]: 0 : if (!groups) {
127 : : ret = ENOMEM;
128 : : goto done;
129 : : }
130 : :
131 [ # # ]: 0 : for (j = 0; j < el->num_values; j++) {
132 : 0 : ret = sysdb_group_dn_name(
133 : : ctx->sysdb, tmp_ctx,
134 : 0 : (char *)el->values[j].data,
135 : 0 : &groups[j]);
136 [ # # ]: 0 : if (ret != EOK) {
137 : : goto done;
138 : : }
139 : : }
140 : : } else {
141 : : /* User is not a member of any groups except primary */
142 : 0 : groups = talloc_array(tmp_ctx, char *, 2);
143 [ # # ]: 0 : if (!groups) {
144 : : ret = ENOMEM;
145 : : goto done;
146 : : }
147 : : j = 0;
148 : : }
149 : :
150 : : /* Get the user's primary group */
151 : 0 : gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
152 [ # # ]: 0 : if (!gid) {
153 : : ret = EINVAL;
154 : : goto done;
155 : : }
156 : 0 : talloc_zfree(msg);
157 : :
158 : 0 : ret = sysdb_search_group_by_gid(tmp_ctx, ctx->sysdb,
159 : : gid, group_attrs, &msg);
160 [ # # ]: 0 : if (ret != EOK) {
161 [ # # ][ # # ]: 0 : DEBUG(1, ("Could not look up primary group [%lu]: [%d][%s]\n",
[ # # ][ # # ]
[ # # ]
162 : : gid, ret, strerror(ret)));
163 : : /* We have to treat this as non-fatal, because the primary
164 : : * group may be local to the machine and not available in
165 : : * our ID provider.
166 : : */
167 : : } else {
168 : 0 : primary_group = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
169 [ # # ]: 0 : if (!primary_group) {
170 : : ret = EINVAL;
171 : : goto done;
172 : : }
173 : :
174 : 0 : groups[j] = talloc_strdup(tmp_ctx, primary_group);
175 [ # # ]: 0 : if (!groups[j]) {
176 : : ret = ENOMEM;
177 : : goto done;
178 : : }
179 : 0 : j++;
180 : :
181 : 0 : talloc_zfree(msg);
182 : : }
183 : :
184 : 0 : groups[j] = NULL;
185 : :
186 : : /* Now process allow and deny group rules
187 : : * If access was already granted above, we'll skip
188 : : * this redundant rule check
189 : : */
190 [ # # ][ # # ]: 0 : if (ctx->allow_groups && !*access_granted) {
191 : : matched = false;
192 [ # # ]: 0 : for (i = 0; ctx->allow_groups[i]; i++) {
193 [ # # ]: 0 : for(j = 0; groups[j]; j++) {
194 [ # # ]: 0 : if (sss_string_equal(cs, groups[j], ctx->allow_groups[i])) {
195 : : matched = true;
196 : : break;
197 : : }
198 : : }
199 : :
200 : : /* If any group has matched, we can skip out on the
201 : : * processing early
202 : : */
203 [ # # ]: 0 : if (matched) {
204 : 0 : *access_granted = true;
205 : 0 : break;
206 : : }
207 : : }
208 : : }
209 : :
210 : : /* Finally, process the deny group rules */
211 [ # # ]: 0 : if (ctx->deny_groups) {
212 : : matched = false;
213 [ # # ]: 0 : for (i = 0; ctx->deny_groups[i]; i++) {
214 [ # # ]: 0 : for(j = 0; groups[j]; j++) {
215 [ # # ]: 0 : if (sss_string_equal(cs, groups[j], ctx->deny_groups[i])) {
216 : : matched = true;
217 : : break;
218 : : }
219 : : }
220 : :
221 : : /* If any group has matched, we can skip out on the
222 : : * processing early
223 : : */
224 [ # # ]: 0 : if (matched) {
225 : 0 : *access_granted = false;
226 : 0 : break;
227 : : }
228 : : }
229 : : }
230 : :
231 : : ret = EOK;
232 : :
233 : : done:
234 : 9 : talloc_free(tmp_ctx);
235 : : return ret;
236 : : }
237 : :
238 : 0 : void simple_access_handler(struct be_req *be_req)
239 : : {
240 : : int ret;
241 : 0 : bool access_granted = false;
242 : : struct pam_data *pd;
243 : : struct simple_ctx *ctx;
244 : :
245 : 0 : pd = talloc_get_type(be_req->req_data, struct pam_data);
246 : :
247 : 0 : pd->pam_status = PAM_SYSTEM_ERR;
248 : :
249 [ # # ]: 0 : if (pd->cmd != SSS_PAM_ACCT_MGMT) {
250 [ # # ][ # # ]: 0 : DEBUG(4, ("simple access does not handles pam task %d.\n", pd->cmd));
[ # # ][ # # ]
[ # # ]
251 : 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
252 : 0 : goto done;
253 : : }
254 : :
255 : 0 : ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
256 : : struct simple_ctx);
257 : :
258 : 0 : ret = simple_access_check(ctx, pd->user, &access_granted);
259 [ # # ]: 0 : if (ret != EOK) {
260 : 0 : pd->pam_status = PAM_SYSTEM_ERR;
261 : 0 : goto done;
262 : : }
263 : :
264 [ # # ]: 0 : if (access_granted) {
265 : 0 : pd->pam_status = PAM_SUCCESS;
266 : : } else {
267 : 0 : pd->pam_status = PAM_PERM_DENIED;
268 : : }
269 : :
270 : : done:
271 : 0 : be_req->fn(be_req, DP_ERR_OK, pd->pam_status, NULL);
272 : 0 : }
273 : :
274 : : struct bet_ops simple_access_ops = {
275 : : .handler = simple_access_handler,
276 : : .finalize = NULL
277 : : };
278 : :
279 : 0 : int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
280 : : void **pvt_data)
281 : : {
282 : 0 : int ret = EINVAL;
283 : : struct simple_ctx *ctx;
284 : :
285 : 0 : ctx = talloc_zero(bectx, struct simple_ctx);
286 [ # # ]: 0 : if (ctx == NULL) {
287 [ # # ][ # # ]: 0 : DEBUG(1, ("talloc_zero failed.\n"));
[ # # ][ # # ]
[ # # ]
288 : : return ENOMEM;
289 : : }
290 : :
291 : 0 : ctx->sysdb = bectx->sysdb;
292 : 0 : ctx->domain = bectx->domain;
293 : :
294 : : /* Users */
295 : 0 : ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
296 : : CONFDB_SIMPLE_ALLOW_USERS,
297 : : &ctx->allow_users);
298 [ # # ]: 0 : if (ret != EOK) {
299 [ # # ]: 0 : if (ret == ENOENT) {
300 [ # # ][ # # ]: 0 : DEBUG(9, ("Allow user list is empty.\n"));
[ # # ][ # # ]
[ # # ]
301 : 0 : ctx->allow_users = NULL;
302 : : } else {
303 [ # # ][ # # ]: 0 : DEBUG(1, ("confdb_get_string_as_list failed.\n"));
[ # # ][ # # ]
[ # # ]
304 : : goto failed;
305 : : }
306 : : }
307 : :
308 : 0 : ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
309 : : CONFDB_SIMPLE_DENY_USERS,
310 : : &ctx->deny_users);
311 [ # # ]: 0 : if (ret != EOK) {
312 [ # # ]: 0 : if (ret == ENOENT) {
313 [ # # ][ # # ]: 0 : DEBUG(9, ("Deny user list is empty.\n"));
[ # # ][ # # ]
[ # # ]
314 : 0 : ctx->deny_users = NULL;
315 : : } else {
316 [ # # ][ # # ]: 0 : DEBUG(1, ("confdb_get_string_as_list failed.\n"));
[ # # ][ # # ]
[ # # ]
317 : : goto failed;
318 : : }
319 : : }
320 : :
321 : : /* Groups */
322 : 0 : ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
323 : : CONFDB_SIMPLE_ALLOW_GROUPS,
324 : : &ctx->allow_groups);
325 [ # # ]: 0 : if (ret != EOK) {
326 [ # # ]: 0 : if (ret == ENOENT) {
327 [ # # ][ # # ]: 0 : DEBUG(9, ("Allow group list is empty.\n"));
[ # # ][ # # ]
[ # # ]
328 : 0 : ctx->allow_groups = NULL;
329 : : } else {
330 [ # # ][ # # ]: 0 : DEBUG(1, ("confdb_get_string_as_list failed.\n"));
[ # # ][ # # ]
[ # # ]
331 : : goto failed;
332 : : }
333 : : }
334 : :
335 : 0 : ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
336 : : CONFDB_SIMPLE_DENY_GROUPS,
337 : : &ctx->deny_groups);
338 [ # # ]: 0 : if (ret != EOK) {
339 [ # # ]: 0 : if (ret == ENOENT) {
340 [ # # ][ # # ]: 0 : DEBUG(9, ("Deny user list is empty.\n"));
[ # # ][ # # ]
[ # # ]
341 : 0 : ctx->deny_groups = NULL;
342 : : } else {
343 [ # # ][ # # ]: 0 : DEBUG(1, ("confdb_get_string_as_list failed.\n"));
[ # # ][ # # ]
[ # # ]
344 : : goto failed;
345 : : }
346 : : }
347 : :
348 [ # # ][ # # ]: 0 : if (!ctx->allow_users &&
349 [ # # ]: 0 : !ctx->allow_groups &&
350 [ # # ]: 0 : !ctx->deny_users &&
351 : 0 : !ctx->deny_groups) {
352 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("No rules supplied for simple access provider. "
[ # # ][ # # ]
[ # # ]
353 : : "Access will be granted for all users.\n"));
354 : : }
355 : :
356 : 0 : *ops = &simple_access_ops;
357 : 0 : *pvt_data = ctx;
358 : :
359 : 0 : return EOK;
360 : :
361 : : failed:
362 : 0 : talloc_free(ctx);
363 : 0 : return ret;
364 : : }
|