Line data Source code
1 : /*
2 : SSSD
3 :
4 : IPA Backend Module -- Authentication
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2009 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 <sys/param.h>
26 : #include <security/pam_modules.h>
27 :
28 : #include "util/util.h"
29 : #include "providers/ldap/ldap_common.h"
30 : #include "providers/ldap/sdap_async.h"
31 : #include "providers/krb5/krb5_auth.h"
32 : #include "providers/ipa/ipa_auth.h"
33 : #include "providers/ipa/ipa_common.h"
34 : #include "providers/ipa/ipa_config.h"
35 :
36 : struct get_password_migration_flag_state {
37 : struct tevent_context *ev;
38 : struct sdap_id_op *sdap_op;
39 : struct sdap_id_ctx *sdap_id_ctx;
40 : struct fo_server *srv;
41 : char *ipa_realm;
42 : bool password_migration;
43 : };
44 :
45 : static void get_password_migration_flag_auth_done(struct tevent_req *subreq);
46 : static void get_password_migration_flag_done(struct tevent_req *subreq);
47 :
48 0 : static struct tevent_req *get_password_migration_flag_send(TALLOC_CTX *memctx,
49 : struct tevent_context *ev,
50 : struct sdap_id_ctx *sdap_id_ctx,
51 : char *ipa_realm)
52 : {
53 : int ret;
54 : struct tevent_req *req, *subreq;
55 : struct get_password_migration_flag_state *state;
56 :
57 0 : if (sdap_id_ctx == NULL || ipa_realm == NULL) {
58 0 : DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n");
59 0 : return NULL;
60 : }
61 :
62 0 : req = tevent_req_create(memctx, &state,
63 : struct get_password_migration_flag_state);
64 0 : if (req == NULL) {
65 0 : DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
66 0 : return NULL;
67 : }
68 :
69 0 : state->ev = ev;
70 0 : state->sdap_id_ctx = sdap_id_ctx;
71 0 : state->srv = NULL;
72 0 : state->password_migration = false;
73 0 : state->ipa_realm = ipa_realm;
74 :
75 0 : state->sdap_op = sdap_id_op_create(state,
76 0 : state->sdap_id_ctx->conn->conn_cache);
77 0 : if (state->sdap_op == NULL) {
78 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
79 0 : goto fail;
80 : }
81 :
82 0 : subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
83 0 : if (!subreq) {
84 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
85 : ret, strerror(ret));
86 0 : goto fail;
87 : }
88 :
89 0 : tevent_req_set_callback(subreq, get_password_migration_flag_auth_done, req);
90 :
91 0 : return req;
92 :
93 : fail:
94 0 : talloc_zfree(req);
95 0 : return NULL;
96 : }
97 :
98 0 : static void get_password_migration_flag_auth_done(struct tevent_req *subreq)
99 : {
100 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
101 : struct tevent_req);
102 0 : struct get_password_migration_flag_state *state = tevent_req_data(req,
103 : struct get_password_migration_flag_state);
104 : int ret, dp_error;
105 :
106 0 : ret = sdap_id_op_connect_recv(subreq, &dp_error);
107 0 : talloc_zfree(subreq);
108 0 : if (ret) {
109 0 : if (dp_error == DP_ERR_OFFLINE) {
110 0 : DEBUG(SSSDBG_MINOR_FAILURE,
111 : "No IPA server is available, cannot get the "
112 : "migration flag while offline\n");
113 : } else {
114 0 : DEBUG(SSSDBG_OP_FAILURE,
115 : "Failed to connect to IPA server: [%d](%s)\n",
116 : ret, strerror(ret));
117 : }
118 :
119 0 : tevent_req_error(req, ret);
120 0 : return;
121 : }
122 :
123 0 : subreq = ipa_get_config_send(state, state->ev,
124 : sdap_id_op_handle(state->sdap_op),
125 0 : state->sdap_id_ctx->opts, state->ipa_realm, NULL);
126 :
127 0 : tevent_req_set_callback(subreq, get_password_migration_flag_done, req);
128 : }
129 :
130 0 : static void get_password_migration_flag_done(struct tevent_req *subreq)
131 : {
132 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
133 : struct tevent_req);
134 0 : struct get_password_migration_flag_state *state = tevent_req_data(req,
135 : struct get_password_migration_flag_state);
136 : int ret;
137 0 : struct sysdb_attrs *reply = NULL;
138 0 : const char *value = NULL;
139 :
140 0 : ret = ipa_get_config_recv(subreq, state, &reply);
141 0 : talloc_zfree(subreq);
142 0 : if (ret) {
143 0 : goto done;
144 : }
145 :
146 0 : ret = sysdb_attrs_get_string(reply, IPA_CONFIG_MIGRATION_ENABLED, &value);
147 0 : if (ret == EOK && strcasecmp(value, "true") == 0) {
148 0 : state->password_migration = true;
149 : }
150 :
151 : done:
152 0 : if (ret != EOK) {
153 0 : tevent_req_error(req, ret);
154 : } else {
155 0 : tevent_req_done(req);
156 : }
157 0 : }
158 :
159 0 : static int get_password_migration_flag_recv(struct tevent_req *req,
160 : bool *password_migration)
161 : {
162 0 : struct get_password_migration_flag_state *state = tevent_req_data(req,
163 : struct get_password_migration_flag_state);
164 :
165 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
166 :
167 0 : *password_migration = state->password_migration;
168 0 : return EOK;
169 : }
170 :
171 :
172 : struct ipa_auth_state {
173 : struct be_req *be_req;
174 : struct tevent_context *ev;
175 : struct ipa_auth_ctx *ipa_auth_ctx;
176 : struct pam_data *pd;
177 : bool password_migration;
178 : struct sdap_handle *sh;
179 : };
180 :
181 : static void ipa_auth_handler_done(struct tevent_req *req);
182 : static void ipa_get_migration_flag_done(struct tevent_req *req);
183 : static void ipa_migration_flag_connect_done(struct tevent_req *req);
184 : static void ipa_auth_ldap_done(struct tevent_req *req);
185 : static void ipa_auth_handler_retry_done(struct tevent_req *req);
186 :
187 0 : void ipa_auth(struct be_req *be_req)
188 : {
189 : struct tevent_req *req;
190 : struct ipa_auth_state *state;
191 0 : struct pam_data *pd =
192 0 : talloc_get_type(be_req_get_data(be_req), struct pam_data);
193 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
194 :
195 0 : state = talloc_zero(be_req, struct ipa_auth_state);
196 0 : if (state == NULL) {
197 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
198 0 : goto fail;
199 : }
200 :
201 0 : state->password_migration = false;
202 0 : state->sh = NULL;
203 :
204 0 : state->be_req = be_req;
205 0 : state->ev = be_ctx->ev;
206 :
207 0 : state->pd = pd;
208 :
209 0 : switch (state->pd->cmd) {
210 : case SSS_PAM_AUTHENTICATE:
211 : case SSS_PAM_PREAUTH:
212 0 : state->ipa_auth_ctx = talloc_get_type(
213 : be_ctx->bet_info[BET_AUTH].pvt_bet_data,
214 : struct ipa_auth_ctx);
215 0 : break;
216 : case SSS_PAM_CHAUTHTOK:
217 : case SSS_PAM_CHAUTHTOK_PRELIM:
218 0 : state->ipa_auth_ctx = talloc_get_type(
219 : be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
220 : struct ipa_auth_ctx);
221 0 : break;
222 : default:
223 0 : DEBUG(SSSDBG_OP_FAILURE, "Unsupported PAM task.\n");
224 0 : goto fail;
225 : }
226 :
227 0 : req = krb5_auth_queue_send(state, state->ev, be_ctx, state->pd,
228 0 : state->ipa_auth_ctx->krb5_auth_ctx);
229 0 : if (req == NULL) {
230 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_send failed.\n");
231 0 : goto fail;
232 : }
233 :
234 0 : tevent_req_set_callback(req, ipa_auth_handler_done, state);
235 0 : return;
236 :
237 : fail:
238 0 : talloc_free(state);
239 0 : pd->pam_status = PAM_SYSTEM_ERR;
240 0 : be_req_terminate(be_req, DP_ERR_FATAL, pd->pam_status, NULL);
241 : }
242 :
243 0 : static void ipa_auth_handler_done(struct tevent_req *req)
244 : {
245 0 : struct ipa_auth_state *state = tevent_req_callback_data(req,
246 : struct ipa_auth_state);
247 : int ret;
248 0 : int pam_status = PAM_SYSTEM_ERR;
249 : int dp_err;
250 :
251 0 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
252 0 : talloc_zfree(req);
253 0 : state->pd->pam_status = pam_status;
254 0 : if (ret != EOK && pam_status != PAM_CRED_ERR) {
255 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_recv request failed.\n");
256 0 : dp_err = DP_ERR_OK;
257 0 : goto done;
258 : }
259 :
260 0 : if (dp_err != DP_ERR_OK) {
261 0 : goto done;
262 : }
263 :
264 0 : if (state->pd->cmd == SSS_PAM_AUTHENTICATE &&
265 0 : state->pd->pam_status == PAM_CRED_ERR) {
266 :
267 0 : req = get_password_migration_flag_send(state, state->ev,
268 0 : state->ipa_auth_ctx->sdap_id_ctx,
269 0 : dp_opt_get_string(
270 : state->ipa_auth_ctx->ipa_options,
271 : IPA_KRB5_REALM));
272 0 : if (req == NULL) {
273 0 : DEBUG(SSSDBG_OP_FAILURE,
274 : "get_password_migration_flag failed.\n");
275 0 : goto done;
276 : }
277 :
278 0 : tevent_req_set_callback(req, ipa_get_migration_flag_done, state);
279 0 : return;
280 : }
281 :
282 : done:
283 0 : be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
284 : }
285 :
286 0 : static void ipa_get_migration_flag_done(struct tevent_req *req)
287 : {
288 0 : struct ipa_auth_state *state = tevent_req_callback_data(req,
289 : struct ipa_auth_state);
290 : int ret;
291 0 : int dp_err = DP_ERR_FATAL;
292 :
293 0 : ret = get_password_migration_flag_recv(req, &state->password_migration);
294 0 : talloc_zfree(req);
295 0 : if (ret != EOK) {
296 0 : DEBUG(SSSDBG_OP_FAILURE, "get_password_migration_flag "
297 : "request failed.\n");
298 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
299 0 : dp_err = DP_ERR_OK;
300 0 : goto done;
301 : }
302 :
303 0 : if (state->password_migration) {
304 0 : req = sdap_cli_connect_send(state, state->ev,
305 0 : state->ipa_auth_ctx->sdap_auth_ctx->opts,
306 0 : state->ipa_auth_ctx->sdap_auth_ctx->be,
307 0 : state->ipa_auth_ctx->sdap_auth_ctx->service,
308 : true, CON_TLS_ON, true);
309 0 : if (req == NULL) {
310 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_cli_connect_send failed.\n");
311 0 : goto done;
312 : }
313 :
314 0 : tevent_req_set_callback(req, ipa_migration_flag_connect_done, state);
315 0 : return;
316 : }
317 :
318 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Password migration is not enabled.\n");
319 0 : dp_err = DP_ERR_OK;
320 : done:
321 0 : be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
322 : }
323 :
324 0 : static void ipa_migration_flag_connect_done(struct tevent_req *req)
325 : {
326 0 : struct ipa_auth_state *state = tevent_req_callback_data(req,
327 : struct ipa_auth_state);
328 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(state->be_req);
329 : const char **attrs;
330 : struct ldb_message *user_msg;
331 : const char *dn;
332 0 : int dp_err = DP_ERR_FATAL;
333 : int ret;
334 : int auth_timeout;
335 :
336 0 : ret = sdap_cli_connect_recv(req, state, NULL, &state->sh, NULL);
337 0 : talloc_zfree(req);
338 0 : if (ret != EOK) {
339 0 : DEBUG(SSSDBG_OP_FAILURE,
340 : "Cannot connect to LDAP server to perform migration\n");
341 0 : goto done;
342 : }
343 :
344 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
345 0 : DEBUG(SSSDBG_TRACE_FUNC, "Assuming Kerberos password is missing, "
346 : "starting password migration.\n");
347 :
348 0 : attrs = talloc_array(state, const char *, 2);
349 0 : if (attrs == NULL) {
350 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
351 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
352 0 : dp_err = DP_ERR_OK;
353 0 : goto done;
354 : }
355 0 : attrs[0] = SYSDB_ORIG_DN;
356 0 : attrs[1] = NULL;
357 :
358 0 : ret = sysdb_search_user_by_name(state, be_ctx->domain, state->pd->user,
359 : attrs, &user_msg);
360 0 : if (ret != EOK) {
361 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
362 0 : goto done;
363 : }
364 :
365 0 : dn = ldb_msg_find_attr_as_string(user_msg, SYSDB_ORIG_DN, NULL);
366 0 : if (dn == NULL) {
367 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Missing original DN for user [%s].\n",
368 : state->pd->user);
369 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
370 0 : dp_err = DP_ERR_OK;
371 0 : goto done;
372 : }
373 :
374 0 : auth_timeout = dp_opt_get_int(
375 : state->ipa_auth_ctx->sdap_auth_ctx->opts->basic,
376 : SDAP_OPT_TIMEOUT);
377 :
378 0 : req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,
379 0 : state->pd->authtok, auth_timeout);
380 0 : if (req == NULL) {
381 0 : DEBUG(SSSDBG_OP_FAILURE, "sdap_auth_send failed.\n");
382 0 : goto done;
383 : }
384 :
385 0 : tevent_req_set_callback(req, ipa_auth_ldap_done, state);
386 0 : return;
387 :
388 : done:
389 0 : be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
390 : }
391 :
392 0 : static void ipa_auth_ldap_done(struct tevent_req *req)
393 : {
394 0 : struct ipa_auth_state *state = tevent_req_callback_data(req,
395 : struct ipa_auth_state);
396 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(state->be_req);
397 : int ret;
398 0 : int dp_err = DP_ERR_FATAL;
399 :
400 0 : ret = sdap_auth_recv(req, state, NULL);
401 0 : talloc_zfree(req);
402 0 : switch (ret) {
403 : case EOK:
404 0 : break;
405 :
406 : case ERR_AUTH_DENIED:
407 : case ERR_AUTH_FAILED:
408 : case ERR_PASSWORD_EXPIRED:
409 : /* TODO: do we need to handle expired passwords? */
410 0 : DEBUG(SSSDBG_MINOR_FAILURE, "LDAP authentication failed, "
411 : "Password migration not possible.\n");
412 0 : state->pd->pam_status = PAM_CRED_INSUFFICIENT;
413 0 : dp_err = DP_ERR_OK;
414 0 : goto done;
415 : default:
416 0 : DEBUG(SSSDBG_OP_FAILURE, "auth_send request failed.\n");
417 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
418 0 : dp_err = DP_ERR_OK;
419 0 : goto done;
420 : }
421 :
422 :
423 0 : DEBUG(SSSDBG_TRACE_FUNC, "LDAP authentication succeded, "
424 : "trying Kerberos authentication again.\n");
425 :
426 0 : req = krb5_auth_queue_send(state, state->ev, be_ctx, state->pd,
427 0 : state->ipa_auth_ctx->krb5_auth_ctx);
428 0 : if (req == NULL) {
429 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_send failed.\n");
430 0 : goto done;
431 : }
432 :
433 0 : tevent_req_set_callback(req, ipa_auth_handler_retry_done, state);
434 0 : return;
435 :
436 : done:
437 0 : be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
438 : }
439 :
440 0 : static void ipa_auth_handler_retry_done(struct tevent_req *req)
441 : {
442 0 : struct ipa_auth_state *state = tevent_req_callback_data(req,
443 : struct ipa_auth_state);
444 : int ret;
445 : int pam_status;
446 : int dp_err;
447 :
448 0 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
449 0 : talloc_zfree(req);
450 0 : if (ret != EOK) {
451 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_recv request failed.\n");
452 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
453 0 : dp_err = DP_ERR_OK;
454 0 : goto done;
455 : }
456 :
457 0 : state->pd->pam_status = pam_status;
458 :
459 : done:
460 0 : be_req_terminate(state->be_req, dp_err, state->pd->pam_status, NULL);
461 0 : }
|