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