Line data Source code
1 : /*
2 : SSSD
3 :
4 : Kerberos 5 Backend Module -- ccache related utilities
5 :
6 : Authors:
7 : Sumit Bose <sbose@redhat.com>
8 : Jakub Hrozek <jhrozek@redhat.com>
9 :
10 : Copyright (C) 2014 Red Hat
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #ifdef HAVE_KRB5_KRB5_H
27 : #include <krb5/krb5.h>
28 : #else
29 : #include <krb5.h>
30 : #endif
31 :
32 : #include "providers/krb5/krb5_ccache.h"
33 : #include "util/sss_krb5.h"
34 : #include "util/util.h"
35 :
36 : struct string_list {
37 : struct string_list *next;
38 : struct string_list *prev;
39 : char *s;
40 : };
41 :
42 4 : static errno_t find_ccdir_parent_data(TALLOC_CTX *mem_ctx,
43 : const char *ccdirname,
44 : struct stat *parent_stat,
45 : struct string_list **missing_parents)
46 : {
47 4 : int ret = EFAULT;
48 4 : char *parent = NULL;
49 : char *end;
50 : struct string_list *li;
51 :
52 4 : ret = stat(ccdirname, parent_stat);
53 4 : if (ret == EOK) {
54 2 : if ( !S_ISDIR(parent_stat->st_mode) ) {
55 0 : DEBUG(SSSDBG_MINOR_FAILURE,
56 : "[%s] is not a directory.\n", ccdirname);
57 0 : return EINVAL;
58 : }
59 2 : return EOK;
60 : } else {
61 2 : if (errno != ENOENT) {
62 0 : ret = errno;
63 0 : DEBUG(SSSDBG_MINOR_FAILURE,
64 : "stat for [%s] failed: [%d][%s].\n", ccdirname, ret,
65 : strerror(ret));
66 0 : return ret;
67 : }
68 : }
69 :
70 2 : li = talloc_zero(mem_ctx, struct string_list);
71 2 : if (li == NULL) {
72 0 : DEBUG(SSSDBG_CRIT_FAILURE,
73 : "talloc_zero failed.\n");
74 0 : return ENOMEM;
75 : }
76 :
77 2 : li->s = talloc_strdup(li, ccdirname);
78 2 : if (li->s == NULL) {
79 0 : DEBUG(SSSDBG_CRIT_FAILURE,
80 : "talloc_strdup failed.\n");
81 0 : return ENOMEM;
82 : }
83 :
84 2 : DLIST_ADD(*missing_parents, li);
85 :
86 2 : parent = talloc_strdup(mem_ctx, ccdirname);
87 2 : if (parent == NULL) {
88 0 : DEBUG(SSSDBG_CRIT_FAILURE,
89 : "talloc_strdup failed.\n");
90 0 : return ENOMEM;
91 : }
92 :
93 : /* We'll remove all trailing slashes from the back so that
94 : * we only pass /some/path to find_ccdir_parent_data, not
95 : * /some/path */
96 : do {
97 2 : end = strrchr(parent, '/');
98 2 : if (end == NULL || end == parent) {
99 0 : DEBUG(SSSDBG_MINOR_FAILURE,
100 : "Cannot find parent directory of [%s], / is not allowed.\n",
101 : ccdirname);
102 0 : ret = EINVAL;
103 0 : goto done;
104 : }
105 2 : *end = '\0';
106 2 : } while (*(end+1) == '\0');
107 :
108 2 : ret = find_ccdir_parent_data(mem_ctx, parent, parent_stat, missing_parents);
109 :
110 : done:
111 2 : talloc_free(parent);
112 2 : return ret;
113 : }
114 :
115 2 : static errno_t check_parent_stat(struct stat *parent_stat, uid_t uid)
116 : {
117 2 : if (parent_stat->st_uid != 0 && parent_stat->st_uid != uid) {
118 0 : DEBUG(SSSDBG_CRIT_FAILURE,
119 : "Private directory can only be created below a directory "
120 : "belonging to root or to [%"SPRIuid"].\n", uid);
121 0 : return EINVAL;
122 : }
123 :
124 2 : if (parent_stat->st_uid == uid) {
125 2 : if (!(parent_stat->st_mode & S_IXUSR)) {
126 0 : DEBUG(SSSDBG_CRIT_FAILURE,
127 : "Parent directory does not have the search bit set for "
128 : "the owner.\n");
129 0 : return EINVAL;
130 : }
131 : } else {
132 0 : if (!(parent_stat->st_mode & S_IXOTH)) {
133 0 : DEBUG(SSSDBG_CRIT_FAILURE,
134 : "Parent directory does not have the search bit set for "
135 : "others.\n");
136 0 : return EINVAL;
137 : }
138 : }
139 :
140 2 : return EOK;
141 : }
142 :
143 2 : static errno_t create_ccache_dir(const char *ccdirname, uid_t uid, gid_t gid)
144 : {
145 2 : int ret = EFAULT;
146 : struct stat parent_stat;
147 2 : struct string_list *missing_parents = NULL;
148 2 : struct string_list *li = NULL;
149 : mode_t old_umask;
150 : mode_t new_dir_mode;
151 2 : TALLOC_CTX *tmp_ctx = NULL;
152 :
153 2 : tmp_ctx = talloc_new(NULL);
154 2 : if (tmp_ctx == NULL) {
155 0 : DEBUG(SSSDBG_CRIT_FAILURE,
156 : "talloc_new failed.\n");
157 0 : return ENOMEM;
158 : }
159 :
160 2 : if (*ccdirname != '/') {
161 0 : DEBUG(SSSDBG_MINOR_FAILURE,
162 : "Only absolute paths are allowed, not [%s] .\n", ccdirname);
163 0 : ret = EINVAL;
164 0 : goto done;
165 : }
166 :
167 2 : ret = find_ccdir_parent_data(tmp_ctx, ccdirname, &parent_stat,
168 : &missing_parents);
169 2 : if (ret != EOK) {
170 0 : DEBUG(SSSDBG_MINOR_FAILURE,
171 : "find_ccdir_parent_data failed.\n");
172 0 : goto done;
173 : }
174 :
175 2 : ret = check_parent_stat(&parent_stat, uid);
176 2 : if (ret != EOK) {
177 0 : DEBUG(SSSDBG_FATAL_FAILURE,
178 : "Check the ownership and permissions of krb5_ccachedir: [%s].\n",
179 : ccdirname);
180 0 : goto done;
181 : }
182 :
183 4 : DLIST_FOR_EACH(li, missing_parents) {
184 2 : DEBUG(SSSDBG_TRACE_INTERNAL,
185 : "Creating directory [%s].\n", li->s);
186 2 : new_dir_mode = 0700;
187 :
188 2 : old_umask = umask(0000);
189 2 : ret = mkdir(li->s, new_dir_mode);
190 2 : umask(old_umask);
191 2 : if (ret != EOK) {
192 0 : ret = errno;
193 0 : DEBUG(SSSDBG_MINOR_FAILURE,
194 : "mkdir [%s] failed: [%d][%s].\n", li->s, ret,
195 : strerror(ret));
196 0 : goto done;
197 : }
198 2 : ret = chown(li->s, uid, gid);
199 2 : if (ret != EOK) {
200 0 : ret = errno;
201 0 : DEBUG(SSSDBG_MINOR_FAILURE,
202 : "chown failed [%d][%s].\n", ret, strerror(ret));
203 0 : goto done;
204 : }
205 : }
206 :
207 2 : ret = EOK;
208 :
209 : done:
210 2 : talloc_free(tmp_ctx);
211 2 : return ret;
212 : }
213 :
214 2 : errno_t sss_krb5_precreate_ccache(const char *ccname, uid_t uid, gid_t gid)
215 : {
216 2 : TALLOC_CTX *tmp_ctx = NULL;
217 : const char *filename;
218 : char *ccdirname;
219 : char *end;
220 : errno_t ret;
221 :
222 2 : if (ccname[0] == '/') {
223 0 : filename = ccname;
224 2 : } else if (strncmp(ccname, "FILE:", 5) == 0) {
225 0 : filename = ccname + 5;
226 2 : } else if (strncmp(ccname, "DIR:", 4) == 0) {
227 2 : filename = ccname + 4;
228 : } else {
229 : /* only FILE and DIR types need precreation so far, we ignore any
230 : * other type */
231 0 : return EOK;
232 : }
233 :
234 2 : tmp_ctx = talloc_new(NULL);
235 2 : if (!tmp_ctx) return ENOMEM;
236 :
237 2 : ccdirname = talloc_strdup(tmp_ctx, filename);
238 2 : if (ccdirname == NULL) {
239 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n");
240 0 : ret = ENOMEM;
241 0 : goto done;
242 : }
243 :
244 : /* We'll remove all trailing slashes from the back so that
245 : * we only pass /some/path to find_ccdir_parent_data, not
246 : * /some/path/ */
247 : do {
248 3 : end = strrchr(ccdirname, '/');
249 3 : if (end == NULL || end == ccdirname) {
250 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find parent directory of [%s], "
251 : "/ is not allowed.\n", ccdirname);
252 0 : ret = EINVAL;
253 0 : goto done;
254 : }
255 3 : *end = '\0';
256 3 : } while (*(end+1) == '\0');
257 :
258 2 : ret = create_ccache_dir(ccdirname, uid, gid);
259 : done:
260 2 : talloc_free(tmp_ctx);
261 2 : return ret;
262 : }
263 :
264 : struct sss_krb5_ccache {
265 : struct sss_creds *creds;
266 : krb5_context context;
267 : krb5_ccache ccache;
268 : };
269 :
270 0 : static int sss_free_krb5_ccache(void *mem)
271 : {
272 0 : struct sss_krb5_ccache *cc = talloc_get_type(mem, struct sss_krb5_ccache);
273 :
274 0 : if (cc->ccache) {
275 0 : krb5_cc_close(cc->context, cc->ccache);
276 : }
277 0 : krb5_free_context(cc->context);
278 0 : restore_creds(cc->creds);
279 0 : return 0;
280 : }
281 :
282 0 : static errno_t sss_open_ccache_as_user(TALLOC_CTX *mem_ctx,
283 : const char *ccname,
284 : uid_t uid, gid_t gid,
285 : struct sss_krb5_ccache **ccache)
286 : {
287 : struct sss_krb5_ccache *cc;
288 : krb5_error_code kerr;
289 : errno_t ret;
290 :
291 0 : cc = talloc_zero(mem_ctx, struct sss_krb5_ccache);
292 0 : if (!cc) {
293 0 : return ENOMEM;
294 : }
295 0 : talloc_set_destructor((TALLOC_CTX *)cc, sss_free_krb5_ccache);
296 :
297 0 : ret = switch_creds(cc, uid, gid, 0, NULL, &cc->creds);
298 0 : if (ret) {
299 0 : goto done;
300 : }
301 :
302 0 : kerr = krb5_init_context(&cc->context);
303 0 : if (kerr) {
304 0 : ret = EIO;
305 0 : goto done;
306 : }
307 :
308 0 : kerr = krb5_cc_resolve(cc->context, ccname, &cc->ccache);
309 0 : if (kerr == KRB5_FCC_NOFILE || cc->ccache == NULL) {
310 0 : DEBUG(SSSDBG_TRACE_FUNC, "ccache %s is missing or empty\n", ccname);
311 0 : ret = ERR_NOT_FOUND;
312 0 : goto done;
313 0 : } else if (kerr != 0) {
314 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
315 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
316 0 : ret = ERR_INTERNAL;
317 0 : goto done;
318 : }
319 :
320 0 : ret = EOK;
321 :
322 : done:
323 0 : if (ret) {
324 0 : talloc_free(cc);
325 : } else {
326 0 : *ccache = cc;
327 : }
328 0 : return ret;
329 : }
330 :
331 0 : static errno_t sss_destroy_ccache(struct sss_krb5_ccache *cc)
332 : {
333 : krb5_error_code kerr;
334 : errno_t ret;
335 :
336 0 : kerr = krb5_cc_destroy(cc->context, cc->ccache);
337 0 : if (kerr) {
338 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, cc->context, kerr);
339 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_destroy failed.\n");
340 0 : ret = EIO;
341 : } else {
342 0 : ret = EOK;
343 : }
344 :
345 : /* krb5_cc_destroy frees cc->ccache in all events */
346 0 : cc->ccache = NULL;
347 :
348 0 : return ret;
349 : }
350 :
351 0 : errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid)
352 : {
353 0 : struct sss_krb5_ccache *cc = NULL;
354 : TALLOC_CTX *tmp_ctx;
355 : errno_t ret;
356 :
357 0 : if (ccname == NULL) {
358 : /* nothing to remove */
359 0 : return EOK;
360 : }
361 :
362 0 : tmp_ctx = talloc_new(NULL);
363 0 : if (tmp_ctx == NULL) {
364 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
365 0 : return ENOMEM;
366 : }
367 :
368 0 : ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
369 0 : if (ret) {
370 0 : goto done;
371 : }
372 :
373 0 : ret = sss_destroy_ccache(cc);
374 :
375 : done:
376 0 : talloc_free(tmp_ctx);
377 0 : return ret;
378 : }
379 :
380 : /* This function is called only as a way to validate that we have the
381 : * right cache */
382 0 : errno_t sss_krb5_check_ccache_princ(krb5_context kctx,
383 : const char *ccname,
384 : krb5_principal user_princ)
385 : {
386 0 : krb5_ccache kcc = NULL;
387 0 : krb5_principal ccprinc = NULL;
388 : krb5_error_code kerr;
389 : const char *cc_type;
390 : errno_t ret;
391 :
392 0 : kerr = krb5_cc_resolve(kctx, ccname, &kcc);
393 0 : if (kerr) {
394 0 : ret = ERR_INTERNAL;
395 0 : goto done;
396 : }
397 :
398 0 : cc_type = krb5_cc_get_type(kctx, kcc);
399 :
400 0 : kerr = krb5_cc_get_principal(kctx, kcc, &ccprinc);
401 0 : if (kerr != 0) {
402 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, kctx, kerr);
403 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_get_principal failed.\n");
404 : }
405 :
406 0 : if (ccprinc) {
407 0 : if (krb5_principal_compare(kctx, user_princ, ccprinc) == TRUE) {
408 : /* found in the primary ccache */
409 0 : ret = EOK;
410 0 : goto done;
411 : }
412 : }
413 :
414 : #ifdef HAVE_KRB5_CC_COLLECTION
415 :
416 0 : if (krb5_cc_support_switch(kctx, cc_type)) {
417 :
418 0 : krb5_cc_close(kctx, kcc);
419 0 : kcc = NULL;
420 :
421 0 : kerr = krb5_cc_set_default_name(kctx, ccname);
422 0 : if (kerr != 0) {
423 0 : KRB5_DEBUG(SSSDBG_MINOR_FAILURE, kctx, kerr);
424 : /* try to continue despite failure */
425 : }
426 :
427 0 : kerr = krb5_cc_cache_match(kctx, user_princ, &kcc);
428 0 : if (kerr == 0) {
429 0 : ret = EOK;
430 0 : goto done;
431 : }
432 0 : KRB5_DEBUG(SSSDBG_TRACE_INTERNAL, kctx, kerr);
433 : }
434 :
435 : #endif /* HAVE_KRB5_CC_COLLECTION */
436 :
437 0 : ret = ERR_NOT_FOUND;
438 :
439 : done:
440 0 : if (ccprinc) {
441 0 : krb5_free_principal(kctx, ccprinc);
442 : }
443 0 : if (kcc) {
444 0 : krb5_cc_close(kctx, kcc);
445 : }
446 0 : return ret;
447 : }
448 :
449 0 : static errno_t sss_low_level_path_check(const char *ccname)
450 : {
451 : const char *filename;
452 : struct stat buf;
453 : int ret;
454 :
455 0 : if (ccname[0] == '/') {
456 0 : filename = ccname;
457 0 : } else if (strncmp(ccname, "FILE:", 5) == 0) {
458 0 : filename = ccname + 5;
459 0 : } else if (strncmp(ccname, "DIR:", 4) == 0) {
460 0 : filename = ccname + 4;
461 0 : if (filename[0] == ':') filename += 1;
462 : } else {
463 : /* only FILE and DIR types need file checks so far, we ignore any
464 : * other type */
465 0 : return EOK;
466 : }
467 :
468 0 : ret = stat(filename, &buf);
469 0 : if (ret == -1) return errno;
470 0 : return EOK;
471 : }
472 :
473 0 : errno_t sss_krb5_cc_verify_ccache(const char *ccname, uid_t uid, gid_t gid,
474 : const char *realm, const char *principal)
475 : {
476 0 : struct sss_krb5_ccache *cc = NULL;
477 0 : TALLOC_CTX *tmp_ctx = NULL;
478 0 : krb5_principal tgt_princ = NULL;
479 0 : krb5_principal princ = NULL;
480 : char *tgt_name;
481 0 : krb5_creds mcred = { 0 };
482 0 : krb5_creds cred = { 0 };
483 : krb5_error_code kerr;
484 : errno_t ret;
485 :
486 : /* first of all verify if the old ccache file/dir exists as we may be
487 : * trying to verify if an old ccache exists at all. If no file/dir
488 : * exists bail out immediately otherwise a following krb5_cc_resolve()
489 : * call may actually create paths and files we do not want to have
490 : * around */
491 0 : ret = sss_low_level_path_check(ccname);
492 0 : if (ret) {
493 0 : return ret;
494 : }
495 :
496 0 : tmp_ctx = talloc_new(NULL);
497 0 : if (tmp_ctx == NULL) {
498 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
499 0 : return ENOMEM;
500 : }
501 :
502 0 : ret = sss_open_ccache_as_user(tmp_ctx, ccname, uid, gid, &cc);
503 0 : if (ret) {
504 0 : goto done;
505 : }
506 :
507 0 : tgt_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
508 0 : if (!tgt_name) {
509 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
510 0 : ret = ENOMEM;
511 0 : goto done;
512 : }
513 :
514 0 : kerr = krb5_parse_name(cc->context, tgt_name, &tgt_princ);
515 0 : if (kerr) {
516 0 : KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
517 0 : if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
518 0 : else ret = ERR_INTERNAL;
519 0 : goto done;
520 : }
521 :
522 0 : kerr = krb5_parse_name(cc->context, principal, &princ);
523 0 : if (kerr) {
524 0 : KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
525 0 : if (kerr == KRB5_PARSE_MALFORMED) ret = EINVAL;
526 0 : else ret = ERR_INTERNAL;
527 0 : goto done;
528 : }
529 :
530 0 : mcred.client = princ;
531 0 : mcred.server = tgt_princ;
532 0 : mcred.times.endtime = time(NULL);
533 :
534 0 : kerr = krb5_cc_retrieve_cred(cc->context, cc->ccache,
535 : KRB5_TC_MATCH_TIMES, &mcred, &cred);
536 0 : if (kerr) {
537 0 : if (kerr == KRB5_CC_NOTFOUND || kerr == KRB5_FCC_NOFILE) {
538 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "TGT not found or expired.\n");
539 0 : ret = EINVAL;
540 : } else {
541 0 : KRB5_DEBUG(SSSDBG_CRIT_FAILURE, cc->context, kerr);
542 0 : ret = ERR_INTERNAL;
543 : }
544 : }
545 0 : krb5_free_cred_contents(cc->context, &cred);
546 :
547 : done:
548 0 : if (tgt_princ) krb5_free_principal(cc->context, tgt_princ);
549 0 : if (princ) krb5_free_principal(cc->context, princ);
550 0 : talloc_free(tmp_ctx);
551 0 : return ret;
552 : }
553 :
554 0 : errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
555 : struct tgt_times *tgtt)
556 : {
557 : krb5_error_code kerr;
558 0 : krb5_context ctx = NULL;
559 0 : krb5_ccache cc = NULL;
560 0 : krb5_principal client_princ = NULL;
561 0 : krb5_principal server_princ = NULL;
562 : char *server_name;
563 : krb5_creds mcred;
564 : krb5_creds cred;
565 : const char *realm_name;
566 : int realm_length;
567 :
568 0 : kerr = krb5_init_context(&ctx);
569 0 : if (kerr != 0) {
570 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n");
571 0 : goto done;
572 : }
573 :
574 0 : kerr = krb5_parse_name(ctx, client_name, &client_princ);
575 0 : if (kerr != 0) {
576 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
577 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
578 0 : goto done;
579 : }
580 :
581 0 : sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length);
582 0 : if (realm_length == 0) {
583 0 : kerr = KRB5KRB_ERR_GENERIC;
584 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sss_krb5_princ_realm failed.\n");
585 0 : goto done;
586 : }
587 :
588 0 : server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s",
589 : realm_length, realm_name,
590 : realm_length, realm_name);
591 0 : if (server_name == NULL) {
592 0 : kerr = KRB5_CC_NOMEM;
593 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
594 0 : goto done;
595 : }
596 :
597 0 : kerr = krb5_parse_name(ctx, server_name, &server_princ);
598 0 : talloc_free(server_name);
599 0 : if (kerr != 0) {
600 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
601 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_parse_name failed.\n");
602 0 : goto done;
603 : }
604 :
605 0 : kerr = krb5_cc_resolve(ctx, ccache_file, &cc);
606 0 : if (kerr != 0) {
607 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
608 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_resolve failed.\n");
609 0 : goto done;
610 : }
611 :
612 0 : memset(&mcred, 0, sizeof(mcred));
613 0 : memset(&cred, 0, sizeof(mcred));
614 :
615 0 : mcred.server = server_princ;
616 0 : mcred.client = client_princ;
617 :
618 0 : kerr = krb5_cc_retrieve_cred(ctx, cc, 0, &mcred, &cred);
619 0 : if (kerr != 0) {
620 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
621 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_retrieve_cred failed.\n");
622 0 : goto done;
623 : }
624 :
625 0 : tgtt->authtime = cred.times.authtime;
626 0 : tgtt->starttime = cred.times.starttime;
627 0 : tgtt->endtime = cred.times.endtime;
628 0 : tgtt->renew_till = cred.times.renew_till;
629 :
630 0 : krb5_free_cred_contents(ctx, &cred);
631 :
632 0 : kerr = krb5_cc_close(ctx, cc);
633 0 : if (kerr != 0) {
634 0 : KRB5_DEBUG(SSSDBG_OP_FAILURE, ctx, kerr);
635 0 : DEBUG(SSSDBG_CRIT_FAILURE, "krb5_cc_close failed.\n");
636 0 : goto done;
637 : }
638 0 : cc = NULL;
639 :
640 0 : kerr = 0;
641 :
642 : done:
643 0 : if (cc != NULL) {
644 0 : krb5_cc_close(ctx, cc);
645 : }
646 :
647 0 : if (client_princ != NULL) {
648 0 : krb5_free_principal(ctx, client_princ);
649 : }
650 :
651 0 : if (server_princ != NULL) {
652 0 : krb5_free_principal(ctx, server_princ);
653 : }
654 :
655 0 : if (ctx != NULL) {
656 0 : krb5_free_context(ctx);
657 : }
658 :
659 0 : if (kerr != 0) {
660 0 : return EIO;
661 : }
662 :
663 0 : return EOK;
664 : }
665 :
666 0 : errno_t safe_remove_old_ccache_file(const char *old_ccache,
667 : const char *new_ccache,
668 : uid_t uid, gid_t gid)
669 : {
670 0 : if ((old_ccache == new_ccache)
671 0 : || (old_ccache && new_ccache
672 0 : && (strcmp(old_ccache, new_ccache) == 0))) {
673 0 : DEBUG(SSSDBG_TRACE_FUNC, "New and old ccache file are the same, "
674 : "none will be deleted.\n");
675 0 : return EOK;
676 : }
677 :
678 0 : return sss_krb5_cc_destroy(old_ccache, uid, gid);
679 : }
680 :
681 0 : krb5_error_code copy_ccache_into_memory(TALLOC_CTX *mem_ctx, krb5_context kctx,
682 : const char *ccache_file,
683 : char **_mem_name)
684 : {
685 : krb5_error_code kerr;
686 : krb5_ccache ccache;
687 0 : krb5_ccache mem_ccache = NULL;
688 0 : char *ccache_name = NULL;
689 0 : krb5_principal princ = NULL;
690 0 : char *mem_name = NULL;
691 : char *sep;
692 :
693 0 : kerr = krb5_cc_resolve(kctx, ccache_file, &ccache);
694 0 : if (kerr != 0) {
695 0 : DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n",
696 : ccache_file);
697 0 : return kerr;
698 : }
699 :
700 0 : kerr = krb5_cc_get_full_name(kctx, ccache, &ccache_name);
701 0 : if (kerr != 0) {
702 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read name for ccache [%s].\n",
703 : ccache_file);
704 0 : goto done;
705 : }
706 :
707 0 : sep = strchr(ccache_name, ':');
708 0 : if (sep == NULL || sep[1] == '\0') {
709 0 : DEBUG(SSSDBG_CRIT_FAILURE,
710 : "Ccache name [%s] does not have delimiter[:] .\n", ccache_name);
711 0 : kerr = KRB5KRB_ERR_GENERIC;
712 0 : goto done;
713 : }
714 :
715 0 : if (strncmp(ccache_name, "MEMORY:", sizeof("MEMORY:") -1) == 0) {
716 0 : DEBUG(SSSDBG_TRACE_FUNC, "Ccache [%s] is already memory ccache.\n",
717 : ccache_name);
718 0 : *_mem_name = talloc_strdup(mem_ctx, ccache_name);
719 0 : if(*_mem_name == NULL) {
720 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
721 0 : kerr = KRB5KRB_ERR_GENERIC;
722 0 : goto done;
723 : }
724 0 : kerr = 0;
725 0 : goto done;
726 : }
727 0 : if (strncmp(ccache_name, "FILE:", sizeof("FILE:") -1) == 0) {
728 0 : mem_name = talloc_asprintf(mem_ctx, "MEMORY:%s", sep + 1);
729 0 : if (mem_name == NULL) {
730 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
731 0 : kerr = KRB5KRB_ERR_GENERIC;
732 0 : goto done;
733 : }
734 : } else {
735 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unexpected ccache type for ccache [%s], " \
736 : "currently only FILE is supported.\n",
737 : ccache_name);
738 0 : kerr = KRB5KRB_ERR_GENERIC;
739 0 : goto done;
740 : }
741 :
742 0 : kerr = krb5_cc_resolve(kctx, mem_name, &mem_ccache);
743 0 : if (kerr != 0) {
744 0 : DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n", mem_name);
745 0 : goto done;
746 : }
747 :
748 0 : kerr = krb5_cc_get_principal(kctx, ccache, &princ);
749 0 : if (kerr != 0) {
750 0 : DEBUG(SSSDBG_CRIT_FAILURE,
751 : "error reading principal from ccache [%s].\n", ccache_name);
752 0 : goto done;
753 : }
754 :
755 0 : kerr = krb5_cc_initialize(kctx, mem_ccache, princ);
756 0 : if (kerr != 0) {
757 0 : DEBUG(SSSDBG_CRIT_FAILURE,
758 : "Failed to initialize ccache [%s].\n", mem_name);
759 0 : goto done;
760 : }
761 :
762 0 : kerr = krb5_cc_copy_creds(kctx, ccache, mem_ccache);
763 0 : if (kerr != 0) {
764 0 : DEBUG(SSSDBG_CRIT_FAILURE,
765 : "Failed to copy ccache [%s] to [%s].\n", ccache_name, mem_name);
766 0 : goto done;
767 : }
768 :
769 0 : *_mem_name = mem_name;
770 0 : kerr = 0;
771 :
772 : done:
773 0 : if (kerr != 0) {
774 0 : talloc_free(mem_name);
775 : }
776 :
777 0 : free(ccache_name);
778 0 : krb5_free_principal(kctx, princ);
779 :
780 0 : if (krb5_cc_close(kctx, ccache) != 0) {
781 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
782 : }
783 :
784 0 : if (krb5_cc_close(kctx, mem_ccache) != 0) {
785 0 : DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
786 : }
787 :
788 0 : return kerr;
789 : }
|