Line data Source code
1 : /*
2 : SSSD
3 :
4 : sdap_access.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@redhat.com>
8 :
9 : Copyright (C) 2010 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "config.h"
26 :
27 : #include <time.h>
28 : #include <sys/param.h>
29 : #include <security/pam_modules.h>
30 : #include <talloc.h>
31 : #include <tevent.h>
32 : #include <errno.h>
33 :
34 : #include "util/util.h"
35 : #include "util/strtonum.h"
36 : #include "db/sysdb.h"
37 : #include "providers/ldap/ldap_common.h"
38 : #include "providers/ldap/sdap.h"
39 : #include "providers/ldap/sdap_access.h"
40 : #include "providers/ldap/sdap_async.h"
41 : #include "providers/data_provider.h"
42 : #include "providers/dp_backend.h"
43 : #include "providers/ldap/ldap_auth.h"
44 :
45 : #define PERMANENTLY_LOCKED_ACCOUNT "000001010000Z"
46 : #define MALFORMED_FILTER "Malformed access control filter [%s]\n"
47 :
48 : enum sdap_pwpolicy_mode {
49 : PWP_LOCKOUT_ONLY,
50 : PWP_LOCKOUT_EXPIRE,
51 : PWP_SENTINEL,
52 : };
53 :
54 : static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
55 : struct sss_domain_info *domain,
56 : struct pam_data *pd,
57 : struct sdap_options *opts);
58 :
59 : static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
60 : const char *username,
61 : const char *attr_name,
62 : bool value);
63 :
64 : static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
65 : const char *username,
66 : const char **_basedn);
67 :
68 : static struct tevent_req *
69 : sdap_access_ppolicy_send(TALLOC_CTX *mem_ctx,
70 : struct tevent_context *ev,
71 : struct be_ctx *be_ctx,
72 : struct sss_domain_info *domain,
73 : struct sdap_access_ctx *access_ctx,
74 : struct sdap_id_conn_ctx *conn,
75 : const char *username,
76 : struct ldb_message *user_entry,
77 : enum sdap_pwpolicy_mode pwpol_mod);
78 :
79 : static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
80 : struct tevent_context *ev,
81 : struct be_ctx *be_ctx,
82 : struct sss_domain_info *domain,
83 : struct sdap_access_ctx *access_ctx,
84 : struct sdap_id_conn_ctx *conn,
85 : const char *username,
86 : struct ldb_message *user_entry);
87 :
88 : static errno_t sdap_access_filter_recv(struct tevent_req *req);
89 :
90 : static errno_t sdap_access_ppolicy_recv(struct tevent_req *req);
91 :
92 : static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
93 : struct pam_data *pd,
94 : struct ldb_message *user_entry);
95 :
96 : static errno_t sdap_access_service(struct pam_data *pd,
97 : struct ldb_message *user_entry);
98 :
99 : static errno_t sdap_access_host(struct ldb_message *user_entry);
100 :
101 : enum sdap_access_control_type {
102 : SDAP_ACCESS_CONTROL_FILTER,
103 : SDAP_ACCESS_CONTROL_PPOLICY_LOCK,
104 : };
105 :
106 : struct sdap_access_req_ctx {
107 : struct pam_data *pd;
108 : struct tevent_context *ev;
109 : struct sdap_access_ctx *access_ctx;
110 : struct sdap_id_conn_ctx *conn;
111 : struct be_ctx *be_ctx;
112 : struct sss_domain_info *domain;
113 : struct ldb_message *user_entry;
114 : size_t current_rule;
115 : enum sdap_access_control_type ac_type;
116 : };
117 :
118 : static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
119 : struct tevent_req *req);
120 : static void sdap_access_done(struct tevent_req *subreq);
121 :
122 : struct tevent_req *
123 0 : sdap_access_send(TALLOC_CTX *mem_ctx,
124 : struct tevent_context *ev,
125 : struct be_ctx *be_ctx,
126 : struct sss_domain_info *domain,
127 : struct sdap_access_ctx *access_ctx,
128 : struct sdap_id_conn_ctx *conn,
129 : struct pam_data *pd)
130 : {
131 : errno_t ret;
132 : struct sdap_access_req_ctx *state;
133 : struct tevent_req *req;
134 : struct ldb_result *res;
135 0 : const char *attrs[] = { "*", NULL };
136 :
137 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_access_req_ctx);
138 0 : if (req == NULL) {
139 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
140 0 : return NULL;
141 : }
142 :
143 0 : state->be_ctx = be_ctx;
144 0 : state->domain = domain;
145 0 : state->pd = pd;
146 0 : state->ev = ev;
147 0 : state->access_ctx = access_ctx;
148 0 : state->conn = conn;
149 0 : state->current_rule = 0;
150 :
151 0 : DEBUG(SSSDBG_TRACE_FUNC,
152 : "Performing access check for user [%s]\n", pd->user);
153 :
154 0 : if (access_ctx->access_rule[0] == LDAP_ACCESS_EMPTY) {
155 0 : DEBUG(SSSDBG_MINOR_FAILURE,
156 : "No access rules defined, access denied.\n");
157 0 : ret = ERR_ACCESS_DENIED;
158 0 : goto done;
159 : }
160 :
161 : /* Get original user DN, domain already points to the right (sub)domain */
162 0 : ret = sysdb_get_user_attr(state, domain, pd->user, attrs, &res);
163 0 : if (ret != EOK) {
164 0 : if (ret == ENOENT) {
165 : /* If we can't find the user, return access denied */
166 0 : ret = ERR_ACCESS_DENIED;
167 0 : goto done;
168 : }
169 0 : goto done;
170 : }
171 : else {
172 0 : if (res->count == 0) {
173 : /* If we can't find the user, return access denied */
174 0 : ret = ERR_ACCESS_DENIED;
175 0 : goto done;
176 : }
177 :
178 0 : if (res->count != 1) {
179 0 : DEBUG(SSSDBG_CRIT_FAILURE,
180 : "Invalid response from sysdb_get_user_attr\n");
181 0 : ret = EINVAL;
182 0 : goto done;
183 : }
184 : }
185 :
186 0 : state->user_entry = res->msgs[0];
187 :
188 0 : ret = sdap_access_check_next_rule(state, req);
189 0 : if (ret == EAGAIN) {
190 0 : return req;
191 : }
192 :
193 : done:
194 0 : if (ret == EOK) {
195 0 : tevent_req_done(req);
196 : } else {
197 0 : tevent_req_error(req, ret);
198 : }
199 0 : tevent_req_post(req, ev);
200 0 : return req;
201 : }
202 :
203 0 : static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
204 : struct tevent_req *req)
205 : {
206 : struct tevent_req *subreq;
207 0 : int ret = EOK;
208 :
209 0 : while (ret == EOK) {
210 0 : switch (state->access_ctx->access_rule[state->current_rule]) {
211 : case LDAP_ACCESS_EMPTY:
212 : /* we are done with no errors */
213 0 : return EOK;
214 :
215 : /* This option is deprecated by LDAP_ACCESS_PPOLICY */
216 : case LDAP_ACCESS_LOCKOUT:
217 0 : DEBUG(SSSDBG_MINOR_FAILURE,
218 : "WARNING: %s option is deprecated and might be removed in "
219 : "a future release. Please migrate to %s option instead.\n",
220 : LDAP_ACCESS_LOCK_NAME, LDAP_ACCESS_PPOLICY_NAME);
221 :
222 0 : subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
223 : state->domain,
224 : state->access_ctx,
225 : state->conn,
226 0 : state->pd->user,
227 : state->user_entry,
228 : PWP_LOCKOUT_ONLY);
229 0 : if (subreq == NULL) {
230 0 : DEBUG(SSSDBG_CRIT_FAILURE,
231 : "sdap_access_ppolicy_send failed.\n");
232 0 : return ENOMEM;
233 : }
234 :
235 0 : state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
236 :
237 0 : tevent_req_set_callback(subreq, sdap_access_done, req);
238 0 : return EAGAIN;
239 :
240 : case LDAP_ACCESS_PPOLICY:
241 0 : subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
242 : state->domain,
243 : state->access_ctx,
244 : state->conn,
245 0 : state->pd->user,
246 : state->user_entry,
247 : PWP_LOCKOUT_EXPIRE);
248 0 : if (subreq == NULL) {
249 0 : DEBUG(SSSDBG_CRIT_FAILURE,
250 : "sdap_access_ppolicy_send failed.\n");
251 0 : return ENOMEM;
252 : }
253 :
254 0 : state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
255 :
256 0 : tevent_req_set_callback(subreq, sdap_access_done, req);
257 0 : return EAGAIN;
258 :
259 : case LDAP_ACCESS_FILTER:
260 0 : subreq = sdap_access_filter_send(state, state->ev, state->be_ctx,
261 : state->domain,
262 : state->access_ctx,
263 : state->conn,
264 0 : state->pd->user,
265 : state->user_entry);
266 0 : if (subreq == NULL) {
267 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_filter_send failed.\n");
268 0 : return ENOMEM;
269 : }
270 :
271 0 : state->ac_type = SDAP_ACCESS_CONTROL_FILTER;
272 :
273 0 : tevent_req_set_callback(subreq, sdap_access_done, req);
274 0 : return EAGAIN;
275 :
276 : case LDAP_ACCESS_EXPIRE:
277 0 : ret = sdap_account_expired(state->access_ctx,
278 : state->pd, state->user_entry);
279 0 : break;
280 :
281 : case LDAP_ACCESS_EXPIRE_POLICY_REJECT:
282 0 : ret = perform_pwexpire_policy(state, state->domain, state->pd,
283 0 : state->access_ctx->id_ctx->opts);
284 0 : if (ret == ERR_PASSWORD_EXPIRED) {
285 0 : ret = ERR_PASSWORD_EXPIRED_REJECT;
286 : }
287 0 : break;
288 :
289 : case LDAP_ACCESS_EXPIRE_POLICY_WARN:
290 0 : ret = perform_pwexpire_policy(state, state->domain, state->pd,
291 0 : state->access_ctx->id_ctx->opts);
292 0 : if (ret == ERR_PASSWORD_EXPIRED) {
293 0 : ret = ERR_PASSWORD_EXPIRED_WARN;
294 : }
295 0 : break;
296 :
297 : case LDAP_ACCESS_EXPIRE_POLICY_RENEW:
298 0 : ret = perform_pwexpire_policy(state, state->domain, state->pd,
299 0 : state->access_ctx->id_ctx->opts);
300 0 : if (ret == ERR_PASSWORD_EXPIRED) {
301 0 : ret = ERR_PASSWORD_EXPIRED_RENEW;
302 : }
303 0 : break;
304 :
305 : case LDAP_ACCESS_SERVICE:
306 0 : ret = sdap_access_service( state->pd, state->user_entry);
307 0 : break;
308 :
309 : case LDAP_ACCESS_HOST:
310 0 : ret = sdap_access_host(state->user_entry);
311 0 : break;
312 :
313 : default:
314 0 : DEBUG(SSSDBG_CRIT_FAILURE,
315 : "Unexpected access rule type. Access denied.\n");
316 0 : ret = ERR_ACCESS_DENIED;
317 : }
318 :
319 0 : state->current_rule++;
320 : }
321 :
322 0 : return ret;
323 : }
324 :
325 0 : static void sdap_access_done(struct tevent_req *subreq)
326 : {
327 : errno_t ret;
328 : struct tevent_req *req;
329 : struct sdap_access_req_ctx *state;
330 :
331 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
332 0 : state = tevent_req_data(req, struct sdap_access_req_ctx);
333 :
334 : /* process subrequest */
335 0 : switch(state->ac_type) {
336 : case SDAP_ACCESS_CONTROL_FILTER:
337 0 : ret = sdap_access_filter_recv(subreq);
338 0 : break;
339 : case SDAP_ACCESS_CONTROL_PPOLICY_LOCK:
340 0 : ret = sdap_access_ppolicy_recv(subreq);
341 0 : break;
342 : default:
343 0 : ret = EINVAL;
344 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unknown access control type: %d.\n",
345 : state->ac_type);
346 0 : break;
347 : }
348 :
349 0 : talloc_zfree(subreq);
350 0 : if (ret != EOK) {
351 0 : if (ret == ERR_ACCESS_DENIED) {
352 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access was denied.\n");
353 : } else {
354 0 : DEBUG(SSSDBG_CRIT_FAILURE,
355 : "Error retrieving access check result.\n");
356 : }
357 0 : tevent_req_error(req, ret);
358 0 : return;
359 : }
360 :
361 0 : state->current_rule++;
362 :
363 0 : ret = sdap_access_check_next_rule(state, req);
364 0 : switch (ret) {
365 : case EAGAIN:
366 0 : return;
367 : case EOK:
368 0 : tevent_req_done(req);
369 0 : return;
370 : default:
371 0 : tevent_req_error(req, ret);
372 0 : return;
373 : }
374 : }
375 :
376 0 : errno_t sdap_access_recv(struct tevent_req *req)
377 : {
378 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
379 :
380 0 : return EOK;
381 : }
382 :
383 : #define SHADOW_EXPIRE_MSG "Account expired according to shadow attributes"
384 :
385 0 : static errno_t sdap_account_expired_shadow(struct pam_data *pd,
386 : struct ldb_message *user_entry)
387 : {
388 : int ret;
389 : const char *val;
390 : long sp_expire;
391 : long today;
392 :
393 0 : DEBUG(SSSDBG_TRACE_FUNC,
394 : "Performing access shadow check for user [%s]\n", pd->user);
395 :
396 0 : val = ldb_msg_find_attr_as_string(user_entry, SYSDB_SHADOWPW_EXPIRE, NULL);
397 0 : if (val == NULL) {
398 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Shadow expire attribute not found. "
399 : "Access will be granted.\n");
400 0 : return EOK;
401 : }
402 0 : ret = string_to_shadowpw_days(val, &sp_expire);
403 0 : if (ret != EOK) {
404 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve shadow expire date.\n");
405 0 : return ret;
406 : }
407 :
408 0 : today = (long) (time(NULL) / (60 * 60 * 24));
409 0 : if (sp_expire > 0 && today > sp_expire) {
410 :
411 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
412 : sizeof(SHADOW_EXPIRE_MSG),
413 : (const uint8_t *) SHADOW_EXPIRE_MSG);
414 0 : if (ret != EOK) {
415 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
416 : }
417 :
418 0 : return ERR_ACCOUNT_EXPIRED;
419 : }
420 :
421 0 : return EOK;
422 : }
423 :
424 : #define UAC_ACCOUNTDISABLE 0x00000002
425 : #define AD_NEVER_EXP 0x7fffffffffffffffLL
426 : #define AD_TO_UNIX_TIME_CONST 11644473600LL
427 : #define AD_DISABLE_MESSAGE "The user account is disabled on the AD server"
428 : #define AD_EXPIRED_MESSAGE "The user account is expired on the AD server"
429 :
430 0 : static bool ad_account_expired(uint64_t expiration_time)
431 : {
432 : time_t now;
433 : int err;
434 : uint64_t nt_now;
435 :
436 0 : if (expiration_time == 0 || expiration_time == AD_NEVER_EXP) {
437 0 : return false;
438 : }
439 :
440 0 : now = time(NULL);
441 0 : if (now == ((time_t) -1)) {
442 0 : err = errno;
443 0 : DEBUG(SSSDBG_CRIT_FAILURE,
444 : "time failed [%d][%s].\n", err, strerror(err));
445 0 : return true;
446 : }
447 :
448 : /* NT timestamps start at 1601-01-01 and use a 100ns base */
449 0 : nt_now = (now + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 * 10;
450 :
451 0 : if (nt_now > expiration_time) {
452 0 : return true;
453 : }
454 :
455 0 : return false;
456 : }
457 :
458 0 : static errno_t sdap_account_expired_ad(struct pam_data *pd,
459 : struct ldb_message *user_entry)
460 : {
461 : uint32_t uac;
462 : uint64_t expiration_time;
463 : int ret;
464 :
465 0 : DEBUG(SSSDBG_TRACE_FUNC,
466 : "Performing AD access check for user [%s]\n", pd->user);
467 :
468 0 : uac = ldb_msg_find_attr_as_uint(user_entry, SYSDB_AD_USER_ACCOUNT_CONTROL,
469 : 0);
470 0 : DEBUG(SSSDBG_TRACE_ALL, "User account control for user [%s] is [%X].\n",
471 : pd->user, uac);
472 :
473 0 : expiration_time = ldb_msg_find_attr_as_uint64(user_entry,
474 : SYSDB_AD_ACCOUNT_EXPIRES, 0);
475 0 : DEBUG(SSSDBG_TRACE_ALL,
476 : "Expiration time for user [%s] is [%"PRIu64"].\n",
477 : pd->user, expiration_time);
478 :
479 0 : if (uac & UAC_ACCOUNTDISABLE) {
480 :
481 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
482 : sizeof(AD_DISABLE_MESSAGE),
483 : (const uint8_t *) AD_DISABLE_MESSAGE);
484 0 : if (ret != EOK) {
485 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
486 : }
487 :
488 0 : return ERR_ACCESS_DENIED;
489 :
490 0 : } else if (ad_account_expired(expiration_time)) {
491 :
492 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
493 : sizeof(AD_EXPIRED_MESSAGE),
494 : (const uint8_t *) AD_EXPIRED_MESSAGE);
495 0 : if (ret != EOK) {
496 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
497 : }
498 :
499 0 : return ERR_ACCOUNT_EXPIRED;
500 : }
501 :
502 0 : return EOK;
503 : }
504 :
505 : #define RHDS_LOCK_MSG "The user account is locked on the server"
506 :
507 0 : static errno_t sdap_account_expired_rhds(struct pam_data *pd,
508 : struct ldb_message *user_entry)
509 : {
510 : bool locked;
511 : int ret;
512 :
513 0 : DEBUG(SSSDBG_TRACE_FUNC,
514 : "Performing RHDS access check for user [%s]\n", pd->user);
515 :
516 0 : locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NS_ACCOUNT_LOCK, false);
517 0 : DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s locked.\n", pd->user,
518 : locked ? "" : " not" );
519 :
520 0 : if (locked) {
521 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
522 : sizeof(RHDS_LOCK_MSG),
523 : (const uint8_t *) RHDS_LOCK_MSG);
524 0 : if (ret != EOK) {
525 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
526 : }
527 :
528 0 : return ERR_ACCESS_DENIED;
529 : }
530 :
531 0 : return EOK;
532 : }
533 :
534 : #define NDS_DISABLE_MSG "The user account is disabled on the server"
535 : #define NDS_EXPIRED_MSG "The user account is expired"
536 : #define NDS_TIME_MAP_MSG "The user account is not allowed at this time"
537 :
538 7 : bool nds_check_expired(const char *exp_time_str)
539 : {
540 : time_t expire_time;
541 : time_t now;
542 : errno_t ret;
543 :
544 7 : if (exp_time_str == NULL) {
545 1 : DEBUG(SSSDBG_TRACE_ALL,
546 : "ndsLoginExpirationTime is not set, access granted.\n");
547 1 : return false;
548 : }
549 :
550 6 : ret = sss_utc_to_time_t(exp_time_str, "%Y%m%d%H%M%SZ",
551 : &expire_time);
552 6 : if (ret != EOK) {
553 2 : DEBUG(SSSDBG_MINOR_FAILURE, "sss_utc_to_time_t failed with %d:%s.\n",
554 : ret, sss_strerror(ret));
555 2 : return true;
556 : }
557 :
558 4 : now = time(NULL);
559 4 : DEBUG(SSSDBG_TRACE_ALL,
560 : "Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
561 : "daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
562 : tzname[1], timezone, daylight, now, expire_time);
563 :
564 4 : if (difftime(now, expire_time) > 0.0) {
565 1 : DEBUG(SSSDBG_CONF_SETTINGS, "NDS account expired.\n");
566 1 : return true;
567 : }
568 :
569 3 : return false;
570 : }
571 :
572 : /* There is no real documentation of the byte string value of
573 : * loginAllowedTimeMap, but some good example code in
574 : * http://http://developer.novell.com/documentation/samplecode/extjndi_sample/CheckBind.java.html
575 : */
576 0 : static bool nds_check_time_map(const struct ldb_val *time_map)
577 : {
578 : time_t now;
579 : struct tm *tm_now;
580 : size_t map_index;
581 : div_t q;
582 0 : uint8_t mask = 0;
583 :
584 0 : if (time_map == NULL) {
585 0 : DEBUG(SSSDBG_TRACE_ALL,
586 : "loginAllowedTimeMap is missing, access granted.\n");
587 0 : return false;
588 : }
589 :
590 0 : if (time_map->length != 42) {
591 0 : DEBUG(SSSDBG_FUNC_DATA,
592 : "Allowed time map has the wrong size, "
593 : "got [%zu], expected 42.\n", time_map->length);
594 0 : return true;
595 : }
596 :
597 0 : now = time(NULL);
598 0 : tm_now = gmtime(&now);
599 :
600 0 : map_index = tm_now->tm_wday * 48 + tm_now->tm_hour * 2 +
601 0 : (tm_now->tm_min < 30 ? 0 : 1);
602 :
603 0 : if (map_index > 335) {
604 0 : DEBUG(SSSDBG_CRIT_FAILURE,
605 : "Unexpected index value [%zu] for time map.\n", map_index);
606 0 : return true;
607 : }
608 :
609 0 : q = div(map_index, 8);
610 :
611 0 : if (q.quot > 41 || q.quot < 0 || q.rem > 7 || q.rem < 0) {
612 0 : DEBUG(SSSDBG_CRIT_FAILURE,
613 : "Unexpected result of div(), [%zu][%d][%d].\n",
614 : map_index, q.quot, q.rem);
615 0 : return true;
616 : }
617 :
618 0 : if (q.rem > 0) {
619 0 : mask = 1 << q.rem;
620 : }
621 :
622 0 : if (time_map->data[q.quot] & mask) {
623 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access allowed by time map.\n");
624 0 : return false;
625 : }
626 :
627 0 : return true;
628 : }
629 :
630 0 : static errno_t sdap_account_expired_nds(struct pam_data *pd,
631 : struct ldb_message *user_entry)
632 : {
633 0 : bool locked = true;
634 : int ret;
635 : const char *exp_time_str;
636 : const struct ldb_val *time_map;
637 :
638 0 : DEBUG(SSSDBG_TRACE_FUNC,
639 : "Performing NDS access check for user [%s]\n", pd->user);
640 :
641 0 : locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NDS_LOGIN_DISABLED,
642 : false);
643 0 : DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s disabled.\n", pd->user,
644 : locked ? "" : " not");
645 :
646 0 : if (locked) {
647 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
648 : sizeof(NDS_DISABLE_MSG),
649 : (const uint8_t *) NDS_DISABLE_MSG);
650 0 : if (ret != EOK) {
651 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
652 : }
653 :
654 0 : return ERR_ACCESS_DENIED;
655 :
656 : } else {
657 0 : exp_time_str = ldb_msg_find_attr_as_string(user_entry,
658 : SYSDB_NDS_LOGIN_EXPIRATION_TIME,
659 : NULL);
660 0 : locked = nds_check_expired(exp_time_str);
661 :
662 0 : DEBUG(SSSDBG_TRACE_ALL,
663 : "Account for user [%s] is%s expired.\n", pd->user,
664 : locked ? "" : " not");
665 :
666 0 : if (locked) {
667 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
668 : sizeof(NDS_EXPIRED_MSG),
669 : (const uint8_t *) NDS_EXPIRED_MSG);
670 0 : if (ret != EOK) {
671 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
672 : }
673 :
674 0 : return ERR_ACCESS_DENIED;
675 :
676 : } else {
677 0 : time_map = ldb_msg_find_ldb_val(user_entry,
678 : SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP);
679 :
680 0 : locked = nds_check_time_map(time_map);
681 :
682 0 : DEBUG(SSSDBG_TRACE_ALL,
683 : "Account for user [%s] is%s locked at this time.\n",
684 : pd->user, locked ? "" : " not");
685 :
686 0 : if (locked) {
687 0 : ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
688 : sizeof(NDS_TIME_MAP_MSG),
689 : (const uint8_t *) NDS_TIME_MAP_MSG);
690 0 : if (ret != EOK) {
691 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
692 : }
693 :
694 0 : return ERR_ACCESS_DENIED;
695 : }
696 : }
697 : }
698 :
699 0 : return EOK;
700 : }
701 :
702 0 : static errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
703 : struct pam_data *pd,
704 : struct ldb_message *user_entry)
705 : {
706 : const char *expire;
707 : int ret;
708 :
709 0 : expire = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic,
710 : SDAP_ACCOUNT_EXPIRE_POLICY);
711 0 : if (expire == NULL) {
712 0 : DEBUG(SSSDBG_CRIT_FAILURE,
713 : "Missing account expire policy. Access denied\n");
714 0 : return ERR_ACCESS_DENIED;
715 : } else {
716 0 : if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_SHADOW) == 0) {
717 0 : ret = sdap_account_expired_shadow(pd, user_entry);
718 0 : if (ret == ERR_ACCOUNT_EXPIRED) {
719 0 : DEBUG(SSSDBG_TRACE_FUNC,
720 : "sdap_account_expired_shadow: %s.\n", sss_strerror(ret));
721 0 : } else if (ret != EOK) {
722 0 : DEBUG(SSSDBG_CRIT_FAILURE,
723 : "sdap_account_expired_shadow failed.\n");
724 : }
725 0 : } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_AD) == 0) {
726 0 : ret = sdap_account_expired_ad(pd, user_entry);
727 0 : if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
728 0 : DEBUG(SSSDBG_TRACE_FUNC,
729 : "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
730 0 : } else if (ret != EOK) {
731 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_account_expired_ad failed.\n");
732 : }
733 0 : } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_RHDS) == 0 ||
734 0 : strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0 ||
735 0 : strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_389DS) == 0) {
736 0 : ret = sdap_account_expired_rhds(pd, user_entry);
737 0 : if (ret == ERR_ACCESS_DENIED) {
738 0 : DEBUG(SSSDBG_TRACE_FUNC,
739 : "sdap_account_expired_rhds: %s.\n", sss_strerror(ret));
740 0 : } else if (ret != EOK) {
741 0 : DEBUG(SSSDBG_CRIT_FAILURE,
742 : "sdap_account_expired_rhds failed.\n");
743 : }
744 0 : } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
745 0 : ret = sdap_account_expired_nds(pd, user_entry);
746 0 : if (ret == ERR_ACCESS_DENIED) {
747 0 : DEBUG(SSSDBG_TRACE_FUNC,
748 : "sdap_account_expired_nds: %s.\n", sss_strerror(ret));
749 0 : } else if (ret != EOK) {
750 0 : DEBUG(SSSDBG_CRIT_FAILURE,
751 : "sdap_account_expired_nds failed.\n");
752 : }
753 : } else {
754 0 : DEBUG(SSSDBG_CRIT_FAILURE,
755 : "Unsupported LDAP account expire policy [%s]. "
756 : "Access denied.\n", expire);
757 0 : ret = ERR_ACCESS_DENIED;
758 : }
759 : }
760 :
761 0 : return ret;
762 : }
763 :
764 0 : static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
765 : struct sss_domain_info *domain,
766 : struct pam_data *pd,
767 : struct sdap_options *opts)
768 : {
769 : enum pwexpire pw_expire_type;
770 : void *pw_expire_data;
771 : errno_t ret;
772 : char *dn;
773 :
774 0 : ret = get_user_dn(mem_ctx, domain, opts, pd->user, &dn, &pw_expire_type,
775 : &pw_expire_data);
776 0 : if (ret != EOK) {
777 0 : DEBUG(SSSDBG_MINOR_FAILURE, "get_user_dn returned %d:[%s].\n",
778 : ret, sss_strerror(ret));
779 0 : goto done;
780 : }
781 :
782 0 : ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, pd,
783 : domain->pwd_expiration_warning);
784 0 : if (ret != EOK) {
785 0 : DEBUG(SSSDBG_MINOR_FAILURE,
786 : "check_pwexpire_policy returned %d:[%s].\n",
787 : ret, sss_strerror(ret));
788 0 : goto done;
789 : }
790 :
791 : done:
792 0 : return ret;
793 : }
794 :
795 : struct sdap_access_filter_req_ctx {
796 : const char *username;
797 : const char *filter;
798 : struct tevent_context *ev;
799 : struct sdap_access_ctx *access_ctx;
800 : struct sdap_options *opts;
801 : struct sdap_id_conn_ctx *conn;
802 : struct sdap_id_op *sdap_op;
803 : struct sysdb_handle *handle;
804 : struct sss_domain_info *domain;
805 : /* cached result of access control checks */
806 : bool cached_access;
807 : const char *basedn;
808 : };
809 :
810 : static errno_t sdap_access_decide_offline(bool cached_ac);
811 : static int sdap_access_filter_retry(struct tevent_req *req);
812 : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq);
813 : static errno_t sdap_access_ppolicy_get_lockout_step(struct tevent_req *req);
814 : static void sdap_access_filter_connect_done(struct tevent_req *subreq);
815 : static void sdap_access_filter_done(struct tevent_req *req);
816 0 : static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
817 : struct tevent_context *ev,
818 : struct be_ctx *be_ctx,
819 : struct sss_domain_info *domain,
820 : struct sdap_access_ctx *access_ctx,
821 : struct sdap_id_conn_ctx *conn,
822 : const char *username,
823 : struct ldb_message *user_entry)
824 : {
825 : struct sdap_access_filter_req_ctx *state;
826 : struct tevent_req *req;
827 : char *clean_username;
828 0 : errno_t ret = ERR_INTERNAL;
829 : char *name;
830 :
831 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_access_filter_req_ctx);
832 0 : if (req == NULL) {
833 0 : return NULL;
834 : }
835 :
836 0 : if (access_ctx->filter == NULL || *access_ctx->filter == '\0') {
837 : /* If no filter is set, default to restrictive */
838 0 : DEBUG(SSSDBG_TRACE_FUNC, "No filter set. Access is denied.\n");
839 0 : ret = ERR_ACCESS_DENIED;
840 0 : goto done;
841 : }
842 :
843 0 : state->filter = NULL;
844 0 : state->username = username;
845 0 : state->opts = access_ctx->id_ctx->opts;
846 0 : state->conn = conn;
847 0 : state->ev = ev;
848 0 : state->access_ctx = access_ctx;
849 0 : state->domain = domain;
850 :
851 0 : DEBUG(SSSDBG_TRACE_FUNC,
852 : "Performing access filter check for user [%s]\n", username);
853 :
854 0 : state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
855 : SYSDB_LDAP_ACCESS_FILTER,
856 : false);
857 :
858 : /* Ok, we have one result, check if we are online or offline */
859 0 : if (be_is_offline(be_ctx)) {
860 : /* Ok, we're offline. Return from the cache */
861 0 : ret = sdap_access_decide_offline(state->cached_access);
862 0 : goto done;
863 : }
864 :
865 0 : ret = sdap_get_basedn_user_entry(user_entry, state->username,
866 0 : &state->basedn);
867 0 : if (ret != EOK) {
868 0 : goto done;
869 : }
870 :
871 : /* Construct the filter */
872 : /* Subdomain users are identified by FQDN. We need to use just the username */
873 0 : ret = sss_parse_name(state, domain->names, username, NULL, &name);
874 0 : if (ret != EOK) {
875 0 : DEBUG(SSSDBG_OP_FAILURE,
876 : "Could not parse [%s] into name and "
877 : "domain components, access might fail\n", username);
878 0 : name = discard_const(username);
879 : }
880 :
881 0 : ret = sss_filter_sanitize(state, name, &clean_username);
882 0 : if (ret != EOK) {
883 0 : goto done;
884 : }
885 :
886 0 : state->filter = talloc_asprintf(
887 : state,
888 : "(&(%s=%s)(objectclass=%s)%s)",
889 0 : state->opts->user_map[SDAP_AT_USER_NAME].name,
890 : clean_username,
891 0 : state->opts->user_map[SDAP_OC_USER].name,
892 0 : state->access_ctx->filter);
893 0 : if (state->filter == NULL) {
894 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not construct access filter\n");
895 0 : ret = ENOMEM;
896 0 : goto done;
897 : }
898 0 : talloc_zfree(clean_username);
899 :
900 0 : DEBUG(SSSDBG_TRACE_FUNC, "Checking filter against LDAP\n");
901 :
902 0 : state->sdap_op = sdap_id_op_create(state,
903 0 : state->conn->conn_cache);
904 0 : if (!state->sdap_op) {
905 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
906 0 : ret = ENOMEM;
907 0 : goto done;
908 : }
909 :
910 0 : ret = sdap_access_filter_retry(req);
911 0 : if (ret != EOK) {
912 0 : goto done;
913 : }
914 :
915 0 : return req;
916 :
917 : done:
918 0 : if (ret == EOK) {
919 0 : tevent_req_done(req);
920 : } else {
921 0 : tevent_req_error(req, ret);
922 : }
923 0 : tevent_req_post(req, ev);
924 0 : return req;
925 : }
926 :
927 : /* Helper function,
928 : * cached_ac => access granted
929 : * !cached_ac => access denied
930 : */
931 0 : static errno_t sdap_access_decide_offline(bool cached_ac)
932 : {
933 0 : if (cached_ac) {
934 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access granted by cached credentials\n");
935 0 : return EOK;
936 : } else {
937 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access denied by cached credentials\n");
938 0 : return ERR_ACCESS_DENIED;
939 : }
940 : }
941 :
942 0 : static int sdap_access_filter_retry(struct tevent_req *req)
943 : {
944 0 : struct sdap_access_filter_req_ctx *state =
945 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
946 : struct tevent_req *subreq;
947 : int ret;
948 :
949 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
950 0 : if (!subreq) {
951 0 : DEBUG(SSSDBG_OP_FAILURE,
952 : "sdap_id_op_connect_send failed: %d (%s)\n", ret, strerror(ret));
953 0 : return ret;
954 : }
955 :
956 0 : tevent_req_set_callback(subreq, sdap_access_filter_connect_done, req);
957 0 : return EOK;
958 : }
959 :
960 0 : static void sdap_access_filter_connect_done(struct tevent_req *subreq)
961 : {
962 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
963 : struct tevent_req);
964 0 : struct sdap_access_filter_req_ctx *state =
965 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
966 : int ret, dp_error;
967 :
968 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
969 0 : talloc_zfree(subreq);
970 :
971 0 : if (ret != EOK) {
972 0 : if (dp_error == DP_ERR_OFFLINE) {
973 0 : ret = sdap_access_decide_offline(state->cached_access);
974 0 : if (ret == EOK) {
975 0 : tevent_req_done(req);
976 0 : return;
977 : }
978 : }
979 :
980 0 : tevent_req_error(req, ret);
981 0 : return;
982 : }
983 :
984 : /* Connection to LDAP succeeded
985 : * Send filter request
986 : */
987 0 : subreq = sdap_get_generic_send(state,
988 : state->ev,
989 : state->opts,
990 : sdap_id_op_handle(state->sdap_op),
991 : state->basedn,
992 : LDAP_SCOPE_BASE,
993 : state->filter, NULL,
994 : NULL, 0,
995 0 : dp_opt_get_int(state->opts->basic,
996 : SDAP_SEARCH_TIMEOUT),
997 : false);
998 0 : if (subreq == NULL) {
999 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
1000 0 : tevent_req_error(req, EIO);
1001 0 : return;
1002 : }
1003 :
1004 0 : tevent_req_set_callback(subreq, sdap_access_filter_done, req);
1005 : }
1006 :
1007 0 : static void sdap_access_filter_done(struct tevent_req *subreq)
1008 : {
1009 : int ret, tret, dp_error;
1010 : size_t num_results;
1011 0 : bool found = false;
1012 : struct sysdb_attrs **results;
1013 0 : struct tevent_req *req =
1014 0 : tevent_req_callback_data(subreq, struct tevent_req);
1015 0 : struct sdap_access_filter_req_ctx *state =
1016 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
1017 :
1018 0 : ret = sdap_get_generic_recv(subreq, state,
1019 : &num_results, &results);
1020 0 : talloc_zfree(subreq);
1021 :
1022 0 : ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1023 0 : if (ret != EOK) {
1024 0 : if (dp_error == DP_ERR_OK) {
1025 : /* retry */
1026 0 : tret = sdap_access_filter_retry(req);
1027 0 : if (tret == EOK) {
1028 0 : return;
1029 : }
1030 0 : } else if (dp_error == DP_ERR_OFFLINE) {
1031 0 : ret = sdap_access_decide_offline(state->cached_access);
1032 0 : } else if (ret == ERR_INVALID_FILTER) {
1033 0 : sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
1034 0 : DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
1035 0 : ret = ERR_ACCESS_DENIED;
1036 : } else {
1037 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1038 : "sdap_get_generic_send() returned error [%d][%s]\n",
1039 : ret, sss_strerror(ret));
1040 : }
1041 :
1042 0 : goto done;
1043 : }
1044 :
1045 : /* Check the number of responses we got
1046 : * If it's exactly 1, we passed the check
1047 : * If it's < 1, we failed the check
1048 : * Anything else is an error
1049 : */
1050 0 : if (num_results < 1) {
1051 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1052 : "User [%s] was not found with the specified filter. "
1053 : "Denying access.\n", state->username);
1054 0 : found = false;
1055 : }
1056 0 : else if (results == NULL) {
1057 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1058 0 : ret = ERR_INTERNAL;
1059 0 : goto done;
1060 : }
1061 0 : else if (num_results > 1) {
1062 : /* It should not be possible to get more than one reply
1063 : * here, since we're doing a base-scoped search
1064 : */
1065 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1066 0 : ret = ERR_INTERNAL;
1067 0 : goto done;
1068 : }
1069 : else { /* Ok, we got a single reply */
1070 0 : found = true;
1071 : }
1072 :
1073 0 : if (found) {
1074 : /* Save "allow" to the cache for future offline access checks. */
1075 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access granted by online lookup\n");
1076 0 : ret = EOK;
1077 : }
1078 : else {
1079 : /* Save "disallow" to the cache for future offline
1080 : * access checks.
1081 : */
1082 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access denied by online lookup\n");
1083 0 : ret = ERR_ACCESS_DENIED;
1084 : }
1085 :
1086 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1087 : SYSDB_LDAP_ACCESS_FILTER, found);
1088 0 : if (tret != EOK) {
1089 : /* Failing to save to the cache is non-fatal.
1090 : * Just return the result.
1091 : */
1092 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
1093 0 : goto done;
1094 : }
1095 :
1096 : done:
1097 0 : if (ret == EOK) {
1098 0 : tevent_req_done(req);
1099 : }
1100 : else {
1101 0 : tevent_req_error(req, ret);
1102 : }
1103 : }
1104 :
1105 0 : static errno_t sdap_access_filter_recv(struct tevent_req *req)
1106 : {
1107 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1108 :
1109 0 : return EOK;
1110 : }
1111 :
1112 : #define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
1113 : "access denied"
1114 : #define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
1115 : #define AUTHR_SRV_NO_MATCH_MSG "Authorized service attribute has " \
1116 : "no matching rule, access denied"
1117 :
1118 0 : static errno_t sdap_access_service(struct pam_data *pd,
1119 : struct ldb_message *user_entry)
1120 : {
1121 : errno_t ret, tret;
1122 : struct ldb_message_element *el;
1123 : unsigned int i;
1124 : char *service;
1125 :
1126 0 : el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_SERVICE);
1127 0 : if (!el || el->num_values == 0) {
1128 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1129 : "Missing authorized services. Access denied\n");
1130 :
1131 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1132 : sizeof(AUTHR_SRV_MISSING_MSG),
1133 : (const uint8_t *) AUTHR_SRV_MISSING_MSG);
1134 0 : if (tret != EOK) {
1135 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1136 : }
1137 :
1138 0 : return ERR_ACCESS_DENIED;
1139 : }
1140 :
1141 0 : ret = ENOENT;
1142 :
1143 0 : for (i = 0; i < el->num_values; i++) {
1144 0 : service = (char *)el->values[i].data;
1145 0 : if (service[0] == '!' &&
1146 0 : strcasecmp(pd->service, service+1) == 0) {
1147 : /* This service is explicitly denied */
1148 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", service);
1149 :
1150 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1151 : sizeof(AUTHR_SRV_DENY_MSG),
1152 : (const uint8_t *) AUTHR_SRV_DENY_MSG);
1153 0 : if (tret != EOK) {
1154 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1155 : }
1156 :
1157 : /* A denial trumps all. Break here */
1158 0 : return ERR_ACCESS_DENIED;
1159 :
1160 0 : } else if (strcasecmp(pd->service, service) == 0) {
1161 : /* This service is explicitly allowed */
1162 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", service);
1163 : /* We still need to loop through to make sure
1164 : * that it's not also explicitly denied
1165 : */
1166 0 : ret = EOK;
1167 0 : } else if (strcmp("*", service) == 0) {
1168 : /* This user has access to all services */
1169 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all services\n");
1170 : /* We still need to loop through to make sure
1171 : * that it's not also explicitly denied
1172 : */
1173 0 : ret = EOK;
1174 : }
1175 : }
1176 :
1177 0 : if (ret == ENOENT) {
1178 0 : DEBUG(SSSDBG_CONF_SETTINGS, "No matching service rule found\n");
1179 :
1180 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1181 : sizeof(AUTHR_SRV_NO_MATCH_MSG),
1182 : (const uint8_t *) AUTHR_SRV_NO_MATCH_MSG);
1183 0 : if (tret != EOK) {
1184 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1185 : }
1186 :
1187 0 : ret = ERR_ACCESS_DENIED;
1188 : }
1189 :
1190 0 : return ret;
1191 : }
1192 :
1193 0 : static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
1194 : const char *username,
1195 : const char *attr_name,
1196 : bool value)
1197 : {
1198 : errno_t ret;
1199 : struct sysdb_attrs *attrs;
1200 :
1201 0 : attrs = sysdb_new_attrs(NULL);
1202 0 : if (attrs == NULL) {
1203 0 : ret = ENOMEM;
1204 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
1205 0 : goto done;
1206 : }
1207 :
1208 0 : ret = sysdb_attrs_add_bool(attrs, attr_name, value);
1209 0 : if (ret != EOK) {
1210 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
1211 0 : goto done;
1212 : }
1213 :
1214 0 : ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
1215 0 : if (ret != EOK) {
1216 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
1217 0 : goto done;
1218 : }
1219 :
1220 : done:
1221 0 : talloc_free(attrs);
1222 0 : return ret;
1223 : }
1224 :
1225 0 : static errno_t sdap_access_host(struct ldb_message *user_entry)
1226 : {
1227 : errno_t ret;
1228 : struct ldb_message_element *el;
1229 : unsigned int i;
1230 : char *host;
1231 : char hostname[HOST_NAME_MAX + 1];
1232 :
1233 0 : el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_HOST);
1234 0 : if (!el || el->num_values == 0) {
1235 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing hosts. Access denied\n");
1236 0 : return ERR_ACCESS_DENIED;
1237 : }
1238 :
1239 0 : if (gethostname(hostname, HOST_NAME_MAX) == -1) {
1240 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1241 : "Unable to get system hostname. Access denied\n");
1242 0 : return ERR_ACCESS_DENIED;
1243 : }
1244 0 : hostname[HOST_NAME_MAX] = '\0';
1245 :
1246 : /* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname
1247 : * in some attempt to get aliases and/or FQDN for the machine.
1248 : * Not sure this is a good idea, but we might want to add it in
1249 : * order to be compatible...
1250 : */
1251 :
1252 0 : ret = ENOENT;
1253 :
1254 0 : for (i = 0; i < el->num_values; i++) {
1255 0 : host = (char *)el->values[i].data;
1256 0 : if (host[0] == '!' &&
1257 0 : strcasecmp(hostname, host+1) == 0) {
1258 : /* This host is explicitly denied */
1259 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", host);
1260 : /* A denial trumps all. Break here */
1261 0 : return ERR_ACCESS_DENIED;
1262 :
1263 0 : } else if (strcasecmp(hostname, host) == 0) {
1264 : /* This host is explicitly allowed */
1265 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", host);
1266 : /* We still need to loop through to make sure
1267 : * that it's not also explicitly denied
1268 : */
1269 0 : ret = EOK;
1270 0 : } else if (strcmp("*", host) == 0) {
1271 : /* This user has access to all hosts */
1272 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all hosts\n");
1273 : /* We still need to loop through to make sure
1274 : * that it's not also explicitly denied
1275 : */
1276 0 : ret = EOK;
1277 : }
1278 : }
1279 :
1280 0 : if (ret == ENOENT) {
1281 0 : DEBUG(SSSDBG_CONF_SETTINGS, "No matching host rule found\n");
1282 0 : ret = ERR_ACCESS_DENIED;
1283 : }
1284 :
1285 0 : return ret;
1286 : }
1287 :
1288 : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq);
1289 : static int sdap_access_ppolicy_retry(struct tevent_req *req);
1290 : static errno_t sdap_access_ppolicy_step(struct tevent_req *req);
1291 : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq);
1292 :
1293 : struct sdap_access_ppolicy_req_ctx {
1294 : const char *username;
1295 : const char *filter;
1296 : struct tevent_context *ev;
1297 : struct sdap_access_ctx *access_ctx;
1298 : struct sdap_options *opts;
1299 : struct sdap_id_conn_ctx *conn;
1300 : struct sdap_id_op *sdap_op;
1301 : struct sysdb_handle *handle;
1302 : struct sss_domain_info *domain;
1303 : /* cached results of access control checks */
1304 : bool cached_access;
1305 : const char *basedn;
1306 : /* default DNs to ppolicy */
1307 : const char **ppolicy_dns;
1308 : unsigned int ppolicy_dns_index;
1309 : enum sdap_pwpolicy_mode pwpol_mode;
1310 : };
1311 :
1312 : static struct tevent_req *
1313 0 : sdap_access_ppolicy_send(TALLOC_CTX *mem_ctx,
1314 : struct tevent_context *ev,
1315 : struct be_ctx *be_ctx,
1316 : struct sss_domain_info *domain,
1317 : struct sdap_access_ctx *access_ctx,
1318 : struct sdap_id_conn_ctx *conn,
1319 : const char *username,
1320 : struct ldb_message *user_entry,
1321 : enum sdap_pwpolicy_mode pwpol_mode)
1322 : {
1323 : struct sdap_access_ppolicy_req_ctx *state;
1324 : struct tevent_req *req;
1325 : errno_t ret;
1326 :
1327 0 : req = tevent_req_create(mem_ctx,
1328 : &state, struct sdap_access_ppolicy_req_ctx);
1329 0 : if (req == NULL) {
1330 0 : return NULL;
1331 : }
1332 :
1333 0 : state->filter = NULL;
1334 0 : state->username = username;
1335 0 : state->opts = access_ctx->id_ctx->opts;
1336 0 : state->conn = conn;
1337 0 : state->ev = ev;
1338 0 : state->access_ctx = access_ctx;
1339 0 : state->domain = domain;
1340 0 : state->ppolicy_dns_index = 0;
1341 0 : state->pwpol_mode = pwpol_mode;
1342 :
1343 0 : DEBUG(SSSDBG_TRACE_FUNC,
1344 : "Performing access ppolicy check for user [%s]\n", username);
1345 :
1346 0 : state->cached_access = ldb_msg_find_attr_as_bool(
1347 : user_entry, SYSDB_LDAP_ACCESS_CACHED_LOCKOUT, false);
1348 :
1349 : /* Ok, we have one result, check if we are online or offline */
1350 0 : if (be_is_offline(be_ctx)) {
1351 : /* Ok, we're offline. Return from the cache */
1352 0 : ret = sdap_access_decide_offline(state->cached_access);
1353 0 : goto done;
1354 : }
1355 :
1356 0 : ret = sdap_get_basedn_user_entry(user_entry, state->username,
1357 0 : &state->basedn);
1358 0 : if (ret != EOK) {
1359 0 : goto done;
1360 : }
1361 :
1362 0 : DEBUG(SSSDBG_TRACE_FUNC, "Checking ppolicy against LDAP\n");
1363 :
1364 0 : state->sdap_op = sdap_id_op_create(state,
1365 0 : state->conn->conn_cache);
1366 0 : if (!state->sdap_op) {
1367 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
1368 0 : ret = ENOMEM;
1369 0 : goto done;
1370 : }
1371 :
1372 0 : ret = sdap_access_ppolicy_retry(req);
1373 0 : if (ret != EOK) {
1374 0 : goto done;
1375 : }
1376 :
1377 0 : return req;
1378 :
1379 : done:
1380 0 : if (ret == EOK) {
1381 0 : tevent_req_done(req);
1382 : } else {
1383 0 : tevent_req_error(req, ret);
1384 : }
1385 0 : tevent_req_post(req, ev);
1386 0 : return req;
1387 : }
1388 :
1389 0 : static int sdap_access_ppolicy_retry(struct tevent_req *req)
1390 : {
1391 : struct sdap_access_ppolicy_req_ctx *state;
1392 : struct tevent_req *subreq;
1393 : int ret;
1394 :
1395 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1396 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
1397 0 : if (!subreq) {
1398 0 : DEBUG(SSSDBG_OP_FAILURE,
1399 : "sdap_id_op_connect_send failed: %d (%s)\n",
1400 : ret, sss_strerror(ret));
1401 0 : return ret;
1402 : }
1403 :
1404 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_connect_done, req);
1405 0 : return EOK;
1406 : }
1407 :
1408 : static const char**
1409 0 : get_default_ppolicy_dns(TALLOC_CTX *mem_ctx, struct sdap_domain *sdom)
1410 : {
1411 : const char **ppolicy_dns;
1412 0 : int count = 0;
1413 : int i;
1414 :
1415 0 : while(sdom->search_bases[count] != NULL) {
1416 0 : count++;
1417 : }
1418 :
1419 : /* +1 to have space for final NULL */
1420 0 : ppolicy_dns = talloc_array(mem_ctx, const char*, count + 1);
1421 :
1422 0 : for(i = 0; i < count; i++) {
1423 0 : ppolicy_dns[i] = talloc_asprintf(mem_ctx, "cn=ppolicy,ou=policies,%s",
1424 0 : sdom->search_bases[i]->basedn);
1425 : }
1426 :
1427 0 : ppolicy_dns[count] = NULL;
1428 0 : return ppolicy_dns;
1429 : }
1430 :
1431 0 : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq)
1432 : {
1433 : struct tevent_req *req;
1434 : struct sdap_access_ppolicy_req_ctx *state;
1435 : int ret, dp_error;
1436 : const char *ppolicy_dn;
1437 :
1438 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1439 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1440 :
1441 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
1442 0 : talloc_zfree(subreq);
1443 :
1444 0 : if (ret != EOK) {
1445 0 : if (dp_error == DP_ERR_OFFLINE) {
1446 0 : ret = sdap_access_decide_offline(state->cached_access);
1447 0 : if (ret == EOK) {
1448 0 : tevent_req_done(req);
1449 0 : return;
1450 : }
1451 : }
1452 :
1453 0 : tevent_req_error(req, ret);
1454 0 : return;
1455 : }
1456 :
1457 0 : ppolicy_dn = dp_opt_get_string(state->opts->basic,
1458 : SDAP_PWDLOCKOUT_DN);
1459 :
1460 : /* option was configured */
1461 0 : if (ppolicy_dn != NULL) {
1462 0 : state->ppolicy_dns = talloc_array(state, const char*, 2);
1463 0 : if (state->ppolicy_dns == NULL) {
1464 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate ppolicy_dns.\n");
1465 0 : tevent_req_error(req, ERR_INTERNAL);
1466 0 : return;
1467 : }
1468 :
1469 0 : state->ppolicy_dns[0] = ppolicy_dn;
1470 0 : state->ppolicy_dns[1] = NULL;
1471 :
1472 : } else {
1473 : /* try to determine default value */
1474 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1475 : "ldap_pwdlockout_dn was not defined in configuration file.\n");
1476 :
1477 0 : state->ppolicy_dns = get_default_ppolicy_dns(state, state->opts->sdom);
1478 0 : if (state->ppolicy_dns == NULL) {
1479 0 : tevent_req_error(req, ERR_INTERNAL);
1480 0 : return;
1481 : }
1482 : }
1483 :
1484 : /* Connection to LDAP succeeded
1485 : * Send 'pwdLockout' request
1486 : */
1487 0 : ret = sdap_access_ppolicy_get_lockout_step(req);
1488 0 : if (ret != EOK && ret != EAGAIN) {
1489 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1490 : "sdap_access_ppolicy_get_lockout_step failed: [%d][%s]\n",
1491 : ret, sss_strerror(ret));
1492 0 : tevent_req_error(req, ERR_INTERNAL);
1493 0 : return;
1494 : }
1495 :
1496 0 : if (ret == EOK) {
1497 0 : tevent_req_done(req);
1498 : }
1499 : }
1500 :
1501 : static errno_t
1502 0 : sdap_access_ppolicy_get_lockout_step(struct tevent_req *req)
1503 : {
1504 0 : const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKOUT, NULL };
1505 : struct sdap_access_ppolicy_req_ctx *state;
1506 : struct tevent_req *subreq;
1507 : errno_t ret;
1508 :
1509 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1510 :
1511 : /* no more DNs to try */
1512 0 : if (state->ppolicy_dns[state->ppolicy_dns_index] == NULL) {
1513 0 : DEBUG(SSSDBG_TRACE_FUNC, "No more DNs to try.\n");
1514 0 : ret = EOK;
1515 0 : goto done;
1516 : }
1517 :
1518 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1519 : "Trying to find out if ppolicy is enabled using the DN: %s\n",
1520 : state->ppolicy_dns[state->ppolicy_dns_index]);
1521 :
1522 0 : subreq = sdap_get_generic_send(state,
1523 : state->ev,
1524 : state->opts,
1525 : sdap_id_op_handle(state->sdap_op),
1526 0 : state->ppolicy_dns[state->ppolicy_dns_index],
1527 : LDAP_SCOPE_BASE,
1528 : NULL, attrs,
1529 : NULL, 0,
1530 0 : dp_opt_get_int(state->opts->basic,
1531 : SDAP_SEARCH_TIMEOUT),
1532 : false);
1533 0 : if (subreq == NULL) {
1534 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
1535 0 : ret = EIO;
1536 0 : goto done;
1537 : }
1538 :
1539 : /* try next basedn */
1540 0 : state->ppolicy_dns_index++;
1541 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_get_lockout_done, req);
1542 :
1543 0 : ret = EAGAIN;
1544 :
1545 : done:
1546 0 : return ret;
1547 : }
1548 :
1549 0 : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq)
1550 : {
1551 : int ret, tret, dp_error;
1552 : size_t num_results;
1553 0 : bool pwdLockout = false;
1554 : struct sysdb_attrs **results;
1555 : struct tevent_req *req;
1556 : struct sdap_access_ppolicy_req_ctx *state;
1557 :
1558 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1559 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1560 :
1561 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
1562 0 : talloc_zfree(subreq);
1563 0 : if (ret != EOK) {
1564 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve ppolicy\n");
1565 0 : ret = ERR_NETWORK_IO;
1566 0 : goto done;
1567 : }
1568 :
1569 : /* Check the number of responses we got
1570 : * If it's exactly 1, we passed the check
1571 : * If it's < 1, we failed the check
1572 : * Anything else is an error
1573 : */
1574 : /* Didn't find ppolicy attribute */
1575 0 : if (num_results < 1) {
1576 : /* Try using next $search_base */
1577 0 : ret = sdap_access_ppolicy_get_lockout_step(req);
1578 0 : if (ret == EOK) {
1579 : /* No more search bases to try */
1580 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1581 : "[%s] was not found. Granting access.\n",
1582 : SYSDB_LDAP_ACCESS_LOCKOUT);
1583 : } else {
1584 0 : if (ret != EAGAIN) {
1585 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1586 : "sdap_access_ppolicy_get_lockout_step failed: "
1587 : "[%d][%s]\n",
1588 : ret, sss_strerror(ret));
1589 : }
1590 0 : goto done;
1591 : }
1592 0 : } else if (results == NULL) {
1593 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1594 0 : ret = ERR_INTERNAL;
1595 0 : goto done;
1596 0 : } else if (num_results > 1) {
1597 : /* It should not be possible to get more than one reply
1598 : * here, since we're doing a base-scoped search
1599 : */
1600 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1601 0 : ret = ERR_INTERNAL;
1602 0 : goto done;
1603 : } else { /* Ok, we got a single reply */
1604 0 : ret = sysdb_attrs_get_bool(results[0], SYSDB_LDAP_ACCESS_LOCKOUT,
1605 : &pwdLockout);
1606 0 : if (ret != EOK) {
1607 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1608 : "Error reading %s: [%s]\n", SYSDB_LDAP_ACCESS_LOCKOUT,
1609 : sss_strerror(ret));
1610 0 : ret = ERR_INTERNAL;
1611 0 : goto done;
1612 : }
1613 : }
1614 :
1615 0 : if (pwdLockout) {
1616 0 : DEBUG(SSSDBG_TRACE_FUNC,
1617 : "Password policy is enabled on LDAP server.\n");
1618 :
1619 : /* ppolicy is enabled => find out if account is locked */
1620 0 : ret = sdap_access_ppolicy_step(req);
1621 0 : if (ret != EOK && ret != EAGAIN) {
1622 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1623 : "sdap_access_ppolicy_step failed: [%d][%s].\n",
1624 : ret, sss_strerror(ret));
1625 : }
1626 0 : goto done;
1627 : } else {
1628 0 : DEBUG(SSSDBG_TRACE_FUNC,
1629 : "Password policy is disabled on LDAP server "
1630 : "- storing 'access granted' in sysdb.\n");
1631 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1632 : SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
1633 : true);
1634 0 : if (tret != EOK) {
1635 : /* Failing to save to the cache is non-fatal.
1636 : * Just return the result.
1637 : */
1638 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1639 : "Failed to set user locked attribute\n");
1640 0 : goto done;
1641 : }
1642 :
1643 0 : ret = EOK;
1644 0 : goto done;
1645 : }
1646 :
1647 : done:
1648 0 : if (ret != EAGAIN) {
1649 : /* release connection */
1650 0 : tret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1651 0 : if (tret != EOK) {
1652 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1653 : "sdap_get_generic_send() returned error [%d][%s]\n",
1654 : ret, sss_strerror(ret));
1655 : }
1656 :
1657 0 : if (ret == EOK) {
1658 0 : tevent_req_done(req);
1659 : } else {
1660 0 : tevent_req_error(req, ret);
1661 : }
1662 : }
1663 0 : }
1664 :
1665 0 : errno_t sdap_access_ppolicy_step(struct tevent_req *req)
1666 : {
1667 : errno_t ret;
1668 : struct tevent_req *subreq;
1669 : struct sdap_access_ppolicy_req_ctx *state;
1670 0 : const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME,
1671 : SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
1672 : NULL };
1673 :
1674 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1675 :
1676 0 : subreq = sdap_get_generic_send(state,
1677 : state->ev,
1678 : state->opts,
1679 : sdap_id_op_handle(state->sdap_op),
1680 : state->basedn,
1681 : LDAP_SCOPE_BASE,
1682 : NULL, attrs,
1683 : NULL, 0,
1684 0 : dp_opt_get_int(state->opts->basic,
1685 : SDAP_SEARCH_TIMEOUT),
1686 : false);
1687 :
1688 0 : if (subreq == NULL) {
1689 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_ppolicy_send failed.\n");
1690 0 : ret = ENOMEM;
1691 0 : goto done;
1692 : }
1693 :
1694 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_step_done, req);
1695 0 : ret = EAGAIN;
1696 :
1697 : done:
1698 0 : return ret;
1699 : }
1700 :
1701 : static errno_t
1702 0 : is_account_locked(const char *pwdAccountLockedTime,
1703 : const char *pwdAccountLockedDurationTime,
1704 : enum sdap_pwpolicy_mode pwpol_mode,
1705 : const char *username,
1706 : bool *_locked)
1707 : {
1708 : errno_t ret;
1709 : time_t lock_time;
1710 : time_t duration;
1711 : time_t now;
1712 : bool locked;
1713 :
1714 : /* Default action is to consider account to be locked. */
1715 0 : locked = true;
1716 :
1717 : /* account is permanently locked */
1718 0 : if (strcasecmp(pwdAccountLockedTime,
1719 : PERMANENTLY_LOCKED_ACCOUNT) == 0) {
1720 0 : ret = EOK;
1721 0 : goto done;
1722 : }
1723 :
1724 0 : switch(pwpol_mode) {
1725 : case PWP_LOCKOUT_ONLY:
1726 : /* We do *not* care about exact value of account locked time, we
1727 : * only *do* care if the value is equal to
1728 : * PERMANENTLY_LOCKED_ACCOUNT, which means that account is locked
1729 : * permanently.
1730 : */
1731 0 : DEBUG(SSSDBG_TRACE_FUNC,
1732 : "Account of: %s is being blocked by password policy, "
1733 : "but value: [%s] value is ignored by SSSD.\n",
1734 : username, pwdAccountLockedTime);
1735 0 : locked = false;
1736 0 : break;
1737 : case PWP_LOCKOUT_EXPIRE:
1738 : /* Account may be locked out from natural reasons (too many attempts,
1739 : * expired password). In this case, pwdAccountLockedTime is also set,
1740 : * to the time of lock out.
1741 : */
1742 0 : ret = sss_utc_to_time_t(pwdAccountLockedTime, "%Y%m%d%H%M%SZ",
1743 : &lock_time);
1744 0 : if (ret != EOK) {
1745 0 : DEBUG(SSSDBG_TRACE_FUNC, "sss_utc_to_time_t failed with %d:%s.\n",
1746 : ret, sss_strerror(ret));
1747 0 : goto done;
1748 : }
1749 :
1750 0 : now = time(NULL);
1751 :
1752 : /* Account was NOT locked in past. */
1753 0 : if (difftime(lock_time, now) > 0.0) {
1754 0 : locked = false;
1755 0 : } else if (pwdAccountLockedDurationTime != NULL) {
1756 0 : errno = 0;
1757 0 : duration = strtouint32(pwdAccountLockedDurationTime, NULL, 0);
1758 0 : if (errno) {
1759 0 : ret = errno;
1760 0 : goto done;
1761 : }
1762 : /* Lockout has expired */
1763 0 : if (duration != 0 && difftime(now, lock_time) > duration) {
1764 0 : locked = false;
1765 : }
1766 : }
1767 0 : break;
1768 : case PWP_SENTINEL:
1769 : default:
1770 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1771 : "Unexpected value of password policy mode: %d.\n", pwpol_mode);
1772 0 : ret = EINVAL;
1773 0 : goto done;
1774 : }
1775 :
1776 0 : ret = EOK;
1777 :
1778 : done:
1779 0 : if (ret == EOK) {
1780 0 : *_locked = locked;
1781 : }
1782 :
1783 0 : return ret;
1784 : }
1785 :
1786 0 : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq)
1787 : {
1788 : int ret, tret, dp_error;
1789 : size_t num_results;
1790 0 : bool locked = false;
1791 : const char *pwdAccountLockedTime;
1792 : const char *pwdAccountLockedDurationTime;
1793 : struct sysdb_attrs **results;
1794 : struct tevent_req *req;
1795 : struct sdap_access_ppolicy_req_ctx *state;
1796 :
1797 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1798 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1799 :
1800 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
1801 0 : talloc_zfree(subreq);
1802 :
1803 0 : ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1804 0 : if (ret != EOK) {
1805 0 : if (dp_error == DP_ERR_OK) {
1806 : /* retry */
1807 0 : tret = sdap_access_ppolicy_retry(req);
1808 0 : if (tret == EOK) {
1809 0 : return;
1810 : }
1811 0 : } else if (dp_error == DP_ERR_OFFLINE) {
1812 0 : ret = sdap_access_decide_offline(state->cached_access);
1813 : } else {
1814 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1815 : "sdap_get_generic_send() returned error [%d][%s]\n",
1816 : ret, sss_strerror(ret));
1817 : }
1818 :
1819 0 : goto done;
1820 : }
1821 :
1822 : /* Check the number of responses we got
1823 : * If it's exactly 1, we passed the check
1824 : * If it's < 1, we failed the check
1825 : * Anything else is an error
1826 : */
1827 0 : if (num_results < 1) {
1828 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1829 : "User [%s] was not found with the specified filter. "
1830 : "Denying access.\n", state->username);
1831 0 : } else if (results == NULL) {
1832 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1833 0 : ret = ERR_INTERNAL;
1834 0 : goto done;
1835 0 : } else if (num_results > 1) {
1836 : /* It should not be possible to get more than one reply
1837 : * here, since we're doing a base-scoped search
1838 : */
1839 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1840 0 : ret = ERR_INTERNAL;
1841 0 : goto done;
1842 : } else { /* Ok, we got a single reply */
1843 0 : ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
1844 : &pwdAccountLockedDurationTime);
1845 0 : if (ret != EOK) {
1846 : /* This attribute might not be set even if account is locked */
1847 0 : pwdAccountLockedDurationTime = NULL;
1848 : }
1849 :
1850 0 : ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACCESS_LOCKED_TIME,
1851 : &pwdAccountLockedTime);
1852 0 : if (ret == EOK) {
1853 :
1854 0 : ret = is_account_locked(pwdAccountLockedTime,
1855 : pwdAccountLockedDurationTime,
1856 : state->pwpol_mode,
1857 : state->username,
1858 : &locked);
1859 0 : if (ret != EOK) {
1860 0 : if (ret == ERR_TIMESPEC_NOT_SUPPORTED) {
1861 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1862 : "timezone specifier in ppolicy is not supported\n");
1863 : } else {
1864 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1865 : "is_account_locked failed: %d:[%s].\n",
1866 : ret, sss_strerror(ret));
1867 : }
1868 :
1869 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1870 : "Account will be considered to be locked.\n");
1871 0 : locked = true;
1872 : }
1873 : } else {
1874 : /* Attribute SYSDB_LDAP_ACCESS_LOCKED_TIME in not be present unless
1875 : * user's account is blocked by password policy.
1876 : */
1877 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1878 : "Attribute %s failed to be obtained - [%d][%s].\n",
1879 : SYSDB_LDAP_ACCESS_LOCKED_TIME, ret, strerror(ret));
1880 : }
1881 : }
1882 :
1883 0 : if (locked) {
1884 0 : DEBUG(SSSDBG_TRACE_FUNC,
1885 : "Access denied by online lookup - account is locked.\n");
1886 0 : ret = ERR_ACCESS_DENIED;
1887 : } else {
1888 0 : DEBUG(SSSDBG_TRACE_FUNC,
1889 : "Access granted by online lookup - account is not locked.\n");
1890 0 : ret = EOK;
1891 : }
1892 :
1893 : /* Save '!locked' to the cache for future offline access checks.
1894 : * Locked == true => access denied,
1895 : * Locked == false => access granted
1896 : */
1897 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1898 : SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
1899 : !locked);
1900 :
1901 0 : if (tret != EOK) {
1902 : /* Failing to save to the cache is non-fatal.
1903 : * Just return the result.
1904 : */
1905 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user locked attribute\n");
1906 0 : goto done;
1907 : }
1908 :
1909 : done:
1910 0 : if (ret == EOK) {
1911 0 : tevent_req_done(req);
1912 : } else {
1913 0 : tevent_req_error(req, ret);
1914 : }
1915 : }
1916 :
1917 0 : static errno_t sdap_access_ppolicy_recv(struct tevent_req *req)
1918 : {
1919 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1920 :
1921 0 : return EOK;
1922 : }
1923 :
1924 0 : static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
1925 : const char *username,
1926 : const char **_basedn)
1927 : {
1928 : const char *basedn;
1929 : errno_t ret;
1930 :
1931 0 : basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
1932 0 : if (basedn == NULL) {
1933 0 : DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",
1934 : username);
1935 0 : ret = EINVAL;
1936 0 : goto done;
1937 : }
1938 :
1939 0 : *_basedn = basedn;
1940 0 : ret = EOK;
1941 :
1942 : done:
1943 0 : return ret;
1944 : }
|