LCOV - code coverage report
Current view: top level - providers/krb5 - krb5_ccache.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 99 401 24.7 %
Date: 2015-10-19 Functions: 5 14 35.7 %

          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           1 : 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           1 :     krb5_ccache mem_ccache = NULL;
     688           1 :     char *ccache_name = NULL;
     689           1 :     krb5_principal princ = NULL;
     690           1 :     char *mem_name = NULL;
     691             :     char *sep;
     692             : 
     693           1 :     kerr = krb5_cc_resolve(kctx, ccache_file, &ccache);
     694           1 :     if (kerr != 0) {
     695           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n",
     696             :                                     ccache_file);
     697           0 :         return kerr;
     698             :     }
     699             : 
     700           1 :     kerr = krb5_cc_get_full_name(kctx, ccache, &ccache_name);
     701           1 :     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           1 :     sep = strchr(ccache_name, ':');
     708           1 :     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           1 :     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           1 :     if (strncmp(ccache_name, "FILE:", sizeof("FILE:") -1) == 0) {
     728           1 :         mem_name = talloc_asprintf(mem_ctx, "MEMORY:%s", sep + 1);
     729           1 :         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           1 :     kerr = krb5_cc_resolve(kctx, mem_name, &mem_ccache);
     743           1 :     if (kerr != 0) {
     744           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "error resolving ccache [%s].\n", mem_name);
     745           0 :         goto done;
     746             :     }
     747             : 
     748           1 :     kerr = krb5_cc_get_principal(kctx, ccache, &princ);
     749           1 :     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           1 :     kerr = krb5_cc_initialize(kctx, mem_ccache, princ);
     756           1 :     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           1 :     kerr = krb5_cc_copy_creds(kctx, ccache, mem_ccache);
     763           1 :     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           1 :     *_mem_name = mem_name;
     770           1 :     kerr = 0;
     771             : 
     772             : done:
     773           1 :     if (kerr != 0) {
     774           0 :         talloc_free(mem_name);
     775             :     }
     776             : 
     777           1 :     free(ccache_name);
     778           1 :     krb5_free_principal(kctx, princ);
     779             : 
     780           1 :     if (krb5_cc_close(kctx, ccache) != 0) {
     781           0 :         DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
     782             :     }
     783             : 
     784           1 :     if (krb5_cc_close(kctx, mem_ccache) != 0) {
     785           0 :         DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_close failed.\n");
     786             :     }
     787             : 
     788           1 :     return  kerr;
     789             : }

Generated by: LCOV version 1.10