Line data Source code
1 : /*
2 : SSSD
3 :
4 : LDAP Backend Module
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2008 Red Hat
10 : Copyright (C) 2010, rhafer@suse.de, Novell Inc.
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #ifdef WITH_MOZLDAP
27 : #define LDAP_OPT_SUCCESS LDAP_SUCCESS
28 : #define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U)
29 : #define LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ((ber_tag_t) 0x81U)
30 : #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U)
31 : #endif
32 :
33 : #include "config.h"
34 :
35 : #include <time.h>
36 : #include <errno.h>
37 : #include <sys/time.h>
38 : #include <strings.h>
39 :
40 : #include <shadow.h>
41 : #include <security/pam_modules.h>
42 :
43 : #include "util/util.h"
44 : #include "util/user_info_msg.h"
45 : #include "db/sysdb.h"
46 : #include "providers/ldap/ldap_common.h"
47 : #include "providers/ldap/sdap_async.h"
48 : #include "providers/ldap/sdap_async_private.h"
49 : #include "providers/ldap/ldap_auth.h"
50 : #include "providers/ldap/sdap_access.h"
51 :
52 : #define LDAP_PWEXPIRE_WARNING_TIME 0
53 :
54 0 : static errno_t add_expired_warning(struct pam_data *pd, long exp_time)
55 : {
56 : int ret;
57 : uint32_t *data;
58 :
59 0 : if (exp_time < 0 || exp_time > UINT32_MAX) {
60 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Time to expire out of range.\n");
61 0 : return EINVAL;
62 : }
63 :
64 0 : data = talloc_array(pd, uint32_t, 2);
65 0 : if (data == NULL) {
66 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
67 0 : return ENOMEM;
68 : }
69 :
70 0 : data[0] = SSS_PAM_USER_INFO_EXPIRE_WARN;
71 0 : data[1] = (uint32_t) exp_time;
72 :
73 0 : ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),
74 : (uint8_t *) data);
75 0 : if (ret != EOK) {
76 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
77 : }
78 :
79 0 : return EOK;
80 : }
81 :
82 6 : static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,
83 : struct pam_data *pd,
84 : int pwd_exp_warning)
85 : {
86 : time_t expire_time;
87 : int expiration_warning;
88 6 : int ret = ERR_INTERNAL;
89 :
90 6 : ret = sss_utc_to_time_t(expire_date, "%Y%m%d%H%M%SZ",
91 : &expire_time);
92 6 : if (ret != EOK) {
93 2 : DEBUG(SSSDBG_MINOR_FAILURE, "sss_utc_to_time_t failed with %d:%s.\n",
94 : ret, sss_strerror(ret));
95 2 : return ret;
96 : }
97 :
98 4 : DEBUG(SSSDBG_TRACE_ALL,
99 : "Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
100 : "daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
101 : tzname[1], timezone, daylight, now, expire_time);
102 :
103 4 : if (difftime(now, expire_time) > 0.0) {
104 2 : DEBUG(SSSDBG_CONF_SETTINGS, "Kerberos password expired.\n");
105 2 : ret = ERR_PASSWORD_EXPIRED;
106 : } else {
107 2 : if (pwd_exp_warning >= 0) {
108 2 : expiration_warning = pwd_exp_warning;
109 : } else {
110 0 : expiration_warning = KERBEROS_PWEXPIRE_WARNING_TIME;
111 : }
112 2 : if (pd != NULL &&
113 0 : (difftime(now + expiration_warning, expire_time) > 0.0 ||
114 : expiration_warning == 0)) {
115 0 : ret = add_expired_warning(pd, (long) difftime(expire_time, now));
116 0 : if (ret != EOK) {
117 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
118 : }
119 : }
120 2 : ret = EOK;
121 : }
122 :
123 4 : return ret;
124 : }
125 :
126 0 : static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,
127 : struct pam_data *pd)
128 : {
129 : long today;
130 : long password_age;
131 : long exp;
132 : int ret;
133 :
134 0 : if (spwd->sp_lstchg <= 0) {
135 0 : DEBUG(SSSDBG_CONF_SETTINGS,
136 : "Last change day is not set, new password needed.\n");
137 0 : return ERR_PASSWORD_EXPIRED;
138 : }
139 :
140 0 : today = (long) (now / (60 * 60 *24));
141 0 : password_age = today - spwd->sp_lstchg;
142 0 : if (password_age < 0) {
143 0 : DEBUG(SSSDBG_OP_FAILURE,
144 : "The last password change time is in the future!.\n");
145 0 : return EOK;
146 : }
147 :
148 0 : if ((spwd->sp_expire != -1 && today > spwd->sp_expire) ||
149 0 : (spwd->sp_max != -1 && spwd->sp_inact != -1 &&
150 0 : password_age > spwd->sp_max + spwd->sp_inact))
151 : {
152 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Account expired.\n");
153 0 : return ERR_ACCOUNT_EXPIRED;
154 : }
155 :
156 0 : if (spwd->sp_max != -1 && password_age > spwd->sp_max) {
157 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Password expired.\n");
158 0 : return ERR_PASSWORD_EXPIRED;
159 : }
160 :
161 0 : if (pd != NULL && spwd->sp_max != -1 && spwd->sp_warn != -1 &&
162 0 : password_age > spwd->sp_max - spwd->sp_warn ) {
163 :
164 : /* add_expired_warning() expects time in seconds */
165 0 : exp = (spwd->sp_max - password_age) * (60 * 60 * 24);
166 0 : if (exp == 0) {
167 : /* Seconds until next midnight */
168 0 : exp = ((today + 1) * (60 * 60 * 24)) - now;
169 : }
170 :
171 0 : ret = add_expired_warning(pd, exp);
172 0 : if (ret != EOK) {
173 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_expired_warning failed.\n");
174 : }
175 : }
176 :
177 0 : return EOK;
178 : }
179 :
180 0 : static errno_t check_pwexpire_ldap(struct pam_data *pd,
181 : struct sdap_ppolicy_data *ppolicy,
182 : int pwd_exp_warning)
183 : {
184 0 : int ret = EOK;
185 :
186 0 : if (ppolicy->grace >= 0 || ppolicy->expire > 0) {
187 : uint32_t *data;
188 : uint32_t *ptr;
189 :
190 0 : if (pwd_exp_warning < 0) {
191 0 : pwd_exp_warning = 0;
192 : }
193 :
194 0 : data = talloc_size(pd, 2* sizeof(uint32_t));
195 0 : if (data == NULL) {
196 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
197 0 : return ENOMEM;
198 : }
199 :
200 0 : ptr = data;
201 0 : if (ppolicy->grace >= 0) {
202 0 : *ptr = SSS_PAM_USER_INFO_GRACE_LOGIN;
203 0 : ptr++;
204 0 : *ptr = ppolicy->grace;
205 0 : } else if (ppolicy->expire > 0) {
206 0 : if (pwd_exp_warning != 0 && ppolicy->expire > pwd_exp_warning) {
207 : /* do not warn */
208 0 : goto done;
209 : }
210 :
211 : /* send warning */
212 0 : *ptr = SSS_PAM_USER_INFO_EXPIRE_WARN;
213 0 : ptr++;
214 0 : *ptr = ppolicy->expire;
215 : }
216 :
217 0 : ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2* sizeof(uint32_t),
218 : (uint8_t*)data);
219 0 : if (ret != EOK) {
220 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
221 : }
222 : }
223 :
224 : done:
225 0 : return ret;
226 : }
227 :
228 6 : errno_t check_pwexpire_policy(enum pwexpire pw_expire_type,
229 : void *pw_expire_data,
230 : struct pam_data *pd,
231 : int pwd_expiration_warning)
232 : {
233 : errno_t ret;
234 :
235 6 : switch (pw_expire_type) {
236 : case PWEXPIRE_SHADOW:
237 0 : ret = check_pwexpire_shadow(pw_expire_data, time(NULL), pd);
238 0 : break;
239 : case PWEXPIRE_KERBEROS:
240 6 : ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), pd,
241 : pwd_expiration_warning);
242 6 : break;
243 : case PWEXPIRE_LDAP_PASSWORD_POLICY:
244 0 : ret = check_pwexpire_ldap(pd, pw_expire_data,
245 : pwd_expiration_warning);
246 0 : break;
247 : case PWEXPIRE_NONE:
248 0 : ret = EOK;
249 0 : break;
250 : default:
251 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n");
252 0 : ret = EINVAL;
253 : }
254 :
255 6 : return ret;
256 : }
257 :
258 : static errno_t
259 0 : find_password_expiration_attributes(TALLOC_CTX *mem_ctx,
260 : const struct ldb_message *msg,
261 : struct dp_option *opts,
262 : enum pwexpire *type, void **data)
263 : {
264 : const char *mark;
265 : const char *val;
266 : struct spwd *spwd;
267 : const char *pwd_policy;
268 : int ret;
269 :
270 0 : *type = PWEXPIRE_NONE;
271 0 : *data = NULL;
272 :
273 0 : pwd_policy = dp_opt_get_string(opts, SDAP_PWD_POLICY);
274 0 : if (pwd_policy == NULL) {
275 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing password policy.\n");
276 0 : return EINVAL;
277 : }
278 :
279 0 : if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) == 0) {
280 0 : DEBUG(SSSDBG_TRACE_ALL, "No password policy requested.\n");
281 0 : return EOK;
282 0 : } else if (strcasecmp(pwd_policy, PWD_POL_OPT_MIT) == 0) {
283 0 : mark = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_LASTCHANGE, NULL);
284 0 : if (mark != NULL) {
285 0 : DEBUG(SSSDBG_TRACE_ALL,
286 : "Found Kerberos password expiration attributes.\n");
287 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_EXPIRATION,
288 : NULL);
289 0 : if (val != NULL) {
290 0 : *data = talloc_strdup(mem_ctx, val);
291 0 : if (*data == NULL) {
292 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
293 0 : return ENOMEM;
294 : }
295 0 : *type = PWEXPIRE_KERBEROS;
296 :
297 0 : return EOK;
298 : }
299 : } else {
300 0 : DEBUG(SSSDBG_CRIT_FAILURE,
301 : "No Kerberos password expiration attributes found, "
302 : "but MIT Kerberos password policy was requested. "
303 : "Access will be denied.\n");
304 0 : return EACCES;
305 : }
306 0 : } else if (strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) == 0) {
307 0 : mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
308 0 : if (mark != NULL) {
309 0 : DEBUG(SSSDBG_TRACE_ALL,
310 : "Found shadow password expiration attributes.\n");
311 0 : spwd = talloc_zero(mem_ctx, struct spwd);
312 0 : if (spwd == NULL) {
313 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
314 0 : return ENOMEM;
315 : }
316 :
317 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL);
318 0 : ret = string_to_shadowpw_days(val, &spwd->sp_lstchg);
319 0 : if (ret != EOK) goto shadow_fail;
320 :
321 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MIN, NULL);
322 0 : ret = string_to_shadowpw_days(val, &spwd->sp_min);
323 0 : if (ret != EOK) goto shadow_fail;
324 :
325 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MAX, NULL);
326 0 : ret = string_to_shadowpw_days(val, &spwd->sp_max);
327 0 : if (ret != EOK) goto shadow_fail;
328 :
329 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_WARNING, NULL);
330 0 : ret = string_to_shadowpw_days(val, &spwd->sp_warn);
331 0 : if (ret != EOK) goto shadow_fail;
332 :
333 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_INACTIVE, NULL);
334 0 : ret = string_to_shadowpw_days(val, &spwd->sp_inact);
335 0 : if (ret != EOK) goto shadow_fail;
336 :
337 0 : val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_EXPIRE, NULL);
338 0 : ret = string_to_shadowpw_days(val, &spwd->sp_expire);
339 0 : if (ret != EOK) goto shadow_fail;
340 :
341 0 : *data = spwd;
342 0 : *type = PWEXPIRE_SHADOW;
343 :
344 0 : return EOK;
345 : } else {
346 0 : DEBUG(SSSDBG_CRIT_FAILURE, "No shadow password attributes found, "
347 : "but shadow password policy was requested. "
348 : "Access will be denied.\n");
349 0 : return EACCES;
350 : }
351 : }
352 :
353 0 : DEBUG(SSSDBG_TRACE_ALL, "No password expiration attributes found.\n");
354 0 : return EOK;
355 :
356 : shadow_fail:
357 0 : talloc_free(spwd);
358 0 : return ret;
359 : }
360 :
361 : /* ==Get-User-DN========================================================== */
362 : struct get_user_dn_state {
363 : const char *username;
364 :
365 : char *orig_dn;
366 : };
367 :
368 : static void get_user_dn_done(struct tevent_req *subreq);
369 :
370 0 : static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx,
371 : struct tevent_context *ev,
372 : struct sss_domain_info *domain,
373 : struct sdap_handle *sh,
374 : struct sdap_options *opts,
375 : const char *username)
376 : {
377 : struct tevent_req *req;
378 : struct tevent_req *subreq;
379 : struct get_user_dn_state *state;
380 : char *clean_name;
381 : char *filter;
382 : const char **attrs;
383 : errno_t ret;
384 :
385 0 : req = tevent_req_create(memctx, &state, struct get_user_dn_state);
386 0 : if (!req) return NULL;
387 :
388 0 : state->username = username;
389 :
390 0 : ret = sss_filter_sanitize(state, username, &clean_name);
391 0 : if (ret != EOK) {
392 0 : goto done;
393 : }
394 :
395 0 : filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
396 0 : opts->user_map[SDAP_AT_USER_NAME].name,
397 : clean_name,
398 0 : opts->user_map[SDAP_OC_USER].name);
399 0 : talloc_zfree(clean_name);
400 0 : if (filter == NULL) {
401 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to build the base filter\n");
402 0 : ret = ENOMEM;
403 0 : goto done;
404 : }
405 :
406 : /* We're mostly interested in the DN anyway */
407 0 : attrs = talloc_array(state, const char *, 3);
408 0 : if (attrs == NULL) {
409 0 : ret = ENOMEM;
410 0 : goto done;
411 : }
412 0 : attrs[0] = "objectclass";
413 0 : attrs[1] = opts->user_map[SDAP_AT_USER_NAME].name;
414 0 : attrs[2] = NULL;
415 :
416 0 : subreq = sdap_search_user_send(state, ev, domain, opts,
417 0 : opts->sdom->user_search_bases,
418 : sh, attrs, filter,
419 : dp_opt_get_int(opts->basic,
420 : SDAP_SEARCH_TIMEOUT),
421 : SDAP_LOOKUP_SINGLE);
422 0 : if (!subreq) {
423 0 : ret = ENOMEM;
424 0 : goto done;
425 : }
426 0 : tevent_req_set_callback(subreq, get_user_dn_done, req);
427 0 : return req;
428 :
429 : done:
430 0 : if (ret == EOK) {
431 0 : tevent_req_done(req);
432 : } else {
433 0 : tevent_req_error(req, ret);
434 : }
435 0 : tevent_req_post(req, ev);
436 0 : return req;
437 : }
438 :
439 0 : static void get_user_dn_done(struct tevent_req *subreq)
440 : {
441 : errno_t ret;
442 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
443 : struct tevent_req);
444 0 : struct get_user_dn_state *state = tevent_req_data(req,
445 : struct get_user_dn_state);
446 : struct ldb_message_element *el;
447 : struct sysdb_attrs **users;
448 : size_t count;
449 :
450 0 : ret = sdap_search_user_recv(state, subreq, NULL, &users, &count);
451 0 : talloc_zfree(subreq);
452 0 : if (ret && ret != ENOENT) {
453 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to retrieve users\n");
454 0 : tevent_req_error(req, ret);
455 0 : return;
456 : }
457 :
458 0 : if (count == 0) {
459 0 : DEBUG(SSSDBG_OP_FAILURE, "No such user\n");
460 0 : tevent_req_error(req, ENOMEM);
461 0 : return;
462 0 : } else if (count > 1) {
463 0 : DEBUG(SSSDBG_OP_FAILURE, "Multiple users matched\n");
464 0 : tevent_req_error(req, EIO);
465 0 : return;
466 : }
467 :
468 : /* exactly one user. Get the originalDN */
469 0 : ret = sysdb_attrs_get_el_ext(users[0], SYSDB_ORIG_DN, false, &el);
470 0 : if (ret != EOK) {
471 0 : DEBUG(SSSDBG_OP_FAILURE,
472 : "originalDN is not available for [%s].\n", state->username);
473 0 : tevent_req_error(req, ret);
474 0 : return;
475 : }
476 :
477 0 : state->orig_dn = talloc_strdup(state, (const char *) el->values[0].data);
478 0 : if (state->orig_dn == NULL) {
479 0 : tevent_req_error(req, ENOMEM);
480 0 : return;
481 : }
482 :
483 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Found originalDN [%s] for [%s]\n",
484 : state->orig_dn, state->username);
485 0 : tevent_req_done(req);
486 : }
487 :
488 0 : static int get_user_dn_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req,
489 : char **orig_dn)
490 : {
491 0 : struct get_user_dn_state *state = tevent_req_data(req,
492 : struct get_user_dn_state);
493 :
494 0 : if (orig_dn) {
495 0 : *orig_dn = talloc_move(mem_ctx, &state->orig_dn);
496 : }
497 :
498 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
499 :
500 0 : return EOK;
501 : }
502 :
503 0 : int get_user_dn(TALLOC_CTX *memctx,
504 : struct sss_domain_info *domain,
505 : struct sdap_options *opts,
506 : const char *username,
507 : char **user_dn,
508 : enum pwexpire *user_pw_expire_type,
509 : void **user_pw_expire_data)
510 : {
511 : TALLOC_CTX *tmpctx;
512 : enum pwexpire pw_expire_type;
513 : void *pw_expire_data;
514 : struct ldb_result *res;
515 : const char **attrs;
516 : const char *dn;
517 : int ret;
518 :
519 0 : tmpctx = talloc_new(memctx);
520 0 : if (!tmpctx) {
521 0 : return ENOMEM;
522 : }
523 :
524 0 : attrs = talloc_array(tmpctx, const char *, 11);
525 0 : if (!attrs) {
526 0 : ret = ENOMEM;
527 0 : goto done;
528 : }
529 :
530 0 : attrs[0] = SYSDB_ORIG_DN;
531 0 : attrs[1] = SYSDB_SHADOWPW_LASTCHANGE;
532 0 : attrs[2] = SYSDB_SHADOWPW_MIN;
533 0 : attrs[3] = SYSDB_SHADOWPW_MAX;
534 0 : attrs[4] = SYSDB_SHADOWPW_WARNING;
535 0 : attrs[5] = SYSDB_SHADOWPW_INACTIVE;
536 0 : attrs[6] = SYSDB_SHADOWPW_EXPIRE;
537 0 : attrs[7] = SYSDB_KRBPW_LASTCHANGE;
538 0 : attrs[8] = SYSDB_KRBPW_EXPIRATION;
539 0 : attrs[9] = SYSDB_PWD_ATTRIBUTE;
540 0 : attrs[10] = NULL;
541 :
542 0 : ret = sysdb_get_user_attr(tmpctx, domain, username, attrs, &res);
543 0 : if (ret) {
544 0 : goto done;
545 : }
546 :
547 0 : switch (res->count) {
548 : case 0:
549 : /* No such user entry? Look it up */
550 0 : ret = EAGAIN;
551 0 : break;
552 :
553 : case 1:
554 0 : dn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_ORIG_DN, NULL);
555 0 : if (dn == NULL) {
556 : /* The user entry has no original DN. This is the case when the ID
557 : * provider is not LDAP-based (proxy perhaps) */
558 0 : ret = EAGAIN;
559 0 : break;
560 : }
561 :
562 0 : dn = talloc_strdup(tmpctx, dn);
563 0 : if (!dn) {
564 0 : ret = ENOMEM;
565 0 : break;
566 : }
567 :
568 0 : ret = find_password_expiration_attributes(tmpctx,
569 0 : res->msgs[0],
570 : opts->basic,
571 : &pw_expire_type,
572 : &pw_expire_data);
573 0 : if (ret != EOK) {
574 0 : DEBUG(SSSDBG_CRIT_FAILURE,
575 : "find_password_expiration_attributes failed.\n");
576 : }
577 0 : break;
578 :
579 : default:
580 0 : DEBUG(SSSDBG_CRIT_FAILURE,
581 : "User search by name (%s) returned > 1 results!\n",
582 : username);
583 0 : ret = EFAULT;
584 0 : break;
585 : }
586 :
587 : done:
588 0 : if (ret == EOK) {
589 0 : *user_dn = talloc_strdup(memctx, dn);
590 0 : if (!*user_dn) {
591 0 : ret = ENOMEM;
592 : }
593 : /* pw_expire_data may be NULL */
594 0 : *user_pw_expire_data = talloc_steal(memctx, pw_expire_data);
595 0 : *user_pw_expire_type = pw_expire_type;
596 : }
597 :
598 0 : talloc_zfree(tmpctx);
599 0 : return ret;
600 : }
601 :
602 : /* ==Authenticate-User==================================================== */
603 :
604 : struct auth_state {
605 : struct tevent_context *ev;
606 : struct sdap_auth_ctx *ctx;
607 : const char *username;
608 : struct sss_auth_token *authtok;
609 : struct sdap_service *sdap_service;
610 :
611 : struct sdap_handle *sh;
612 :
613 : char *dn;
614 : enum pwexpire pw_expire_type;
615 : void *pw_expire_data;
616 :
617 : struct fo_server *srv;
618 : };
619 :
620 : static struct tevent_req *auth_get_server(struct tevent_req *req);
621 : static void auth_get_dn_done(struct tevent_req *subreq);
622 : static void auth_do_bind(struct tevent_req *req);
623 : static void auth_resolve_done(struct tevent_req *subreq);
624 : static void auth_connect_done(struct tevent_req *subreq);
625 : static void auth_bind_user_done(struct tevent_req *subreq);
626 :
627 0 : static struct tevent_req *auth_send(TALLOC_CTX *memctx,
628 : struct tevent_context *ev,
629 : struct sdap_auth_ctx *ctx,
630 : const char *username,
631 : struct sss_auth_token *authtok,
632 : bool try_chpass_service)
633 : {
634 : struct tevent_req *req;
635 : struct auth_state *state;
636 :
637 0 : req = tevent_req_create(memctx, &state, struct auth_state);
638 0 : if (!req) return NULL;
639 :
640 : /* The token must be a password token */
641 0 : if (sss_authtok_get_type(authtok) != SSS_AUTHTOK_TYPE_PASSWORD) {
642 0 : tevent_req_error(req, ERR_AUTH_FAILED);
643 0 : return tevent_req_post(req, ev);
644 : }
645 :
646 0 : state->ev = ev;
647 0 : state->ctx = ctx;
648 0 : state->username = username;
649 0 : state->authtok = authtok;
650 0 : state->srv = NULL;
651 0 : if (try_chpass_service && ctx->chpass_service != NULL &&
652 0 : ctx->chpass_service->name != NULL) {
653 0 : state->sdap_service = ctx->chpass_service;
654 : } else {
655 0 : state->sdap_service = ctx->service;
656 : }
657 :
658 0 : if (!auth_get_server(req)) goto fail;
659 :
660 0 : return req;
661 :
662 : fail:
663 0 : talloc_zfree(req);
664 0 : return NULL;
665 : }
666 :
667 0 : static struct tevent_req *auth_get_server(struct tevent_req *req)
668 : {
669 : struct tevent_req *next_req;
670 0 : struct auth_state *state = tevent_req_data(req,
671 : struct auth_state);
672 :
673 : /* NOTE: this call may cause service->uri to be refreshed
674 : * with a new valid server. Do not use service->uri before */
675 0 : next_req = be_resolve_server_send(state,
676 : state->ev,
677 0 : state->ctx->be,
678 0 : state->sdap_service->name,
679 0 : state->srv == NULL ? true : false);
680 0 : if (!next_req) {
681 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n");
682 0 : return NULL;
683 : }
684 :
685 0 : tevent_req_set_callback(next_req, auth_resolve_done, req);
686 0 : return next_req;
687 : }
688 :
689 0 : static void auth_resolve_done(struct tevent_req *subreq)
690 : {
691 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
692 : struct tevent_req);
693 0 : struct auth_state *state = tevent_req_data(req,
694 : struct auth_state);
695 : int ret;
696 : bool use_tls;
697 :
698 0 : ret = be_resolve_server_recv(subreq, &state->srv);
699 0 : talloc_zfree(subreq);
700 0 : if (ret) {
701 : /* all servers have been tried and none
702 : * was found good, go offline */
703 0 : tevent_req_error(req, ETIMEDOUT);
704 0 : return;
705 : }
706 :
707 : /* Determine whether we need to use TLS */
708 0 : if (sdap_is_secure_uri(state->ctx->service->uri)) {
709 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
710 : "[%s] is a secure channel. No need to run START_TLS\n",
711 : state->ctx->service->uri);
712 0 : use_tls = false;
713 : } else {
714 :
715 : /* Check for undocumented debugging feature to disable TLS
716 : * for authentication. This should never be used in production
717 : * for obvious reasons.
718 : */
719 0 : use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS);
720 0 : if (!use_tls) {
721 0 : sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over "
722 : "insecure connection. This should be done "
723 : "for debugging purposes only.");
724 : }
725 : }
726 :
727 0 : subreq = sdap_connect_send(state, state->ev, state->ctx->opts,
728 0 : state->sdap_service->uri,
729 0 : state->sdap_service->sockaddr, use_tls);
730 0 : if (!subreq) {
731 0 : tevent_req_error(req, ENOMEM);
732 0 : return;
733 : }
734 :
735 0 : tevent_req_set_callback(subreq, auth_connect_done, req);
736 : }
737 :
738 0 : static void auth_connect_done(struct tevent_req *subreq)
739 : {
740 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
741 : struct tevent_req);
742 0 : struct auth_state *state = tevent_req_data(req,
743 : struct auth_state);
744 : int ret;
745 :
746 0 : ret = sdap_connect_recv(subreq, state, &state->sh);
747 0 : talloc_zfree(subreq);
748 0 : if (ret) {
749 0 : if (state->srv) {
750 : /* mark this server as bad if connection failed */
751 0 : be_fo_set_port_status(state->ctx->be,
752 : state->sdap_service->name,
753 : state->srv, PORT_NOT_WORKING);
754 : }
755 :
756 0 : if (auth_get_server(req) == NULL) {
757 0 : tevent_req_error(req, ENOMEM);
758 : }
759 0 : return;
760 0 : } else if (state->srv) {
761 0 : be_fo_set_port_status(state->ctx->be, state->sdap_service->name,
762 : state->srv, PORT_WORKING);
763 : }
764 :
765 : /* In case the ID provider is set to proxy, this might be the first
766 : * LDAP operation at all, so we need to set the connection status
767 : */
768 0 : if (state->sh->connected == false) {
769 0 : ret = sdap_set_connected(state->sh, state->ev);
770 0 : if (ret) {
771 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot set connected status\n");
772 0 : tevent_req_error(req, ret);
773 0 : return;
774 : }
775 : }
776 :
777 0 : ret = get_user_dn(state, state->ctx->be->domain,
778 0 : state->ctx->opts, state->username, &state->dn,
779 : &state->pw_expire_type, &state->pw_expire_data);
780 0 : if (ret == EOK) {
781 : /* All required user data was pre-cached during an identity lookup.
782 : * We can proceed with the bind */
783 0 : auth_do_bind(req);
784 0 : return;
785 0 : } else if (ret == EAGAIN) {
786 : /* The cached user entry was missing the bind DN. Need to look
787 : * it up based on user name in order to perform the bind */
788 0 : subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain,
789 0 : state->sh, state->ctx->opts, state->username);
790 0 : if (subreq == NULL) {
791 0 : tevent_req_error(req, ENOMEM);
792 0 : return;
793 : }
794 0 : tevent_req_set_callback(subreq, auth_get_dn_done, req);
795 0 : return;
796 : }
797 :
798 0 : tevent_req_error(req, ret);
799 0 : return;
800 : }
801 :
802 0 : static void auth_get_dn_done(struct tevent_req *subreq)
803 : {
804 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
805 : struct tevent_req);
806 0 : struct auth_state *state = tevent_req_data(req, struct auth_state);
807 : errno_t ret;
808 :
809 0 : ret = get_user_dn_recv(state, subreq, &state->dn);
810 0 : talloc_zfree(subreq);
811 0 : if (ret != EOK) {
812 0 : tevent_req_error(req, ERR_ACCOUNT_UNKNOWN);
813 0 : return;
814 : }
815 :
816 : /* The DN was found with an LDAP lookup
817 : * We can proceed with the bind */
818 0 : return auth_do_bind(req);
819 : }
820 :
821 0 : static void auth_do_bind(struct tevent_req *req)
822 : {
823 0 : struct auth_state *state = tevent_req_data(req, struct auth_state);
824 : struct tevent_req *subreq;
825 :
826 0 : subreq = sdap_auth_send(state, state->ev, state->sh,
827 0 : NULL, NULL, state->dn,
828 : state->authtok,
829 0 : dp_opt_get_int(state->ctx->opts->basic,
830 : SDAP_OPT_TIMEOUT));
831 0 : if (!subreq) {
832 0 : tevent_req_error(req, ENOMEM);
833 0 : return;
834 : }
835 :
836 0 : tevent_req_set_callback(subreq, auth_bind_user_done, req);
837 : }
838 :
839 0 : static void auth_bind_user_done(struct tevent_req *subreq)
840 : {
841 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
842 : struct tevent_req);
843 0 : struct auth_state *state = tevent_req_data(req,
844 : struct auth_state);
845 : int ret;
846 0 : struct sdap_ppolicy_data *ppolicy = NULL;
847 :
848 0 : ret = sdap_auth_recv(subreq, state, &ppolicy);
849 0 : talloc_zfree(subreq);
850 0 : if (ppolicy != NULL) {
851 0 : DEBUG(SSSDBG_TRACE_ALL,"Found ppolicy data, "
852 : "assuming LDAP password policies are active.\n");
853 0 : state->pw_expire_type = PWEXPIRE_LDAP_PASSWORD_POLICY;
854 0 : state->pw_expire_data = ppolicy;
855 : }
856 0 : switch (ret) {
857 : case EOK:
858 0 : break;
859 : case ETIMEDOUT:
860 : case ERR_NETWORK_IO:
861 0 : if (auth_get_server(req) == NULL) {
862 0 : tevent_req_error(req, ENOMEM);
863 : }
864 0 : return;
865 : default:
866 0 : tevent_req_error(req, ret);
867 0 : return;
868 : }
869 :
870 0 : tevent_req_done(req);
871 : }
872 :
873 0 : static errno_t auth_recv(struct tevent_req *req, TALLOC_CTX *memctx,
874 : struct sdap_handle **sh, char **dn,
875 : enum pwexpire *pw_expire_type, void **pw_expire_data)
876 : {
877 0 : struct auth_state *state = tevent_req_data(req, struct auth_state);
878 :
879 0 : if (sh != NULL) {
880 0 : *sh = talloc_steal(memctx, state->sh);
881 0 : if (*sh == NULL) return ENOMEM;
882 : }
883 :
884 0 : if (dn != NULL) {
885 0 : *dn = talloc_steal(memctx, state->dn);
886 0 : if (*dn == NULL) return ENOMEM;
887 : }
888 :
889 0 : if (pw_expire_data != NULL) {
890 0 : *pw_expire_data = talloc_steal(memctx, state->pw_expire_data);
891 : }
892 :
893 0 : *pw_expire_type = state->pw_expire_type;
894 :
895 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
896 :
897 0 : return EOK;
898 : }
899 :
900 : /* ==Perform-Password-Change===================== */
901 :
902 : struct sdap_pam_chpass_state {
903 : struct be_req *breq;
904 : struct pam_data *pd;
905 : const char *username;
906 : char *dn;
907 : struct sdap_handle *sh;
908 :
909 : struct sdap_auth_ctx *ctx;
910 : };
911 :
912 : static void sdap_auth4chpass_done(struct tevent_req *req);
913 : static void sdap_pam_chpass_done(struct tevent_req *req);
914 :
915 0 : void sdap_pam_chpass_handler(struct be_req *breq)
916 : {
917 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
918 : struct sdap_pam_chpass_state *state;
919 : struct sdap_auth_ctx *ctx;
920 : struct tevent_req *subreq;
921 : struct pam_data *pd;
922 0 : int dp_err = DP_ERR_FATAL;
923 :
924 0 : ctx = talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
925 : struct sdap_auth_ctx);
926 0 : pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
927 :
928 0 : if (be_is_offline(ctx->be)) {
929 0 : DEBUG(SSSDBG_CONF_SETTINGS,
930 : "Backend is marked offline, retry later!\n");
931 0 : pd->pam_status = PAM_AUTHINFO_UNAVAIL;
932 0 : dp_err = DP_ERR_OFFLINE;
933 0 : goto done;
934 : }
935 :
936 0 : if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) &&
937 0 : (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) {
938 0 : DEBUG(SSSDBG_CONF_SETTINGS,
939 : "Password reset by root is not supported.\n");
940 0 : pd->pam_status = PAM_PERM_DENIED;
941 0 : dp_err = DP_ERR_OK;
942 0 : goto done;
943 : }
944 :
945 0 : DEBUG(SSSDBG_OP_FAILURE,
946 : "starting password change request for user [%s].\n", pd->user);
947 :
948 0 : pd->pam_status = PAM_SYSTEM_ERR;
949 :
950 0 : if (pd->cmd != SSS_PAM_CHAUTHTOK && pd->cmd != SSS_PAM_CHAUTHTOK_PRELIM) {
951 0 : DEBUG(SSSDBG_OP_FAILURE,
952 : "chpass target was called by wrong pam command.\n");
953 0 : goto done;
954 : }
955 :
956 0 : state = talloc_zero(breq, struct sdap_pam_chpass_state);
957 0 : if (!state) goto done;
958 :
959 0 : state->breq = breq;
960 0 : state->pd = pd;
961 0 : state->username = pd->user;
962 0 : state->ctx = ctx;
963 :
964 0 : subreq = auth_send(breq, be_ctx->ev, ctx,
965 : state->username, pd->authtok, true);
966 0 : if (!subreq) goto done;
967 :
968 0 : tevent_req_set_callback(subreq, sdap_auth4chpass_done, state);
969 0 : return;
970 :
971 : done:
972 0 : be_req_terminate(breq, dp_err, pd->pam_status, NULL);
973 : }
974 :
975 : static void sdap_lastchange_done(struct tevent_req *req);
976 0 : static void sdap_auth4chpass_done(struct tevent_req *req)
977 : {
978 0 : struct sdap_pam_chpass_state *state =
979 0 : tevent_req_callback_data(req, struct sdap_pam_chpass_state);
980 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
981 : struct tevent_req *subreq;
982 : enum pwexpire pw_expire_type;
983 : void *pw_expire_data;
984 0 : int dp_err = DP_ERR_FATAL;
985 : int ret;
986 : size_t msg_len;
987 : uint8_t *msg;
988 :
989 0 : ret = auth_recv(req, state, &state->sh, &state->dn,
990 : &pw_expire_type, &pw_expire_data);
991 0 : talloc_zfree(req);
992 0 : if ((ret == EOK || ret == ERR_PASSWORD_EXPIRED) &&
993 0 : state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
994 0 : DEBUG(SSSDBG_TRACE_ALL,
995 : "Initial authentication for change password operation "
996 : "successful.\n");
997 0 : state->pd->pam_status = PAM_SUCCESS;
998 0 : dp_err = DP_ERR_OK;
999 0 : goto done;
1000 : }
1001 :
1002 0 : if (ret == EOK) {
1003 0 : switch (pw_expire_type) {
1004 : case PWEXPIRE_SHADOW:
1005 0 : ret = check_pwexpire_shadow(pw_expire_data, time(NULL), NULL);
1006 0 : break;
1007 : case PWEXPIRE_KERBEROS:
1008 0 : ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), NULL,
1009 0 : be_ctx->domain->pwd_expiration_warning);
1010 :
1011 0 : if (ret == ERR_PASSWORD_EXPIRED) {
1012 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1013 : "LDAP provider cannot change kerberos "
1014 : "passwords.\n");
1015 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1016 0 : goto done;
1017 : }
1018 0 : break;
1019 : case PWEXPIRE_LDAP_PASSWORD_POLICY:
1020 : case PWEXPIRE_NONE:
1021 0 : break;
1022 : default:
1023 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n");
1024 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1025 0 : goto done;
1026 : }
1027 : }
1028 :
1029 0 : switch (ret) {
1030 : case EOK:
1031 : case ERR_PASSWORD_EXPIRED:
1032 0 : DEBUG(SSSDBG_TRACE_LIBS,
1033 : "user [%s] successfully authenticated.\n", state->dn);
1034 0 : if (pw_expire_type == PWEXPIRE_SHADOW) {
1035 : /* TODO: implement async ldap modify request */
1036 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1037 : "Changing shadow password attributes not implemented.\n");
1038 0 : state->pd->pam_status = PAM_MODULE_UNKNOWN;
1039 0 : goto done;
1040 : } else {
1041 : const char *password;
1042 : const char *new_password;
1043 : int timeout;
1044 :
1045 0 : ret = sss_authtok_get_password(state->pd->authtok,
1046 : &password, NULL);
1047 0 : if (ret) {
1048 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1049 0 : goto done;
1050 : }
1051 0 : ret = sss_authtok_get_password(state->pd->newauthtok,
1052 : &new_password, NULL);
1053 0 : if (ret) {
1054 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1055 0 : goto done;
1056 : }
1057 :
1058 0 : timeout = dp_opt_get_int(state->ctx->opts->basic, SDAP_OPT_TIMEOUT);
1059 :
1060 0 : subreq = sdap_exop_modify_passwd_send(state, be_ctx->ev,
1061 : state->sh, state->dn,
1062 : password, new_password,
1063 : timeout);
1064 0 : if (!subreq) {
1065 0 : DEBUG(SSSDBG_OP_FAILURE,
1066 : "Failed to change password for %s\n", state->username);
1067 0 : goto done;
1068 : }
1069 0 : tevent_req_set_callback(subreq, sdap_pam_chpass_done, state);
1070 0 : return;
1071 : }
1072 : break;
1073 : case ERR_AUTH_DENIED:
1074 : case ERR_AUTH_FAILED:
1075 0 : state->pd->pam_status = PAM_AUTH_ERR;
1076 0 : ret = pack_user_info_chpass_error(state->pd, "Old password not accepted.",
1077 : &msg_len, &msg);
1078 0 : if (ret != EOK) {
1079 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1080 : "pack_user_info_chpass_error failed.\n");
1081 : } else {
1082 0 : ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len,
1083 : msg);
1084 0 : if (ret != EOK) {
1085 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1086 : }
1087 : }
1088 :
1089 0 : break;
1090 : case ETIMEDOUT:
1091 : case ERR_NETWORK_IO:
1092 0 : state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
1093 0 : be_mark_offline(be_ctx);
1094 0 : dp_err = DP_ERR_OFFLINE;
1095 0 : break;
1096 : default:
1097 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1098 : }
1099 :
1100 : done:
1101 0 : be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
1102 : }
1103 :
1104 0 : static void sdap_pam_chpass_done(struct tevent_req *req)
1105 : {
1106 0 : struct sdap_pam_chpass_state *state =
1107 0 : tevent_req_callback_data(req, struct sdap_pam_chpass_state);
1108 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
1109 0 : int dp_err = DP_ERR_FATAL;
1110 : int ret;
1111 0 : char *user_error_message = NULL;
1112 : char *lastchanged_name;
1113 : struct tevent_req *subreq;
1114 : size_t msg_len;
1115 : uint8_t *msg;
1116 :
1117 0 : ret = sdap_exop_modify_passwd_recv(req, state, &user_error_message);
1118 0 : talloc_zfree(req);
1119 :
1120 0 : switch (ret) {
1121 : case EOK:
1122 0 : state->pd->pam_status = PAM_SUCCESS;
1123 0 : dp_err = DP_ERR_OK;
1124 0 : break;
1125 : case ERR_CHPASS_DENIED:
1126 0 : state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
1127 0 : break;
1128 : case ERR_NETWORK_IO:
1129 0 : state->pd->pam_status = PAM_AUTHTOK_ERR;
1130 0 : break;
1131 : default:
1132 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1133 0 : break;
1134 : }
1135 :
1136 0 : if (state->pd->pam_status != PAM_SUCCESS && user_error_message != NULL) {
1137 0 : ret = pack_user_info_chpass_error(state->pd, user_error_message,
1138 : &msg_len, &msg);
1139 0 : if (ret != EOK) {
1140 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pack_user_info_chpass_error failed.\n");
1141 : } else {
1142 0 : ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len,
1143 : msg);
1144 0 : if (ret != EOK) {
1145 0 : DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
1146 : }
1147 : }
1148 : }
1149 :
1150 0 : if (state->pd->pam_status == PAM_SUCCESS &&
1151 0 : dp_opt_get_bool(state->ctx->opts->basic,
1152 : SDAP_CHPASS_UPDATE_LAST_CHANGE)) {
1153 0 : lastchanged_name = state->ctx->opts->user_map[SDAP_AT_SP_LSTCHG].name;
1154 :
1155 0 : subreq = sdap_modify_shadow_lastchange_send(state, be_ctx->ev,
1156 0 : state->sh, state->dn,
1157 : lastchanged_name);
1158 0 : if (subreq == NULL) {
1159 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1160 0 : goto done;
1161 : }
1162 :
1163 0 : tevent_req_set_callback(subreq, sdap_lastchange_done, state);
1164 0 : return;
1165 : }
1166 :
1167 : done:
1168 0 : be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
1169 : }
1170 :
1171 0 : static void sdap_lastchange_done(struct tevent_req *req)
1172 : {
1173 0 : struct sdap_pam_chpass_state *state =
1174 0 : tevent_req_callback_data(req, struct sdap_pam_chpass_state);
1175 0 : int dp_err = DP_ERR_FATAL;
1176 : errno_t ret;
1177 :
1178 0 : ret = sdap_modify_shadow_lastchange_recv(req);
1179 0 : if (ret != EOK) {
1180 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1181 0 : goto done;
1182 : }
1183 :
1184 0 : dp_err = DP_ERR_OK;
1185 0 : state->pd->pam_status = PAM_SUCCESS;
1186 :
1187 : done:
1188 0 : be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
1189 0 : }
1190 :
1191 : /* ==Perform-User-Authentication-and-Password-Caching===================== */
1192 :
1193 : struct sdap_pam_auth_state {
1194 : struct be_req *breq;
1195 : struct pam_data *pd;
1196 : };
1197 :
1198 : static void sdap_pam_auth_done(struct tevent_req *req);
1199 :
1200 0 : void sdap_pam_auth_handler(struct be_req *breq)
1201 : {
1202 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
1203 : struct sdap_pam_auth_state *state;
1204 : struct sdap_auth_ctx *ctx;
1205 : struct tevent_req *subreq;
1206 : struct pam_data *pd;
1207 0 : int dp_err = DP_ERR_FATAL;
1208 :
1209 0 : ctx = talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
1210 : struct sdap_auth_ctx);
1211 0 : pd = talloc_get_type(be_req_get_data(breq), struct pam_data);
1212 :
1213 0 : if (be_is_offline(ctx->be)) {
1214 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1215 : "Backend is marked offline, retry later!\n");
1216 0 : pd->pam_status = PAM_AUTHINFO_UNAVAIL;
1217 0 : dp_err = DP_ERR_OFFLINE;
1218 0 : goto done;
1219 : }
1220 :
1221 0 : pd->pam_status = PAM_SYSTEM_ERR;
1222 :
1223 0 : switch (pd->cmd) {
1224 : case SSS_PAM_AUTHENTICATE:
1225 : case SSS_PAM_CHAUTHTOK_PRELIM:
1226 :
1227 0 : state = talloc_zero(breq, struct sdap_pam_auth_state);
1228 0 : if (!state) goto done;
1229 :
1230 0 : state->breq = breq;
1231 0 : state->pd = pd;
1232 :
1233 0 : subreq = auth_send(breq, be_ctx->ev, ctx,
1234 0 : pd->user, pd->authtok,
1235 0 : pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ? true : false);
1236 0 : if (!subreq) goto done;
1237 :
1238 0 : tevent_req_set_callback(subreq, sdap_pam_auth_done, state);
1239 0 : return;
1240 :
1241 : case SSS_PAM_CHAUTHTOK:
1242 0 : break;
1243 :
1244 : case SSS_PAM_ACCT_MGMT:
1245 : case SSS_PAM_SETCRED:
1246 : case SSS_PAM_OPEN_SESSION:
1247 : case SSS_PAM_CLOSE_SESSION:
1248 0 : pd->pam_status = PAM_SUCCESS;
1249 0 : dp_err = DP_ERR_OK;
1250 0 : break;
1251 : default:
1252 0 : pd->pam_status = PAM_MODULE_UNKNOWN;
1253 0 : dp_err = DP_ERR_OK;
1254 : }
1255 :
1256 : done:
1257 0 : be_req_terminate(breq, dp_err, pd->pam_status, NULL);
1258 : }
1259 :
1260 0 : static void sdap_pam_auth_done(struct tevent_req *req)
1261 : {
1262 0 : struct sdap_pam_auth_state *state =
1263 0 : tevent_req_callback_data(req, struct sdap_pam_auth_state);
1264 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(state->breq);
1265 : enum pwexpire pw_expire_type;
1266 : void *pw_expire_data;
1267 : const char *password;
1268 0 : int dp_err = DP_ERR_OK;
1269 : int ret;
1270 :
1271 0 : ret = auth_recv(req, state, NULL, NULL,
1272 : &pw_expire_type, &pw_expire_data);
1273 0 : talloc_zfree(req);
1274 :
1275 0 : if (ret == EOK) {
1276 0 : ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, state->pd,
1277 0 : be_ctx->domain->pwd_expiration_warning);
1278 0 : if (ret == EINVAL) {
1279 : /* Unknown password expiration type. */
1280 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1281 0 : goto done;
1282 : }
1283 : }
1284 :
1285 0 : switch (ret) {
1286 : case EOK:
1287 0 : state->pd->pam_status = PAM_SUCCESS;
1288 0 : break;
1289 : case ERR_AUTH_DENIED:
1290 0 : state->pd->pam_status = PAM_PERM_DENIED;
1291 0 : break;
1292 : case ERR_AUTH_FAILED:
1293 0 : state->pd->pam_status = PAM_AUTH_ERR;
1294 0 : break;
1295 : case ETIMEDOUT:
1296 : case ERR_NETWORK_IO:
1297 0 : state->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
1298 0 : break;
1299 : case ERR_ACCOUNT_EXPIRED:
1300 0 : state->pd->pam_status = PAM_ACCT_EXPIRED;
1301 0 : break;
1302 : case ERR_PASSWORD_EXPIRED:
1303 0 : state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
1304 0 : break;
1305 : default:
1306 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
1307 0 : dp_err = DP_ERR_FATAL;
1308 : }
1309 :
1310 0 : if (ret == ETIMEDOUT || ret == ERR_NETWORK_IO) {
1311 0 : be_mark_offline(be_ctx);
1312 0 : dp_err = DP_ERR_OFFLINE;
1313 0 : goto done;
1314 : }
1315 :
1316 0 : if (ret == EOK && be_ctx->domain->cache_credentials) {
1317 :
1318 0 : ret = sss_authtok_get_password(state->pd->authtok, &password, NULL);
1319 0 : if (ret == EOK) {
1320 0 : ret = sysdb_cache_password(be_ctx->domain, state->pd->user,
1321 : password);
1322 : }
1323 :
1324 : /* password caching failures are not fatal errors */
1325 0 : if (ret != EOK) {
1326 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password for %s\n",
1327 : state->pd->user);
1328 : } else {
1329 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Password successfully cached for %s\n",
1330 : state->pd->user);
1331 : }
1332 : }
1333 :
1334 : done:
1335 0 : be_req_terminate(state->breq, dp_err, state->pd->pam_status, NULL);
1336 0 : }
|