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 <security/pam_modules.h>
23 :
24 : #include "providers/simple/simple_access.h"
25 : #include "util/sss_utf8.h"
26 : #include "providers/backend.h"
27 : #include "db/sysdb.h"
28 :
29 : #define CONFDB_SIMPLE_ALLOW_USERS "simple_allow_users"
30 : #define CONFDB_SIMPLE_DENY_USERS "simple_deny_users"
31 :
32 : #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
33 : #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
34 :
35 : #define TIMEOUT_OF_REFRESH_FILTER_LISTS 5
36 :
37 4 : static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx,
38 : struct be_ctx *be_ctx,
39 : char **list,
40 : char ***_out)
41 : {
42 4 : TALLOC_CTX *tmp_ctx = NULL;
43 4 : char **out = NULL;
44 4 : char *domain = NULL;
45 4 : char *name = NULL;
46 : size_t size;
47 : size_t i;
48 : errno_t ret;
49 :
50 4 : if (list == NULL) {
51 0 : *_out = NULL;
52 0 : return EOK;
53 : }
54 :
55 4 : tmp_ctx = talloc_new(NULL);
56 4 : if (tmp_ctx == NULL) {
57 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
58 0 : ret = ENOMEM;
59 0 : goto done;
60 : }
61 :
62 4 : for (size = 0; list[size] != NULL; size++) {
63 : /* count size */
64 : }
65 :
66 4 : out = talloc_zero_array(tmp_ctx, char*, size + 1);
67 4 : if (out == NULL) {
68 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
69 0 : ret = ENOMEM;
70 0 : goto done;
71 : }
72 :
73 : /* Since this is access provider, we should fail on any error so we don't
74 : * allow unauthorized access. */
75 20 : for (i = 0; i < size; i++) {
76 16 : ret = sss_parse_name(tmp_ctx, be_ctx->domain->names, list[i],
77 : &domain, &name);
78 16 : if (ret != EOK) {
79 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n",
80 : list[i], ret, sss_strerror(ret));
81 0 : goto done;
82 : }
83 :
84 16 : if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0 ||
85 0 : (be_ctx->domain->flat_name != NULL &&
86 0 : strcasecmp(domain, be_ctx->domain->flat_name) == 0)) {
87 : /* This object belongs to main SSSD domain. Those users and groups
88 : * are stored without domain part, so we will strip it off.
89 : * */
90 16 : out[i] = talloc_move(out, &name);
91 : } else {
92 : /* Subdomain users and groups are stored as fully qualified names,
93 : * thus we will remember the domain part.
94 : *
95 : * Since subdomains may come and go, we will look for their
96 : * existence later, during each access check.
97 : */
98 0 : out[i] = talloc_move(out, &list[i]);
99 : }
100 : }
101 :
102 4 : *_out = talloc_steal(mem_ctx, out);
103 4 : ret = EOK;
104 :
105 : done:
106 4 : talloc_free(tmp_ctx);
107 4 : return ret;
108 : }
109 :
110 1 : int simple_access_obtain_filter_lists(struct simple_ctx *ctx)
111 : {
112 1 : struct be_ctx *bectx = ctx->be_ctx;
113 : int ret;
114 : int i;
115 : struct {
116 : const char *name;
117 : const char *option;
118 : char **orig_list;
119 : char ***ctx_list;
120 1 : } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL},
121 : {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL},
122 : {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL},
123 : {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL},
124 : {NULL, NULL, NULL, NULL}};
125 :
126 1 : lists[0].ctx_list = &ctx->allow_users;
127 1 : lists[1].ctx_list = &ctx->deny_users;
128 1 : lists[2].ctx_list = &ctx->allow_groups;
129 1 : lists[3].ctx_list = &ctx->deny_groups;
130 :
131 1 : ret = sysdb_master_domain_update(bectx->domain);
132 1 : if (ret != EOK) {
133 0 : DEBUG(SSSDBG_FUNC_DATA, "Update of master domain failed [%d]: %s.\n",
134 : ret, sss_strerror(ret));
135 0 : goto failed;
136 : }
137 :
138 5 : for (i = 0; lists[i].name != NULL; i++) {
139 4 : ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
140 : lists[i].option, &lists[i].orig_list);
141 4 : if (ret == ENOENT) {
142 0 : DEBUG(SSSDBG_FUNC_DATA, "%s list is empty.\n", lists[i].name);
143 0 : *lists[i].ctx_list = NULL;
144 0 : continue;
145 4 : } else if (ret != EOK) {
146 0 : DEBUG(SSSDBG_CRIT_FAILURE, "confdb_get_string_as_list failed.\n");
147 0 : goto failed;
148 : }
149 :
150 4 : ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list,
151 : lists[i].ctx_list);
152 4 : if (ret != EOK) {
153 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse %s list [%d]: %s\n",
154 : lists[i].name, ret, sss_strerror(ret));
155 0 : goto failed;
156 : }
157 : }
158 :
159 1 : if (!ctx->allow_users &&
160 0 : !ctx->allow_groups &&
161 0 : !ctx->deny_users &&
162 0 : !ctx->deny_groups) {
163 0 : DEBUG(SSSDBG_OP_FAILURE,
164 : "No rules supplied for simple access provider. "
165 : "Access will be granted for all users.\n");
166 : }
167 1 : return EOK;
168 :
169 : failed:
170 0 : return ret;
171 : }
172 :
173 : struct simple_access_handler_state {
174 : struct pam_data *pd;
175 : };
176 :
177 : static void simple_access_handler_done(struct tevent_req *subreq);
178 :
179 : static struct tevent_req *
180 0 : simple_access_handler_send(TALLOC_CTX *mem_ctx,
181 : struct simple_ctx *simple_ctx,
182 : struct pam_data *pd,
183 : struct dp_req_params *params)
184 : {
185 : struct simple_access_handler_state *state;
186 : struct tevent_req *subreq;
187 : struct tevent_req *req;
188 : errno_t ret;
189 : time_t now;
190 :
191 0 : req = tevent_req_create(mem_ctx, &state,
192 : struct simple_access_handler_state);
193 0 : if (req == NULL) {
194 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
195 0 : return NULL;
196 : }
197 :
198 0 : state->pd = pd;
199 :
200 0 : pd->pam_status = PAM_SYSTEM_ERR;
201 0 : if (pd->cmd != SSS_PAM_ACCT_MGMT) {
202 0 : DEBUG(SSSDBG_CONF_SETTINGS,
203 : "simple access does not handle pam task %d.\n", pd->cmd);
204 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
205 0 : goto immediately;
206 : }
207 :
208 0 : now = time(NULL);
209 0 : if ((now - simple_ctx->last_refresh_of_filter_lists)
210 : > TIMEOUT_OF_REFRESH_FILTER_LISTS) {
211 :
212 0 : ret = simple_access_obtain_filter_lists(simple_ctx);
213 0 : if (ret != EOK) {
214 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Failed to refresh filter lists\n");
215 : }
216 0 : simple_ctx->last_refresh_of_filter_lists = now;
217 : }
218 :
219 0 : subreq = simple_access_check_send(state, params->ev, simple_ctx, pd->user);
220 0 : if (subreq == NULL) {
221 0 : pd->pam_status = PAM_SYSTEM_ERR;
222 0 : goto immediately;
223 : }
224 :
225 0 : tevent_req_set_callback(subreq, simple_access_handler_done, req);
226 :
227 0 : return req;
228 :
229 : immediately:
230 : /* TODO For backward compatibility we always return EOK to DP now. */
231 0 : tevent_req_done(req);
232 0 : tevent_req_post(req, params->ev);
233 :
234 0 : return req;
235 : }
236 :
237 0 : static void simple_access_handler_done(struct tevent_req *subreq)
238 : {
239 : struct simple_access_handler_state *state;
240 : struct tevent_req *req;
241 : bool access_granted;
242 : errno_t ret;
243 :
244 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
245 0 : state = tevent_req_data(req, struct simple_access_handler_state);
246 :
247 0 : ret = simple_access_check_recv(subreq, &access_granted);
248 0 : talloc_free(subreq);
249 0 : if (ret != EOK) {
250 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
251 0 : goto done;
252 : }
253 :
254 0 : if (access_granted) {
255 0 : state->pd->pam_status = PAM_SUCCESS;
256 : } else {
257 0 : state->pd->pam_status = PAM_PERM_DENIED;
258 : }
259 :
260 : done:
261 : /* TODO For backward compatibility we always return EOK to DP now. */
262 0 : tevent_req_done(req);
263 0 : }
264 :
265 : static errno_t
266 0 : simple_access_handler_recv(TALLOC_CTX *mem_ctx,
267 : struct tevent_req *req,
268 : struct pam_data **_data)
269 : {
270 0 : struct simple_access_handler_state *state = NULL;
271 :
272 0 : state = tevent_req_data(req, struct simple_access_handler_state);
273 :
274 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
275 :
276 0 : *_data = talloc_steal(mem_ctx, state->pd);
277 :
278 0 : return EOK;
279 : }
280 :
281 0 : errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx,
282 : struct be_ctx *be_ctx,
283 : void *module_data,
284 : struct dp_method *dp_methods)
285 : {
286 : struct simple_ctx *ctx;
287 : errno_t ret;
288 :
289 0 : ctx = talloc_zero(mem_ctx, struct simple_ctx);
290 0 : if (ctx == NULL) {
291 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed.\n");
292 0 : return ENOMEM;
293 : }
294 :
295 0 : ctx->domain = be_ctx->domain;
296 0 : ctx->be_ctx = be_ctx;
297 0 : ctx->last_refresh_of_filter_lists = 0;
298 :
299 0 : ret = simple_access_obtain_filter_lists(ctx);
300 0 : if (ret != EOK) {
301 0 : talloc_free(ctx);
302 0 : return ret;
303 : }
304 :
305 0 : dp_set_method(dp_methods, DPM_ACCESS_HANDLER,
306 : simple_access_handler_send, simple_access_handler_recv, ctx,
307 : struct simple_ctx, struct pam_data, struct pam_data *);
308 :
309 0 : return EOK;
310 : }
|