Line data Source code
1 : /*
2 : SSSD
3 :
4 : Kerberos 5 Backend Module -- Request a TGT when the system gets online
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 :
9 : Copyright (C) 2010 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 <security/pam_modules.h>
26 : #ifdef USE_KEYRING
27 : #include <sys/types.h>
28 : #include <keyutils.h>
29 : #endif
30 : #include <dhash.h>
31 :
32 : #include "providers/krb5/krb5_auth.h"
33 : #include "util/util.h"
34 : #include "util/find_uid.h"
35 :
36 : #define INITIAL_USER_TABLE_SIZE 10
37 :
38 : struct deferred_auth_ctx {
39 : hash_table_t *user_table;
40 : struct be_ctx *be_ctx;
41 : struct tevent_context *ev;
42 : struct krb5_ctx *krb5_ctx;
43 : };
44 :
45 : struct auth_data {
46 : struct be_ctx *be_ctx;
47 : struct krb5_ctx *krb5_ctx;
48 : struct pam_data *pd;
49 : };
50 :
51 0 : static void *hash_talloc(const size_t size, void *pvt)
52 : {
53 0 : return talloc_size(pvt, size);
54 : }
55 :
56 0 : static void hash_talloc_free(void *ptr, void *pvt)
57 : {
58 0 : talloc_free(ptr);
59 0 : }
60 :
61 : static void authenticate_user_done(struct tevent_req *req);
62 0 : static void authenticate_user(struct tevent_context *ev,
63 : struct tevent_timer *te,
64 : struct timeval current_time,
65 : void *private_data)
66 : {
67 0 : struct auth_data *auth_data = talloc_get_type(private_data,
68 : struct auth_data);
69 0 : struct pam_data *pd = auth_data->pd;
70 : struct tevent_req *req;
71 :
72 0 : DEBUG_PAM_DATA(SSSDBG_TRACE_ALL, pd);
73 :
74 : #ifdef USE_KEYRING
75 : char *password;
76 : long keysize;
77 : long keyrevoke;
78 : errno_t ret;
79 :
80 0 : keysize = keyctl_read_alloc(pd->key_serial, (void **)&password);
81 0 : if (keysize == -1) {
82 0 : ret = errno;
83 0 : DEBUG(SSSDBG_CRIT_FAILURE,
84 : "keyctl_read failed [%d][%s].\n", ret, strerror(ret));
85 0 : return;
86 : }
87 :
88 0 : ret = sss_authtok_set_password(pd->authtok, password, keysize);
89 0 : safezero(password, keysize);
90 0 : free(password);
91 0 : if (ret) {
92 0 : DEBUG(SSSDBG_CRIT_FAILURE,
93 : "failed to set password in auth token [%d][%s].\n",
94 : ret, strerror(ret));
95 0 : return;
96 : }
97 :
98 0 : keyrevoke = keyctl_revoke(pd->key_serial);
99 0 : if (keyrevoke == -1) {
100 0 : ret = errno;
101 0 : DEBUG(SSSDBG_CRIT_FAILURE,
102 : "keyctl_revoke failed [%d][%s].\n", ret, strerror(ret));
103 : }
104 : #endif
105 :
106 0 : req = krb5_auth_queue_send(auth_data, ev, auth_data->be_ctx,
107 : auth_data->pd, auth_data->krb5_ctx);
108 0 : if (req == NULL) {
109 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
110 0 : talloc_free(auth_data);
111 0 : return;
112 : }
113 :
114 0 : tevent_req_set_callback(req, authenticate_user_done, auth_data);
115 : }
116 :
117 0 : static void authenticate_user_done(struct tevent_req *req)
118 : {
119 0 : struct auth_data *auth_data = tevent_req_callback_data(req,
120 : struct auth_data);
121 : int ret;
122 0 : int pam_status = PAM_SYSTEM_ERR;
123 0 : int dp_err = DP_ERR_OK;
124 :
125 0 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
126 0 : talloc_free(req);
127 0 : if (ret) {
128 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth request failed.\n");
129 : } else {
130 0 : if (pam_status == PAM_SUCCESS) {
131 0 : DEBUG(SSSDBG_CONF_SETTINGS,
132 : "Successfully authenticated user [%s].\n",
133 : auth_data->pd->user);
134 : } else {
135 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to authenticate user [%s].\n",
136 : auth_data->pd->user);
137 : }
138 : }
139 :
140 0 : talloc_free(auth_data);
141 0 : }
142 :
143 0 : static errno_t authenticate_stored_users(
144 : struct deferred_auth_ctx *deferred_auth_ctx)
145 : {
146 : int ret;
147 : hash_table_t *uid_table;
148 : struct hash_iter_context_t *iter;
149 : hash_entry_t *entry;
150 : hash_key_t key;
151 : hash_value_t value;
152 : struct pam_data *pd;
153 : struct auth_data *auth_data;
154 : struct tevent_timer *te;
155 :
156 0 : ret = get_uid_table(deferred_auth_ctx, &uid_table);
157 0 : if (ret != HASH_SUCCESS) {
158 0 : DEBUG(SSSDBG_CRIT_FAILURE, "get_uid_table failed.\n");
159 0 : return ret;
160 : }
161 :
162 0 : iter = new_hash_iter_context(deferred_auth_ctx->user_table);
163 0 : if (iter == NULL) {
164 0 : DEBUG(SSSDBG_CRIT_FAILURE, "new_hash_iter_context failed.\n");
165 0 : return EINVAL;
166 : }
167 :
168 0 : while ((entry = iter->next(iter)) != NULL) {
169 0 : key.type = HASH_KEY_ULONG;
170 0 : key.ul = entry->key.ul;
171 0 : pd = talloc_get_type(entry->value.ptr, struct pam_data);
172 :
173 0 : ret = hash_lookup(uid_table, &key, &value);
174 :
175 0 : if (ret == HASH_SUCCESS) {
176 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User [%s] is still logged in, "
177 : "trying online authentication.\n", pd->user);
178 :
179 0 : auth_data = talloc_zero(deferred_auth_ctx->be_ctx,
180 : struct auth_data);
181 0 : if (auth_data == NULL) {
182 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
183 : } else {
184 0 : auth_data->pd = talloc_steal(auth_data, pd);
185 0 : auth_data->krb5_ctx = deferred_auth_ctx->krb5_ctx;
186 0 : auth_data->be_ctx = deferred_auth_ctx->be_ctx;
187 :
188 0 : te = tevent_add_timer(deferred_auth_ctx->ev,
189 : auth_data, tevent_timeval_current(),
190 : authenticate_user, auth_data);
191 0 : if (te == NULL) {
192 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
193 : }
194 : }
195 : } else {
196 0 : DEBUG(SSSDBG_CRIT_FAILURE, "User [%s] is not logged in anymore, "
197 : "discarding online authentication.\n", pd->user);
198 0 : talloc_free(pd);
199 : }
200 :
201 0 : ret = hash_delete(deferred_auth_ctx->user_table,
202 : &entry->key);
203 0 : if (ret != HASH_SUCCESS) {
204 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed [%s].\n",
205 : hash_error_string(ret));
206 : }
207 : }
208 :
209 0 : talloc_free(iter);
210 :
211 0 : return EOK;
212 : }
213 :
214 0 : static void delayed_online_authentication_callback(void *private_data)
215 : {
216 0 : struct deferred_auth_ctx *deferred_auth_ctx =
217 : talloc_get_type(private_data, struct deferred_auth_ctx);
218 : int ret;
219 :
220 0 : if (deferred_auth_ctx->user_table == NULL) {
221 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Delayed online authentication activated, "
222 : "but user table does not exists.\n");
223 0 : return;
224 : }
225 :
226 0 : DEBUG(SSSDBG_FUNC_DATA,
227 : "Backend is online, starting delayed online authentication.\n");
228 0 : ret = authenticate_stored_users(deferred_auth_ctx);
229 0 : if (ret != EOK) {
230 0 : DEBUG(SSSDBG_CRIT_FAILURE, "authenticate_stored_users failed.\n");
231 : }
232 :
233 0 : return;
234 : }
235 :
236 0 : errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
237 : struct pam_data *pd,
238 : uid_t uid)
239 : {
240 : int ret;
241 : hash_key_t key;
242 : hash_value_t value;
243 : struct pam_data *new_pd;
244 :
245 0 : if (krb5_ctx->deferred_auth_ctx == NULL) {
246 0 : DEBUG(SSSDBG_CRIT_FAILURE,
247 : "Missing context for delayed online authentication.\n");
248 0 : return EINVAL;
249 : }
250 :
251 0 : if (krb5_ctx->deferred_auth_ctx->user_table == NULL) {
252 0 : DEBUG(SSSDBG_CRIT_FAILURE, "user_table not available.\n");
253 0 : return EINVAL;
254 : }
255 :
256 0 : if (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) {
257 0 : DEBUG(SSSDBG_CRIT_FAILURE,
258 : "Invalid authtok for user [%s].\n", pd->user);
259 0 : return EINVAL;
260 : }
261 :
262 0 : ret = copy_pam_data(krb5_ctx->deferred_auth_ctx, pd, &new_pd);
263 0 : if (ret != EOK) {
264 0 : DEBUG(SSSDBG_CRIT_FAILURE, "copy_pam_data failed\n");
265 0 : return ENOMEM;
266 : }
267 :
268 :
269 : #ifdef USE_KEYRING
270 : const char *password;
271 : size_t len;
272 :
273 0 : ret = sss_authtok_get_password(new_pd->authtok, &password, &len);
274 0 : if (ret) {
275 0 : DEBUG(SSSDBG_CRIT_FAILURE,
276 : "Failed to get password [%d][%s].\n", ret, strerror(ret));
277 0 : sss_authtok_set_empty(new_pd->authtok);
278 0 : talloc_free(new_pd);
279 0 : return ret;
280 : }
281 :
282 0 : new_pd->key_serial = add_key("user", new_pd->user, password, len,
283 : KEY_SPEC_SESSION_KEYRING);
284 0 : if (new_pd->key_serial == -1) {
285 0 : ret = errno;
286 0 : DEBUG(SSSDBG_CRIT_FAILURE,
287 : "add_key failed [%d][%s].\n", ret, strerror(ret));
288 0 : sss_authtok_set_empty(new_pd->authtok);
289 0 : talloc_free(new_pd);
290 0 : return ret;
291 : }
292 0 : DEBUG(SSSDBG_TRACE_ALL,
293 : "Saved authtok of user [%s] with serial [%"SPRIkey_ser"].\n",
294 : new_pd->user, new_pd->key_serial);
295 0 : sss_authtok_set_empty(new_pd->authtok);
296 : #endif
297 :
298 0 : key.type = HASH_KEY_ULONG;
299 0 : key.ul = uid;
300 0 : value.type = HASH_VALUE_PTR;
301 0 : value.ptr = new_pd;
302 :
303 0 : ret = hash_enter(krb5_ctx->deferred_auth_ctx->user_table,
304 : &key, &value);
305 0 : if (ret != HASH_SUCCESS) {
306 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add user [%s] to table [%s], "
307 : "delayed online authentication not possible.\n",
308 : pd->user, hash_error_string(ret));
309 0 : talloc_free(new_pd);
310 0 : return ENOMEM;
311 : }
312 :
313 0 : DEBUG(SSSDBG_TRACE_ALL, "Added user [%s] successfully to "
314 : "delayed online authentication.\n", pd->user);
315 :
316 0 : return EOK;
317 : }
318 :
319 0 : errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx,
320 : struct be_ctx *be_ctx,
321 : struct tevent_context *ev)
322 : {
323 : int ret;
324 : hash_table_t *tmp_table;
325 :
326 0 : ret = get_uid_table(krb5_ctx, &tmp_table);
327 0 : if (ret != EOK) {
328 0 : if (ret == ENOSYS) {
329 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Delayed online auth was requested "
330 : "on an unsupported system.\n");
331 : } else {
332 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Delayed online auth was requested "
333 : "but initialisation failed.\n");
334 : }
335 0 : return ret;
336 : }
337 0 : ret = hash_destroy(tmp_table);
338 0 : if (ret != HASH_SUCCESS) {
339 0 : DEBUG(SSSDBG_CRIT_FAILURE,
340 : "hash_destroy failed [%s].\n", hash_error_string(ret));
341 0 : return EFAULT;
342 : }
343 :
344 0 : krb5_ctx->deferred_auth_ctx = talloc_zero(krb5_ctx,
345 : struct deferred_auth_ctx);
346 0 : if (krb5_ctx->deferred_auth_ctx == NULL) {
347 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
348 0 : return ENOMEM;
349 : }
350 :
351 0 : ret = hash_create_ex(INITIAL_USER_TABLE_SIZE,
352 0 : &krb5_ctx->deferred_auth_ctx->user_table,
353 : 0, 0, 0, 0, hash_talloc, hash_talloc_free,
354 0 : krb5_ctx->deferred_auth_ctx,
355 : NULL, NULL);
356 0 : if (ret != HASH_SUCCESS) {
357 0 : DEBUG(SSSDBG_CRIT_FAILURE,
358 : "hash_create_ex failed [%s]\n", hash_error_string(ret));
359 0 : ret = ENOMEM;
360 0 : goto fail;
361 : }
362 :
363 0 : krb5_ctx->deferred_auth_ctx->be_ctx = be_ctx;
364 0 : krb5_ctx->deferred_auth_ctx->krb5_ctx = krb5_ctx;
365 0 : krb5_ctx->deferred_auth_ctx->ev = ev;
366 :
367 0 : ret = be_add_online_cb(krb5_ctx, be_ctx,
368 : delayed_online_authentication_callback,
369 0 : krb5_ctx->deferred_auth_ctx, NULL);
370 0 : if (ret != EOK) {
371 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_add_online_cb failed.\n");
372 0 : goto fail;
373 : }
374 :
375 : /* TODO: add destructor */
376 :
377 0 : return EOK;
378 : fail:
379 0 : talloc_zfree(krb5_ctx->deferred_auth_ctx);
380 0 : return ret;
381 : }
|