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 : struct ipa_pam_auth_handler_state {
172 : struct tevent_context *ev;
173 : struct ipa_auth_ctx *auth_ctx;
174 : struct be_ctx *be_ctx;
175 : struct pam_data *pd;
176 : };
177 :
178 : static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq);
179 : static void ipa_pam_auth_handler_flag_done(struct tevent_req *subreq);
180 : static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq);
181 : static void ipa_pam_auth_handler_auth_done(struct tevent_req *subreq);
182 : static void ipa_pam_auth_handler_retry_done(struct tevent_req *subreq);
183 :
184 : struct tevent_req *
185 0 : ipa_pam_auth_handler_send(TALLOC_CTX *mem_ctx,
186 : struct ipa_auth_ctx *auth_ctx,
187 : struct pam_data *pd,
188 : struct dp_req_params *params)
189 : {
190 : struct ipa_pam_auth_handler_state *state;
191 : struct tevent_req *subreq;
192 : struct tevent_req *req;
193 :
194 0 : req = tevent_req_create(mem_ctx, &state,
195 : struct ipa_pam_auth_handler_state);
196 0 : if (req == NULL) {
197 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
198 0 : return NULL;
199 : }
200 :
201 0 : state->pd = pd;
202 0 : state->ev = params->ev;
203 0 : state->auth_ctx = auth_ctx;
204 0 : state->be_ctx = params->be_ctx;
205 :
206 0 : pd->pam_status = PAM_SYSTEM_ERR;
207 :
208 0 : subreq = krb5_auth_queue_send(state, params->ev, params->be_ctx,
209 : pd, auth_ctx->krb5_auth_ctx);
210 0 : if (subreq == NULL) {
211 0 : pd->pam_status = PAM_SYSTEM_ERR;
212 0 : goto immediately;
213 : }
214 :
215 0 : tevent_req_set_callback(subreq, ipa_pam_auth_handler_krb5_done, req);
216 :
217 0 : return req;
218 :
219 : immediately:
220 : /* TODO For backward compatibility we always return EOK to DP now. */
221 0 : tevent_req_done(req);
222 0 : tevent_req_post(req, params->ev);
223 :
224 0 : return req;
225 : }
226 :
227 0 : static void ipa_pam_auth_handler_krb5_done(struct tevent_req *subreq)
228 : {
229 : struct ipa_pam_auth_handler_state *state;
230 : struct tevent_req *req;
231 : int dp_err;
232 : char *realm;
233 : errno_t ret;
234 :
235 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
236 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
237 :
238 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
239 0 : ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, &dp_err);
240 0 : talloc_free(subreq);
241 0 : if (ret != EOK && state->pd->pam_status != PAM_CRED_ERR) {
242 0 : DEBUG(SSSDBG_OP_FAILURE, "KRB5 auth failed [%d]: %s\n",
243 : ret, sss_strerror(ret));
244 0 : goto done;
245 : }
246 :
247 0 : if (dp_err != DP_ERR_OK) {
248 0 : goto done;
249 : }
250 :
251 0 : if (state->pd->cmd == SSS_PAM_AUTHENTICATE
252 0 : && state->pd->pam_status == PAM_CRED_ERR) {
253 0 : realm = dp_opt_get_string(state->auth_ctx->ipa_options, IPA_KRB5_REALM);
254 0 : subreq = get_password_migration_flag_send(state, state->ev,
255 0 : state->auth_ctx->sdap_id_ctx,
256 : realm);
257 0 : if (subreq == NULL) {
258 0 : goto done;
259 : }
260 :
261 0 : tevent_req_set_callback(subreq, ipa_pam_auth_handler_flag_done, req);
262 0 : return;
263 : }
264 :
265 : done:
266 : /* TODO For backward compatibility we always return EOK to DP now. */
267 0 : tevent_req_done(req);
268 : }
269 :
270 0 : static void ipa_pam_auth_handler_flag_done(struct tevent_req *subreq)
271 : {
272 : struct ipa_pam_auth_handler_state *state;
273 : struct sdap_auth_ctx *sdap_auth_ctx;
274 0 : bool password_migration = false;
275 : struct tevent_req *req;
276 : errno_t ret;
277 :
278 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
279 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
280 :
281 0 : ret = get_password_migration_flag_recv(subreq, &password_migration);
282 0 : talloc_free(subreq);
283 0 : if (ret != EOK) {
284 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to get password migration flag "
285 : "[%d]: %s\n", ret, sss_strerror(ret));
286 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
287 0 : goto done;
288 : }
289 :
290 0 : if (password_migration) {
291 0 : sdap_auth_ctx = state->auth_ctx->sdap_auth_ctx;
292 0 : subreq = sdap_cli_connect_send(state, state->ev,
293 : sdap_auth_ctx->opts,
294 : sdap_auth_ctx->be,
295 : sdap_auth_ctx->service,
296 : true, CON_TLS_ON, true);
297 0 : if (subreq == NULL) {
298 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
299 0 : goto done;
300 : }
301 :
302 0 : tevent_req_set_callback(subreq, ipa_pam_auth_handler_connect_done, req);
303 0 : return;
304 : }
305 :
306 : done:
307 : /* TODO For backward compatibility we always return EOK to DP now. */
308 0 : tevent_req_done(req);
309 : }
310 :
311 0 : static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq)
312 : {
313 : struct ipa_pam_auth_handler_state *state;
314 : struct tevent_req *req;
315 : struct sdap_handle *sh;
316 0 : const char *attrs[] = {SYSDB_ORIG_DN, NULL};
317 : struct ldb_message *msg;
318 : const char *dn;
319 : int timeout;
320 : errno_t ret;
321 :
322 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
323 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
324 :
325 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
326 :
327 0 : ret = sdap_cli_connect_recv(subreq, state, NULL, &sh, NULL);
328 0 : talloc_free(subreq);
329 0 : if (ret != EOK) {
330 0 : DEBUG(SSSDBG_OP_FAILURE, "Cannot connect to LDAP server to perform "
331 : "migration [%d]: %s\n", ret, sss_strerror(ret));
332 0 : goto done;
333 : }
334 :
335 0 : DEBUG(SSSDBG_TRACE_FUNC, "Assuming Kerberos password is missing, "
336 : "starting password migration.\n");
337 :
338 0 : ret = sysdb_search_user_by_name(state, state->be_ctx->domain,
339 0 : state->pd->user, attrs, &msg);
340 0 : if (ret != EOK) {
341 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
342 0 : goto done;
343 : }
344 :
345 0 : dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
346 0 : if (dn == NULL) {
347 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Missing original DN for user [%s].\n",
348 : state->pd->user);
349 0 : goto done;
350 : }
351 :
352 0 : timeout = dp_opt_get_int(state->auth_ctx->sdap_auth_ctx->opts->basic,
353 : SDAP_OPT_TIMEOUT);
354 :
355 0 : subreq = sdap_auth_send(state, state->ev, sh, NULL, NULL, dn,
356 0 : state->pd->authtok, timeout);
357 0 : if (subreq == NULL) {
358 0 : goto done;
359 : }
360 :
361 0 : tevent_req_set_callback(subreq, ipa_pam_auth_handler_auth_done, req);
362 0 : return;
363 :
364 : done:
365 : /* TODO For backward compatibility we always return EOK to DP now. */
366 0 : tevent_req_done(req);
367 : }
368 :
369 0 : static void ipa_pam_auth_handler_auth_done(struct tevent_req *subreq)
370 : {
371 : struct ipa_pam_auth_handler_state *state;
372 : struct tevent_req *req;
373 : errno_t ret;
374 :
375 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
376 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
377 :
378 0 : ret = sdap_auth_recv(subreq, state, NULL);
379 :
380 0 : talloc_free(subreq);
381 0 : switch (ret) {
382 : case EOK:
383 0 : break;
384 : case ERR_AUTH_DENIED:
385 : case ERR_AUTH_FAILED:
386 : case ERR_PASSWORD_EXPIRED:
387 : /* TODO: do we need to handle expired passwords? */
388 0 : DEBUG(SSSDBG_MINOR_FAILURE, "LDAP authentication failed, "
389 : "password migration not possible.\n");
390 0 : state->pd->pam_status = PAM_CRED_INSUFFICIENT;
391 0 : goto done;
392 : default:
393 0 : DEBUG(SSSDBG_OP_FAILURE, "auth_send request failed.\n");
394 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
395 0 : goto done;
396 : }
397 :
398 0 : DEBUG(SSSDBG_TRACE_FUNC, "LDAP authentication succeded, "
399 : "trying Kerberos authentication again.\n");
400 :
401 0 : subreq = krb5_auth_queue_send(state, state->ev, state->be_ctx, state->pd,
402 0 : state->auth_ctx->krb5_auth_ctx);
403 0 : if (subreq == NULL) {
404 0 : goto done;
405 : }
406 :
407 0 : tevent_req_set_callback(subreq, ipa_pam_auth_handler_retry_done, req);
408 0 : return;
409 :
410 : done:
411 : /* TODO For backward compatibility we always return EOK to DP now. */
412 0 : tevent_req_done(req);
413 : }
414 :
415 0 : static void ipa_pam_auth_handler_retry_done(struct tevent_req *subreq)
416 : {
417 : struct ipa_pam_auth_handler_state *state;
418 : struct tevent_req *req;
419 : int dp_err;
420 : errno_t ret;
421 :
422 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
423 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
424 :
425 0 : ret = krb5_auth_queue_recv(subreq, &state->pd->pam_status, &dp_err);
426 0 : talloc_free(subreq);
427 0 : if (ret != EOK) {
428 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_auth_recv request failed.\n");
429 0 : state->pd->pam_status = PAM_SYSTEM_ERR;
430 : }
431 :
432 : /* TODO For backward compatibility we always return EOK to DP now. */
433 0 : tevent_req_done(req);
434 0 : }
435 :
436 : errno_t
437 0 : ipa_pam_auth_handler_recv(TALLOC_CTX *mem_ctx,
438 : struct tevent_req *req,
439 : struct pam_data **_data)
440 : {
441 0 : struct ipa_pam_auth_handler_state *state = NULL;
442 :
443 0 : state = tevent_req_data(req, struct ipa_pam_auth_handler_state);
444 :
445 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
446 :
447 0 : *_data = talloc_steal(mem_ctx, state->pd);
448 :
449 0 : return EOK;
450 : }
|