Line data Source code
1 : /*
2 : SSSD
3 :
4 : Kerberos 5 Backend Module -- Renew a TGT automatically
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 : #include <security/pam_modules.h>
25 :
26 : #include "util/util.h"
27 : #include "providers/krb5/krb5_common.h"
28 : #include "providers/krb5/krb5_auth.h"
29 : #include "providers/krb5/krb5_utils.h"
30 : #include "providers/krb5/krb5_ccache.h"
31 :
32 : #define INITIAL_TGT_TABLE_SIZE 10
33 :
34 : struct renew_tgt_ctx {
35 : hash_table_t *tgt_table;
36 : struct be_ctx *be_ctx;
37 : struct tevent_context *ev;
38 : struct krb5_ctx *krb5_ctx;
39 : time_t timer_interval;
40 : struct tevent_timer *te;
41 : };
42 :
43 : struct renew_data {
44 : const char *ccfile;
45 : time_t start_time;
46 : time_t lifetime;
47 : time_t start_renew_at;
48 : struct pam_data *pd;
49 : };
50 :
51 : struct auth_data {
52 : struct be_ctx *be_ctx;
53 : struct krb5_ctx *krb5_ctx;
54 : struct pam_data *pd;
55 : struct renew_data *renew_data;
56 : hash_table_t *table;
57 : hash_key_t key;
58 : };
59 :
60 :
61 : static void renew_tgt_done(struct tevent_req *req);
62 0 : static void renew_tgt(struct tevent_context *ev, struct tevent_timer *te,
63 : struct timeval current_time, void *private_data)
64 : {
65 0 : struct auth_data *auth_data = talloc_get_type(private_data,
66 : struct auth_data);
67 : struct tevent_req *req;
68 :
69 0 : req = krb5_auth_queue_send(auth_data, ev, auth_data->be_ctx, auth_data->pd,
70 : auth_data->krb5_ctx);
71 0 : if (req == NULL) {
72 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth_send failed.\n");
73 : /* Give back the pam data to the renewal item to be able to retry at the next
74 : * time the renewals re run. */
75 0 : auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
76 : auth_data->pd);
77 0 : talloc_free(auth_data);
78 0 : return;
79 : }
80 :
81 0 : tevent_req_set_callback(req, renew_tgt_done, auth_data);
82 : }
83 :
84 0 : static void renew_tgt_done(struct tevent_req *req)
85 : {
86 0 : struct auth_data *auth_data = tevent_req_callback_data(req,
87 : struct auth_data);
88 : int ret;
89 0 : int pam_status = PAM_SYSTEM_ERR;
90 : int dp_err;
91 : hash_value_t value;
92 :
93 0 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
94 0 : talloc_free(req);
95 0 : if (ret) {
96 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_auth request failed.\n");
97 0 : if (auth_data->renew_data != NULL) {
98 0 : DEBUG(SSSDBG_FUNC_DATA, "Giving back pam data.\n");
99 0 : auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
100 : auth_data->pd);
101 : }
102 : } else {
103 0 : switch (pam_status) {
104 : case PAM_SUCCESS:
105 0 : DEBUG(SSSDBG_CONF_SETTINGS,
106 : "Successfully renewed TGT for user [%s].\n",
107 : auth_data->pd->user);
108 : /* In general a successful renewal will update the renewal item and free the
109 : * old data. But if the TGT has reached the end of his renewable lifetime it
110 : * will not be put into the list of renewable tickets again. In this case the
111 : * renewal item is not updated and the value from the hash and the one we have
112 : * stored are the same. Since the TGT cannot be renewed anymore we want to
113 : * remove it from the list of renewable tickets. */
114 0 : ret = hash_lookup(auth_data->table, &auth_data->key, &value);
115 0 : if (ret == HASH_SUCCESS) {
116 0 : if (value.type == HASH_VALUE_PTR &&
117 0 : auth_data->renew_data == talloc_get_type(value.ptr,
118 : struct renew_data)) {
119 0 : DEBUG(SSSDBG_FUNC_DATA,
120 : "New TGT was not added for renewal, "
121 : "removing list entry for user [%s].\n",
122 : auth_data->pd->user);
123 0 : ret = hash_delete(auth_data->table, &auth_data->key);
124 0 : if (ret != HASH_SUCCESS) {
125 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
126 : }
127 : }
128 : }
129 0 : break;
130 : case PAM_AUTHINFO_UNAVAIL:
131 : case PAM_AUTHTOK_LOCK_BUSY:
132 0 : DEBUG(SSSDBG_CONF_SETTINGS,
133 : "Cannot renewed TGT for user [%s] while offline, "
134 : "will retry later.\n",
135 : auth_data->pd->user);
136 0 : if (auth_data->renew_data != NULL) {
137 0 : DEBUG(SSSDBG_FUNC_DATA, "Giving back pam data.\n");
138 0 : auth_data->renew_data->pd = talloc_steal(auth_data->renew_data,
139 : auth_data->pd);
140 : }
141 0 : break;
142 : default:
143 0 : DEBUG(SSSDBG_CRIT_FAILURE,
144 : "Failed to renew TGT for user [%s].\n",
145 : auth_data->pd->user);
146 0 : ret = hash_delete(auth_data->table, &auth_data->key);
147 0 : if (ret != HASH_SUCCESS) {
148 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
149 : }
150 : }
151 : }
152 :
153 0 : talloc_zfree(auth_data);
154 0 : }
155 :
156 0 : static errno_t renew_all_tgts(struct renew_tgt_ctx *renew_tgt_ctx)
157 : {
158 : int ret;
159 : hash_entry_t *entries;
160 : unsigned long count;
161 : size_t c;
162 : time_t now;
163 : struct auth_data *auth_data;
164 : struct renew_data *renew_data;
165 0 : struct tevent_timer *te = NULL;
166 :
167 0 : ret = hash_entries(renew_tgt_ctx->tgt_table, &count, &entries);
168 0 : if (ret != HASH_SUCCESS) {
169 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_entries failed.\n");
170 0 : return ENOMEM;
171 : }
172 :
173 0 : now = time(NULL);
174 :
175 0 : for (c = 0; c < count; c++) {
176 0 : renew_data = talloc_get_type(entries[c].value.ptr, struct renew_data);
177 0 : DEBUG(SSSDBG_TRACE_ALL,
178 : "Checking [%s] for renewal at [%.24s].\n", renew_data->ccfile,
179 : ctime(&renew_data->start_renew_at));
180 : /* If renew_data->pd == NULL a renewal request for this data is
181 : * currently running so we skip it. */
182 0 : if (renew_data->start_renew_at < now && renew_data->pd != NULL) {
183 0 : auth_data = talloc_zero(renew_tgt_ctx, struct auth_data);
184 0 : if (auth_data == NULL) {
185 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
186 : } else {
187 : /* We need to steal the pam_data here, because a successful renewal of the
188 : * ticket might add a new renewal item to the list with the same key (upn).
189 : * This would delete renew_data and all its children. But we cannot be sure
190 : * that adding the new renewal item is the last operation of the renewal
191 : * process with access the pam_data. To be on the safe side we steal the
192 : * pam_data and make it a child of auth_data which is only freed after the
193 : * renewal process is finished. In the case of an error during renewal we
194 : * might want to steal the pam_data back to renew_data before freeing
195 : * auth_data to allow a new renewal attempt. */
196 0 : auth_data->pd = talloc_move(auth_data, &renew_data->pd);
197 0 : auth_data->krb5_ctx = renew_tgt_ctx->krb5_ctx;
198 0 : auth_data->be_ctx = renew_tgt_ctx->be_ctx;
199 0 : auth_data->table = renew_tgt_ctx->tgt_table;
200 0 : auth_data->renew_data = renew_data;
201 0 : auth_data->key.type = entries[c].key.type;
202 0 : auth_data->key.str = talloc_strdup(auth_data,
203 0 : entries[c].key.str);
204 0 : if (auth_data->key.str == NULL) {
205 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
206 : } else {
207 0 : te = tevent_add_timer(renew_tgt_ctx->ev,
208 : auth_data, tevent_timeval_current(),
209 : renew_tgt, auth_data);
210 0 : if (te == NULL) {
211 0 : DEBUG(SSSDBG_CRIT_FAILURE,
212 : "tevent_add_timer failed.\n");
213 : }
214 : }
215 : }
216 :
217 0 : if (auth_data == NULL || te == NULL) {
218 0 : DEBUG(SSSDBG_CRIT_FAILURE,
219 : "Failed to renew TGT in [%s].\n", renew_data->ccfile);
220 0 : ret = hash_delete(renew_tgt_ctx->tgt_table, &entries[c].key);
221 0 : if (ret != HASH_SUCCESS) {
222 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_delete failed.\n");
223 : }
224 : }
225 : }
226 : }
227 :
228 0 : talloc_free(entries);
229 :
230 0 : return EOK;
231 : }
232 :
233 : static void renew_handler(struct renew_tgt_ctx *renew_tgt_ctx);
234 :
235 0 : static void renew_tgt_offline_callback(void *private_data)
236 : {
237 0 : struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(private_data,
238 : struct renew_tgt_ctx);
239 :
240 0 : talloc_zfree(renew_tgt_ctx->te);
241 0 : }
242 :
243 0 : static void renew_tgt_online_callback(void *private_data)
244 : {
245 0 : struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(private_data,
246 : struct renew_tgt_ctx);
247 :
248 0 : renew_handler(renew_tgt_ctx);
249 0 : }
250 :
251 0 : static void renew_tgt_timer_handler(struct tevent_context *ev,
252 : struct tevent_timer *te,
253 : struct timeval current_time, void *data)
254 : {
255 0 : struct renew_tgt_ctx *renew_tgt_ctx = talloc_get_type(data,
256 : struct renew_tgt_ctx);
257 :
258 : /* forget the timer event, it will be freed by the tevent timer loop */
259 0 : renew_tgt_ctx->te = NULL;
260 :
261 0 : renew_handler(renew_tgt_ctx);
262 0 : }
263 :
264 0 : static void renew_handler(struct renew_tgt_ctx *renew_tgt_ctx)
265 : {
266 : struct timeval next;
267 : int ret;
268 :
269 0 : if (be_is_offline(renew_tgt_ctx->be_ctx)) {
270 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Offline, disable renew timer.\n");
271 0 : return;
272 : }
273 :
274 0 : ret = renew_all_tgts(renew_tgt_ctx);
275 0 : if (ret != EOK) {
276 0 : DEBUG(SSSDBG_CRIT_FAILURE, "renew_all_tgts failed. "
277 : "Disabling automatic TGT renewal\n");
278 0 : sss_log(SSS_LOG_ERR, "Disabling automatic TGT renewal.");
279 0 : talloc_zfree(renew_tgt_ctx);
280 0 : return;
281 : }
282 :
283 0 : if (renew_tgt_ctx->te != NULL) {
284 0 : DEBUG(SSSDBG_TRACE_LIBS,
285 : "There is an active renewal timer, doing nothing.\n");
286 0 : return;
287 : }
288 :
289 0 : DEBUG(SSSDBG_TRACE_LIBS, "Adding new renew timer.\n");
290 :
291 0 : next = tevent_timeval_current_ofs(renew_tgt_ctx->timer_interval,
292 : 0);
293 0 : renew_tgt_ctx->te = tevent_add_timer(renew_tgt_ctx->ev, renew_tgt_ctx,
294 : next, renew_tgt_timer_handler,
295 : renew_tgt_ctx);
296 0 : if (renew_tgt_ctx->te == NULL) {
297 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
298 0 : sss_log(SSS_LOG_ERR, "Disabling automatic TGT renewal.");
299 0 : talloc_zfree(renew_tgt_ctx);
300 : }
301 :
302 0 : return;
303 : }
304 :
305 0 : static void renew_del_cb(hash_entry_t *entry, hash_destroy_enum type, void *pvt)
306 : {
307 : struct renew_data *renew_data;
308 :
309 0 : if (entry->value.type == HASH_VALUE_PTR) {
310 0 : renew_data = talloc_get_type(entry->value.ptr, struct renew_data);
311 0 : talloc_zfree(renew_data);
312 0 : return;
313 : }
314 :
315 0 : DEBUG(SSSDBG_CRIT_FAILURE,
316 : "Unexpected value type [%d].\n", entry->value.type);
317 : }
318 :
319 0 : static errno_t check_ccache_file(struct renew_tgt_ctx *renew_tgt_ctx,
320 : const char *ccache_file, const char *upn,
321 : const char *user_name)
322 : {
323 : int ret;
324 : struct stat stat_buf;
325 : struct tgt_times tgtt;
326 : struct pam_data pd;
327 : time_t now;
328 : const char *filename;
329 :
330 0 : if (ccache_file == NULL || upn == NULL || user_name == NULL) {
331 0 : DEBUG(SSSDBG_TRACE_FUNC,
332 : "Missing one of the needed attributes: [%s][%s][%s].\n",
333 : ccache_file == NULL ? "cache file missing" : ccache_file,
334 : upn == NULL ? "principal missing" : upn,
335 : user_name == NULL ? "user name missing" : user_name);
336 0 : return EINVAL;
337 : }
338 :
339 0 : if (strncmp(ccache_file, "FILE:", 5) == 0) {
340 0 : filename = ccache_file + 5;
341 : } else {
342 0 : filename = ccache_file;
343 : }
344 :
345 0 : ret = stat(filename, &stat_buf);
346 0 : if (ret != EOK) {
347 0 : if (ret == ENOENT) {
348 0 : return EOK;
349 : }
350 0 : return ret;
351 : }
352 :
353 0 : DEBUG(SSSDBG_TRACE_ALL, "Found ccache file [%s].\n", ccache_file);
354 :
355 0 : memset(&tgtt, 0, sizeof(tgtt));
356 0 : ret = get_ccache_file_data(ccache_file, upn, &tgtt);
357 0 : if (ret != EOK) {
358 0 : DEBUG(SSSDBG_CRIT_FAILURE, "get_ccache_file_data failed.\n");
359 0 : return ret;
360 : }
361 :
362 0 : memset(&pd, 0, sizeof(pd));
363 0 : pd.cmd = SSS_CMD_RENEW;
364 0 : pd.user = discard_const_p(char, user_name);
365 0 : now = time(NULL);
366 0 : if (tgtt.renew_till > tgtt.endtime && tgtt.renew_till > now &&
367 0 : tgtt.endtime > now) {
368 0 : DEBUG(SSSDBG_TRACE_LIBS,
369 : "Adding [%s] for automatic renewal.\n", ccache_file);
370 0 : ret = add_tgt_to_renew_table(renew_tgt_ctx->krb5_ctx, ccache_file,
371 : &tgtt, &pd, upn);
372 0 : if (ret != EOK) {
373 0 : DEBUG(SSSDBG_CRIT_FAILURE, "add_tgt_to_renew_table failed, "
374 : "automatic renewal not possible.\n");
375 : }
376 : } else {
377 0 : DEBUG(SSSDBG_TRACE_ALL,
378 : "TGT in [%s] for [%s] is too old.\n", ccache_file, upn);
379 : }
380 :
381 0 : return EOK;
382 : }
383 :
384 0 : static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
385 : {
386 : TALLOC_CTX *tmp_ctx;
387 : int ret;
388 0 : const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)" \
389 : "("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS"))";
390 0 : const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME,
391 : SYSDB_CANONICAL_UPN, NULL };
392 0 : size_t msgs_count = 0;
393 0 : struct ldb_message **msgs = NULL;
394 : size_t c;
395 : const char *ccache_file;
396 : char *upn;
397 : const char *user_name;
398 : struct ldb_dn *base_dn;
399 : const struct ldb_val *user_dom_val;
400 : char *user_dom;
401 :
402 0 : tmp_ctx = talloc_new(NULL);
403 0 : if (tmp_ctx == NULL) {
404 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
405 0 : return ENOMEM;
406 : }
407 :
408 0 : base_dn = sysdb_base_dn(renew_tgt_ctx->be_ctx->domain->sysdb, tmp_ctx);
409 0 : if (base_dn == NULL) {
410 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n");
411 0 : ret = ENOMEM;
412 0 : goto done;
413 : }
414 :
415 0 : ret = sysdb_search_entry(tmp_ctx, renew_tgt_ctx->be_ctx->domain->sysdb, base_dn,
416 : LDB_SCOPE_SUBTREE, ccache_filter, ccache_attrs,
417 : &msgs_count, &msgs);
418 0 : if (ret != EOK) {
419 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry failed.\n");
420 0 : goto done;
421 : }
422 :
423 0 : if (msgs_count == 0) {
424 0 : DEBUG(SSSDBG_TRACE_ALL,
425 : "No entries with ccache file found in cache.\n");
426 0 : ret = EOK;
427 0 : goto done;
428 : }
429 0 : DEBUG(SSSDBG_TRACE_ALL,
430 : "Found [%zu] entries with ccache file in cache.\n", msgs_count);
431 :
432 0 : for (c = 0; c < msgs_count; c++) {
433 0 : user_name = ldb_msg_find_attr_as_string(msgs[c], SYSDB_NAME, NULL);
434 0 : if (user_name == NULL) {
435 0 : DEBUG(SSSDBG_CRIT_FAILURE,
436 : "No user name found, this is a severe error, "
437 : "but we ignore it here.\n");
438 0 : continue;
439 : }
440 :
441 : /* The DNs of users in sysdb looks like
442 : * name=username,cn=users,cn=domain.name,cn=sysdb
443 : * the value of the third component (index 2) is the domain name. */
444 :
445 0 : user_dom_val = ldb_dn_get_component_val(msgs[c]->dn, 2);
446 0 : if (user_dom_val == NULL) {
447 0 : DEBUG(SSSDBG_OP_FAILURE, "Invalid user DN [%s].\n",
448 : ldb_dn_get_linearized(msgs[c]->dn));
449 0 : ret = EINVAL;
450 0 : goto done;
451 : }
452 0 : user_dom = talloc_strndup(tmp_ctx, (char *) user_dom_val->data,
453 : user_dom_val->length);
454 0 : if (user_dom == NULL) {
455 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed,\n");
456 0 : ret = ENOMEM;
457 0 : goto done;
458 : }
459 :
460 0 : ret = find_or_guess_upn(tmp_ctx, msgs[c], renew_tgt_ctx->krb5_ctx,
461 0 : renew_tgt_ctx->be_ctx->domain,
462 : user_name, user_dom, &upn);
463 0 : if (ret != EOK) {
464 0 : DEBUG(SSSDBG_OP_FAILURE, "find_or_guess_upn failed.\n");
465 0 : goto done;
466 : }
467 :
468 0 : ccache_file = ldb_msg_find_attr_as_string(msgs[c], SYSDB_CCACHE_FILE,
469 : NULL);
470 :
471 0 : ret = check_ccache_file(renew_tgt_ctx, ccache_file, upn, user_name);
472 0 : if (ret != EOK) {
473 0 : DEBUG(SSSDBG_FUNC_DATA,
474 : "Failed to check ccache file [%s].\n", ccache_file);
475 : }
476 : }
477 :
478 0 : ret = EOK;
479 :
480 : done:
481 0 : talloc_free(tmp_ctx);
482 :
483 0 : return ret;
484 : }
485 :
486 0 : errno_t init_renew_tgt(struct krb5_ctx *krb5_ctx, struct be_ctx *be_ctx,
487 : struct tevent_context *ev, time_t renew_intv)
488 : {
489 : int ret;
490 : struct timeval next;
491 :
492 0 : krb5_ctx->renew_tgt_ctx = talloc_zero(krb5_ctx, struct renew_tgt_ctx);
493 0 : if (krb5_ctx->renew_tgt_ctx == NULL) {
494 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
495 0 : return ENOMEM;
496 : }
497 :
498 0 : ret = sss_hash_create_ex(krb5_ctx->renew_tgt_ctx, INITIAL_TGT_TABLE_SIZE,
499 0 : &krb5_ctx->renew_tgt_ctx->tgt_table, 0, 0, 0, 0,
500 : renew_del_cb, NULL);
501 0 : if (ret != EOK) {
502 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_hash_create failed.\n");
503 0 : goto fail;
504 : }
505 :
506 0 : krb5_ctx->renew_tgt_ctx->be_ctx = be_ctx;
507 0 : krb5_ctx->renew_tgt_ctx->krb5_ctx = krb5_ctx;
508 0 : krb5_ctx->renew_tgt_ctx->ev = ev;
509 0 : krb5_ctx->renew_tgt_ctx->timer_interval = renew_intv;
510 :
511 0 : ret = check_ccache_files(krb5_ctx->renew_tgt_ctx);
512 0 : if (ret != EOK) {
513 0 : DEBUG(SSSDBG_CRIT_FAILURE,
514 : "Failed to read ccache files, continuing ...\n");
515 : }
516 :
517 0 : next = tevent_timeval_current_ofs(krb5_ctx->renew_tgt_ctx->timer_interval,
518 : 0);
519 0 : krb5_ctx->renew_tgt_ctx->te = tevent_add_timer(ev, krb5_ctx->renew_tgt_ctx,
520 : next, renew_tgt_timer_handler,
521 : krb5_ctx->renew_tgt_ctx);
522 0 : if (krb5_ctx->renew_tgt_ctx->te == NULL) {
523 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
524 0 : ret = ENOMEM;
525 0 : goto fail;
526 : }
527 :
528 0 : DEBUG(SSSDBG_TRACE_LIBS,
529 : "Adding offline callback to remove renewal timer.\n");
530 0 : ret = be_add_offline_cb(krb5_ctx->renew_tgt_ctx, be_ctx,
531 0 : renew_tgt_offline_callback, krb5_ctx->renew_tgt_ctx,
532 : NULL);
533 0 : if (ret != EOK) {
534 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add offline callback.\n");
535 0 : goto fail;
536 : }
537 :
538 0 : DEBUG(SSSDBG_TRACE_LIBS, "Adding renewal task to online callbacks.\n");
539 0 : ret = be_add_online_cb(krb5_ctx->renew_tgt_ctx, be_ctx,
540 0 : renew_tgt_online_callback, krb5_ctx->renew_tgt_ctx,
541 : NULL);
542 0 : if (ret != EOK) {
543 0 : DEBUG(SSSDBG_CRIT_FAILURE,
544 : "Failed to add renewal task to online callbacks.\n");
545 0 : goto fail;
546 : }
547 :
548 0 : return EOK;
549 :
550 : fail:
551 0 : talloc_zfree(krb5_ctx->renew_tgt_ctx);
552 0 : return ret;
553 : }
554 :
555 0 : errno_t add_tgt_to_renew_table(struct krb5_ctx *krb5_ctx, const char *ccfile,
556 : struct tgt_times *tgtt, struct pam_data *pd,
557 : const char *upn)
558 : {
559 : int ret;
560 : hash_key_t key;
561 : hash_value_t value;
562 0 : struct renew_data *renew_data = NULL;
563 :
564 0 : if (krb5_ctx->renew_tgt_ctx == NULL) {
565 0 : DEBUG(SSSDBG_TRACE_LIBS ,"Renew context not initialized, "
566 : "automatic renewal not available.\n");
567 0 : return EOK;
568 : }
569 :
570 0 : if (pd->cmd != SSS_PAM_AUTHENTICATE && pd->cmd != SSS_CMD_RENEW &&
571 0 : pd->cmd != SSS_PAM_CHAUTHTOK) {
572 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected pam task [%d].\n", pd->cmd);
573 0 : return EINVAL;
574 : }
575 :
576 0 : if (upn == NULL) {
577 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing user principal name.\n");
578 0 : return EINVAL;
579 : }
580 :
581 : /* hash_enter copies the content of the hash string, so it is safe to use
582 : * discard_const_p here. */
583 0 : key.type = HASH_KEY_STRING;
584 0 : key.str = discard_const_p(char, upn);
585 :
586 0 : renew_data = talloc_zero(krb5_ctx->renew_tgt_ctx, struct renew_data);
587 0 : if (renew_data == NULL) {
588 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
589 0 : ret = ENOMEM;
590 0 : goto done;
591 : }
592 :
593 0 : if (ccfile[0] == '/') {
594 0 : renew_data->ccfile = talloc_asprintf(renew_data, "FILE:%s", ccfile);
595 0 : if (renew_data->ccfile == NULL) {
596 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
597 0 : ret = ENOMEM;
598 0 : goto done;
599 : }
600 : } else {
601 0 : renew_data->ccfile = talloc_strdup(renew_data, ccfile);
602 : }
603 :
604 0 : renew_data->start_time = tgtt->starttime;
605 0 : renew_data->lifetime = tgtt->endtime;
606 0 : renew_data->start_renew_at = (time_t) (tgtt->starttime +
607 0 : 0.5 *(tgtt->endtime - tgtt->starttime));
608 :
609 0 : ret = copy_pam_data(renew_data, pd, &renew_data->pd);
610 0 : if (ret != EOK) {
611 0 : DEBUG(SSSDBG_CRIT_FAILURE, "copy_pam_data failed.\n");
612 0 : goto done;
613 : }
614 :
615 0 : sss_authtok_set_empty(renew_data->pd->newauthtok);
616 :
617 0 : ret = sss_authtok_set_ccfile(renew_data->pd->authtok, renew_data->ccfile, 0);
618 0 : if (ret) {
619 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to store ccfile in auth token.\n");
620 0 : goto done;
621 : }
622 :
623 0 : renew_data->pd->cmd = SSS_CMD_RENEW;
624 :
625 0 : value.type = HASH_VALUE_PTR;
626 0 : value.ptr = renew_data;
627 :
628 0 : ret = hash_enter(krb5_ctx->renew_tgt_ctx->tgt_table, &key, &value);
629 0 : if (ret != HASH_SUCCESS) {
630 0 : DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n");
631 0 : ret = EFAULT;
632 0 : goto done;
633 : }
634 :
635 0 : DEBUG(SSSDBG_TRACE_LIBS,
636 : "Added [%s] for renewal at [%.24s].\n", renew_data->ccfile,
637 : ctime(&renew_data->start_renew_at));
638 :
639 0 : ret = EOK;
640 :
641 : done:
642 0 : if (ret != EOK) {
643 0 : talloc_free(renew_data);
644 : }
645 0 : return ret;
646 : }
|