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_common.h"
33
34 #define IPA_CONFIG_MIRATION_ENABLED "ipaMigrationEnabled"
35 #define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s"
36 #define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))"
37
38 static void ipa_auth_reply(struct be_req *be_req, int dp_err, int result)
39 {
40 be_req->fn(be_req, dp_err, result, NULL);
41 }
42
43 struct get_password_migration_flag_state {
44 struct tevent_context *ev;
45 struct sdap_auth_ctx *sdap_auth_ctx;
46 struct sdap_handle *sh;
47 enum sdap_result result;
48 struct fo_server *srv;
49 char *ipa_domain;
50 bool password_migration;
51 };
52
53 static void get_password_migration_flag_auth_done(struct tevent_req *subreq);
54 static void get_password_migration_flag_done(struct tevent_req *subreq);
55
56 static struct tevent_req *get_password_migration_flag_send(TALLOC_CTX *memctx,
57 struct tevent_context *ev,
58 struct sdap_auth_ctx *sdap_auth_ctx,
59 char *ipa_domain)
60 {
61 int ret;
62 struct tevent_req *req, *subreq;
63 struct get_password_migration_flag_state *state;
64
65 if (sdap_auth_ctx == NULL || ipa_domain == NULL) {
66 DEBUG(1, ("Missing parameter.\n"));
67 return NULL;
68 }
69
70 req = tevent_req_create(memctx, &state,
71 struct get_password_migration_flag_state);
72 if (req == NULL) {
73 DEBUG(1, ("tevent_req_create failed.\n"));
74 return NULL;
75 }
76
77 state->ev = ev;
78 state->sdap_auth_ctx = sdap_auth_ctx;
79 state->sh = NULL;
80 state->result = SDAP_ERROR;
81 state->srv = NULL;
82 state->password_migration = false;
83 state->ipa_domain = ipa_domain;
84
85 /* We request to use StartTLS here, because if password migration is
86 * enabled we will use this connection for authentication, too. */
87 ret = dp_opt_set_bool(sdap_auth_ctx->opts->basic, SDAP_ID_TLS, true);
88 if (ret != EOK) {
89 DEBUG(1, ("Failed to set SDAP_ID_TLS to true.\n"));
90 goto fail;
91 }
92
93 subreq = sdap_cli_connect_send(state, ev, sdap_auth_ctx->opts,
94 sdap_auth_ctx->be, sdap_auth_ctx->service,
95 NULL);
96 if (subreq == NULL) {
97 DEBUG(1, ("sdap_cli_connect_send failed.\n"));
98 goto fail;
99 }
100 tevent_req_set_callback(subreq, get_password_migration_flag_auth_done,
101 req);
102
103 return req;
104
105 fail:
106 talloc_zfree(req);
107 return NULL;
108 }
109
110 static void get_password_migration_flag_auth_done(struct tevent_req *subreq)
111 {
112 struct tevent_req *req = tevent_req_callback_data(subreq,
113 struct tevent_req);
114 struct get_password_migration_flag_state *state = tevent_req_data(req,
115 struct get_password_migration_flag_state);
116 int ret;
117 char *ldap_basedn;
118 char *search_base;
119 const char **attrs;
120
121 ret = sdap_cli_connect_recv(subreq, state, &state->sh, NULL);
122 talloc_zfree(subreq);
123 if (ret) {
124 DEBUG(1, ("sdap_auth request failed.\n"));
125 tevent_req_error(req, ret);
126 return;
127 }
128
129 ret = domain_to_basedn(state, state->ipa_domain, &ldap_basedn);
130 if (ret != EOK) {
131 DEBUG(1, ("domain_to_basedn failed.\n"));
132 tevent_req_error(req, ret);
133 return;
134 }
135
136 search_base = talloc_asprintf(state, IPA_CONFIG_SEARCH_BASE_TEMPLATE,
137 ldap_basedn);
138 if (search_base == NULL) {
139 DEBUG(1, ("talloc_asprintf failed.\n"));
140 tevent_req_error(req, ENOMEM);
141 return;
142 }
143
144 attrs = talloc_array(state, const char*, 2);
145 if (attrs == NULL) {
146 DEBUG(1, ("talloc_array failed.\n"));
147 tevent_req_error(req, ENOMEM);
148 return;
149 }
150
151 attrs[0] = IPA_CONFIG_MIRATION_ENABLED;
152 attrs[1] = NULL;
153
154 subreq = sdap_get_generic_send(state, state->ev, state->sdap_auth_ctx->opts,
155 state->sh, search_base, LDAP_SCOPE_SUBTREE,
156 IPA_CONFIG_FILTER, attrs, NULL, 0);
157 if (!subreq) {
158 tevent_req_error(req, ENOMEM);
159 return;
160 }
161
162 tevent_req_set_callback(subreq, get_password_migration_flag_done, req);
163 }
164
165 static void get_password_migration_flag_done(struct tevent_req *subreq)
166 {
167 struct tevent_req *req = tevent_req_callback_data(subreq,
168 struct tevent_req);
169 struct get_password_migration_flag_state *state = tevent_req_data(req,
170 struct get_password_migration_flag_state);
171 int ret;
172 size_t reply_count;
173 struct sysdb_attrs **reply = NULL;
174 const char *value = NULL;
175
176 ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
177 talloc_zfree(subreq);
178 if (ret) {
179 tevent_req_error(req, ret);
180 return;
181 }
182
183 if (reply_count != 1) {
184 DEBUG(1, ("Unexpected number of results, expected 1, got %d.\n",
185 reply_count));
186 tevent_req_error(req, EINVAL);
187 return;
188 }
189
190 ret = sysdb_attrs_get_string(reply[0], IPA_CONFIG_MIRATION_ENABLED, &value);
191 if (strcasecmp(value, "true") == 0) {
192 state->password_migration = true;
193 }
194
195 tevent_req_done(req);
196 }
197
198 static int get_password_migration_flag_recv(struct tevent_req *req,
199 TALLOC_CTX *mem_ctx,
200 bool *password_migration,
201 struct sdap_handle **sh)
202 {
203 struct get_password_migration_flag_state *state = tevent_req_data(req,
204 struct get_password_migration_flag_state);
205
206 TEVENT_REQ_RETURN_ON_ERROR(req);
207
208 *password_migration = state->password_migration;
209 if (sh != NULL) {
210 *sh = talloc_steal(mem_ctx, state->sh);
211 }
212
213 return EOK;
214 }
215
216
217 struct ipa_auth_state {
218 struct be_req *be_req;
219 struct tevent_context *ev;
220 struct ipa_auth_ctx *ipa_auth_ctx;
221 struct pam_data *pd;
222 bool password_migration;
223 struct sdap_handle *sh;
224 };
225
226 static void ipa_auth_handler_done(struct tevent_req *req);
227 static void ipa_get_migration_flag_done(struct tevent_req *req);
228 static void ipa_auth_get_user_dn_done(struct tevent_req *req);
229 static void ipa_auth_ldap_done(struct tevent_req *req);
230 static void ipa_auth_handler_retry_done(struct tevent_req *req);
231
232 void ipa_auth(struct be_req *be_req)
233 {
234 struct tevent_req *req;
235 struct ipa_auth_state *state;
236
237 state = talloc_zero(be_req, struct ipa_auth_state);
Event var_compare_op: Comparing "state" to null implies that "state" might be null.
Also see events: [var_deref_op]At conditional (1): "state == NULL": Taking true branch.
| | |
238 if (state == NULL) {
At conditional (2): "1 <= debug_level": Taking true branch.
At conditional (3): "debug_timestamps": Taking true branch.
| |
239 DEBUG(1, ("talloc_zero failed.\n"));
240 goto fail;
241 }
242
243 state->password_migration = false;
244 state->sh = NULL;
245
246 state->be_req = be_req;
247 state->ev = be_req->be_ctx->ev;
248
249 state->pd = talloc_get_type(be_req->req_data, struct pam_data);
250
251 switch (state->pd->cmd) {
252 case SSS_PAM_AUTHENTICATE:
253 state->ipa_auth_ctx = talloc_get_type(
254 be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
255 struct ipa_auth_ctx);
256 break;
257 case SSS_PAM_CHAUTHTOK:
258 case SSS_PAM_CHAUTHTOK_PRELIM:
259 state->ipa_auth_ctx = talloc_get_type(
260 be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
261 struct ipa_auth_ctx);
262 break;
263 default:
264 DEBUG(1, ("Unsupported PAM task.\n"));
265 goto fail;
266 }
267
268 req = krb5_auth_send(state, state->ev, be_req->be_ctx, state->pd,
269 state->ipa_auth_ctx->krb5_auth_ctx);
270 if (req == NULL) {
271 DEBUG(1, ("krb5_auth_send failed.\n"));
272 goto fail;
273 }
274
275 tevent_req_set_callback(req, ipa_auth_handler_done, state);
276 return;
277
278 fail:
Event var_deref_op: Dereferencing null variable "state".
Also see events: [var_compare_op] | |
279 state->pd->pam_status = PAM_SYSTEM_ERR;
280 ipa_auth_reply(be_req, DP_ERR_FATAL, state->pd->pam_status);
281 }
282
283 static void ipa_auth_handler_done(struct tevent_req *req)
284 {
285 struct ipa_auth_state *state = tevent_req_callback_data(req,
286 struct ipa_auth_state);
287 int ret;
288 int pam_status = PAM_SYSTEM_ERR;
289 int dp_err;
290
291 ret = krb5_auth_recv(req, &pam_status, &dp_err);
292 talloc_zfree(req);
293 state->pd->pam_status = pam_status;
294 if (ret != EOK && pam_status != PAM_CRED_ERR) {
295 DEBUG(1, ("krb5_auth_recv request failed.\n"));
296 dp_err = DP_ERR_OK;
297 goto done;
298 }
299
300 if (dp_err != DP_ERR_OK) {
301 goto done;
302 }
303
304 if (state->pd->cmd == SSS_PAM_AUTHENTICATE &&
305 state->pd->pam_status == PAM_CRED_ERR) {
306
307 req = get_password_migration_flag_send(state, state->ev,
308 state->ipa_auth_ctx->sdap_auth_ctx,
309 dp_opt_get_string(
310 state->ipa_auth_ctx->ipa_options,
311 IPA_DOMAIN));
312 if (req == NULL) {
313 DEBUG(1, ("get_password_migration_flag failed.\n"));
314 goto done;
315 }
316
317 tevent_req_set_callback(req, ipa_get_migration_flag_done, state);
318 return;
319 }
320
321 done:
322 ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
323 }
324
325 static void ipa_get_migration_flag_done(struct tevent_req *req)
326 {
327 struct ipa_auth_state *state = tevent_req_callback_data(req,
328 struct ipa_auth_state);
329 int ret;
330 int dp_err = DP_ERR_FATAL;
331 const char **attrs;
332
333 ret = get_password_migration_flag_recv(req, state,
334 &state->password_migration,
335 &state->sh);
336 talloc_zfree(req);
337 if (ret != EOK) {
338 DEBUG(1, ("get_password_migration_flag request failed.\n"));
339 state->pd->pam_status = PAM_SYSTEM_ERR;
340 dp_err = DP_ERR_OK;
341 goto done;
342 }
343
344 if (state->password_migration) {
345 state->pd->pam_status = PAM_SYSTEM_ERR;
346 DEBUG(1, ("Assuming Kerberos password is missing, "
347 "starting password migration.\n"));
348
349 attrs = talloc_array(state, const char *, 2);
350 if (attrs == NULL) {
351 DEBUG(1, ("talloc_array failed.\n"));
352 state->pd->pam_status = PAM_SYSTEM_ERR;
353 dp_err = DP_ERR_OK;
354 goto done;
355 }
356 attrs[0] = SYSDB_ORIG_DN;
357 attrs[1] = NULL;
358
359 req = sysdb_search_user_by_name_send(state, state->ev,
360 state->be_req->be_ctx->sysdb, NULL,
361 state->be_req->be_ctx->domain,
362 state->pd->user, attrs);
363 if (req == NULL) {
364 DEBUG(1, ("sysdb_search_user_by_name_send failed.\n"));
365 goto done;
366 }
367
368 tevent_req_set_callback(req, ipa_auth_get_user_dn_done, state);
369 return;
370 } else {
371 DEBUG(5, ("Password migration is not enabled.\n"));
372 }
373
374 dp_err = DP_ERR_OK;
375
376 done:
377 ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
378 }
379
380 void ipa_auth_get_user_dn_done(struct tevent_req *req)
381 {
382 struct ipa_auth_state *state = tevent_req_callback_data(req,
383 struct ipa_auth_state);
384 int ret;
385 int dp_err = DP_ERR_FATAL;
386 struct dp_opt_blob password;
387 struct ldb_message *msg;
388 const char *dn;
389
390 ret = sysdb_search_user_recv(req, state, &msg);
391 talloc_zfree(req);
392 if (ret != EOK) {
393 DEBUG(1, ("sysdb_search_user request failed.\n"));
394 state->pd->pam_status = PAM_SYSTEM_ERR;
395 dp_err = DP_ERR_OK;
396 goto done;
397 }
398
399 dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
400 if (dn == NULL) {
401 DEBUG(1, ("Missing original DN for user [%s].\n", state->pd->user));
402 state->pd->pam_status = PAM_SYSTEM_ERR;
403 dp_err = DP_ERR_OK;
404 goto done;
405 }
406
407 password.data = state->pd->authtok;
408 password.length = state->pd->authtok_size;
409
410 req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,
411 "password", password);
412 if (req == NULL) {
413 DEBUG(1, ("sdap_auth_send failed.\n"));
414 goto done;
415 }
416
417 tevent_req_set_callback(req, ipa_auth_ldap_done, state);
418 return;
419
420 done:
421 ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
422 }
423
424
425 static void ipa_auth_ldap_done(struct tevent_req *req)
426 {
427 struct ipa_auth_state *state = tevent_req_callback_data(req,
428 struct ipa_auth_state);
429 int ret;
430 int dp_err = DP_ERR_FATAL;
431 enum sdap_result result;
432
433 ret = sdap_auth_recv(req, state, &result, NULL);
434 talloc_zfree(req);
435 if (ret != EOK) {
436 DEBUG(1, ("auth_send request failed.\n"));
437 state->pd->pam_status = PAM_SYSTEM_ERR;
438 dp_err = DP_ERR_OK;
439 goto done;
440 }
441
442 /* TODO: do we need to handle expired passwords? */
443 if (result != SDAP_AUTH_SUCCESS) {
444 DEBUG(1, ("LDAP authentication failed, "
445 "Password migration not possible.\n"));
446 state->pd->pam_status = PAM_CRED_INSUFFICIENT;
447 dp_err = DP_ERR_OK;
448 goto done;
449 }
450
451 DEBUG(1, ("LDAP authentication succeded, "
452 "trying Kerberos authentication again.\n"));
453
454 req = krb5_auth_send(state, state->ev,
455 state->be_req->be_ctx, state->pd,
456 state->ipa_auth_ctx->krb5_auth_ctx);
457 if (req == NULL) {
458 DEBUG(1, ("krb5_auth_send failed.\n"));
459 goto done;
460 }
461
462 tevent_req_set_callback(req, ipa_auth_handler_retry_done, state);
463 return;
464
465 done:
466 ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
467 }
468
469 static void ipa_auth_handler_retry_done(struct tevent_req *req)
470 {
471 struct ipa_auth_state *state = tevent_req_callback_data(req,
472 struct ipa_auth_state);
473 int ret;
474 int pam_status;
475 int dp_err;
476
477 ret = krb5_auth_recv(req, &pam_status, &dp_err);
478 talloc_zfree(req);
479 if (ret != EOK) {
480 DEBUG(1, ("krb5_auth_recv request failed.\n"));
481 state->pd->pam_status = PAM_SYSTEM_ERR;
482 dp_err = DP_ERR_OK;
483 goto done;
484 }
485
486 state->pd->pam_status = pam_status;
487
488 done:
489 ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
490 }