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/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 :
745 0 : if (ret == EOK &&
746 0 : strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0) {
747 0 : DEBUG(SSSDBG_TRACE_FUNC,
748 : "IPA access control succeeded, checking AD "
749 : "access control\n");
750 0 : ret = sdap_account_expired_ad(pd, user_entry);
751 0 : if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
752 0 : DEBUG(SSSDBG_TRACE_FUNC,
753 : "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
754 0 : } else if (ret != EOK) {
755 0 : DEBUG(SSSDBG_CRIT_FAILURE,
756 : "sdap_account_expired_ad failed.\n");
757 : }
758 : }
759 0 : } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
760 0 : ret = sdap_account_expired_nds(pd, user_entry);
761 0 : if (ret == ERR_ACCESS_DENIED) {
762 0 : DEBUG(SSSDBG_TRACE_FUNC,
763 : "sdap_account_expired_nds: %s.\n", sss_strerror(ret));
764 0 : } else if (ret != EOK) {
765 0 : DEBUG(SSSDBG_CRIT_FAILURE,
766 : "sdap_account_expired_nds failed.\n");
767 : }
768 : } else {
769 0 : DEBUG(SSSDBG_CRIT_FAILURE,
770 : "Unsupported LDAP account expire policy [%s]. "
771 : "Access denied.\n", expire);
772 0 : ret = ERR_ACCESS_DENIED;
773 : }
774 : }
775 :
776 0 : return ret;
777 : }
778 :
779 0 : static errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
780 : struct sss_domain_info *domain,
781 : struct pam_data *pd,
782 : struct sdap_options *opts)
783 : {
784 : enum pwexpire pw_expire_type;
785 : void *pw_expire_data;
786 : errno_t ret;
787 : char *dn;
788 :
789 0 : ret = get_user_dn(mem_ctx, domain, opts, pd->user, &dn, &pw_expire_type,
790 : &pw_expire_data);
791 0 : if (ret != EOK) {
792 0 : DEBUG(SSSDBG_MINOR_FAILURE, "get_user_dn returned %d:[%s].\n",
793 : ret, sss_strerror(ret));
794 0 : goto done;
795 : }
796 :
797 0 : ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, pd,
798 : domain->pwd_expiration_warning);
799 0 : if (ret != EOK) {
800 0 : DEBUG(SSSDBG_MINOR_FAILURE,
801 : "check_pwexpire_policy returned %d:[%s].\n",
802 : ret, sss_strerror(ret));
803 0 : goto done;
804 : }
805 :
806 : done:
807 0 : return ret;
808 : }
809 :
810 : struct sdap_access_filter_req_ctx {
811 : const char *username;
812 : const char *filter;
813 : struct tevent_context *ev;
814 : struct sdap_access_ctx *access_ctx;
815 : struct sdap_options *opts;
816 : struct sdap_id_conn_ctx *conn;
817 : struct sdap_id_op *sdap_op;
818 : struct sysdb_handle *handle;
819 : struct sss_domain_info *domain;
820 : /* cached result of access control checks */
821 : bool cached_access;
822 : const char *basedn;
823 : };
824 :
825 : static errno_t sdap_access_decide_offline(bool cached_ac);
826 : static int sdap_access_filter_retry(struct tevent_req *req);
827 : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq);
828 : static errno_t sdap_access_ppolicy_get_lockout_step(struct tevent_req *req);
829 : static void sdap_access_filter_connect_done(struct tevent_req *subreq);
830 : static void sdap_access_filter_done(struct tevent_req *req);
831 0 : static struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
832 : struct tevent_context *ev,
833 : struct be_ctx *be_ctx,
834 : struct sss_domain_info *domain,
835 : struct sdap_access_ctx *access_ctx,
836 : struct sdap_id_conn_ctx *conn,
837 : const char *username,
838 : struct ldb_message *user_entry)
839 : {
840 : struct sdap_access_filter_req_ctx *state;
841 : struct tevent_req *req;
842 : char *clean_username;
843 0 : errno_t ret = ERR_INTERNAL;
844 : char *name;
845 :
846 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_access_filter_req_ctx);
847 0 : if (req == NULL) {
848 0 : return NULL;
849 : }
850 :
851 0 : if (access_ctx->filter == NULL || *access_ctx->filter == '\0') {
852 : /* If no filter is set, default to restrictive */
853 0 : DEBUG(SSSDBG_TRACE_FUNC, "No filter set. Access is denied.\n");
854 0 : ret = ERR_ACCESS_DENIED;
855 0 : goto done;
856 : }
857 :
858 0 : state->filter = NULL;
859 0 : state->username = username;
860 0 : state->opts = access_ctx->id_ctx->opts;
861 0 : state->conn = conn;
862 0 : state->ev = ev;
863 0 : state->access_ctx = access_ctx;
864 0 : state->domain = domain;
865 :
866 0 : DEBUG(SSSDBG_TRACE_FUNC,
867 : "Performing access filter check for user [%s]\n", username);
868 :
869 0 : state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
870 : SYSDB_LDAP_ACCESS_FILTER,
871 : false);
872 :
873 : /* Ok, we have one result, check if we are online or offline */
874 0 : if (be_is_offline(be_ctx)) {
875 : /* Ok, we're offline. Return from the cache */
876 0 : ret = sdap_access_decide_offline(state->cached_access);
877 0 : goto done;
878 : }
879 :
880 0 : ret = sdap_get_basedn_user_entry(user_entry, state->username,
881 0 : &state->basedn);
882 0 : if (ret != EOK) {
883 0 : goto done;
884 : }
885 :
886 : /* Construct the filter */
887 : /* Subdomain users are identified by FQDN. We need to use just the username */
888 0 : ret = sss_parse_name(state, domain->names, username, NULL, &name);
889 0 : if (ret != EOK) {
890 0 : DEBUG(SSSDBG_OP_FAILURE,
891 : "Could not parse [%s] into name and "
892 : "domain components, access might fail\n", username);
893 0 : name = discard_const(username);
894 : }
895 :
896 0 : ret = sss_filter_sanitize(state, name, &clean_username);
897 0 : if (ret != EOK) {
898 0 : goto done;
899 : }
900 :
901 0 : state->filter = talloc_asprintf(
902 : state,
903 : "(&(%s=%s)(objectclass=%s)%s)",
904 0 : state->opts->user_map[SDAP_AT_USER_NAME].name,
905 : clean_username,
906 0 : state->opts->user_map[SDAP_OC_USER].name,
907 0 : state->access_ctx->filter);
908 0 : if (state->filter == NULL) {
909 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not construct access filter\n");
910 0 : ret = ENOMEM;
911 0 : goto done;
912 : }
913 0 : talloc_zfree(clean_username);
914 :
915 0 : DEBUG(SSSDBG_TRACE_FUNC, "Checking filter against LDAP\n");
916 :
917 0 : state->sdap_op = sdap_id_op_create(state,
918 0 : state->conn->conn_cache);
919 0 : if (!state->sdap_op) {
920 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
921 0 : ret = ENOMEM;
922 0 : goto done;
923 : }
924 :
925 0 : ret = sdap_access_filter_retry(req);
926 0 : if (ret != EOK) {
927 0 : goto done;
928 : }
929 :
930 0 : return req;
931 :
932 : done:
933 0 : if (ret == EOK) {
934 0 : tevent_req_done(req);
935 : } else {
936 0 : tevent_req_error(req, ret);
937 : }
938 0 : tevent_req_post(req, ev);
939 0 : return req;
940 : }
941 :
942 : /* Helper function,
943 : * cached_ac => access granted
944 : * !cached_ac => access denied
945 : */
946 0 : static errno_t sdap_access_decide_offline(bool cached_ac)
947 : {
948 0 : if (cached_ac) {
949 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access granted by cached credentials\n");
950 0 : return EOK;
951 : } else {
952 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access denied by cached credentials\n");
953 0 : return ERR_ACCESS_DENIED;
954 : }
955 : }
956 :
957 0 : static int sdap_access_filter_retry(struct tevent_req *req)
958 : {
959 0 : struct sdap_access_filter_req_ctx *state =
960 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
961 : struct tevent_req *subreq;
962 : int ret;
963 :
964 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
965 0 : if (!subreq) {
966 0 : DEBUG(SSSDBG_OP_FAILURE,
967 : "sdap_id_op_connect_send failed: %d (%s)\n", ret, strerror(ret));
968 0 : return ret;
969 : }
970 :
971 0 : tevent_req_set_callback(subreq, sdap_access_filter_connect_done, req);
972 0 : return EOK;
973 : }
974 :
975 0 : static void sdap_access_filter_connect_done(struct tevent_req *subreq)
976 : {
977 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
978 : struct tevent_req);
979 0 : struct sdap_access_filter_req_ctx *state =
980 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
981 : int ret, dp_error;
982 :
983 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
984 0 : talloc_zfree(subreq);
985 :
986 0 : if (ret != EOK) {
987 0 : if (dp_error == DP_ERR_OFFLINE) {
988 0 : ret = sdap_access_decide_offline(state->cached_access);
989 0 : if (ret == EOK) {
990 0 : tevent_req_done(req);
991 0 : return;
992 : }
993 : }
994 :
995 0 : tevent_req_error(req, ret);
996 0 : return;
997 : }
998 :
999 : /* Connection to LDAP succeeded
1000 : * Send filter request
1001 : */
1002 0 : subreq = sdap_get_generic_send(state,
1003 : state->ev,
1004 : state->opts,
1005 : sdap_id_op_handle(state->sdap_op),
1006 : state->basedn,
1007 : LDAP_SCOPE_BASE,
1008 : state->filter, NULL,
1009 : NULL, 0,
1010 0 : dp_opt_get_int(state->opts->basic,
1011 : SDAP_SEARCH_TIMEOUT),
1012 : false);
1013 0 : if (subreq == NULL) {
1014 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
1015 0 : tevent_req_error(req, EIO);
1016 0 : return;
1017 : }
1018 :
1019 0 : tevent_req_set_callback(subreq, sdap_access_filter_done, req);
1020 : }
1021 :
1022 0 : static void sdap_access_filter_done(struct tevent_req *subreq)
1023 : {
1024 : int ret, tret, dp_error;
1025 : size_t num_results;
1026 0 : bool found = false;
1027 : struct sysdb_attrs **results;
1028 0 : struct tevent_req *req =
1029 0 : tevent_req_callback_data(subreq, struct tevent_req);
1030 0 : struct sdap_access_filter_req_ctx *state =
1031 0 : tevent_req_data(req, struct sdap_access_filter_req_ctx);
1032 :
1033 0 : ret = sdap_get_generic_recv(subreq, state,
1034 : &num_results, &results);
1035 0 : talloc_zfree(subreq);
1036 :
1037 0 : ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1038 0 : if (ret != EOK) {
1039 0 : if (dp_error == DP_ERR_OK) {
1040 : /* retry */
1041 0 : tret = sdap_access_filter_retry(req);
1042 0 : if (tret == EOK) {
1043 0 : return;
1044 : }
1045 0 : } else if (dp_error == DP_ERR_OFFLINE) {
1046 0 : ret = sdap_access_decide_offline(state->cached_access);
1047 0 : } else if (ret == ERR_INVALID_FILTER) {
1048 0 : sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
1049 0 : DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
1050 0 : ret = ERR_ACCESS_DENIED;
1051 : } else {
1052 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1053 : "sdap_get_generic_send() returned error [%d][%s]\n",
1054 : ret, sss_strerror(ret));
1055 : }
1056 :
1057 0 : goto done;
1058 : }
1059 :
1060 : /* Check the number of responses we got
1061 : * If it's exactly 1, we passed the check
1062 : * If it's < 1, we failed the check
1063 : * Anything else is an error
1064 : */
1065 0 : if (num_results < 1) {
1066 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1067 : "User [%s] was not found with the specified filter. "
1068 : "Denying access.\n", state->username);
1069 0 : found = false;
1070 : }
1071 0 : else if (results == NULL) {
1072 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1073 0 : ret = ERR_INTERNAL;
1074 0 : goto done;
1075 : }
1076 0 : else if (num_results > 1) {
1077 : /* It should not be possible to get more than one reply
1078 : * here, since we're doing a base-scoped search
1079 : */
1080 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1081 0 : ret = ERR_INTERNAL;
1082 0 : goto done;
1083 : }
1084 : else { /* Ok, we got a single reply */
1085 0 : found = true;
1086 : }
1087 :
1088 0 : if (found) {
1089 : /* Save "allow" to the cache for future offline access checks. */
1090 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access granted by online lookup\n");
1091 0 : ret = EOK;
1092 : }
1093 : else {
1094 : /* Save "disallow" to the cache for future offline
1095 : * access checks.
1096 : */
1097 0 : DEBUG(SSSDBG_TRACE_FUNC, "Access denied by online lookup\n");
1098 0 : ret = ERR_ACCESS_DENIED;
1099 : }
1100 :
1101 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1102 : SYSDB_LDAP_ACCESS_FILTER, found);
1103 0 : if (tret != EOK) {
1104 : /* Failing to save to the cache is non-fatal.
1105 : * Just return the result.
1106 : */
1107 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
1108 0 : goto done;
1109 : }
1110 :
1111 : done:
1112 0 : if (ret == EOK) {
1113 0 : tevent_req_done(req);
1114 : }
1115 : else {
1116 0 : tevent_req_error(req, ret);
1117 : }
1118 : }
1119 :
1120 0 : static errno_t sdap_access_filter_recv(struct tevent_req *req)
1121 : {
1122 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1123 :
1124 0 : return EOK;
1125 : }
1126 :
1127 : #define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
1128 : "access denied"
1129 : #define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
1130 : #define AUTHR_SRV_NO_MATCH_MSG "Authorized service attribute has " \
1131 : "no matching rule, access denied"
1132 :
1133 0 : static errno_t sdap_access_service(struct pam_data *pd,
1134 : struct ldb_message *user_entry)
1135 : {
1136 : errno_t ret, tret;
1137 : struct ldb_message_element *el;
1138 : unsigned int i;
1139 : char *service;
1140 :
1141 0 : el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_SERVICE);
1142 0 : if (!el || el->num_values == 0) {
1143 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1144 : "Missing authorized services. Access denied\n");
1145 :
1146 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1147 : sizeof(AUTHR_SRV_MISSING_MSG),
1148 : (const uint8_t *) AUTHR_SRV_MISSING_MSG);
1149 0 : if (tret != EOK) {
1150 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1151 : }
1152 :
1153 0 : return ERR_ACCESS_DENIED;
1154 : }
1155 :
1156 0 : ret = ENOENT;
1157 :
1158 0 : for (i = 0; i < el->num_values; i++) {
1159 0 : service = (char *)el->values[i].data;
1160 0 : if (service[0] == '!' &&
1161 0 : strcasecmp(pd->service, service+1) == 0) {
1162 : /* This service is explicitly denied */
1163 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", service);
1164 :
1165 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1166 : sizeof(AUTHR_SRV_DENY_MSG),
1167 : (const uint8_t *) AUTHR_SRV_DENY_MSG);
1168 0 : if (tret != EOK) {
1169 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1170 : }
1171 :
1172 : /* A denial trumps all. Break here */
1173 0 : return ERR_ACCESS_DENIED;
1174 :
1175 0 : } else if (strcasecmp(pd->service, service) == 0) {
1176 : /* This service is explicitly allowed */
1177 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", service);
1178 : /* We still need to loop through to make sure
1179 : * that it's not also explicitly denied
1180 : */
1181 0 : ret = EOK;
1182 0 : } else if (strcmp("*", service) == 0) {
1183 : /* This user has access to all services */
1184 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all services\n");
1185 : /* We still need to loop through to make sure
1186 : * that it's not also explicitly denied
1187 : */
1188 0 : ret = EOK;
1189 : }
1190 : }
1191 :
1192 0 : if (ret == ENOENT) {
1193 0 : DEBUG(SSSDBG_CONF_SETTINGS, "No matching service rule found\n");
1194 :
1195 0 : tret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
1196 : sizeof(AUTHR_SRV_NO_MATCH_MSG),
1197 : (const uint8_t *) AUTHR_SRV_NO_MATCH_MSG);
1198 0 : if (tret != EOK) {
1199 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1200 : }
1201 :
1202 0 : ret = ERR_ACCESS_DENIED;
1203 : }
1204 :
1205 0 : return ret;
1206 : }
1207 :
1208 0 : static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
1209 : const char *username,
1210 : const char *attr_name,
1211 : bool value)
1212 : {
1213 : errno_t ret;
1214 : struct sysdb_attrs *attrs;
1215 :
1216 0 : attrs = sysdb_new_attrs(NULL);
1217 0 : if (attrs == NULL) {
1218 0 : ret = ENOMEM;
1219 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
1220 0 : goto done;
1221 : }
1222 :
1223 0 : ret = sysdb_attrs_add_bool(attrs, attr_name, value);
1224 0 : if (ret != EOK) {
1225 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
1226 0 : goto done;
1227 : }
1228 :
1229 0 : ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
1230 0 : if (ret != EOK) {
1231 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
1232 0 : goto done;
1233 : }
1234 :
1235 : done:
1236 0 : talloc_free(attrs);
1237 0 : return ret;
1238 : }
1239 :
1240 0 : static errno_t sdap_access_host(struct ldb_message *user_entry)
1241 : {
1242 : errno_t ret;
1243 : struct ldb_message_element *el;
1244 : unsigned int i;
1245 : char *host;
1246 : char hostname[HOST_NAME_MAX + 1];
1247 :
1248 0 : el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_HOST);
1249 0 : if (!el || el->num_values == 0) {
1250 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing hosts. Access denied\n");
1251 0 : return ERR_ACCESS_DENIED;
1252 : }
1253 :
1254 0 : if (gethostname(hostname, HOST_NAME_MAX) == -1) {
1255 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1256 : "Unable to get system hostname. Access denied\n");
1257 0 : return ERR_ACCESS_DENIED;
1258 : }
1259 0 : hostname[HOST_NAME_MAX] = '\0';
1260 :
1261 : /* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname
1262 : * in some attempt to get aliases and/or FQDN for the machine.
1263 : * Not sure this is a good idea, but we might want to add it in
1264 : * order to be compatible...
1265 : */
1266 :
1267 0 : ret = ENOENT;
1268 :
1269 0 : for (i = 0; i < el->num_values; i++) {
1270 0 : host = (char *)el->values[i].data;
1271 0 : if (host[0] == '!' &&
1272 0 : strcasecmp(hostname, host+1) == 0) {
1273 : /* This host is explicitly denied */
1274 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", host);
1275 : /* A denial trumps all. Break here */
1276 0 : return ERR_ACCESS_DENIED;
1277 :
1278 0 : } else if (strcasecmp(hostname, host) == 0) {
1279 : /* This host is explicitly allowed */
1280 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", host);
1281 : /* We still need to loop through to make sure
1282 : * that it's not also explicitly denied
1283 : */
1284 0 : ret = EOK;
1285 0 : } else if (strcmp("*", host) == 0) {
1286 : /* This user has access to all hosts */
1287 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all hosts\n");
1288 : /* We still need to loop through to make sure
1289 : * that it's not also explicitly denied
1290 : */
1291 0 : ret = EOK;
1292 : }
1293 : }
1294 :
1295 0 : if (ret == ENOENT) {
1296 0 : DEBUG(SSSDBG_CONF_SETTINGS, "No matching host rule found\n");
1297 0 : ret = ERR_ACCESS_DENIED;
1298 : }
1299 :
1300 0 : return ret;
1301 : }
1302 :
1303 : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq);
1304 : static int sdap_access_ppolicy_retry(struct tevent_req *req);
1305 : static errno_t sdap_access_ppolicy_step(struct tevent_req *req);
1306 : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq);
1307 :
1308 : struct sdap_access_ppolicy_req_ctx {
1309 : const char *username;
1310 : const char *filter;
1311 : struct tevent_context *ev;
1312 : struct sdap_access_ctx *access_ctx;
1313 : struct sdap_options *opts;
1314 : struct sdap_id_conn_ctx *conn;
1315 : struct sdap_id_op *sdap_op;
1316 : struct sysdb_handle *handle;
1317 : struct sss_domain_info *domain;
1318 : /* cached results of access control checks */
1319 : bool cached_access;
1320 : const char *basedn;
1321 : /* default DNs to ppolicy */
1322 : const char **ppolicy_dns;
1323 : unsigned int ppolicy_dns_index;
1324 : enum sdap_pwpolicy_mode pwpol_mode;
1325 : };
1326 :
1327 : static struct tevent_req *
1328 0 : sdap_access_ppolicy_send(TALLOC_CTX *mem_ctx,
1329 : struct tevent_context *ev,
1330 : struct be_ctx *be_ctx,
1331 : struct sss_domain_info *domain,
1332 : struct sdap_access_ctx *access_ctx,
1333 : struct sdap_id_conn_ctx *conn,
1334 : const char *username,
1335 : struct ldb_message *user_entry,
1336 : enum sdap_pwpolicy_mode pwpol_mode)
1337 : {
1338 : struct sdap_access_ppolicy_req_ctx *state;
1339 : struct tevent_req *req;
1340 : errno_t ret;
1341 :
1342 0 : req = tevent_req_create(mem_ctx,
1343 : &state, struct sdap_access_ppolicy_req_ctx);
1344 0 : if (req == NULL) {
1345 0 : return NULL;
1346 : }
1347 :
1348 0 : state->filter = NULL;
1349 0 : state->username = username;
1350 0 : state->opts = access_ctx->id_ctx->opts;
1351 0 : state->conn = conn;
1352 0 : state->ev = ev;
1353 0 : state->access_ctx = access_ctx;
1354 0 : state->domain = domain;
1355 0 : state->ppolicy_dns_index = 0;
1356 0 : state->pwpol_mode = pwpol_mode;
1357 :
1358 0 : DEBUG(SSSDBG_TRACE_FUNC,
1359 : "Performing access ppolicy check for user [%s]\n", username);
1360 :
1361 0 : state->cached_access = ldb_msg_find_attr_as_bool(
1362 : user_entry, SYSDB_LDAP_ACCESS_CACHED_LOCKOUT, false);
1363 :
1364 : /* Ok, we have one result, check if we are online or offline */
1365 0 : if (be_is_offline(be_ctx)) {
1366 : /* Ok, we're offline. Return from the cache */
1367 0 : ret = sdap_access_decide_offline(state->cached_access);
1368 0 : goto done;
1369 : }
1370 :
1371 0 : ret = sdap_get_basedn_user_entry(user_entry, state->username,
1372 0 : &state->basedn);
1373 0 : if (ret != EOK) {
1374 0 : goto done;
1375 : }
1376 :
1377 0 : DEBUG(SSSDBG_TRACE_FUNC, "Checking ppolicy against LDAP\n");
1378 :
1379 0 : state->sdap_op = sdap_id_op_create(state,
1380 0 : state->conn->conn_cache);
1381 0 : if (!state->sdap_op) {
1382 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
1383 0 : ret = ENOMEM;
1384 0 : goto done;
1385 : }
1386 :
1387 0 : ret = sdap_access_ppolicy_retry(req);
1388 0 : if (ret != EOK) {
1389 0 : goto done;
1390 : }
1391 :
1392 0 : return req;
1393 :
1394 : done:
1395 0 : if (ret == EOK) {
1396 0 : tevent_req_done(req);
1397 : } else {
1398 0 : tevent_req_error(req, ret);
1399 : }
1400 0 : tevent_req_post(req, ev);
1401 0 : return req;
1402 : }
1403 :
1404 0 : static int sdap_access_ppolicy_retry(struct tevent_req *req)
1405 : {
1406 : struct sdap_access_ppolicy_req_ctx *state;
1407 : struct tevent_req *subreq;
1408 : int ret;
1409 :
1410 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1411 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
1412 0 : if (!subreq) {
1413 0 : DEBUG(SSSDBG_OP_FAILURE,
1414 : "sdap_id_op_connect_send failed: %d (%s)\n",
1415 : ret, sss_strerror(ret));
1416 0 : return ret;
1417 : }
1418 :
1419 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_connect_done, req);
1420 0 : return EOK;
1421 : }
1422 :
1423 : static const char**
1424 0 : get_default_ppolicy_dns(TALLOC_CTX *mem_ctx, struct sdap_domain *sdom)
1425 : {
1426 : const char **ppolicy_dns;
1427 0 : int count = 0;
1428 : int i;
1429 :
1430 0 : while(sdom->search_bases[count] != NULL) {
1431 0 : count++;
1432 : }
1433 :
1434 : /* +1 to have space for final NULL */
1435 0 : ppolicy_dns = talloc_array(mem_ctx, const char*, count + 1);
1436 :
1437 0 : for(i = 0; i < count; i++) {
1438 0 : ppolicy_dns[i] = talloc_asprintf(mem_ctx, "cn=ppolicy,ou=policies,%s",
1439 0 : sdom->search_bases[i]->basedn);
1440 : }
1441 :
1442 0 : ppolicy_dns[count] = NULL;
1443 0 : return ppolicy_dns;
1444 : }
1445 :
1446 0 : static void sdap_access_ppolicy_connect_done(struct tevent_req *subreq)
1447 : {
1448 : struct tevent_req *req;
1449 : struct sdap_access_ppolicy_req_ctx *state;
1450 : int ret, dp_error;
1451 : const char *ppolicy_dn;
1452 :
1453 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1454 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1455 :
1456 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
1457 0 : talloc_zfree(subreq);
1458 :
1459 0 : if (ret != EOK) {
1460 0 : if (dp_error == DP_ERR_OFFLINE) {
1461 0 : ret = sdap_access_decide_offline(state->cached_access);
1462 0 : if (ret == EOK) {
1463 0 : tevent_req_done(req);
1464 0 : return;
1465 : }
1466 : }
1467 :
1468 0 : tevent_req_error(req, ret);
1469 0 : return;
1470 : }
1471 :
1472 0 : ppolicy_dn = dp_opt_get_string(state->opts->basic,
1473 : SDAP_PWDLOCKOUT_DN);
1474 :
1475 : /* option was configured */
1476 0 : if (ppolicy_dn != NULL) {
1477 0 : state->ppolicy_dns = talloc_array(state, const char*, 2);
1478 0 : if (state->ppolicy_dns == NULL) {
1479 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate ppolicy_dns.\n");
1480 0 : tevent_req_error(req, ERR_INTERNAL);
1481 0 : return;
1482 : }
1483 :
1484 0 : state->ppolicy_dns[0] = ppolicy_dn;
1485 0 : state->ppolicy_dns[1] = NULL;
1486 :
1487 : } else {
1488 : /* try to determine default value */
1489 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1490 : "ldap_pwdlockout_dn was not defined in configuration file.\n");
1491 :
1492 0 : state->ppolicy_dns = get_default_ppolicy_dns(state, state->opts->sdom);
1493 0 : if (state->ppolicy_dns == NULL) {
1494 0 : tevent_req_error(req, ERR_INTERNAL);
1495 0 : return;
1496 : }
1497 : }
1498 :
1499 : /* Connection to LDAP succeeded
1500 : * Send 'pwdLockout' request
1501 : */
1502 0 : ret = sdap_access_ppolicy_get_lockout_step(req);
1503 0 : if (ret != EOK && ret != EAGAIN) {
1504 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1505 : "sdap_access_ppolicy_get_lockout_step failed: [%d][%s]\n",
1506 : ret, sss_strerror(ret));
1507 0 : tevent_req_error(req, ERR_INTERNAL);
1508 0 : return;
1509 : }
1510 :
1511 0 : if (ret == EOK) {
1512 0 : tevent_req_done(req);
1513 : }
1514 : }
1515 :
1516 : static errno_t
1517 0 : sdap_access_ppolicy_get_lockout_step(struct tevent_req *req)
1518 : {
1519 0 : const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKOUT, NULL };
1520 : struct sdap_access_ppolicy_req_ctx *state;
1521 : struct tevent_req *subreq;
1522 : errno_t ret;
1523 :
1524 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1525 :
1526 : /* no more DNs to try */
1527 0 : if (state->ppolicy_dns[state->ppolicy_dns_index] == NULL) {
1528 0 : DEBUG(SSSDBG_TRACE_FUNC, "No more DNs to try.\n");
1529 0 : ret = EOK;
1530 0 : goto done;
1531 : }
1532 :
1533 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1534 : "Trying to find out if ppolicy is enabled using the DN: %s\n",
1535 : state->ppolicy_dns[state->ppolicy_dns_index]);
1536 :
1537 0 : subreq = sdap_get_generic_send(state,
1538 : state->ev,
1539 : state->opts,
1540 : sdap_id_op_handle(state->sdap_op),
1541 0 : state->ppolicy_dns[state->ppolicy_dns_index],
1542 : LDAP_SCOPE_BASE,
1543 : NULL, attrs,
1544 : NULL, 0,
1545 0 : dp_opt_get_int(state->opts->basic,
1546 : SDAP_SEARCH_TIMEOUT),
1547 : false);
1548 0 : if (subreq == NULL) {
1549 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
1550 0 : ret = EIO;
1551 0 : goto done;
1552 : }
1553 :
1554 : /* try next basedn */
1555 0 : state->ppolicy_dns_index++;
1556 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_get_lockout_done, req);
1557 :
1558 0 : ret = EAGAIN;
1559 :
1560 : done:
1561 0 : return ret;
1562 : }
1563 :
1564 0 : static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq)
1565 : {
1566 : int ret, tret, dp_error;
1567 : size_t num_results;
1568 0 : bool pwdLockout = false;
1569 : struct sysdb_attrs **results;
1570 : struct tevent_req *req;
1571 : struct sdap_access_ppolicy_req_ctx *state;
1572 :
1573 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1574 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1575 :
1576 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
1577 0 : talloc_zfree(subreq);
1578 0 : if (ret != EOK) {
1579 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve ppolicy\n");
1580 0 : ret = ERR_NETWORK_IO;
1581 0 : goto done;
1582 : }
1583 :
1584 : /* Check the number of responses we got
1585 : * If it's exactly 1, we passed the check
1586 : * If it's < 1, we failed the check
1587 : * Anything else is an error
1588 : */
1589 : /* Didn't find ppolicy attribute */
1590 0 : if (num_results < 1) {
1591 : /* Try using next $search_base */
1592 0 : ret = sdap_access_ppolicy_get_lockout_step(req);
1593 0 : if (ret == EOK) {
1594 : /* No more search bases to try */
1595 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1596 : "[%s] was not found. Granting access.\n",
1597 : SYSDB_LDAP_ACCESS_LOCKOUT);
1598 : } else {
1599 0 : if (ret != EAGAIN) {
1600 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1601 : "sdap_access_ppolicy_get_lockout_step failed: "
1602 : "[%d][%s]\n",
1603 : ret, sss_strerror(ret));
1604 : }
1605 0 : goto done;
1606 : }
1607 0 : } else if (results == NULL) {
1608 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1609 0 : ret = ERR_INTERNAL;
1610 0 : goto done;
1611 0 : } else if (num_results > 1) {
1612 : /* It should not be possible to get more than one reply
1613 : * here, since we're doing a base-scoped search
1614 : */
1615 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1616 0 : ret = ERR_INTERNAL;
1617 0 : goto done;
1618 : } else { /* Ok, we got a single reply */
1619 0 : ret = sysdb_attrs_get_bool(results[0], SYSDB_LDAP_ACCESS_LOCKOUT,
1620 : &pwdLockout);
1621 0 : if (ret != EOK) {
1622 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1623 : "Error reading %s: [%s]\n", SYSDB_LDAP_ACCESS_LOCKOUT,
1624 : sss_strerror(ret));
1625 0 : ret = ERR_INTERNAL;
1626 0 : goto done;
1627 : }
1628 : }
1629 :
1630 0 : if (pwdLockout) {
1631 0 : DEBUG(SSSDBG_TRACE_FUNC,
1632 : "Password policy is enabled on LDAP server.\n");
1633 :
1634 : /* ppolicy is enabled => find out if account is locked */
1635 0 : ret = sdap_access_ppolicy_step(req);
1636 0 : if (ret != EOK && ret != EAGAIN) {
1637 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1638 : "sdap_access_ppolicy_step failed: [%d][%s].\n",
1639 : ret, sss_strerror(ret));
1640 : }
1641 0 : goto done;
1642 : } else {
1643 0 : DEBUG(SSSDBG_TRACE_FUNC,
1644 : "Password policy is disabled on LDAP server "
1645 : "- storing 'access granted' in sysdb.\n");
1646 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1647 : SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
1648 : true);
1649 0 : if (tret != EOK) {
1650 : /* Failing to save to the cache is non-fatal.
1651 : * Just return the result.
1652 : */
1653 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1654 : "Failed to set user locked attribute\n");
1655 0 : goto done;
1656 : }
1657 :
1658 0 : ret = EOK;
1659 0 : goto done;
1660 : }
1661 :
1662 : done:
1663 0 : if (ret != EAGAIN) {
1664 : /* release connection */
1665 0 : tret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1666 0 : if (tret != EOK) {
1667 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1668 : "sdap_get_generic_send() returned error [%d][%s]\n",
1669 : ret, sss_strerror(ret));
1670 : }
1671 :
1672 0 : if (ret == EOK) {
1673 0 : tevent_req_done(req);
1674 : } else {
1675 0 : tevent_req_error(req, ret);
1676 : }
1677 : }
1678 0 : }
1679 :
1680 0 : errno_t sdap_access_ppolicy_step(struct tevent_req *req)
1681 : {
1682 : errno_t ret;
1683 : struct tevent_req *subreq;
1684 : struct sdap_access_ppolicy_req_ctx *state;
1685 0 : const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME,
1686 : SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
1687 : NULL };
1688 :
1689 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1690 :
1691 0 : subreq = sdap_get_generic_send(state,
1692 : state->ev,
1693 : state->opts,
1694 : sdap_id_op_handle(state->sdap_op),
1695 : state->basedn,
1696 : LDAP_SCOPE_BASE,
1697 : NULL, attrs,
1698 : NULL, 0,
1699 0 : dp_opt_get_int(state->opts->basic,
1700 : SDAP_SEARCH_TIMEOUT),
1701 : false);
1702 :
1703 0 : if (subreq == NULL) {
1704 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_ppolicy_send failed.\n");
1705 0 : ret = ENOMEM;
1706 0 : goto done;
1707 : }
1708 :
1709 0 : tevent_req_set_callback(subreq, sdap_access_ppolicy_step_done, req);
1710 0 : ret = EAGAIN;
1711 :
1712 : done:
1713 0 : return ret;
1714 : }
1715 :
1716 : static errno_t
1717 0 : is_account_locked(const char *pwdAccountLockedTime,
1718 : const char *pwdAccountLockedDurationTime,
1719 : enum sdap_pwpolicy_mode pwpol_mode,
1720 : const char *username,
1721 : bool *_locked)
1722 : {
1723 : errno_t ret;
1724 : time_t lock_time;
1725 : time_t duration;
1726 : time_t now;
1727 : bool locked;
1728 :
1729 : /* Default action is to consider account to be locked. */
1730 0 : locked = true;
1731 :
1732 : /* account is permanently locked */
1733 0 : if (strcasecmp(pwdAccountLockedTime,
1734 : PERMANENTLY_LOCKED_ACCOUNT) == 0) {
1735 0 : ret = EOK;
1736 0 : goto done;
1737 : }
1738 :
1739 0 : switch(pwpol_mode) {
1740 : case PWP_LOCKOUT_ONLY:
1741 : /* We do *not* care about exact value of account locked time, we
1742 : * only *do* care if the value is equal to
1743 : * PERMANENTLY_LOCKED_ACCOUNT, which means that account is locked
1744 : * permanently.
1745 : */
1746 0 : DEBUG(SSSDBG_TRACE_FUNC,
1747 : "Account of: %s is being blocked by password policy, "
1748 : "but value: [%s] value is ignored by SSSD.\n",
1749 : username, pwdAccountLockedTime);
1750 0 : locked = false;
1751 0 : break;
1752 : case PWP_LOCKOUT_EXPIRE:
1753 : /* Account may be locked out from natural reasons (too many attempts,
1754 : * expired password). In this case, pwdAccountLockedTime is also set,
1755 : * to the time of lock out.
1756 : */
1757 0 : ret = sss_utc_to_time_t(pwdAccountLockedTime, "%Y%m%d%H%M%SZ",
1758 : &lock_time);
1759 0 : if (ret != EOK) {
1760 0 : DEBUG(SSSDBG_TRACE_FUNC, "sss_utc_to_time_t failed with %d:%s.\n",
1761 : ret, sss_strerror(ret));
1762 0 : goto done;
1763 : }
1764 :
1765 0 : now = time(NULL);
1766 :
1767 : /* Account was NOT locked in past. */
1768 0 : if (difftime(lock_time, now) > 0.0) {
1769 0 : locked = false;
1770 0 : } else if (pwdAccountLockedDurationTime != NULL) {
1771 0 : errno = 0;
1772 0 : duration = strtouint32(pwdAccountLockedDurationTime, NULL, 0);
1773 0 : if (errno) {
1774 0 : ret = errno;
1775 0 : goto done;
1776 : }
1777 : /* Lockout has expired */
1778 0 : if (duration != 0 && difftime(now, lock_time) > duration) {
1779 0 : locked = false;
1780 : }
1781 : }
1782 0 : break;
1783 : case PWP_SENTINEL:
1784 : default:
1785 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1786 : "Unexpected value of password policy mode: %d.\n", pwpol_mode);
1787 0 : ret = EINVAL;
1788 0 : goto done;
1789 : }
1790 :
1791 0 : ret = EOK;
1792 :
1793 : done:
1794 0 : if (ret == EOK) {
1795 0 : *_locked = locked;
1796 : }
1797 :
1798 0 : return ret;
1799 : }
1800 :
1801 0 : static void sdap_access_ppolicy_step_done(struct tevent_req *subreq)
1802 : {
1803 : int ret, tret, dp_error;
1804 : size_t num_results;
1805 0 : bool locked = false;
1806 : const char *pwdAccountLockedTime;
1807 : const char *pwdAccountLockedDurationTime;
1808 : struct sysdb_attrs **results;
1809 : struct tevent_req *req;
1810 : struct sdap_access_ppolicy_req_ctx *state;
1811 :
1812 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
1813 0 : state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
1814 :
1815 0 : ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
1816 0 : talloc_zfree(subreq);
1817 :
1818 0 : ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1819 0 : if (ret != EOK) {
1820 0 : if (dp_error == DP_ERR_OK) {
1821 : /* retry */
1822 0 : tret = sdap_access_ppolicy_retry(req);
1823 0 : if (tret == EOK) {
1824 0 : return;
1825 : }
1826 0 : } else if (dp_error == DP_ERR_OFFLINE) {
1827 0 : ret = sdap_access_decide_offline(state->cached_access);
1828 : } else {
1829 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1830 : "sdap_get_generic_send() returned error [%d][%s]\n",
1831 : ret, sss_strerror(ret));
1832 : }
1833 :
1834 0 : goto done;
1835 : }
1836 :
1837 : /* Check the number of responses we got
1838 : * If it's exactly 1, we passed the check
1839 : * If it's < 1, we failed the check
1840 : * Anything else is an error
1841 : */
1842 0 : if (num_results < 1) {
1843 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1844 : "User [%s] was not found with the specified filter. "
1845 : "Denying access.\n", state->username);
1846 0 : } else if (results == NULL) {
1847 0 : DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
1848 0 : ret = ERR_INTERNAL;
1849 0 : goto done;
1850 0 : } else if (num_results > 1) {
1851 : /* It should not be possible to get more than one reply
1852 : * here, since we're doing a base-scoped search
1853 : */
1854 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
1855 0 : ret = ERR_INTERNAL;
1856 0 : goto done;
1857 : } else { /* Ok, we got a single reply */
1858 0 : ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
1859 : &pwdAccountLockedDurationTime);
1860 0 : if (ret != EOK) {
1861 : /* This attribute might not be set even if account is locked */
1862 0 : pwdAccountLockedDurationTime = NULL;
1863 : }
1864 :
1865 0 : ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACCESS_LOCKED_TIME,
1866 : &pwdAccountLockedTime);
1867 0 : if (ret == EOK) {
1868 :
1869 0 : ret = is_account_locked(pwdAccountLockedTime,
1870 : pwdAccountLockedDurationTime,
1871 : state->pwpol_mode,
1872 : state->username,
1873 : &locked);
1874 0 : if (ret != EOK) {
1875 0 : if (ret == ERR_TIMESPEC_NOT_SUPPORTED) {
1876 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1877 : "timezone specifier in ppolicy is not supported\n");
1878 : } else {
1879 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1880 : "is_account_locked failed: %d:[%s].\n",
1881 : ret, sss_strerror(ret));
1882 : }
1883 :
1884 0 : DEBUG(SSSDBG_MINOR_FAILURE,
1885 : "Account will be considered to be locked.\n");
1886 0 : locked = true;
1887 : }
1888 : } else {
1889 : /* Attribute SYSDB_LDAP_ACCESS_LOCKED_TIME in not be present unless
1890 : * user's account is blocked by password policy.
1891 : */
1892 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1893 : "Attribute %s failed to be obtained - [%d][%s].\n",
1894 : SYSDB_LDAP_ACCESS_LOCKED_TIME, ret, strerror(ret));
1895 : }
1896 : }
1897 :
1898 0 : if (locked) {
1899 0 : DEBUG(SSSDBG_TRACE_FUNC,
1900 : "Access denied by online lookup - account is locked.\n");
1901 0 : ret = ERR_ACCESS_DENIED;
1902 : } else {
1903 0 : DEBUG(SSSDBG_TRACE_FUNC,
1904 : "Access granted by online lookup - account is not locked.\n");
1905 0 : ret = EOK;
1906 : }
1907 :
1908 : /* Save '!locked' to the cache for future offline access checks.
1909 : * Locked == true => access denied,
1910 : * Locked == false => access granted
1911 : */
1912 0 : tret = sdap_save_user_cache_bool(state->domain, state->username,
1913 : SYSDB_LDAP_ACCESS_CACHED_LOCKOUT,
1914 0 : !locked);
1915 :
1916 0 : if (tret != EOK) {
1917 : /* Failing to save to the cache is non-fatal.
1918 : * Just return the result.
1919 : */
1920 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user locked attribute\n");
1921 0 : goto done;
1922 : }
1923 :
1924 : done:
1925 0 : if (ret == EOK) {
1926 0 : tevent_req_done(req);
1927 : } else {
1928 0 : tevent_req_error(req, ret);
1929 : }
1930 : }
1931 :
1932 0 : static errno_t sdap_access_ppolicy_recv(struct tevent_req *req)
1933 : {
1934 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
1935 :
1936 0 : return EOK;
1937 : }
1938 :
1939 0 : static errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
1940 : const char *username,
1941 : const char **_basedn)
1942 : {
1943 : const char *basedn;
1944 : errno_t ret;
1945 :
1946 0 : basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
1947 0 : if (basedn == NULL) {
1948 0 : DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",
1949 : username);
1950 0 : ret = EINVAL;
1951 0 : goto done;
1952 : }
1953 :
1954 0 : *_basedn = basedn;
1955 0 : ret = EOK;
1956 :
1957 : done:
1958 0 : return ret;
1959 : }
|