LCOV - code coverage report
Current view: top level - util - sss_krb5.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 12 271 4.4 %
Date: 2012-11-29 Functions: 2 26 7.7 %
Branches: 6 566 1.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     Authors:
       3                 :            :         Sumit Bose <sbose@redhat.com>
       4                 :            : 
       5                 :            :     Copyright (C) 2009-2010 Red Hat
       6                 :            : 
       7                 :            :     This program is free software; you can redistribute it and/or modify
       8                 :            :     it under the terms of the GNU General Public License as published by
       9                 :            :     the Free Software Foundation; either version 3 of the License, or
      10                 :            :     (at your option) any later version.
      11                 :            : 
      12                 :            :     This program is distributed in the hope that it will be useful,
      13                 :            :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :     GNU General Public License for more details.
      16                 :            : 
      17                 :            :     You should have received a copy of the GNU General Public License
      18                 :            :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19                 :            : */
      20                 :            : #include <stdio.h>
      21                 :            : #include <errno.h>
      22                 :            : #include <talloc.h>
      23                 :            : 
      24                 :            : #include "config.h"
      25                 :            : 
      26                 :            : #include "util/util.h"
      27                 :            : #include "util/sss_krb5.h"
      28                 :            : 
      29                 :          0 : errno_t select_principal_from_keytab(TALLOC_CTX *mem_ctx,
      30                 :            :                                      const char *hostname,
      31                 :            :                                      const char *desired_realm,
      32                 :            :                                      const char *keytab_name,
      33                 :            :                                      char **_principal,
      34                 :            :                                      char **_primary,
      35                 :            :                                      char **_realm)
      36                 :            : {
      37                 :          0 :     krb5_error_code kerr = 0;
      38                 :          0 :     krb5_context krb_ctx = NULL;
      39                 :          0 :     krb5_keytab keytab = NULL;
      40                 :          0 :     krb5_principal client_princ = NULL;
      41                 :            :     TALLOC_CTX *tmp_ctx;
      42                 :          0 :     char *primary = NULL;
      43                 :          0 :     char *realm = NULL;
      44                 :          0 :     int i = 0;
      45                 :            :     errno_t ret;
      46                 :            :     char *principal_string;
      47                 :            :     const char *realm_name;
      48                 :            :     int realm_len;
      49                 :            : 
      50                 :            :     /**
      51                 :            :      * Priority of lookup:
      52                 :            :      * - foobar$@REALM (AD domain)
      53                 :            :      * - host/our.hostname@REALM
      54                 :            :      * - host/foobar@REALM
      55                 :            :      * - host/foo@BAR
      56                 :            :      * - pick the first principal in the keytab
      57                 :            :      */
      58                 :          0 :     const char *primary_patterns[] = {"%s$", "*$", "host/%s", "host/*", "host/*", NULL};
      59                 :          0 :     const char *realm_patterns[] = {"%s", "%s", "%s", "%s", NULL, NULL};
      60                 :            : 
      61 [ #  # ][ #  # ]:          0 :     DEBUG(5, ("trying to select the most appropriate principal from keytab\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      62                 :          0 :     tmp_ctx = talloc_new(NULL);
      63         [ #  # ]:          0 :     if (!tmp_ctx) {
      64 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_new failed\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      65                 :            :         return ENOMEM;
      66                 :            :     }
      67                 :            : 
      68                 :          0 :     kerr = krb5_init_context(&krb_ctx);
      69         [ #  # ]:          0 :     if (kerr) {
      70 [ #  # ][ #  # ]:          0 :         DEBUG(2, ("Failed to init kerberos context\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      71                 :            :         ret = EFAULT;
      72                 :            :         goto done;
      73                 :            :     }
      74                 :            : 
      75         [ #  # ]:          0 :     if (keytab_name != NULL) {
      76                 :          0 :         kerr = krb5_kt_resolve(krb_ctx, keytab_name, &keytab);
      77                 :            :     } else {
      78                 :          0 :         kerr = krb5_kt_default(krb_ctx, &keytab);
      79                 :            :     }
      80         [ #  # ]:          0 :     if (kerr) {
      81 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_FATAL_FAILURE,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      82                 :            :               ("Failed to read keytab [%s]: %s\n",
      83                 :            :                KEYTAB_CLEAN_NAME,
      84                 :            :                sss_krb5_get_error_message(krb_ctx, kerr)));
      85                 :            :         ret = EFAULT;
      86                 :            :         goto done;
      87                 :            :     }
      88                 :            : 
      89         [ #  # ]:          0 :     if (!desired_realm) {
      90                 :          0 :         desired_realm = "*";
      91                 :            :     }
      92         [ #  # ]:          0 :     if (!hostname) {
      93                 :          0 :         hostname = "*";
      94                 :            :     }
      95                 :            : 
      96                 :            :     do {
      97         [ #  # ]:          0 :         if (primary_patterns[i]) {
      98                 :          0 :             primary = talloc_asprintf(tmp_ctx, primary_patterns[i], hostname);
      99         [ #  # ]:          0 :             if (primary == NULL) {
     100                 :            :                 ret = ENOMEM;
     101                 :            :                 goto done;
     102                 :            :             }
     103                 :            :         } else {
     104                 :            :             primary = NULL;
     105                 :            :         }
     106         [ #  # ]:          0 :         if (realm_patterns[i]) {
     107                 :          0 :             realm = talloc_asprintf(tmp_ctx, realm_patterns[i], desired_realm);
     108         [ #  # ]:          0 :             if (realm == NULL) {
     109                 :            :                 ret = ENOMEM;
     110                 :            :                 goto done;
     111                 :            :             }
     112                 :            :         } else {
     113                 :            :             realm = NULL;
     114                 :            :         }
     115                 :            : 
     116                 :          0 :         kerr = find_principal_in_keytab(krb_ctx, keytab, primary, realm,
     117                 :            :                                         &client_princ);
     118                 :          0 :         talloc_zfree(primary);
     119                 :          0 :         talloc_zfree(realm);
     120         [ #  # ]:          0 :         if (kerr == 0) {
     121                 :            :             break;
     122                 :            :         }
     123         [ #  # ]:          0 :         if (client_princ != NULL) {
     124                 :          0 :             krb5_free_principal(krb_ctx, client_princ);
     125                 :          0 :             client_princ = NULL;
     126                 :            :         }
     127                 :          0 :         i++;
     128 [ #  # ][ #  # ]:          0 :     } while(primary_patterns[i-1] != NULL || realm_patterns[i-1] != NULL);
     129                 :            : 
     130         [ #  # ]:          0 :     if (kerr == 0) {
     131         [ #  # ]:          0 :         if (_principal) {
     132                 :          0 :             kerr = krb5_unparse_name(krb_ctx, client_princ, &principal_string);
     133         [ #  # ]:          0 :             if (kerr) {
     134 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("krb5_unparse_name failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
     135                 :            :                 ret = EFAULT;
     136                 :            :                 goto done;
     137                 :            :             }
     138                 :            : 
     139                 :          0 :             *_principal = talloc_strdup(mem_ctx, principal_string);
     140                 :          0 :             free(principal_string);
     141         [ #  # ]:          0 :             if (!*_principal) {
     142 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("talloc_strdup failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
     143                 :            :                 ret = ENOMEM;
     144                 :            :                 goto done;
     145                 :            :             }
     146 [ #  # ][ #  # ]:          0 :             DEBUG(5, ("Selected principal: %s\n", *_principal));
         [ #  # ][ #  # ]
                 [ #  # ]
     147                 :            :         }
     148                 :            : 
     149         [ #  # ]:          0 :         if (_primary) {
     150                 :          0 :             kerr = sss_krb5_unparse_name_flags(krb_ctx, client_princ,
     151                 :            :                                                KRB5_PRINCIPAL_UNPARSE_NO_REALM,
     152                 :            :                                                &principal_string);
     153         [ #  # ]:          0 :             if (kerr) {
     154 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("krb5_unparse_name failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
     155                 :            :                 ret = EFAULT;
     156                 :            :                 goto done;
     157                 :            :             }
     158                 :            : 
     159                 :          0 :             *_primary = talloc_strdup(mem_ctx, principal_string);
     160                 :          0 :             free(principal_string);
     161         [ #  # ]:          0 :             if (!*_primary) {
     162 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("talloc_strdup failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
     163         [ #  # ]:          0 :                 if (_principal) talloc_zfree(*_principal);
     164                 :            :                 ret = ENOMEM;
     165                 :            :                 goto done;
     166                 :            :             }
     167 [ #  # ][ #  # ]:          0 :             DEBUG(5, ("Selected primary: %s\n", *_primary));
         [ #  # ][ #  # ]
                 [ #  # ]
     168                 :            :         }
     169                 :            : 
     170         [ #  # ]:          0 :         if (_realm) {
     171                 :          0 :             sss_krb5_princ_realm(krb_ctx, client_princ,
     172                 :            :                                  &realm_name,
     173                 :            :                                  &realm_len);
     174                 :          0 :             *_realm = talloc_asprintf(mem_ctx, "%.*s",
     175                 :            :                                       realm_len, realm_name);
     176         [ #  # ]:          0 :             if (!*_realm) {
     177 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("talloc_asprintf failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
     178         [ #  # ]:          0 :                 if (_principal) talloc_zfree(*_principal);
     179         [ #  # ]:          0 :                 if (_primary) talloc_zfree(*_primary);
     180                 :            :                 ret = ENOMEM;
     181                 :            :                 goto done;
     182                 :            :             }
     183 [ #  # ][ #  # ]:          0 :             DEBUG(5, ("Selected realm: %s\n", *_realm));
         [ #  # ][ #  # ]
                 [ #  # ]
     184                 :            :         }
     185                 :            : 
     186                 :            :         ret = EOK;
     187                 :            :     } else {
     188 [ #  # ][ #  # ]:          0 :         DEBUG(3, ("No suitable principal found in keytab\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     189                 :            :         ret = ENOENT;
     190                 :            :     }
     191                 :            : 
     192                 :            : done:
     193         [ #  # ]:          0 :     if (keytab) krb5_kt_close(krb_ctx, keytab);
     194         [ #  # ]:          0 :     if (krb_ctx) krb5_free_context(krb_ctx);
     195         [ #  # ]:          0 :     if (client_princ != NULL) {
     196                 :          0 :         krb5_free_principal(krb_ctx, client_princ);
     197                 :          0 :         client_princ = NULL;
     198                 :            :     }
     199                 :          0 :     talloc_free(tmp_ctx);
     200                 :            :     return ret;
     201                 :            : }
     202                 :            : 
     203                 :          0 : int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
     204                 :            :                               krb5_context context, krb5_keytab keytab)
     205                 :            : {
     206                 :            :     bool found;
     207                 :            :     char *kt_principal;
     208                 :            :     krb5_error_code krberr;
     209                 :            :     krb5_kt_cursor cursor;
     210                 :            :     krb5_keytab_entry entry;
     211                 :            : 
     212                 :          0 :     krberr = krb5_kt_start_seq_get(context, keytab, &cursor);
     213         [ #  # ]:          0 :     if (krberr) {
     214 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_FATAL_FAILURE,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     215                 :            :               ("Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME));
     216                 :            : 
     217         [ #  # ]:          0 :         sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "
     218                 :            :                              "Unable to create GSSAPI-encrypted LDAP "
     219                 :            :                              "connection.",
     220                 :            :                              KEYTAB_CLEAN_NAME, krberr,
     221                 :            :                              sss_krb5_get_error_message(context, krberr));
     222                 :            : 
     223                 :            :         return EIO;
     224                 :            :     }
     225                 :            : 
     226                 :            :     found = false;
     227         [ #  # ]:          0 :     while((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
     228                 :          0 :         krberr = krb5_unparse_name(context, entry.principal, &kt_principal);
     229         [ #  # ]:          0 :         if (krberr) {
     230 [ #  # ][ #  # ]:          0 :             DEBUG(SSSDBG_FATAL_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     231                 :            :                   ("Could not parse keytab entry\n"));
     232                 :          0 :             sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n");
     233                 :            :             return EIO;
     234                 :            :         }
     235                 :            : 
     236         [ #  # ]:          0 :         if (strcmp(principal, kt_principal) == 0) {
     237                 :          0 :             found = true;
     238                 :            :         }
     239                 :          0 :         free(kt_principal);
     240                 :          0 :         krberr = sss_krb5_free_keytab_entry_contents(context, &entry);
     241         [ #  # ]:          0 :         if (krberr) {
     242                 :            :             /* This should never happen. The API docs for this function
     243                 :            :              * specify only success for this function
     244                 :            :              */
     245 [ #  # ][ #  # ]:          0 :             DEBUG(1,("Could not free keytab entry contents\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     246                 :            :             /* This is non-fatal, so we'll continue here */
     247                 :            :         }
     248                 :            : 
     249         [ #  # ]:          0 :         if (found) {
     250                 :            :             break;
     251                 :            :         }
     252                 :            :     }
     253                 :            : 
     254                 :          0 :     krberr = krb5_kt_end_seq_get(context, keytab, &cursor);
     255         [ #  # ]:          0 :     if (krberr) {
     256 [ #  # ][ #  # ]:          0 :         DEBUG(0, ("Could not close keytab.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     257         [ #  # ]:          0 :         sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",
     258                 :            :                              KEYTAB_CLEAN_NAME);
     259                 :            :         return EIO;
     260                 :            :     }
     261                 :            : 
     262         [ #  # ]:          0 :     if (!found) {
     263 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_FATAL_FAILURE,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     264                 :            :               ("Principal [%s] not found in keytab [%s]\n",
     265                 :            :                principal,
     266                 :            :                KEYTAB_CLEAN_NAME));
     267         [ #  # ]:          0 :         sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "
     268                 :            :                              "Principal [%s] was not found. "
     269                 :            :                              "Unable to create GSSAPI-encrypted LDAP connection.",
     270                 :            :                              KEYTAB_CLEAN_NAME, principal);
     271                 :            : 
     272                 :            :         return EFAULT;
     273                 :            :     }
     274                 :            : 
     275                 :            :     return EOK;
     276                 :            : }
     277                 :            : 
     278                 :            : 
     279                 :            : enum matching_mode {MODE_NORMAL, MODE_PREFIX, MODE_POSTFIX};
     280                 :            : /**
     281                 :            :  * We only have primary and instances stored separately, we need to
     282                 :            :  * join them to one string and compare that string.
     283                 :            :  *
     284                 :            :  * @param ctx kerberos context
     285                 :            :  * @param principal principal we want to match
     286                 :            :  * @param pattern_primary primary part of the principal we want to
     287                 :            :  *        perform matching against. It is possible to use * wildcard
     288                 :            :  *        at the beginning or at the end of the string. If NULL, it
     289                 :            :  *        will act as "*"
     290                 :            :  * @param pattern_realm realm part of the principal we want to perform
     291                 :            :  *        the matching against. If NULL, it will act as "*"
     292                 :            :  */
     293                 :          0 : static bool match_principal(krb5_context ctx,
     294                 :            :                      krb5_principal principal,
     295                 :            :                      const char *pattern_primary,
     296                 :            :                      const char *pattern_realm)
     297                 :            : {
     298                 :          0 :     char *primary = NULL;
     299                 :          0 :     char *primary_str = NULL;
     300                 :          0 :     int primary_str_len = 0;
     301                 :            :     int tmp_len;
     302                 :            :     int len_diff;
     303                 :            :     const char *realm_name;
     304                 :            :     int realm_len;
     305                 :            : 
     306                 :          0 :     enum matching_mode mode = MODE_NORMAL;
     307                 :            :     TALLOC_CTX *tmp_ctx;
     308                 :          0 :     bool ret = false;
     309                 :            : 
     310                 :            :     sss_krb5_princ_realm(ctx, principal, &realm_name, &realm_len);
     311                 :            : 
     312                 :          0 :     tmp_ctx = talloc_new(NULL);
     313         [ #  # ]:          0 :     if (!tmp_ctx) {
     314 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_new failed\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     315                 :            :         return false;
     316                 :            :     }
     317                 :            : 
     318         [ #  # ]:          0 :     if (pattern_primary) {
     319                 :          0 :         tmp_len = strlen(pattern_primary);
     320         [ #  # ]:          0 :         if (pattern_primary[tmp_len-1] == '*') {
     321                 :          0 :             mode = MODE_PREFIX;
     322                 :          0 :             primary_str = talloc_strdup(tmp_ctx, pattern_primary);
     323                 :          0 :             primary_str[tmp_len-1] = '\0';
     324                 :          0 :             primary_str_len = tmp_len-1;
     325         [ #  # ]:          0 :         } else if (pattern_primary[0] == '*') {
     326                 :          0 :             mode = MODE_POSTFIX;
     327                 :          0 :             primary_str = talloc_strdup(tmp_ctx, pattern_primary+1);
     328                 :          0 :             primary_str_len = tmp_len-1;
     329                 :            :         }
     330                 :            : 
     331                 :          0 :         sss_krb5_unparse_name_flags(ctx, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM,
     332                 :            :                                     &primary);
     333                 :            : 
     334                 :          0 :         len_diff = strlen(primary)-primary_str_len;
     335                 :            : 
     336 [ #  # ][ #  # ]:          0 :         if ((mode == MODE_NORMAL &&
     337         [ #  # ]:          0 :                 strcmp(primary, pattern_primary) != 0) ||
     338         [ #  # ]:          0 :             (mode == MODE_PREFIX &&
     339         [ #  # ]:          0 :                 strncmp(primary, primary_str, primary_str_len) != 0) ||
     340         [ #  # ]:          0 :             (mode == MODE_POSTFIX &&
     341                 :          0 :                 strcmp(primary+len_diff, primary_str) != 0)) {
     342                 :            :             goto done;
     343                 :            :         }
     344                 :            :     }
     345                 :            : 
     346 [ #  # ][ #  # ]:          0 :     if (!pattern_realm || (realm_len == strlen(pattern_realm) &&
                 [ #  # ]
     347                 :          0 :         strncmp(realm_name, pattern_realm, realm_len) == 0)) {
     348 [ #  # ][ #  # ]:          0 :         DEBUG(7, ("Principal matched to the sample (%s@%s).\n", pattern_primary,
         [ #  # ][ #  # ]
                 [ #  # ]
     349                 :            :                                                                 pattern_realm));
     350                 :            :         ret = true;
     351                 :            :     }
     352                 :            : 
     353                 :            : done:
     354                 :          0 :     free(primary);
     355                 :          0 :     talloc_free(tmp_ctx);
     356                 :            :     return ret;
     357                 :            : }
     358                 :            : 
     359                 :          0 : krb5_error_code find_principal_in_keytab(krb5_context ctx,
     360                 :            :                                          krb5_keytab keytab,
     361                 :            :                                          const char *pattern_primary,
     362                 :            :                                          const char *pattern_realm,
     363                 :            :                                          krb5_principal *princ)
     364                 :            : {
     365                 :            :     krb5_error_code kerr;
     366                 :            :     krb5_error_code kt_err;
     367                 :            :     krb5_error_code kerr_d;
     368                 :            :     krb5_kt_cursor cursor;
     369                 :            :     krb5_keytab_entry entry;
     370                 :          0 :     bool principal_found = false;
     371                 :            : 
     372                 :          0 :     memset(&cursor, 0, sizeof(cursor));
     373                 :          0 :     kerr = krb5_kt_start_seq_get(ctx, keytab, &cursor);
     374         [ #  # ]:          0 :     if (kerr != 0) {
     375 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_kt_start_seq_get failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     376                 :            :         return kerr;
     377                 :            :     }
     378                 :            : 
     379 [ #  # ][ #  # ]:          0 :     DEBUG(9, ("Trying to find principal %s@%s in keytab.\n", pattern_primary, pattern_realm));
         [ #  # ][ #  # ]
                 [ #  # ]
     380                 :          0 :     memset(&entry, 0, sizeof(entry));
     381         [ #  # ]:          0 :     while ((kt_err = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) {
     382                 :          0 :         principal_found = match_principal(ctx, entry.principal, pattern_primary, pattern_realm);
     383         [ #  # ]:          0 :         if (principal_found) {
     384                 :            :             break;
     385                 :            :         }
     386                 :            : 
     387                 :          0 :         kerr = sss_krb5_free_keytab_entry_contents(ctx, &entry);
     388         [ #  # ]:          0 :         if (kerr != 0) {
     389 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Failed to free keytab entry.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     390                 :            :         }
     391                 :          0 :         memset(&entry, 0, sizeof(entry));
     392                 :            :     }
     393                 :            : 
     394                 :            :     /* Close the keytab here.  Even though we're using cursors, the file
     395                 :            :      * handle is stored in the krb5_keytab structure, and it gets
     396                 :            :      * overwritten by other keytab calls, creating a leak. */
     397                 :          0 :     kerr = krb5_kt_end_seq_get(ctx, keytab, &cursor);
     398         [ #  # ]:          0 :     if (kerr != 0) {
     399 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_kt_end_seq_get failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     400                 :            :         goto done;
     401                 :            :     }
     402                 :            : 
     403         [ #  # ]:          0 :     if (!principal_found) {
     404                 :          0 :         kerr = KRB5_KT_NOTFOUND;
     405 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_TRACE_FUNC,
         [ #  # ][ #  # ]
                 [ #  # ]
     406                 :            :               ("No principal matching %s@%s found in keytab.\n",
     407                 :            :                pattern_primary, pattern_realm));
     408                 :            :         goto done;
     409                 :            :     }
     410                 :            : 
     411                 :            :     /* check if we got any errors from krb5_kt_next_entry */
     412         [ #  # ]:          0 :     if (kt_err != 0 && kt_err != KRB5_KT_END) {
     413 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Error while reading keytab.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     414                 :            :         goto done;
     415                 :            :     }
     416                 :            : 
     417                 :          0 :     kerr = krb5_copy_principal(ctx, entry.principal, princ);
     418         [ #  # ]:          0 :     if (kerr != 0) {
     419 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_copy_principal failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     420                 :            :         goto done;
     421                 :            :     }
     422                 :            : 
     423                 :            :     kerr = 0;
     424                 :            : 
     425                 :            : done:
     426                 :          0 :     kerr_d = sss_krb5_free_keytab_entry_contents(ctx, &entry);
     427         [ #  # ]:          0 :     if (kerr_d != 0) {
     428 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Failed to free keytab entry.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     429                 :            :     }
     430                 :            : 
     431                 :            :     return kerr;
     432                 :            : }
     433                 :            : 
     434                 :          0 : const char *KRB5_CALLCONV sss_krb5_get_error_message(krb5_context ctx,
     435                 :            :                                                krb5_error_code ec)
     436                 :            : {
     437                 :            : #ifdef HAVE_KRB5_GET_ERROR_MESSAGE
     438                 :          0 :     return krb5_get_error_message(ctx, ec);
     439                 :            : #else
     440                 :            :     int ret;
     441                 :            :     char *s = NULL;
     442                 :            :     int size = sizeof("Kerberos error [XXXXXXXXXXXX]");
     443                 :            : 
     444                 :            :     s = malloc(sizeof(char) * (size));
     445                 :            :     if (s == NULL) {
     446                 :            :         return NULL;
     447                 :            :     }
     448                 :            : 
     449                 :            :     ret = snprintf(s, size, "Kerberos error [%12d]", ec);
     450                 :            : 
     451                 :            :     if (ret < 0 || ret >= size) {
     452                 :            :         return NULL;
     453                 :            :     }
     454                 :            : 
     455                 :            :     return s;
     456                 :            : #endif
     457                 :            : }
     458                 :            : 
     459                 :          0 : void KRB5_CALLCONV sss_krb5_free_error_message(krb5_context ctx, const char *s)
     460                 :            : {
     461                 :            : #ifdef HAVE_KRB5_GET_ERROR_MESSAGE
     462                 :          0 :     krb5_free_error_message(ctx, s);
     463                 :            : #else
     464                 :            :     free(s);
     465                 :            : #endif
     466                 :            : 
     467                 :          0 :     return;
     468                 :            : }
     469                 :            : 
     470                 :          0 : krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_alloc(
     471                 :            :                                                   krb5_context context,
     472                 :            :                                                   krb5_get_init_creds_opt **opt)
     473                 :            : {
     474                 :            : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
     475                 :          0 :     return krb5_get_init_creds_opt_alloc(context, opt);
     476                 :            : #else
     477                 :            :     *opt = calloc(1, sizeof(krb5_get_init_creds_opt));
     478                 :            :     if (*opt == NULL) {
     479                 :            :         return ENOMEM;
     480                 :            :     }
     481                 :            :     krb5_get_init_creds_opt_init(*opt);
     482                 :            : 
     483                 :            :     return 0;
     484                 :            : #endif
     485                 :            : }
     486                 :            : 
     487                 :          0 : void KRB5_CALLCONV sss_krb5_get_init_creds_opt_free (krb5_context context,
     488                 :            :                                                    krb5_get_init_creds_opt *opt)
     489                 :            : {
     490                 :            : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
     491                 :          0 :     krb5_get_init_creds_opt_free(context, opt);
     492                 :            : #else
     493                 :            :     free(opt);
     494                 :            : #endif
     495                 :            : 
     496                 :          0 :     return;
     497                 :            : }
     498                 :            : 
     499                 :          0 : void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name)
     500                 :            : {
     501                 :            : #ifdef HAVE_KRB5_FREE_UNPARSED_NAME
     502                 :          0 :     krb5_free_unparsed_name(context, name);
     503                 :            : #else
     504                 :            :     if (name != NULL) {
     505                 :            :         memset(name, 0, strlen(name));
     506                 :            :         free(name);
     507                 :            :     }
     508                 :            : #endif
     509                 :          0 : }
     510                 :            : 
     511                 :            : 
     512                 :          0 : krb5_error_code check_for_valid_tgt(krb5_context context,
     513                 :            :                                     krb5_ccache ccache, const char *realm,
     514                 :            :                                     const char *client_princ_str, bool *result)
     515                 :            : {
     516                 :            :     krb5_error_code krberr;
     517                 :          0 :     TALLOC_CTX *tmp_ctx = NULL;
     518                 :            :     krb5_creds mcred;
     519                 :            :     krb5_creds cred;
     520                 :          0 :     char *server_name = NULL;
     521                 :          0 :     krb5_principal client_principal = NULL;
     522                 :          0 :     krb5_principal server_principal = NULL;
     523                 :            : 
     524                 :          0 :     *result = false;
     525                 :            : 
     526                 :          0 :     tmp_ctx = talloc_new(NULL);
     527         [ #  # ]:          0 :     if (tmp_ctx == NULL) {
     528 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_new failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     529                 :            :         return ENOMEM;
     530                 :            :     }
     531                 :            : 
     532                 :          0 :     server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm);
     533         [ #  # ]:          0 :     if (server_name == NULL) {
     534 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("talloc_asprintf failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     535                 :            :         krberr = ENOMEM;
     536                 :            :         goto done;
     537                 :            :     }
     538                 :            : 
     539                 :          0 :     krberr = krb5_parse_name(context, server_name, &server_principal);
     540         [ #  # ]:          0 :     if (krberr != 0) {
     541 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_parse_name failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     542                 :            :         goto done;
     543                 :            :     }
     544                 :            : 
     545                 :          0 :     krberr = krb5_parse_name(context, client_princ_str, &client_principal);
     546         [ #  # ]:          0 :     if (krberr != 0) {
     547 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_parse_name failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     548                 :            :         goto done;
     549                 :            :     }
     550                 :            : 
     551                 :          0 :     memset(&mcred, 0, sizeof(mcred));
     552                 :          0 :     memset(&cred, 0, sizeof(mcred));
     553                 :          0 :     mcred.client = client_principal;
     554                 :          0 :     mcred.server = server_principal;
     555                 :            : 
     556                 :          0 :     krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
     557         [ #  # ]:          0 :     if (krberr != 0) {
     558 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("krb5_cc_retrieve_cred failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     559                 :            :         krberr = 0;
     560                 :            :         goto done;
     561                 :            :     }
     562                 :            : 
     563 [ #  # ][ #  # ]:          0 :     DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime));
         [ #  # ][ #  # ]
                 [ #  # ]
     564                 :            : 
     565         [ #  # ]:          0 :     if (cred.times.endtime > time(NULL)) {
     566 [ #  # ][ #  # ]:          0 :         DEBUG(3, ("TGT is valid.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     567                 :          0 :         *result = true;
     568                 :            :     }
     569                 :          0 :     krb5_free_cred_contents(context, &cred);
     570                 :            : 
     571                 :            :     krberr = 0;
     572                 :            : 
     573                 :            : done:
     574         [ #  # ]:          0 :     if (client_principal != NULL) {
     575                 :          0 :         krb5_free_principal(context, client_principal);
     576                 :            :     }
     577         [ #  # ]:          0 :     if (server_principal != NULL) {
     578                 :          0 :         krb5_free_principal(context, server_principal);
     579                 :            :     }
     580                 :          0 :     talloc_free(tmp_ctx);
     581                 :            :     return krberr;
     582                 :            : }
     583                 :            : 
     584                 :          0 : krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_expire_callback(
     585                 :            :                                                    krb5_context context,
     586                 :            :                                                    krb5_get_init_creds_opt *opt,
     587                 :            :                                                    krb5_expire_callback_func cb,
     588                 :            :                                                    void *data)
     589                 :            : {
     590                 :            : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_EXPIRE_CALLBACK
     591                 :          0 :     return krb5_get_init_creds_opt_set_expire_callback(context, opt, cb, data);
     592                 :            : #else
     593                 :            :     DEBUG(5, ("krb5_get_init_creds_opt_set_expire_callback not available.\n"));
     594                 :            :     return 0;
     595                 :            : #endif
     596                 :            : }
     597                 :            : 
     598                 :          0 : errno_t check_fast(const char *str, bool *use_fast)
     599                 :            : {
     600                 :            : #if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_FLAGS
     601         [ #  # ]:          0 :     if (strcasecmp(str, "never") == 0 ) {
     602                 :          0 :         *use_fast = false;
     603 [ #  # ][ #  # ]:          0 :     } else if (strcasecmp(str, "try") == 0 || strcasecmp(str, "demand") == 0) {
     604                 :          0 :         *use_fast = true;
     605                 :            :     } else {
     606                 :          0 :         sss_log(SSS_LOG_ALERT, "Unsupported value [%s] for option krb5_use_fast,"
     607                 :            :                                "please use never, try, or demand.\n");
     608                 :          0 :         return EINVAL;
     609                 :            :     }
     610                 :            : 
     611                 :            :     return EOK;
     612                 :            : #else
     613                 :            :     sss_log(SSS_LOG_ALERT, "This build of sssd done not support FAST. "
     614                 :            :                            "Please remove option krb5_use_fast.\n");
     615                 :            :     return EINVAL;
     616                 :            : #endif
     617                 :            : }
     618                 :            : 
     619                 :          0 : krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_ccache_name(
     620                 :            :                                                    krb5_context context,
     621                 :            :                                                    krb5_get_init_creds_opt *opt,
     622                 :            :                                                    const char *fast_ccache_name)
     623                 :            : {
     624                 :            : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME
     625                 :          0 :     return krb5_get_init_creds_opt_set_fast_ccache_name(context, opt,
     626                 :            :                                                         fast_ccache_name);
     627                 :            : #else
     628                 :            :     DEBUG(5, ("krb5_get_init_creds_opt_set_fast_ccache_name not available.\n"));
     629                 :            :     return 0;
     630                 :            : #endif
     631                 :            : }
     632                 :            : 
     633                 :          0 : krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_flags(
     634                 :            :                                                    krb5_context context,
     635                 :            :                                                    krb5_get_init_creds_opt *opt,
     636                 :            :                                                    krb5_flags flags)
     637                 :            : {
     638                 :            : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_FLAGS
     639                 :          0 :     return krb5_get_init_creds_opt_set_fast_flags(context, opt, flags);
     640                 :            : #else
     641                 :            :     DEBUG(5, ("krb5_get_init_creds_opt_set_fast_flags not available.\n"));
     642                 :            :     return 0;
     643                 :            : #endif
     644                 :            : }
     645                 :            : 
     646                 :            : 
     647                 :            : #ifndef HAVE_KRB5_UNPARSE_NAME_FLAGS
     648                 :            : #ifndef REALM_SEP
     649                 :            : #define REALM_SEP       '@'
     650                 :            : #endif
     651                 :            : #ifndef COMPONENT_SEP
     652                 :            : #define COMPONENT_SEP   '/'
     653                 :            : #endif
     654                 :            : 
     655                 :            : static int
     656                 :            : sss_krb5_copy_component_quoting(char *dest, const krb5_data *src, int flags)
     657                 :            : {
     658                 :            :     int j;
     659                 :            :     const char *cp = src->data;
     660                 :            :     char *q = dest;
     661                 :            :     int length = src->length;
     662                 :            : 
     663                 :            :     if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) {
     664                 :            :         memcpy(dest, src->data, src->length);
     665                 :            :         return src->length;
     666                 :            :     }
     667                 :            : 
     668                 :            :     for (j=0; j < length; j++,cp++) {
     669                 :            :         int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
     670                 :            :             !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
     671                 :            : 
     672                 :            :         switch (*cp) {
     673                 :            :         case REALM_SEP:
     674                 :            :             if (no_realm) {
     675                 :            :                 *q++ = *cp;
     676                 :            :                 break;
     677                 :            :             }
     678                 :            :         case COMPONENT_SEP:
     679                 :            :         case '\\':
     680                 :            :             *q++ = '\\';
     681                 :            :             *q++ = *cp;
     682                 :            :             break;
     683                 :            :         case '\t':
     684                 :            :             *q++ = '\\';
     685                 :            :             *q++ = 't';
     686                 :            :             break;
     687                 :            :         case '\n':
     688                 :            :             *q++ = '\\';
     689                 :            :             *q++ = 'n';
     690                 :            :             break;
     691                 :            :         case '\b':
     692                 :            :             *q++ = '\\';
     693                 :            :             *q++ = 'b';
     694                 :            :             break;
     695                 :            :         case '\0':
     696                 :            :             *q++ = '\\';
     697                 :            :             *q++ = '0';
     698                 :            :             break;
     699                 :            :         default:
     700                 :            :             *q++ = *cp;
     701                 :            :         }
     702                 :            :     }
     703                 :            :     return q - dest;
     704                 :            : }
     705                 :            : 
     706                 :            : static int
     707                 :            : sss_krb5_component_length_quoted(const krb5_data *src, int flags)
     708                 :            : {
     709                 :            :     const char *cp = src->data;
     710                 :            :     int length = src->length;
     711                 :            :     int j;
     712                 :            :     int size = length;
     713                 :            : 
     714                 :            :     if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) {
     715                 :            :         int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
     716                 :            :             !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
     717                 :            : 
     718                 :            :         for (j = 0; j < length; j++,cp++)
     719                 :            :             if ((!no_realm && *cp == REALM_SEP) ||
     720                 :            :                 *cp == COMPONENT_SEP ||
     721                 :            :                 *cp == '\0' || *cp == '\\' || *cp == '\t' ||
     722                 :            :                 *cp == '\n' || *cp == '\b')
     723                 :            :                 size++;
     724                 :            :     }
     725                 :            : 
     726                 :            :     return size;
     727                 :            : }
     728                 :            : 
     729                 :            : #endif /* HAVE_KRB5_UNPARSE_NAME_FLAGS */
     730                 :            : 
     731                 :            : 
     732                 :            : krb5_error_code
     733                 :          0 : sss_krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal,
     734                 :            :                         int flags, char **name)
     735                 :            : {
     736                 :            : #ifdef HAVE_KRB5_UNPARSE_NAME_FLAGS
     737                 :          0 :     return krb5_unparse_name_flags(context, principal, flags, name);
     738                 :            : #else
     739                 :            :     char *cp, *q;
     740                 :            :     int i;
     741                 :            :     int length;
     742                 :            :     krb5_int32 nelem;
     743                 :            :     unsigned int totalsize = 0;
     744                 :            :     char *default_realm = NULL;
     745                 :            :     krb5_error_code ret = 0;
     746                 :            : 
     747                 :            :     if (name != NULL)
     748                 :            :         *name = NULL;
     749                 :            : 
     750                 :            :     if (!principal || !name)
     751                 :            :         return KRB5_PARSE_MALFORMED;
     752                 :            : 
     753                 :            :     if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) {
     754                 :            :         /* omit realm if local realm */
     755                 :            :         krb5_principal_data p;
     756                 :            : 
     757                 :            :         ret = krb5_get_default_realm(context, &default_realm);
     758                 :            :         if (ret != 0)
     759                 :            :             goto cleanup;
     760                 :            : 
     761                 :            :         krb5_princ_realm(context, &p)->length = strlen(default_realm);
     762                 :            :         krb5_princ_realm(context, &p)->data = default_realm;
     763                 :            : 
     764                 :            :         if (krb5_realm_compare(context, &p, principal))
     765                 :            :             flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
     766                 :            :     }
     767                 :            : 
     768                 :            :     if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
     769                 :            :         totalsize += sss_krb5_component_length_quoted(krb5_princ_realm(context,
     770                 :            :                                                               principal),
     771                 :            :                                              flags);
     772                 :            :         totalsize++;
     773                 :            :     }
     774                 :            : 
     775                 :            :     nelem = krb5_princ_size(context, principal);
     776                 :            :     for (i = 0; i < (int) nelem; i++) {
     777                 :            :         cp = krb5_princ_component(context, principal, i)->data;
     778                 :            :         totalsize += sss_krb5_component_length_quoted(krb5_princ_component(context, principal, i), flags);
     779                 :            :         totalsize++;
     780                 :            :     }
     781                 :            :     if (nelem == 0)
     782                 :            :         totalsize++;
     783                 :            : 
     784                 :            :     *name = malloc(totalsize);
     785                 :            : 
     786                 :            :     if (!*name) {
     787                 :            :         ret = ENOMEM;
     788                 :            :         goto cleanup;
     789                 :            :     }
     790                 :            : 
     791                 :            :     q = *name;
     792                 :            : 
     793                 :            :     for (i = 0; i < (int) nelem; i++) {
     794                 :            :         cp = krb5_princ_component(context, principal, i)->data;
     795                 :            :         length = krb5_princ_component(context, principal, i)->length;
     796                 :            :         q += sss_krb5_copy_component_quoting(q,
     797                 :            :                                     krb5_princ_component(context,
     798                 :            :                                                          principal,
     799                 :            :                                                          i),
     800                 :            :                                     flags);
     801                 :            :         *q++ = COMPONENT_SEP;
     802                 :            :     }
     803                 :            : 
     804                 :            :     if (i > 0)
     805                 :            :         q--;
     806                 :            :     if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
     807                 :            :         *q++ = REALM_SEP;
     808                 :            :         q += sss_krb5_copy_component_quoting(q, krb5_princ_realm(context, principal), flags);
     809                 :            :     }
     810                 :            :     *q++ = '\0';
     811                 :            : 
     812                 :            : cleanup:
     813                 :            :     free(default_realm);
     814                 :            : 
     815                 :            :     return ret;
     816                 :            : #endif /* HAVE_KRB5_UNPARSE_NAME_FLAGS */
     817                 :            : }
     818                 :            : 
     819                 :          0 : void sss_krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opts,
     820                 :            :                                                   int canonicalize)
     821                 :            : {
     822                 :            :     /* FIXME: The extra check for HAVE_KRB5_TICKET_TIMES is a workaround due to Heimdal
     823                 :            :      * defining krb5_get_init_creds_opt_set_canonicalize() with a different set of
     824                 :            :      * arguments. We should use a better configure check in the future.
     825                 :            :      */
     826                 :            : #if defined(HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CANONICALIZE) && defined(HAVE_KRB5_TICKET_TIMES)
     827                 :          0 :     krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize);
     828                 :            : #else
     829                 :            :     DEBUG(SSSDBG_OP_FAILURE, ("Kerberos principal canonicalization is not available!\n"));
     830                 :            : #endif
     831                 :          0 : }
     832                 :            : 
     833                 :            : #ifdef HAVE_KRB5_PRINCIPAL_GET_REALM
     834                 :            : void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ,
     835                 :            :                           const char **realm, int *len)
     836                 :            : {
     837                 :            :     *realm = krb5_principal_get_realm(context, princ);
     838                 :            :     *len = strlen(*realm);
     839                 :            : }
     840                 :            : #else
     841                 :          0 : void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ,
     842                 :            :                           const char **realm, int *len)
     843                 :            : {
     844                 :            :     const krb5_data *data;
     845                 :            : 
     846                 :          0 :     data = krb5_princ_realm(context, princ);
     847 [ #  # ][ #  # ]:          0 :     if (data) {
                 [ #  # ]
     848                 :          0 :         *realm = data->data;
     849                 :          0 :         *len = data->length;
     850                 :            :     } else {
     851                 :          0 :         *realm = NULL;
     852                 :          0 :         *len = 0;
     853                 :            :     }
     854                 :          0 : }
     855                 :            : #endif
     856                 :            : 
     857                 :            : #ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
     858                 :            : krb5_error_code
     859                 :          0 : sss_krb5_free_keytab_entry_contents(krb5_context context,
     860                 :            :                                     krb5_keytab_entry *entry)
     861                 :            : {
     862                 :          0 :     return krb5_free_keytab_entry_contents(context, entry);
     863                 :            : }
     864                 :            : #else
     865                 :            : krb5_error_code
     866                 :            : sss_krb5_free_keytab_entry_contents(krb5_context context,
     867                 :            :                                     krb5_keytab_entry *entry)
     868                 :            : {
     869                 :            :     return krb5_kt_free_entry(context, entry);
     870                 :            : }
     871                 :            : #endif
     872                 :            : 
     873                 :            : #define SSS_KRB5_FILE   "FILE:"
     874                 :            : #define SSS_KRB5_DIR    "DIR:"
     875                 :            : 
     876                 :            : enum sss_krb5_cc_type
     877                 :          2 : sss_krb5_get_type(const char *full_location)
     878                 :            : {
     879         [ +  - ]:          2 :     if (!full_location) {
     880                 :            :         return SSS_KRB5_TYPE_UNKNOWN;
     881                 :            :     }
     882                 :            : 
     883         [ +  - ]:          2 :     if (strncmp(full_location, SSS_KRB5_FILE,
     884                 :            :                 sizeof(SSS_KRB5_FILE)-1) == 0) {
     885                 :            :         return SSS_KRB5_TYPE_FILE;
     886                 :            :     }
     887                 :            : #ifdef HAVE_KRB5_DIRCACHE
     888         [ -  + ]:          2 :     else if (strncmp(full_location, SSS_KRB5_DIR,
     889                 :            :                sizeof(SSS_KRB5_DIR)-1) == 0) {
     890                 :            :         return SSS_KRB5_TYPE_DIR;
     891                 :            :     }
     892                 :            : #endif /* HAVE_KRB5_DIRCACHE */
     893         [ #  # ]:          0 :     else if (full_location[0] == '/') {
     894                 :            :         return SSS_KRB5_TYPE_FILE;
     895                 :            :     }
     896                 :            : 
     897                 :          2 :     return SSS_KRB5_TYPE_UNKNOWN;
     898                 :            : }
     899                 :            : 
     900                 :            : const char *
     901                 :          0 : sss_krb5_residual_by_type(const char *full_location,
     902                 :            :                           enum sss_krb5_cc_type type)
     903                 :            : {
     904                 :            :     size_t offset;
     905                 :            : 
     906   [ +  -  #  # ]:          2 :     if (full_location == NULL) return NULL;
                 [ #  # ]
     907                 :            : 
     908      [ -  +  - ]:          2 :     switch (type) {
              [ #  #  # ]
              [ #  #  # ]
     909                 :            :         case SSS_KRB5_TYPE_FILE:
     910 [ #  # ][ #  # ]:          0 :             if (full_location[0] == '/') {
                 [ #  # ]
     911                 :            :                 offset = 0;
     912                 :            :             } else {
     913                 :          0 :                 offset = sizeof(SSS_KRB5_FILE)-1;
     914                 :            :             }
     915                 :            :             break;
     916                 :            : #ifdef HAVE_KRB5_DIRCACHE
     917                 :            :         case SSS_KRB5_TYPE_DIR:
     918                 :            :             offset = sizeof(SSS_KRB5_DIR)-1;
     919                 :            :             break;
     920                 :            : #endif /* HAVE_KRB5_DIRCACHE */
     921                 :            :         default:
     922                 :            :             return NULL;
     923                 :            :     }
     924                 :            : 
     925                 :          2 :     return full_location + offset;
     926                 :            : }
     927                 :            : 
     928                 :            : const char *
     929                 :          0 : sss_krb5_cc_file_path(const char *full_location)
     930                 :            : {
     931                 :            :     enum sss_krb5_cc_type cc_type;
     932                 :            :     const char *residual;
     933                 :            : 
     934                 :          0 :     cc_type = sss_krb5_get_type(full_location);
     935                 :          0 :     residual = sss_krb5_residual_by_type(full_location, cc_type);
     936                 :            : 
     937      [ #  #  # ]:          0 :     switch(cc_type) {
     938                 :            :         case SSS_KRB5_TYPE_FILE:
     939                 :          0 :             return residual;
     940                 :            : #ifdef HAVE_KRB5_DIRCACHE
     941                 :            :         case SSS_KRB5_TYPE_DIR:
     942                 :            :             /* DIR::/run/user/tkt_foo */
     943         [ #  # ]:          0 :             if (residual[0] == ':') return residual+1;
     944                 :            : #endif
     945                 :            :         case SSS_KRB5_TYPE_UNKNOWN:
     946                 :            :             break;
     947                 :            :     }
     948                 :            : 
     949                 :            :     return NULL;
     950                 :            : }
     951                 :            : 
     952                 :            : const char *
     953                 :          2 : sss_krb5_residual_check_type(const char *full_location,
     954                 :            :                              enum sss_krb5_cc_type expected_type)
     955                 :            : {
     956                 :            :     enum sss_krb5_cc_type type;
     957                 :            : 
     958                 :          2 :     type = sss_krb5_get_type(full_location);
     959         [ -  + ]:          2 :     if (type != expected_type) {
     960 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_OP_FAILURE, ("Unexpected ccache type\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     961                 :            :         return NULL;
     962                 :            :     }
     963                 :            : 
     964                 :          2 :     return sss_krb5_residual_by_type(full_location, type);
     965                 :            : }
     966                 :            : 
     967                 :            : #ifdef HAVE_KRB5_SET_TRACE_CALLBACK
     968                 :            : static void
     969                 :          0 : sss_child_krb5_trace_cb(krb5_context context,
     970                 :            :                         const struct krb5_trace_info *info, void *data)
     971                 :            : {
     972         [ #  # ]:          0 :     if (info == NULL) {
     973                 :            :         /* Null info means destroy the callback data. */
     974                 :          0 :         return;
     975                 :            :     }
     976                 :            : 
     977 [ #  # ][ #  # ]:          0 :     DEBUG(SSSDBG_TRACE_ALL, ("%s\n", info->message));
         [ #  # ][ #  # ]
                 [ #  # ]
     978                 :            : }
     979                 :            : 
     980                 :            : errno_t
     981                 :          0 : sss_child_set_krb5_tracing(krb5_context ctx)
     982                 :            : {
     983                 :          0 :     return krb5_set_trace_callback(ctx, sss_child_krb5_trace_cb, NULL);
     984                 :            : }
     985                 :            : #else /* HAVE_KRB5_SET_TRACE_CALLBACK */
     986                 :            : errno_t
     987                 :            : sss_child_set_krb5_tracing(krb5_context ctx)
     988                 :            : {
     989                 :            :     DEBUG(SSSDBG_CONF_SETTINGS, ("krb5 tracing is not available\n"));
     990                 :            :     return 0;
     991                 :            : }
     992                 :            : #endif /* HAVE_KRB5_SET_TRACE_CALLBACK */
     993                 :            : 
     994                 :          0 : krb5_error_code sss_krb5_find_authdata(krb5_context context,
     995                 :            :                                        krb5_authdata *const *ticket_authdata,
     996                 :            :                                        krb5_authdata *const *ap_req_authdata,
     997                 :            :                                        krb5_authdatatype ad_type,
     998                 :            :                                        krb5_authdata ***results)
     999                 :            : {
    1000                 :            : #ifdef HAVE_KRB5_FIND_AUTHDATA
    1001                 :          0 :     return krb5_find_authdata(context, ticket_authdata, ap_req_authdata,
    1002                 :            :                               ad_type, results);
    1003                 :            : #else
    1004                 :            :     return ENOTSUP;
    1005                 :            : #endif
    1006                 :            : }
    1007                 :            : 
    1008                 :          0 : krb5_error_code sss_extract_pac(krb5_context ctx,
    1009                 :            :                                 krb5_ccache ccache,
    1010                 :            :                                 krb5_principal server_principal,
    1011                 :            :                                 krb5_principal client_principal,
    1012                 :            :                                 krb5_keytab keytab,
    1013                 :            :                                 krb5_authdata ***_pac_authdata)
    1014                 :            : {
    1015                 :            : #ifdef HAVE_PAC_RESPONDER
    1016                 :            :     krb5_error_code kerr;
    1017                 :            :     krb5_creds mcred;
    1018                 :            :     krb5_creds cred;
    1019                 :            :     krb5_authdata **pac_authdata = NULL;
    1020                 :            :     krb5_pac pac = NULL;
    1021                 :            :     int ret;
    1022                 :            :     krb5_ticket *ticket = NULL;
    1023                 :            :     krb5_keytab_entry entry;
    1024                 :            : 
    1025                 :            :     memset(&entry, 0, sizeof(entry));
    1026                 :            :     memset(&mcred, 0, sizeof(mcred));
    1027                 :            :     memset(&cred, 0, sizeof(mcred));
    1028                 :            : 
    1029                 :            :     mcred.server = server_principal;
    1030                 :            :     mcred.client = client_principal;
    1031                 :            : 
    1032                 :            :     kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
    1033                 :            :     if (kerr != 0) {
    1034                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_cc_retrieve_cred failed.\n"));
    1035                 :            :         goto done;
    1036                 :            :     }
    1037                 :            : 
    1038                 :            :     kerr = krb5_decode_ticket(&cred.ticket, &ticket);
    1039                 :            :     if (kerr != 0) {
    1040                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_decode_ticket failed.\n"));
    1041                 :            :         goto done;
    1042                 :            :     }
    1043                 :            : 
    1044                 :            :     kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket);
    1045                 :            :     if (kerr != 0) {
    1046                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_server_decrypt_ticket_keytab failed.\n"));
    1047                 :            :         goto done;
    1048                 :            :     }
    1049                 :            : 
    1050                 :            :     kerr = sss_krb5_find_authdata(ctx,
    1051                 :            :                                   ticket->enc_part2->authorization_data, NULL,
    1052                 :            :                                   KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata);
    1053                 :            :     if (kerr != 0) {
    1054                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_find_authdata failed.\n"));
    1055                 :            :         goto done;
    1056                 :            :     }
    1057                 :            : 
    1058                 :            :     if (pac_authdata == NULL || pac_authdata[0] == NULL) {
    1059                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("No PAC authdata available.\n"));
    1060                 :            :         kerr = ENOENT;
    1061                 :            :         goto done;
    1062                 :            :     }
    1063                 :            : 
    1064                 :            :     if (pac_authdata[1] != NULL) {
    1065                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("More than one PAC autdata found.\n"));
    1066                 :            :         kerr = EINVAL;
    1067                 :            :         goto done;
    1068                 :            :     }
    1069                 :            : 
    1070                 :            :     kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents,
    1071                 :            :                           pac_authdata[0]->length, &pac);
    1072                 :            :     if (kerr != 0) {
    1073                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_pac_parse failed.\n"));
    1074                 :            :         goto done;
    1075                 :            :     }
    1076                 :            : 
    1077                 :            :     kerr = krb5_kt_get_entry(ctx, keytab, ticket->server,
    1078                 :            :                              ticket->enc_part.kvno, ticket->enc_part.enctype,
    1079                 :            :                              &entry);
    1080                 :            :     if (kerr != 0) {
    1081                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_kt_get_entry failed.\n"));
    1082                 :            :         goto done;
    1083                 :            :     }
    1084                 :            : 
    1085                 :            :     kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL);
    1086                 :            :     if (kerr != 0) {
    1087                 :            :         DEBUG(SSSDBG_OP_FAILURE, ("krb5_pac_verify failed.\n"));
    1088                 :            :         goto done;
    1089                 :            :     }
    1090                 :            : 
    1091                 :            :     ret = unsetenv("_SSS_LOOPS");
    1092                 :            :     if (ret != EOK) {
    1093                 :            :         DEBUG(1, ("Failed to unset _SSS_LOOPS, "
    1094                 :            :                   "sss_pac_make_request will most certainly fail.\n"));
    1095                 :            :     }
    1096                 :            : 
    1097                 :            :     *_pac_authdata = pac_authdata;
    1098                 :            :     kerr = 0;
    1099                 :            : 
    1100                 :            : done:
    1101                 :            :     if (kerr != 0) {
    1102                 :            :         krb5_free_authdata(ctx, pac_authdata);
    1103                 :            :     }
    1104                 :            :     if (entry.magic != 0) {
    1105                 :            :         krb5_free_keytab_entry_contents(ctx, &entry);
    1106                 :            :     }
    1107                 :            :     krb5_pac_free(ctx, pac);
    1108                 :            :     if (ticket != NULL) {
    1109                 :            :         krb5_free_ticket(ctx, ticket);
    1110                 :            :     }
    1111                 :            : 
    1112                 :            :     krb5_free_cred_contents(ctx, &cred);
    1113                 :            :     return kerr;
    1114                 :            : #else
    1115                 :          0 :     return ENOTSUP;
    1116                 :            : #endif
    1117                 :            : }

Generated by: LCOV version 1.9