LCOV - code coverage report
Current view: top level - lib/krb5_wrap - krb5_samba.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 766 1527 50.2 %
Date: 2024-05-31 13:13:24 Functions: 48 63 76.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    simple kerberos5 routines for active directory
       4             :    Copyright (C) Andrew Tridgell 2001
       5             :    Copyright (C) Luke Howard 2002-2003
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       7             :    Copyright (C) Guenther Deschner 2005-2009
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/filesys.h"
      25             : #include "krb5_samba.h"
      26             : #include "lib/crypto/md4.h"
      27             : #include "../libds/common/flags.h"
      28             : 
      29             : #ifdef HAVE_COM_ERR_H
      30             : #include <com_err.h>
      31             : #endif /* HAVE_COM_ERR_H */
      32             : 
      33             : #ifndef KRB5_AUTHDATA_WIN2K_PAC
      34             : #define KRB5_AUTHDATA_WIN2K_PAC 128
      35             : #endif
      36             : 
      37             : #ifndef KRB5_AUTHDATA_IF_RELEVANT
      38             : #define KRB5_AUTHDATA_IF_RELEVANT 1
      39             : #endif
      40             : 
      41             : #ifdef HAVE_KRB5
      42             : 
      43             : #define GSSAPI_CHECKSUM      0x8003             /* Checksum type value for Kerberos */
      44             : #define GSSAPI_BNDLENGTH     16                 /* Bind Length (rfc-1964 pg.3) */
      45             : #define GSSAPI_CHECKSUM_SIZE (4+GSSAPI_BNDLENGTH+4) /* Length of bind length,
      46             :                                                         bind field, flags field. */
      47             : #define GSS_C_DELEG_FLAG 1
      48             : 
      49             : /* MIT krb5 1.7beta3 (in Ubuntu Karmic) is missing the prototype,
      50             :    but still has the symbol */
      51             : #if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
      52             : krb5_error_code krb5_auth_con_set_req_cksumtype(
      53             :         krb5_context     context,
      54             :         krb5_auth_context      auth_context,
      55             :         krb5_cksumtype     cksumtype);
      56             : #endif
      57             : 
      58             : #if !defined(SMB_MALLOC)
      59             : #undef malloc
      60             : #define SMB_MALLOC(s) malloc((s))
      61             : #endif
      62             : 
      63             : #ifndef SMB_STRDUP
      64             : #define SMB_STRDUP(s) strdup(s)
      65             : #endif
      66             : 
      67             : /**********************************************************
      68             :  * MISSING FUNCTIONS
      69             :  **********************************************************/
      70             : 
      71             : #if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
      72             : 
      73             : #if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
      74             : 
      75             : /* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
      76             :  * to krb5_set_default_tgs_ktypes. See
      77             :  *         http://lists.samba.org/archive/samba-technical/2006-July/048271.html
      78             :  *
      79             :  * If the MIT libraries are not exporting internal symbols, we will end up in
      80             :  * this branch, which is correct. Otherwise we will continue to use the
      81             :  * internal symbol
      82             :  */
      83             :  krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
      84             : {
      85             :     return krb5_set_default_tgs_enctypes(ctx, enc);
      86             : }
      87             : 
      88             : #elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
      89             : 
      90             : /* Heimdal */
      91           0 :  krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
      92             : {
      93           0 :         return krb5_set_default_in_tkt_etypes(ctx, enc);
      94             : }
      95             : 
      96             : #endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
      97             : 
      98             : #endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
      99             : 
     100             : 
     101             : #if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
     102           0 : krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
     103             :                                              krb5_auth_context auth_context,
     104             :                                              krb5_keyblock *keyblock)
     105             : {
     106           0 :         return krb5_auth_con_setkey(context, auth_context, keyblock);
     107             : }
     108             : #endif
     109             : 
     110             : #if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
     111             : void krb5_free_unparsed_name(krb5_context context, char *val)
     112             : {
     113             :         SAFE_FREE(val);
     114             : }
     115             : #endif
     116             : 
     117             : #if !defined(HAVE_KRB5_FREE_ENCTYPES)
     118       17553 : void krb5_free_enctypes(krb5_context context, krb5_enctype *val) {
     119       17553 :         krb5_xfree(val);
     120       17553 : }
     121             : #endif
     122             : 
     123             : #if !defined(HAVE_KRB5_FREE_STRING)
     124        1858 : void krb5_free_string(krb5_context context, char *val) {
     125        1858 :         SAFE_FREE(val);
     126        1858 : }
     127             : #endif
     128             : 
     129             : krb5_error_code smb_krb5_princ_component(krb5_context context,
     130             :                                          krb5_const_principal principal,
     131             :                                          int i,
     132             :                                          krb5_data *data);
     133       60862 : krb5_error_code smb_krb5_princ_component(krb5_context context,
     134             :                                          krb5_const_principal principal,
     135             :                                          int i,
     136             :                                          krb5_data *data)
     137             : {
     138             : #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
     139       60482 :         const char *component = NULL;
     140             : 
     141       60482 :         if (i < 0) {
     142           0 :                 return EINVAL;
     143             :         }
     144             : 
     145       60482 :         component = krb5_principal_get_comp_string(context, principal, i);
     146       60482 :         if (component == NULL) {
     147           0 :                 return ENOENT;
     148             :         }
     149             : 
     150       60482 :         *data = smb_krb5_make_data(discard_const_p(char, component), strlen(component));
     151             : 
     152       60482 :         return 0;
     153             : #else
     154         380 :         const krb5_data *kdata = NULL;
     155             : 
     156         380 :         if (i < 0) {
     157           0 :                 return EINVAL;
     158             :         }
     159             : 
     160         380 :         kdata = krb5_princ_component(context, principal, i);
     161         380 :         if (kdata == NULL) {
     162           0 :                 return ENOENT;
     163             :         }
     164             : 
     165         380 :         *data = *kdata;
     166             : 
     167         380 :         return 0;
     168             : #endif
     169             : }
     170             : 
     171             : /**********************************************************
     172             :  * WRAPPING FUNCTIONS
     173             :  **********************************************************/
     174             : 
     175             : /**
     176             :  * @brief Stores the address of a 'struct sockaddr_storage' into a krb5_address
     177             :  *
     178             :  * @param[in]  paddr    A pointer to a 'struct sockaddr_storage to extract the
     179             :  *                      address from.
     180             :  *
     181             :  * @param[out] pkaddr   A Kerberos address to store the address in.
     182             :  *
     183             :  * @return True on success, false if an error occurred.
     184             :  */
     185         168 : bool smb_krb5_sockaddr_to_kaddr(struct sockaddr_storage *paddr,
     186             :                                 krb5_address *pkaddr)
     187             : {
     188         168 :         memset(pkaddr, '\0', sizeof(krb5_address));
     189             : #if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
     190             : /* HEIMDAL */
     191             : #ifdef HAVE_IPV6
     192          68 :         if (paddr->ss_family == AF_INET6) {
     193           0 :                 pkaddr->addr_type = KRB5_ADDRESS_INET6;
     194           0 :                 pkaddr->address.length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
     195           0 :                 pkaddr->address.data = (char *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
     196           0 :                 return true;
     197             :         }
     198             : #endif
     199          68 :         if (paddr->ss_family == AF_INET) {
     200          68 :                 pkaddr->addr_type = KRB5_ADDRESS_INET;
     201          68 :                 pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
     202          68 :                 pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
     203          68 :                 return true;
     204             :         }
     205             : #elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
     206             : /* MIT */
     207             : #ifdef HAVE_IPV6
     208         100 :         if (paddr->ss_family == AF_INET6) {
     209           0 :                 pkaddr->addrtype = ADDRTYPE_INET6;
     210           0 :                 pkaddr->length = sizeof(((struct sockaddr_in6 *)paddr)->sin6_addr);
     211           0 :                 pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in6 *)paddr)->sin6_addr);
     212           0 :                 return true;
     213             :         }
     214             : #endif
     215         100 :         if (paddr->ss_family == AF_INET) {
     216         100 :                 pkaddr->addrtype = ADDRTYPE_INET;
     217         100 :                 pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
     218         100 :                 pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
     219         100 :                 return true;
     220             :         }
     221             : #else
     222             : #error UNKNOWN_ADDRTYPE
     223             : #endif
     224           0 :         return false;
     225             : }
     226             : 
     227          34 : krb5_error_code smb_krb5_mk_error(krb5_context context,
     228             :                                   krb5_error_code error_code,
     229             :                                   const char *e_text,
     230             :                                   krb5_data *e_data,
     231             :                                   const krb5_principal client,
     232             :                                   const krb5_principal server,
     233             :                                   krb5_data *enc_err)
     234             : {
     235          34 :         krb5_error_code code = EINVAL;
     236             : #ifdef SAMBA4_USES_HEIMDAL
     237          17 :         code = krb5_mk_error(context,
     238             :                              error_code,
     239             :                              e_text,
     240             :                              e_data,
     241             :                              client,
     242             :                              server,
     243             :                              NULL, /* client_time */
     244             :                              NULL, /* client_usec */
     245             :                              enc_err);
     246             : #else
     247          17 :         krb5_principal unspec_server = NULL;
     248             :         krb5_error errpkt;
     249             : 
     250          17 :         errpkt.ctime = 0;
     251          17 :         errpkt.cusec = 0;
     252             : 
     253          17 :         code = krb5_us_timeofday(context,
     254             :                                  &errpkt.stime,
     255             :                                  &errpkt.susec);
     256          17 :         if (code != 0) {
     257           0 :                 return code;
     258             :         }
     259             : 
     260          17 :         errpkt.error = error_code - ERROR_TABLE_BASE_krb5;
     261             : 
     262          17 :         errpkt.text.length = 0;
     263          17 :         if (e_text != NULL) {
     264           0 :                 errpkt.text = smb_krb5_make_data(discard_const_p(char, e_text), strlen(e_text));
     265             :         }
     266             : 
     267          17 :         errpkt.e_data = smb_krb5_make_data(NULL, 0);
     268          17 :         if (e_data != NULL) {
     269          17 :                 errpkt.e_data = *e_data;
     270             :         }
     271             : 
     272          17 :         errpkt.client = client;
     273             : 
     274          17 :         if (server != NULL) {
     275          17 :                 errpkt.server = server;
     276             :         } else {
     277           0 :                 code = smb_krb5_make_principal(context,
     278             :                                                &unspec_server,
     279             :                                                "<unspecified realm>",
     280             :                                                NULL);
     281           0 :                 if (code != 0) {
     282           0 :                         return code;
     283             :                 }
     284           0 :                 errpkt.server = unspec_server;
     285             :         }
     286             : 
     287          17 :         code = krb5_mk_error(context,
     288             :                              &errpkt,
     289             :                              enc_err);
     290          17 :         krb5_free_principal(context, unspec_server);
     291             : #endif
     292          34 :         return code;
     293             : }
     294             : 
     295             : /**
     296             : * @brief Create a keyblock based on input parameters
     297             : *
     298             : * @param context        The krb5_context
     299             : * @param host_princ     The krb5_principal to use
     300             : * @param salt           The optional salt, if omitted, salt is calculated with
     301             : *                       the provided principal.
     302             : * @param password       The krb5_data containing the password
     303             : * @param enctype        The krb5_enctype to use for the keyblock generation
     304             : * @param key            The returned krb5_keyblock, caller needs to free with
     305             : *                       krb5_free_keyblock().
     306             : *
     307             : * @return krb5_error_code
     308             : */
     309       50381 : int smb_krb5_create_key_from_string(krb5_context context,
     310             :                                     krb5_const_principal host_princ,
     311             :                                     const krb5_data *salt,
     312             :                                     const krb5_data *password,
     313             :                                     krb5_enctype enctype,
     314             :                                     krb5_keyblock *key)
     315             : {
     316       50381 :         int ret = 0;
     317             : 
     318       50381 :         if (host_princ == NULL && salt == NULL) {
     319           0 :                 return -1;
     320             :         }
     321             : 
     322       50381 :         if ((int)enctype == (int)ENCTYPE_ARCFOUR_HMAC) {
     323         529 :                 TALLOC_CTX *frame = talloc_stackframe();
     324         529 :                 uint8_t *utf16 = NULL;
     325         529 :                 size_t utf16_size = 0;
     326          26 :                 uint8_t nt_hash[16];
     327          26 :                 bool ok;
     328             : 
     329         555 :                 ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16LE,
     330         529 :                                            password->data, password->length,
     331             :                                            &utf16, &utf16_size);
     332         529 :                 if (!ok) {
     333           0 :                         if (errno == 0) {
     334           0 :                                 errno = EINVAL;
     335             :                         }
     336           0 :                         ret = errno;
     337           0 :                         TALLOC_FREE(frame);
     338           0 :                         return ret;
     339             :                 }
     340             : 
     341         529 :                 mdfour(nt_hash, utf16, utf16_size);
     342         529 :                 BURN_PTR_SIZE(utf16, utf16_size);
     343         529 :                 ret = smb_krb5_keyblock_init_contents(context,
     344             :                                                       ENCTYPE_ARCFOUR_HMAC,
     345             :                                                       nt_hash,
     346             :                                                       sizeof(nt_hash),
     347             :                                                       key);
     348         529 :                 ZERO_STRUCT(nt_hash);
     349         529 :                 if (ret != 0) {
     350           0 :                         TALLOC_FREE(frame);
     351           0 :                         return ret;
     352             :                 }
     353             : 
     354         529 :                 TALLOC_FREE(frame);
     355         529 :                 return 0;
     356             :         }
     357             : 
     358             : #if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_C_STRING_TO_KEY)
     359             : {/* MIT */
     360             :         krb5_data _salt;
     361             : 
     362       17071 :         if (salt == NULL) {
     363         308 :                 ret = krb5_principal2salt(context, host_princ, &_salt);
     364         308 :                 if (ret) {
     365           0 :                         DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
     366           0 :                         return ret;
     367             :                 }
     368             :         } else {
     369       16763 :                 _salt = *salt;
     370             :         }
     371       17071 :         ret = krb5_c_string_to_key(context, enctype, password, &_salt, key);
     372       17071 :         if (salt == NULL) {
     373         308 :                 SAFE_FREE(_salt.data);
     374             :         }
     375             : }
     376             : #elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
     377             : {/* Heimdal */
     378         482 :         krb5_salt _salt;
     379             : 
     380       32781 :         if (salt == NULL) {
     381         754 :                 ret = krb5_get_pw_salt(context, host_princ, &_salt);
     382         754 :                 if (ret) {
     383           0 :                         DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
     384           0 :                         return ret;
     385             :                 }
     386             :         } else {
     387       32027 :                 _salt.saltvalue = *salt;
     388       32027 :                 _salt.salttype = KRB5_PW_SALT;
     389             :         }
     390             : 
     391       32781 :         ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, _salt, key);
     392       32781 :         if (salt == NULL) {
     393         754 :                 krb5_free_salt(context, _salt);
     394             :         }
     395             : }
     396             : #else
     397             : #error UNKNOWN_CREATE_KEY_FUNCTIONS
     398             : #endif
     399       49852 :         return ret;
     400             : }
     401             : 
     402             : /**
     403             : * @brief Create a salt for a given principal
     404             : *
     405             : * @param context        The initialized krb5_context
     406             : * @param host_princ     The krb5_principal to create the salt for
     407             : * @param psalt          A pointer to a krb5_data struct
     408             : *
     409             : * caller has to free the contents of psalt with smb_krb5_free_data_contents
     410             : * when function has succeeded
     411             : *
     412             : * @return krb5_error_code, returns 0 on success, error code otherwise
     413             : */
     414             : 
     415       23632 : int smb_krb5_get_pw_salt(krb5_context context,
     416             :                          krb5_const_principal host_princ,
     417             :                          krb5_data *psalt)
     418             : #if defined(HAVE_KRB5_GET_PW_SALT)
     419             : /* Heimdal */
     420             : {
     421         199 :         int ret;
     422         199 :         krb5_salt salt;
     423             : 
     424       15649 :         ret = krb5_get_pw_salt(context, host_princ, &salt);
     425       15649 :         if (ret) {
     426           0 :                 return ret;
     427             :         }
     428             : 
     429       15649 :         *psalt = salt.saltvalue;
     430             : 
     431       15649 :         return ret;
     432             : }
     433             : #elif defined(HAVE_KRB5_PRINCIPAL2SALT)
     434             : /* MIT */
     435             : {
     436        7983 :         return krb5_principal2salt(context, host_princ, psalt);
     437             : }
     438             : #else
     439             : #error UNKNOWN_SALT_FUNCTIONS
     440             : #endif
     441             : 
     442             : /**
     443             :  * @brief This constructs the salt principal used by active directory
     444             :  *
     445             :  * Most Kerberos encryption types require a salt in order to
     446             :  * calculate the long term private key for user/computer object
     447             :  * based on a password.
     448             :  *
     449             :  * The returned _salt_principal is a string in forms like this:
     450             :  * - host/somehost.example.com@EXAMPLE.COM
     451             :  * - SomeAccount@EXAMPLE.COM
     452             :  * - SomePrincipal@EXAMPLE.COM
     453             :  *
     454             :  * This is not the form that's used as salt, it's just
     455             :  * the human readable form. It needs to be converted by
     456             :  * smb_krb5_salt_principal2data().
     457             :  *
     458             :  * @param[in]  realm              The realm the user/computer is added too.
     459             :  *
     460             :  * @param[in]  sAMAccountName     The sAMAccountName attribute of the object.
     461             :  *
     462             :  * @param[in]  userPrincipalName  The userPrincipalName attribute of the object
     463             :  *                                or NULL if not available.
     464             :  *
     465             :  * @param[in]  uac_flags          UF_ACCOUNT_TYPE_MASKed userAccountControl field
     466             :  *
     467             :  * @param[in]  mem_ctx            The TALLOC_CTX to allocate _salt_principal.
     468             :  *
     469             :  * @param[out]  _salt_principal   The resulting principal as string.
     470             :  *
     471             :  * @retval 0 Success; otherwise - Kerberos error codes
     472             :  *
     473             :  * @see smb_krb5_salt_principal2data
     474             :  */
     475       21664 : int smb_krb5_salt_principal(krb5_context krb5_ctx,
     476             :                             const char *realm,
     477             :                             const char *sAMAccountName,
     478             :                             const char *userPrincipalName,
     479             :                             uint32_t uac_flags,
     480             :                             krb5_principal *salt_princ)
     481             : {
     482       21664 :         TALLOC_CTX *frame = talloc_stackframe();
     483       21664 :         char *upper_realm = NULL;
     484       21664 :         const char *principal = NULL;
     485       21664 :         int principal_len = 0;
     486         199 :         krb5_error_code krb5_ret;
     487             : 
     488       21664 :         *salt_princ = NULL;
     489             : 
     490       21664 :         if (sAMAccountName == NULL) {
     491           0 :                 TALLOC_FREE(frame);
     492           0 :                 return EINVAL;
     493             :         }
     494             : 
     495       21664 :         if (realm == NULL) {
     496           0 :                 TALLOC_FREE(frame);
     497           0 :                 return EINVAL;
     498             :         }
     499             : 
     500       21664 :         if (uac_flags & ~UF_ACCOUNT_TYPE_MASK) {
     501             :                 /*
     502             :                  * catch callers which still
     503             :                  * pass 'true'.
     504             :                  */
     505           0 :                 TALLOC_FREE(frame);
     506           0 :                 return EINVAL;
     507             :         }
     508       21664 :         if (uac_flags == 0) {
     509             :                 /*
     510             :                  * catch callers which still
     511             :                  * pass 'false'.
     512             :                  */
     513           0 :                 TALLOC_FREE(frame);
     514           0 :                 return EINVAL;
     515             :         }
     516             : 
     517       21664 :         upper_realm = strupper_talloc(frame, realm);
     518       21664 :         if (upper_realm == NULL) {
     519           0 :                 TALLOC_FREE(frame);
     520           0 :                 return ENOMEM;
     521             :         }
     522             : 
     523             :         /* Many, many thanks to lukeh@padl.com for this
     524             :          * algorithm, described in his Nov 10 2004 mail to
     525             :          * samba-technical@lists.samba.org */
     526             : 
     527             :         /*
     528             :          * Determine a salting principal
     529             :          */
     530       21664 :         if (uac_flags & UF_TRUST_ACCOUNT_MASK) {
     531        3300 :                 int computer_len = 0;
     532             : 
     533        3300 :                 computer_len = strlen(sAMAccountName);
     534        3300 :                 if (sAMAccountName[computer_len-1] == '$') {
     535        3292 :                         computer_len -= 1;
     536             :                 }
     537             : 
     538        3300 :                 if (uac_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) {
     539         190 :                         const char *krbtgt = "krbtgt";
     540         190 :                         krb5_ret = krb5_build_principal_ext(krb5_ctx,
     541             :                                                             salt_princ,
     542         190 :                                                             strlen(upper_realm),
     543             :                                                             upper_realm,
     544             :                                                             strlen(krbtgt),
     545             :                                                             krbtgt,
     546             :                                                             computer_len,
     547             :                                                             sAMAccountName,
     548             :                                                             0);
     549         190 :                         if (krb5_ret != 0) {
     550           0 :                                 TALLOC_FREE(frame);
     551           0 :                                 return krb5_ret;
     552             :                         }
     553             :                 } else {
     554        3110 :                         const char *host = "host";
     555        3110 :                         char *tmp = NULL;
     556        3110 :                         char *tmp_lower = NULL;
     557             : 
     558        3110 :                         tmp = talloc_asprintf(frame, "%*.*s.%s",
     559             :                                               computer_len,
     560             :                                               computer_len,
     561             :                                               sAMAccountName,
     562             :                                               realm);
     563        3110 :                         if (tmp == NULL) {
     564           0 :                                 TALLOC_FREE(frame);
     565           0 :                                 return ENOMEM;
     566             :                         }
     567             : 
     568        3110 :                         tmp_lower = strlower_talloc(frame, tmp);
     569        3110 :                         if (tmp_lower == NULL) {
     570           0 :                                 TALLOC_FREE(frame);
     571           0 :                                 return ENOMEM;
     572             :                         }
     573             : 
     574        3231 :                         krb5_ret = krb5_build_principal_ext(krb5_ctx,
     575             :                                                             salt_princ,
     576        3110 :                                                             strlen(upper_realm),
     577             :                                                             upper_realm,
     578             :                                                             strlen(host),
     579             :                                                             host,
     580             :                                                             strlen(tmp_lower),
     581             :                                                             tmp_lower,
     582             :                                                             0);
     583        3110 :                         if (krb5_ret != 0) {
     584           0 :                                 TALLOC_FREE(frame);
     585           0 :                                 return krb5_ret;
     586             :                         }
     587             :                 }
     588             : 
     589       18364 :         } else if (userPrincipalName != NULL) {
     590             :                 /*
     591             :                  * We parse the name not only to allow an easy
     592             :                  * replacement of the realm (no matter the realm in
     593             :                  * the UPN, the salt comes from the upper-case real
     594             :                  * realm, but also to correctly provide a salt when
     595             :                  * the UPN is host/foo.bar
     596             :                  *
     597             :                  * This can fail for a UPN of the form foo@bar@REALM
     598             :                  * (which is accepted by windows) however.
     599             :                  */
     600       14287 :                 krb5_ret = krb5_parse_name(krb5_ctx,
     601             :                                            userPrincipalName,
     602             :                                            salt_princ);
     603             : 
     604       14287 :                 if (krb5_ret != 0) {
     605           2 :                         TALLOC_FREE(frame);
     606           2 :                         return krb5_ret;
     607             :                 }
     608             : 
     609             :                 /*
     610             :                  * No matter what realm (including none) in the UPN,
     611             :                  * the realm is replaced with our upper-case realm
     612             :                  */
     613       14285 :                 krb5_ret = smb_krb5_principal_set_realm(krb5_ctx,
     614             :                                                         *salt_princ,
     615             :                                                         upper_realm);
     616       14285 :                 if (krb5_ret != 0) {
     617           0 :                         krb5_free_principal(krb5_ctx, *salt_princ);
     618           0 :                         TALLOC_FREE(frame);
     619           0 :                         return krb5_ret;
     620             :                 }
     621             :         } else {
     622        4077 :                 principal = sAMAccountName;
     623        4077 :                 principal_len = strlen(principal);
     624             : 
     625        4123 :                 krb5_ret = krb5_build_principal_ext(krb5_ctx,
     626             :                                                     salt_princ,
     627        4077 :                                                     strlen(upper_realm),
     628             :                                                     upper_realm,
     629             :                                                     principal_len,
     630             :                                                     principal,
     631             :                                                     0);
     632        4077 :                 if (krb5_ret != 0) {
     633           0 :                         TALLOC_FREE(frame);
     634           0 :                         return krb5_ret;
     635             :                 }
     636             :         }
     637             : 
     638       21662 :         TALLOC_FREE(frame);
     639       21463 :         return 0;
     640             : }
     641             : 
     642             : /**
     643             :  * @brief This constructs the salt principal used by active directory
     644             :  *
     645             :  * Most Kerberos encryption types require a salt in order to
     646             :  * calculate the long term private key for user/computer object
     647             :  * based on a password.
     648             :  *
     649             :  * The returned _salt_principal is a string in forms like this:
     650             :  * - host/somehost.example.com@EXAMPLE.COM
     651             :  * - SomeAccount@EXAMPLE.COM
     652             :  * - SomePrincipal@EXAMPLE.COM
     653             :  *
     654             :  * This is not the form that's used as salt, it's just
     655             :  * the human readable form. It needs to be converted by
     656             :  * smb_krb5_salt_principal2data().
     657             :  *
     658             :  * @param[in]  realm              The realm the user/computer is added too.
     659             :  *
     660             :  * @param[in]  sAMAccountName     The sAMAccountName attribute of the object.
     661             :  *
     662             :  * @param[in]  userPrincipalName  The userPrincipalName attribute of the object
     663             :  *                                or NULL if not available.
     664             :  *
     665             :  * @param[in]  uac_flags          UF_ACCOUNT_TYPE_MASKed userAccountControl field
     666             :  *
     667             :  * @param[in]  mem_ctx            The TALLOC_CTX to allocate _salt_principal.
     668             :  *
     669             :  * @param[out]  _salt_principal   The resulting principal as string.
     670             :  *
     671             :  * @retval 0 Success; otherwise - Kerberos error codes
     672             :  *
     673             :  * @see smb_krb5_salt_principal2data
     674             :  */
     675         117 : int smb_krb5_salt_principal_str(const char *realm,
     676             :                                 const char *sAMAccountName,
     677             :                                 const char *userPrincipalName,
     678             :                                 uint32_t uac_flags,
     679             :                                 TALLOC_CTX *mem_ctx,
     680             :                                 char **_salt_principal_str)
     681             : {
     682         117 :         krb5_principal salt_principal = NULL;
     683           0 :         char *salt_principal_malloc;
     684           0 :         krb5_context krb5_ctx;
     685           0 :         krb5_error_code krb5_ret
     686         117 :                 = smb_krb5_init_context_common(&krb5_ctx);
     687         117 :         if (krb5_ret != 0) {
     688           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     689             :                         error_message(krb5_ret));
     690           0 :                 return krb5_ret;
     691             :         }
     692             : 
     693         117 :         krb5_ret = smb_krb5_salt_principal(krb5_ctx,
     694             :                                            realm,
     695             :                                            sAMAccountName,
     696             :                                            userPrincipalName,
     697             :                                            uac_flags,
     698             :                                            &salt_principal);
     699         117 :         if (krb5_ret != 0) {
     700           0 :                 DBG_ERR("unable to create salt principal:%s\n",
     701             :                         error_message(krb5_ret));
     702           0 :                 return krb5_ret;
     703             :         }
     704             : 
     705         117 :         krb5_ret = krb5_unparse_name(krb5_ctx, salt_principal,
     706             :                                      &salt_principal_malloc);
     707         117 :         if (krb5_ret != 0) {
     708           0 :                 krb5_free_principal(krb5_ctx, salt_principal);
     709           0 :                 DBG_ERR("kerberos unparse of salt principal failed (%s)\n",
     710             :                         error_message(krb5_ret));
     711           0 :                 return krb5_ret;
     712             :         }
     713         117 :         krb5_free_principal(krb5_ctx, salt_principal);
     714           0 :         *_salt_principal_str
     715         117 :                 = talloc_strdup(mem_ctx, salt_principal_malloc);
     716         117 :         krb5_free_unparsed_name(krb5_ctx, salt_principal_malloc);
     717             : 
     718         117 :         if (*_salt_principal_str == NULL) {
     719           0 :                 return ENOMEM;
     720             :         }
     721         117 :         return 0;
     722             : }
     723             : 
     724             : /**
     725             :  * @brief Converts the salt principal string into the salt data blob
     726             :  *
     727             :  * This function takes a salt_principal as string in forms like this:
     728             :  * - host/somehost.example.com@EXAMPLE.COM
     729             :  * - SomeAccount@EXAMPLE.COM
     730             :  * - SomePrincipal@EXAMPLE.COM
     731             :  *
     732             :  * It generates values like:
     733             :  * - EXAMPLE.COMhost/somehost.example.com
     734             :  * - EXAMPLE.COMSomeAccount
     735             :  * - EXAMPLE.COMSomePrincipal
     736             :  *
     737             :  * @param[in]  realm              The realm the user/computer is added too.
     738             :  *
     739             :  * @param[in]  sAMAccountName     The sAMAccountName attribute of the object.
     740             :  *
     741             :  * @param[in]  userPrincipalName  The userPrincipalName attribute of the object
     742             :  *                                or NULL if not available.
     743             :  *
     744             :  * @param[in]  is_computer        The indication of the object includes
     745             :  *                                objectClass=computer.
     746             :  *
     747             :  * @param[in]  mem_ctx            The TALLOC_CTX to allocate _salt_principal.
     748             :  *
     749             :  * @param[out]  _salt_principal   The resulting principal as string.
     750             :  *
     751             :  * @retval 0 Success; otherwise - Kerberos error codes
     752             :  *
     753             :  * @see smb_krb5_salt_principal
     754             :  */
     755          84 : int smb_krb5_salt_principal2data(krb5_context context,
     756             :                                  const char *salt_principal,
     757             :                                  TALLOC_CTX *mem_ctx,
     758             :                                  char **_salt_data)
     759             : {
     760           0 :         krb5_error_code ret;
     761          84 :         krb5_principal salt_princ = NULL;
     762           0 :         krb5_data salt;
     763             : 
     764          84 :         *_salt_data = NULL;
     765             : 
     766          84 :         ret = krb5_parse_name(context, salt_principal, &salt_princ);
     767          84 :         if (ret != 0) {
     768           0 :                 return ret;
     769             :         }
     770             : 
     771          84 :         ret = smb_krb5_get_pw_salt(context, salt_princ, &salt);
     772          84 :         krb5_free_principal(context, salt_princ);
     773          84 :         if (ret != 0) {
     774           0 :                 return ret;
     775             :         }
     776             : 
     777         168 :         *_salt_data = talloc_strndup(mem_ctx,
     778          84 :                                      (char *)salt.data,
     779          35 :                                      salt.length);
     780          84 :         smb_krb5_free_data_contents(context, &salt);
     781          84 :         if (*_salt_data == NULL) {
     782           0 :                 return ENOMEM;
     783             :         }
     784             : 
     785          84 :         return 0;
     786             : }
     787             : 
     788             : #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
     789             : /**
     790             :  * @brief Get a list of encryption types allowed for session keys
     791             :  *
     792             :  * @param[in]  context  The library context
     793             :  *
     794             :  * @param[in]  enctypes An allocated, zero-terminated list of encryption types
     795             :  *
     796             :  * This function returns an allocated list of encryption types allowed for
     797             :  * session keys.
     798             :  *
     799             :  * Use krb5_free_enctypes() to free the enctypes when it is no longer needed.
     800             :  *
     801             :  * @retval 0 Success; otherwise - Kerberos error codes
     802             :  */
     803        8055 : krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
     804             :                                             krb5_enctype **enctypes)
     805             : {
     806        8055 :         return krb5_get_permitted_enctypes(context, enctypes);
     807             : }
     808             : #elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
     809       17553 : krb5_error_code smb_krb5_get_allowed_etypes(krb5_context context,
     810             :                                             krb5_enctype **enctypes)
     811             : {
     812             : #ifdef HAVE_KRB5_PDU_NONE_DECL
     813       17553 :         return krb5_get_default_in_tkt_etypes(context, KRB5_PDU_NONE, enctypes);
     814             : #else
     815             :         return krb5_get_default_in_tkt_etypes(context, enctypes);
     816             : #endif
     817             : }
     818             : #else
     819             : #error UNKNOWN_GET_ENCTYPES_FUNCTIONS
     820             : #endif
     821             : 
     822             : 
     823             : /**
     824             :  * @brief Convert a string principal name to a Kerberos principal.
     825             :  *
     826             :  * @param[in]  context  The library context
     827             :  *
     828             :  * @param[in]  name     The principal as a unix charset string.
     829             :  *
     830             :  * @param[out] principal The newly allocated principal.
     831             :  *
     832             :  * Use krb5_free_principal() to free a principal when it is no longer needed.
     833             :  *
     834             :  * @return 0 on success, a Kerberos error code otherwise.
     835             :  */
     836        3699 : krb5_error_code smb_krb5_parse_name(krb5_context context,
     837             :                                     const char *name,
     838             :                                     krb5_principal *principal)
     839             : {
     840           0 :         krb5_error_code ret;
     841           0 :         char *utf8_name;
     842           0 :         size_t converted_size;
     843        3699 :         TALLOC_CTX *frame = talloc_stackframe();
     844             : 
     845        3699 :         if (!push_utf8_talloc(frame, &utf8_name, name, &converted_size)) {
     846           0 :                 talloc_free(frame);
     847           0 :                 return ENOMEM;
     848             :         }
     849             : 
     850        3699 :         ret = krb5_parse_name(context, utf8_name, principal);
     851        3699 :         if (ret == KRB5_PARSE_MALFORMED) {
     852           2 :                 ret = krb5_parse_name_flags(context, utf8_name,
     853             :                                             KRB5_PRINCIPAL_PARSE_ENTERPRISE,
     854             :                                             principal);
     855             :         }
     856        3699 :         TALLOC_FREE(frame);
     857        3699 :         return ret;
     858             : }
     859             : 
     860             : /**
     861             :  * @brief Convert a Kerberos principal structure to a string representation.
     862             :  *
     863             :  * The resulting string representation will be a unix charset name and is
     864             :  * talloc'ed.
     865             :  *
     866             :  * @param[in]  mem_ctx  The talloc context to allocate memory on.
     867             :  *
     868             :  * @param[in]  context  The library context.
     869             :  *
     870             :  * @param[in]  principal The principal.
     871             :  *
     872             :  * @param[out] unix_name A string representation of the principal name as with
     873             :  *                       unix charset.
     874             :  *
     875             :  * Use talloc_free() to free the string representation if it is no longer
     876             :  * needed.
     877             :  *
     878             :  * @return 0 on success, a Kerberos error code otherwise.
     879             :  */
     880       19766 : krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx,
     881             :                                       krb5_context context,
     882             :                                       krb5_const_principal principal,
     883             :                                       char **unix_name)
     884             : {
     885           0 :         krb5_error_code ret;
     886           0 :         char *utf8_name;
     887           0 :         size_t converted_size;
     888             : 
     889       19766 :         *unix_name = NULL;
     890       19766 :         ret = krb5_unparse_name(context, principal, &utf8_name);
     891       19766 :         if (ret) {
     892           0 :                 return ret;
     893             :         }
     894             : 
     895       19766 :         if (!pull_utf8_talloc(mem_ctx, unix_name, utf8_name, &converted_size)) {
     896           0 :                 krb5_free_unparsed_name(context, utf8_name);
     897           0 :                 return ENOMEM;
     898             :         }
     899       19766 :         krb5_free_unparsed_name(context, utf8_name);
     900       19766 :         return 0;
     901             : }
     902             : 
     903             : /**
     904             :  * @brief Free the contents of a krb5_data structure and zero the data field.
     905             :  *
     906             :  * @param[in]  context  The krb5 context
     907             :  *
     908             :  * @param[in]  pdata    The data structure to free contents of
     909             :  *
     910             :  * This function frees the contents, not the structure itself.
     911             :  */
     912      815360 : void smb_krb5_free_data_contents(krb5_context context, krb5_data *pdata)
     913             : {
     914             : #if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
     915       25175 :         if (pdata->data) {
     916       25174 :                 krb5_free_data_contents(context, pdata);
     917             :         }
     918             : #elif defined(HAVE_KRB5_DATA_FREE)
     919             :         krb5_data_free(context, pdata);
     920             : #else
     921      790185 :         SAFE_FREE(pdata->data);
     922             : #endif
     923      815360 : }
     924             : 
     925             : /*
     926             :  * @brief copy a buffer into a krb5_data struct
     927             :  *
     928             :  * @param[in] p                 The krb5_data
     929             :  * @param[in] data              The data to copy
     930             :  * @param[in] length            The length of the data to copy
     931             :  * @return krb5_error_code
     932             :  *
     933             :  * Caller has to free krb5_data with smb_krb5_free_data_contents().
     934             :  */
     935     1498993 : krb5_error_code smb_krb5_copy_data_contents(krb5_data *p,
     936             :                                             const void *data,
     937             :                                             size_t len)
     938             : {
     939             : #if defined(HAVE_KRB5_DATA_COPY)
     940     1492010 :         return krb5_data_copy(p, data, len);
     941             : #else
     942        6983 :         if (len) {
     943        6983 :                 p->data = malloc(len);
     944        6983 :                 if (p->data == NULL) {
     945           0 :                         return ENOMEM;
     946             :                 }
     947        6983 :                 memmove(p->data, data, len);
     948             :         } else {
     949           0 :                 p->data = NULL;
     950             :         }
     951        6983 :         p->length = len;
     952        6983 :         p->magic = KV5M_DATA;
     953        6983 :         return 0;
     954             : #endif
     955             : }
     956             : 
     957             : /*
     958             :  * @brief put a buffer reference into a krb5_data struct
     959             :  *
     960             :  * @param[in] data              The data to reference
     961             :  * @param[in] length            The length of the data to reference
     962             :  * @return krb5_data
     963             :  *
     964             :  * Caller should not free krb5_data.
     965             :  */
     966      749936 : krb5_data smb_krb5_make_data(void *data,
     967             :                              size_t len)
     968             : {
     969       27546 :         krb5_data d;
     970             : 
     971             : #ifdef SAMBA4_USES_HEIMDAL
     972      749887 :         d.data = (uint8_t *)data;
     973      749887 :         d.length = len;
     974             : #else
     975          49 :         d.magic = KV5M_DATA;
     976          49 :         d.data = data;
     977          49 :         d.length = len;
     978             : #endif
     979      749936 :         return d;
     980             : }
     981             : 
     982      310354 : krb5_data smb_krb5_data_from_blob(DATA_BLOB blob)
     983             : {
     984      310354 :         return smb_krb5_make_data(blob.data, blob.length);
     985             : }
     986             : 
     987        1384 : bool smb_krb5_get_smb_session_key(TALLOC_CTX *mem_ctx,
     988             :                                   krb5_context context,
     989             :                                   krb5_auth_context auth_context,
     990             :                                   DATA_BLOB *session_key,
     991             :                                   bool remote)
     992             : {
     993        1384 :         krb5_keyblock *skey = NULL;
     994        1384 :         krb5_error_code err = 0;
     995        1384 :         bool ret = false;
     996             : 
     997        1384 :         if (remote) {
     998             : #ifdef HAVE_KRB5_AUTH_CON_GETRECVSUBKEY
     999          42 :                 err = krb5_auth_con_getrecvsubkey(context,
    1000             :                                                   auth_context,
    1001             :                                                   &skey);
    1002             : #else /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
    1003        1212 :                 err = krb5_auth_con_getremotesubkey(context,
    1004             :                                                     auth_context, &skey);
    1005             : #endif /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
    1006             :         } else {
    1007             : #ifdef HAVE_KRB5_AUTH_CON_GETSENDSUBKEY
    1008          64 :                 err = krb5_auth_con_getsendsubkey(context,
    1009             :                                                   auth_context,
    1010             :                                                   &skey);
    1011             : #else /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
    1012          66 :                 err = krb5_auth_con_getlocalsubkey(context,
    1013             :                                                    auth_context, &skey);
    1014             : #endif /* HAVE_KRB5_AUTH_CON_GETSENDSUBKEY */
    1015             :         }
    1016             : 
    1017        1384 :         if (err || skey == NULL) {
    1018           0 :                 DEBUG(10, ("KRB5 error getting session key %d\n", err));
    1019           0 :                 goto done;
    1020             :         }
    1021             : 
    1022        1384 :         DEBUG(10, ("Got KRB5 session key of length %d\n",
    1023             :                    (int)KRB5_KEY_LENGTH(skey)));
    1024             : 
    1025        1384 :         *session_key = data_blob_talloc(mem_ctx,
    1026             :                                          KRB5_KEY_DATA(skey),
    1027             :                                          KRB5_KEY_LENGTH(skey));
    1028        1384 :         dump_data_pw("KRB5 Session Key:\n",
    1029        1384 :                      session_key->data,
    1030             :                      session_key->length);
    1031             : 
    1032        1384 :         ret = true;
    1033             : 
    1034        1384 : done:
    1035        1384 :         if (skey) {
    1036        1384 :                 krb5_free_keyblock(context, skey);
    1037             :         }
    1038             : 
    1039        1384 :         return ret;
    1040             : }
    1041             : 
    1042             : 
    1043             : /**
    1044             :  * @brief Get talloced string component of a principal
    1045             :  *
    1046             :  * @param[in] mem_ctx           The TALLOC_CTX
    1047             :  * @param[in] context           The krb5_context
    1048             :  * @param[in] principal         The principal
    1049             :  * @param[in] component         The component
    1050             :  * @param[out] out                      The output string
    1051             :  * @return krb5_error_code
    1052             :  *
    1053             :  * Caller must talloc_free if the return value is not NULL.
    1054             :  *
    1055             :  */
    1056      468853 : krb5_error_code smb_krb5_principal_get_comp_string(TALLOC_CTX *mem_ctx,
    1057             :                                                    krb5_context context,
    1058             :                                                    krb5_const_principal principal,
    1059             :                                                    unsigned int component,
    1060             :                                                    char **out)
    1061             : {
    1062      468853 :         char *out_str = NULL;
    1063             : #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
    1064      467771 :         const char *str = NULL;
    1065             : 
    1066      467771 :         str = krb5_principal_get_comp_string(context, principal, component);
    1067      467771 :         if (str == NULL) {
    1068          37 :                 return ENOENT;
    1069             :         }
    1070             : 
    1071      467734 :         out_str = talloc_strdup(mem_ctx, str);
    1072      467734 :         if (out_str == NULL) {
    1073           0 :                 return ENOMEM;
    1074             :         }
    1075             : #else
    1076             :         krb5_data *data;
    1077             : 
    1078        1082 :         if (component >= krb5_princ_size(context, principal)) {
    1079           0 :                 return ENOENT;
    1080             :         }
    1081             : 
    1082        1082 :         data = krb5_princ_component(context, principal, component);
    1083        1082 :         if (data == NULL) {
    1084           0 :                 return ENOENT;
    1085             :         }
    1086             : 
    1087        1082 :         out_str = talloc_strndup(mem_ctx, data->data, data->length);
    1088        1082 :         if (out_str == NULL) {
    1089           0 :                 return ENOMEM;
    1090             :         }
    1091             : #endif
    1092      468816 :         *out = out_str;
    1093      468816 :         return 0;
    1094             : }
    1095             : 
    1096       56799 : krb5_error_code smb_krb5_cc_new_unique_memory(krb5_context context,
    1097             :                                               TALLOC_CTX *mem_ctx,
    1098             :                                               char **ccache_name,
    1099             :                                               krb5_ccache *id)
    1100             : {
    1101        1518 :         krb5_error_code code;
    1102       56799 :         const char *type = NULL;
    1103       56799 :         const char *name = NULL;
    1104             : 
    1105       56799 :         if (ccache_name != NULL) {
    1106       48885 :                 *ccache_name = NULL;
    1107             :         }
    1108       56799 :         *id = NULL;
    1109             : 
    1110             : #ifdef SAMBA4_USES_HEIMDAL
    1111             :         /*
    1112             :          * "MEMORY:anonymous" is not visible to
    1113             :          * the credential cache collection iterator
    1114             :          *
    1115             :          * It creates anonymous-POINTER-UNIQUECOUNTTER
    1116             :          * in the background.
    1117             :          */
    1118       37016 :         code = krb5_cc_resolve(context, "MEMORY:anonymous", id);
    1119       37016 :         if (code != 0) {
    1120           0 :                 DBG_ERR("krb5_cc_resolve(MEMORY:anonymous) failed: %s\n",
    1121             :                         smb_get_krb5_error_message(
    1122             :                                 context, code, mem_ctx));
    1123           0 :                 return code;
    1124             :         }
    1125             : #else /* MIT */
    1126             :         /*
    1127             :          * In MIT the "MEMORY:" credential cache collection
    1128             :          * only contains the default cache (at most).
    1129             :          */
    1130       19783 :         code = krb5_cc_new_unique(context, "MEMORY", NULL, id);
    1131       19783 :         if (code != 0) {
    1132           0 :                 DBG_ERR("krb5_cc_new_unique failed: %s\n",
    1133             :                         smb_get_krb5_error_message(
    1134             :                                 context, code, mem_ctx));
    1135           0 :                 return code;
    1136             :         }
    1137             : #endif /* MIT */
    1138             : 
    1139       56799 :         type = krb5_cc_get_type(context, *id);
    1140       56799 :         if (type == NULL) {
    1141           0 :                 DBG_ERR("krb5_cc_get_type failed...\n");
    1142           0 :                 krb5_cc_destroy(context, *id);
    1143           0 :                 *id = NULL;
    1144           0 :                 return KRB5_CC_UNKNOWN_TYPE;
    1145             :         }
    1146             : 
    1147       56799 :         name = krb5_cc_get_name(context, *id);
    1148       56799 :         if (name == NULL) {
    1149           0 :                 DBG_ERR("krb5_cc_get_name failed...\n");
    1150           0 :                 krb5_cc_destroy(context, *id);
    1151           0 :                 *id = NULL;
    1152           0 :                 return KRB5_CC_BADNAME;
    1153             :         }
    1154             : 
    1155       56799 :         if (ccache_name == NULL) {
    1156        7876 :                 return 0;
    1157             :         }
    1158             : 
    1159       48885 :         *ccache_name = talloc_asprintf(mem_ctx, "%s:%s", type, name);
    1160       48885 :         if (*ccache_name == NULL) {
    1161           0 :                 DBG_ERR("krb5_cc_get_name failed...\n");
    1162           0 :                 krb5_cc_destroy(context, *id);
    1163           0 :                 *id = NULL;
    1164           0 :                 return ENOMEM;
    1165             :         }
    1166             : 
    1167       47405 :         return 0;
    1168             : }
    1169             : 
    1170             : /**
    1171             :  * @brief
    1172             :  *
    1173             :  * @param[in]  ccache_string A string pointing to the cache to renew the ticket
    1174             :  *                           (e.g. FILE:/tmp/krb5cc_0) or NULL. If the principal
    1175             :  *                           ccache has not been specified, the default ccache
    1176             :  *                           will be used.
    1177             :  *
    1178             :  * @param[in]  client_string The client principal string (e.g. user@SAMBA.SITE)
    1179             :  *                           or NULL. If the principal string has not been
    1180             :  *                           specified, the principal from the ccache will be
    1181             :  *                           retrieved.
    1182             :  *
    1183             :  * @param[in]  service_string The service ticket string
    1184             :  *                            (e.g. krbtgt/SAMBA.SITE@SAMBA.SITE) or NULL. If
    1185             :  *                            the service ticket is specified, it is parsed
    1186             :  *                            (with the realm part ignored) and used as the
    1187             :  *                            server principal of the credential. Otherwise
    1188             :  *                            the ticket-granting service is used.
    1189             :  *
    1190             :  * @param[in]  expire_time    A pointer to store the credentials end time or
    1191             :  *                            NULL.
    1192             :  *
    1193             :  * @return 0 on Success, a Kerberos error code otherwise.
    1194             :  */
    1195           0 : krb5_error_code smb_krb5_renew_ticket(const char *ccache_string,
    1196             :                                       const char *client_string,
    1197             :                                       const char *service_string,
    1198             :                                       time_t *expire_time)
    1199             : {
    1200           0 :         krb5_error_code ret;
    1201           0 :         krb5_context context = NULL;
    1202           0 :         krb5_ccache ccache = NULL;
    1203           0 :         krb5_principal client = NULL;
    1204           0 :         krb5_creds creds, creds_in;
    1205             : 
    1206           0 :         ZERO_STRUCT(creds);
    1207           0 :         ZERO_STRUCT(creds_in);
    1208             : 
    1209           0 :         ret = smb_krb5_init_context_common(&context);
    1210           0 :         if (ret) {
    1211           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
    1212             :                         error_message(ret));
    1213           0 :                 goto done;
    1214             :         }
    1215             : 
    1216           0 :         if (!ccache_string) {
    1217             :                 /*
    1218             :                  * A renew has low risk in mixing different
    1219             :                  * ccaches, so we allow callers to pass
    1220             :                  * NULL for the default cache.
    1221             :                  */
    1222           0 :                 ccache_string = smb_force_krb5_cc_default_name(context);
    1223             :         }
    1224             : 
    1225           0 :         if (!ccache_string) {
    1226           0 :                 ret = EINVAL;
    1227           0 :                 goto done;
    1228             :         }
    1229             : 
    1230           0 :         DBG_DEBUG("Using %s as ccache for client '%s' and service '%s'\n",
    1231             :                   ccache_string, client_string, service_string);
    1232             : 
    1233             :         /* FIXME: we should not fall back to defaults */
    1234           0 :         ret = krb5_cc_resolve(context, discard_const_p(char, ccache_string), &ccache);
    1235           0 :         if (ret) {
    1236           0 :                 goto done;
    1237             :         }
    1238             : 
    1239           0 :         if (client_string) {
    1240           0 :                 ret = smb_krb5_parse_name(context, client_string, &client);
    1241           0 :                 if (ret) {
    1242           0 :                         goto done;
    1243             :                 }
    1244             :         } else {
    1245           0 :                 ret = krb5_cc_get_principal(context, ccache, &client);
    1246           0 :                 if (ret) {
    1247           0 :                         goto done;
    1248             :                 }
    1249             :         }
    1250             : 
    1251           0 :         ret = krb5_get_renewed_creds(context, &creds, client, ccache, discard_const_p(char, service_string));
    1252           0 :         if (ret) {
    1253           0 :                 DBG_DEBUG("krb5_get_renewed_creds using ccache '%s' "
    1254             :                           "for client '%s' and service '%s' failed: %s\n",
    1255             :                           ccache_string, client_string, service_string,
    1256             :                           error_message(ret));
    1257           0 :                 goto done;
    1258             :         }
    1259             : 
    1260             :         /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
    1261           0 :         ret = krb5_cc_initialize(context, ccache, client);
    1262           0 :         if (ret) {
    1263           0 :                 goto done;
    1264             :         }
    1265             : 
    1266           0 :         ret = krb5_cc_store_cred(context, ccache, &creds);
    1267             : 
    1268           0 :         if (expire_time) {
    1269           0 :                 *expire_time = (time_t) creds.times.endtime;
    1270             :         }
    1271             : 
    1272           0 : done:
    1273           0 :         krb5_free_cred_contents(context, &creds_in);
    1274           0 :         krb5_free_cred_contents(context, &creds);
    1275             : 
    1276           0 :         if (client) {
    1277           0 :                 krb5_free_principal(context, client);
    1278             :         }
    1279           0 :         if (ccache) {
    1280           0 :                 krb5_cc_close(context, ccache);
    1281             :         }
    1282           0 :         if (context) {
    1283           0 :                 krb5_free_context(context);
    1284             :         }
    1285             : 
    1286           0 :         return ret;
    1287             : }
    1288             : 
    1289             : /**
    1290             :  * @brief Free the data stored in an smb_krb5_addresses structure.
    1291             :  *
    1292             :  * @param[in]  context  The library context
    1293             :  *
    1294             :  * @param[in]  addr     The address structure to free.
    1295             :  *
    1296             :  * @return 0 on success, a Kerberos error code otherwise.
    1297             :  */
    1298           6 : krb5_error_code smb_krb5_free_addresses(krb5_context context,
    1299             :                                         smb_krb5_addresses *addr)
    1300             : {
    1301           6 :         krb5_error_code ret = 0;
    1302           6 :         if (addr == NULL) {
    1303           0 :                 return ret;
    1304             :         }
    1305             : #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
    1306           3 :         krb5_free_addresses(context, addr->addrs);
    1307             : #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
    1308           3 :         ret = krb5_free_addresses(context, addr->addrs);
    1309           3 :         SAFE_FREE(addr->addrs);
    1310             : #endif
    1311           6 :         SAFE_FREE(addr);
    1312           6 :         addr = NULL;
    1313           6 :         return ret;
    1314             : }
    1315             : 
    1316             : #define MAX_NETBIOSNAME_LEN 16
    1317             : 
    1318             : /**
    1319             :  * @brief Add a netbios name to the array of addresses
    1320             :  *
    1321             :  * @param[in]  kerb_addr A pointer to the smb_krb5_addresses to add the
    1322             :  *                       netbios name to.
    1323             :  *
    1324             :  * @param[in]  netbios_name The netbios name to add.
    1325             :  *
    1326             :  * @return 0 on success, a Kerberos error code otherwise.
    1327             :  */
    1328           6 : krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr,
    1329             :                                                    const char *netbios_name)
    1330             : {
    1331           6 :         krb5_error_code ret = 0;
    1332           0 :         char buf[MAX_NETBIOSNAME_LEN];
    1333           0 :         int len;
    1334             : #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
    1335           3 :         krb5_address **addrs = NULL;
    1336             : #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
    1337           3 :         krb5_addresses *addrs = NULL;
    1338             : #endif
    1339             : 
    1340           6 :         *kerb_addr = (smb_krb5_addresses *)SMB_MALLOC(sizeof(smb_krb5_addresses));
    1341           6 :         if (*kerb_addr == NULL) {
    1342           0 :                 return ENOMEM;
    1343             :         }
    1344             : 
    1345             :         /* temporarily duplicate put_name() code here to avoid dependency
    1346             :          * issues for a 5 lines function */
    1347           6 :         len = strlen(netbios_name);
    1348           6 :         memcpy(buf, netbios_name,
    1349           6 :                 (len < MAX_NETBIOSNAME_LEN) ? len : MAX_NETBIOSNAME_LEN - 1);
    1350           6 :         if (len < MAX_NETBIOSNAME_LEN - 1) {
    1351           6 :                 memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - 1 - len);
    1352             :         }
    1353           6 :         buf[MAX_NETBIOSNAME_LEN - 1] = 0x20;
    1354             : 
    1355             : #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
    1356             :         {
    1357           3 :                 int num_addr = 2;
    1358             : 
    1359           3 :                 addrs = (krb5_address **)SMB_MALLOC(sizeof(krb5_address *) * num_addr);
    1360           3 :                 if (addrs == NULL) {
    1361           0 :                         SAFE_FREE(*kerb_addr);
    1362           0 :                         return ENOMEM;
    1363             :                 }
    1364             : 
    1365           3 :                 memset(addrs, 0, sizeof(krb5_address *) * num_addr);
    1366             : 
    1367           3 :                 addrs[0] = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
    1368           3 :                 if (addrs[0] == NULL) {
    1369           0 :                         SAFE_FREE(addrs);
    1370           0 :                         SAFE_FREE(*kerb_addr);
    1371           0 :                         return ENOMEM;
    1372             :                 }
    1373             : 
    1374           3 :                 addrs[0]->magic = KV5M_ADDRESS;
    1375           3 :                 addrs[0]->addrtype = KRB5_ADDR_NETBIOS;
    1376           3 :                 addrs[0]->length = MAX_NETBIOSNAME_LEN;
    1377           3 :                 addrs[0]->contents = (unsigned char *)SMB_MALLOC(addrs[0]->length);
    1378           3 :                 if (addrs[0]->contents == NULL) {
    1379           0 :                         SAFE_FREE(addrs[0]);
    1380           0 :                         SAFE_FREE(addrs);
    1381           0 :                         SAFE_FREE(*kerb_addr);
    1382           0 :                         return ENOMEM;
    1383             :                 }
    1384             : 
    1385           3 :                 memcpy(addrs[0]->contents, buf, addrs[0]->length);
    1386             : 
    1387           3 :                 addrs[1] = NULL;
    1388             :         }
    1389             : #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
    1390             :         {
    1391           3 :                 addrs = (krb5_addresses *)SMB_MALLOC(sizeof(krb5_addresses));
    1392           3 :                 if (addrs == NULL) {
    1393           0 :                         SAFE_FREE(*kerb_addr);
    1394           0 :                         return ENOMEM;
    1395             :                 }
    1396             : 
    1397           3 :                 memset(addrs, 0, sizeof(krb5_addresses));
    1398             : 
    1399           3 :                 addrs->len = 1;
    1400           3 :                 addrs->val = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
    1401           3 :                 if (addrs->val == NULL) {
    1402           0 :                         SAFE_FREE(addrs);
    1403           0 :                         SAFE_FREE(*kerb_addr);
    1404           0 :                         return ENOMEM;
    1405             :                 }
    1406             : 
    1407           3 :                 addrs->val[0].addr_type = KRB5_ADDR_NETBIOS;
    1408           3 :                 addrs->val[0].address.length = MAX_NETBIOSNAME_LEN;
    1409           3 :                 addrs->val[0].address.data = (unsigned char *)SMB_MALLOC(addrs->val[0].address.length);
    1410           3 :                 if (addrs->val[0].address.data == NULL) {
    1411           0 :                         SAFE_FREE(addrs->val);
    1412           0 :                         SAFE_FREE(addrs);
    1413           0 :                         SAFE_FREE(*kerb_addr);
    1414           0 :                         return ENOMEM;
    1415             :                 }
    1416             : 
    1417           3 :                 memcpy(addrs->val[0].address.data, buf, addrs->val[0].address.length);
    1418             :         }
    1419             : #else
    1420             : #error UNKNOWN_KRB5_ADDRESS_FORMAT
    1421             : #endif
    1422           6 :         (*kerb_addr)->addrs = addrs;
    1423             : 
    1424           6 :         return ret;
    1425             : }
    1426             : 
    1427             : /**
    1428             :  * @brief Get the enctype from a key table entry
    1429             :  *
    1430             :  * @param[in]  kt_entry Key table entry to get the enctype from.
    1431             :  *
    1432             :  * @return The enctype from the entry.
    1433             :  */
    1434       17832 : krb5_enctype smb_krb5_kt_get_enctype_from_entry(krb5_keytab_entry *kt_entry)
    1435             : {
    1436       17832 :         return KRB5_KEY_TYPE(KRB5_KT_KEY(kt_entry));
    1437             : }
    1438             : 
    1439             : /**
    1440             :  * @brief Free the contents of a key table entry.
    1441             :  *
    1442             :  * @param[in]  context The library context.
    1443             :  *
    1444             :  * @param[in]  kt_entry The key table entry to free the contents of.
    1445             :  *
    1446             :  * @return 0 on success, a Kerberos error code otherwise.
    1447             :  *
    1448             :  * The pointer itself is not freed.
    1449             :  */
    1450       20601 : krb5_error_code smb_krb5_kt_free_entry(krb5_context context,
    1451             :                                         krb5_keytab_entry *kt_entry)
    1452             : {
    1453             : /* Try krb5_free_keytab_entry_contents first, since
    1454             :  * MIT Kerberos >= 1.7 has both krb5_free_keytab_entry_contents and
    1455             :  * krb5_kt_free_entry but only has a prototype for the first, while the
    1456             :  * second is considered private.
    1457             :  */
    1458             : #if defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
    1459       11369 :         return krb5_free_keytab_entry_contents(context, kt_entry);
    1460             : #elif defined(HAVE_KRB5_KT_FREE_ENTRY)
    1461        9232 :         return krb5_kt_free_entry(context, kt_entry);
    1462             : #else
    1463             : #error UNKNOWN_KT_FREE_FUNCTION
    1464             : #endif
    1465             : }
    1466             : 
    1467             : 
    1468             : /**
    1469             :  * @brief Convert an encryption type to a string.
    1470             :  *
    1471             :  * @param[in]  context The library context.
    1472             :  *
    1473             :  * @param[in]  enctype The encryption type.
    1474             :  *
    1475             :  * @param[in]  etype_s A pointer to store the allocated encryption type as a
    1476             :  *                     string.
    1477             :  *
    1478             :  * @return 0 on success, a Kerberos error code otherwise.
    1479             :  *
    1480             :  * The caller needs to free the allocated string etype_s.
    1481             :  */
    1482        1070 : krb5_error_code smb_krb5_enctype_to_string(krb5_context context,
    1483             :                                            krb5_enctype enctype,
    1484             :                                            char **etype_s)
    1485             : {
    1486             : #ifdef HAVE_KRB5_ENCTYPE_TO_STRING_WITH_KRB5_CONTEXT_ARG
    1487         533 :         return krb5_enctype_to_string(context, enctype, etype_s); /* Heimdal */
    1488             : #elif defined(HAVE_KRB5_ENCTYPE_TO_STRING_WITH_SIZE_T_ARG)
    1489             :         char buf[256];
    1490         537 :         krb5_error_code ret = krb5_enctype_to_string(enctype, buf, 256); /* MIT */
    1491         537 :         if (ret) {
    1492           0 :                 return ret;
    1493             :         }
    1494         537 :         *etype_s = SMB_STRDUP(buf);
    1495         537 :         if (!*etype_s) {
    1496           0 :                 return ENOMEM;
    1497             :         }
    1498         537 :         return ret;
    1499             : #else
    1500             : #error UNKNOWN_KRB5_ENCTYPE_TO_STRING_FUNCTION
    1501             : #endif
    1502             : }
    1503             : 
    1504             : /* This MAX_NAME_LEN is a constant defined in krb5.h */
    1505             : #ifndef MAX_KEYTAB_NAME_LEN
    1506             : #define MAX_KEYTAB_NAME_LEN 1100
    1507             : #endif
    1508             : 
    1509             : /**
    1510             :  * @brief Open a key table readonly or with readwrite access.
    1511             :  *
    1512             :  * Allows one to use a different keytab than the default one using a relative
    1513             :  * path to the keytab.
    1514             :  *
    1515             :  * @param[in]  context  The library context
    1516             :  *
    1517             :  * @param[in]  keytab_name_req The path to the key table.
    1518             :  *
    1519             :  * @param[in]  write_access Open with readwrite access.
    1520             :  *
    1521             :  * @param[in]  keytab A pointer to the opened key table.
    1522             :  *
    1523             :  * The keytab pointer should be freed using krb5_kt_close().
    1524             :  *
    1525             :  * @return 0 on success, a Kerberos error code otherwise.
    1526             :  */
    1527         211 : krb5_error_code smb_krb5_kt_open_relative(krb5_context context,
    1528             :                                           const char *keytab_name_req,
    1529             :                                           bool write_access,
    1530             :                                           krb5_keytab *keytab)
    1531             : {
    1532         211 :         krb5_error_code ret = 0;
    1533           3 :         TALLOC_CTX *mem_ctx;
    1534           3 :         char keytab_string[MAX_KEYTAB_NAME_LEN];
    1535         211 :         char *kt_str = NULL;
    1536         211 :         bool found_valid_name = false;
    1537         211 :         const char *pragma = "FILE";
    1538         211 :         const char *tmp = NULL;
    1539             : 
    1540         211 :         if (!write_access && !keytab_name_req) {
    1541             :                 /* caller just wants to read the default keytab readonly, so be it */
    1542           0 :                 return krb5_kt_default(context, keytab);
    1543             :         }
    1544             : 
    1545         211 :         mem_ctx = talloc_init("smb_krb5_kt_open_relative");
    1546         211 :         if (!mem_ctx) {
    1547           0 :                 return ENOMEM;
    1548             :         }
    1549             : 
    1550             : #ifdef HAVE_WRFILE_KEYTAB
    1551         103 :         if (write_access) {
    1552          93 :                 pragma = "WRFILE";
    1553             :         }
    1554             : #endif
    1555             : 
    1556         211 :         if (keytab_name_req) {
    1557             : 
    1558         210 :                 if (strlen(keytab_name_req) > MAX_KEYTAB_NAME_LEN) {
    1559           0 :                         ret = KRB5_CONFIG_NOTENUFSPACE;
    1560           0 :                         goto out;
    1561             :                 }
    1562             : 
    1563         210 :                 if ((strncmp(keytab_name_req, "WRFILE:", 7) == 0) ||
    1564         210 :                     (strncmp(keytab_name_req, "FILE:", 5) == 0)) {
    1565           7 :                         tmp = keytab_name_req;
    1566           7 :                         goto resolve;
    1567             :                 }
    1568             : 
    1569         203 :                 tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, keytab_name_req);
    1570         203 :                 if (!tmp) {
    1571           0 :                         ret = ENOMEM;
    1572           0 :                         goto out;
    1573             :                 }
    1574             : 
    1575         203 :                 goto resolve;
    1576             :         }
    1577             : 
    1578             :         /* we need to handle more complex keytab_strings, like:
    1579             :          * "ANY:FILE:/etc/krb5.keytab,krb4:/etc/srvtab" */
    1580             : 
    1581           1 :         ret = krb5_kt_default_name(context, &keytab_string[0], MAX_KEYTAB_NAME_LEN - 2);
    1582           1 :         if (ret) {
    1583           0 :                 goto out;
    1584             :         }
    1585             : 
    1586           1 :         DBG_DEBUG("krb5_kt_default_name returned %s\n", keytab_string);
    1587             : 
    1588           1 :         tmp = talloc_strdup(mem_ctx, keytab_string);
    1589           1 :         if (!tmp) {
    1590           0 :                 ret = ENOMEM;
    1591           0 :                 goto out;
    1592             :         }
    1593             : 
    1594           1 :         if (strncmp(tmp, "ANY:", 4) == 0) {
    1595           0 :                 tmp += 4;
    1596             :         }
    1597             : 
    1598           1 :         memset(&keytab_string, '\0', sizeof(keytab_string));
    1599             : 
    1600           1 :         while (next_token_talloc(mem_ctx, &tmp, &kt_str, ",")) {
    1601           1 :                 if (strncmp(kt_str, "WRFILE:", 7) == 0) {
    1602           0 :                         found_valid_name = true;
    1603           0 :                         tmp = kt_str;
    1604           0 :                         tmp += 7;
    1605             :                 }
    1606             : 
    1607           1 :                 if (strncmp(kt_str, "FILE:", 5) == 0) {
    1608           1 :                         found_valid_name = true;
    1609           1 :                         tmp = kt_str;
    1610           1 :                         tmp += 5;
    1611             :                 }
    1612             : 
    1613           1 :                 if (tmp[0] == '/') {
    1614             :                         /* Treat as a FILE: keytab definition. */
    1615           0 :                         found_valid_name = true;
    1616             :                 }
    1617             : 
    1618           0 :                 if (found_valid_name) {
    1619           1 :                         if (tmp[0] != '/') {
    1620           0 :                                 ret = KRB5_KT_BADNAME;
    1621           0 :                                 goto out;
    1622             :                         }
    1623             : 
    1624           1 :                         tmp = talloc_asprintf(mem_ctx, "%s:%s", pragma, tmp);
    1625           1 :                         if (!tmp) {
    1626           0 :                                 ret = ENOMEM;
    1627           0 :                                 goto out;
    1628             :                         }
    1629           0 :                         break;
    1630             :                 }
    1631             :         }
    1632             : 
    1633           1 :         if (!found_valid_name) {
    1634           0 :                 ret = KRB5_KT_UNKNOWN_TYPE;
    1635           0 :                 goto out;
    1636             :         }
    1637             : 
    1638           1 : resolve:
    1639         211 :         DBG_DEBUG("resolving: %s\n", tmp);
    1640         211 :         ret = krb5_kt_resolve(context, tmp, keytab);
    1641             : 
    1642         211 : out:
    1643         211 :         TALLOC_FREE(mem_ctx);
    1644         211 :         return ret;
    1645             : }
    1646             : 
    1647             : /**
    1648             :  * @brief Open a key table readonly or with readwrite access.
    1649             :  *
    1650             :  * Allows one to use a different keytab than the default one. The path needs to be
    1651             :  * an absolute path or an error will be returned.
    1652             :  *
    1653             :  * @param[in]  context  The library context
    1654             :  *
    1655             :  * @param[in]  keytab_name_req The path to the key table.
    1656             :  *
    1657             :  * @param[in]  write_access Open with readwrite access.
    1658             :  *
    1659             :  * @param[in]  keytab A pointer to the opened key table.
    1660             :  *
    1661             :  * The keytab pointer should be freed using krb5_kt_close().
    1662             :  *
    1663             :  * @return 0 on success, a Kerberos error code otherwise.
    1664             :  */
    1665         140 : krb5_error_code smb_krb5_kt_open(krb5_context context,
    1666             :                                  const char *keytab_name_req,
    1667             :                                  bool write_access,
    1668             :                                  krb5_keytab *keytab)
    1669             : {
    1670           6 :         int cmp;
    1671             : 
    1672         140 :         if (keytab_name_req == NULL) {
    1673           0 :                 return KRB5_KT_BADNAME;
    1674             :         }
    1675             : 
    1676         139 :         if (keytab_name_req[0] == '/') {
    1677         129 :                 goto open_keytab;
    1678             :         }
    1679             : 
    1680          10 :         cmp = strncmp(keytab_name_req, "FILE:/", 6);
    1681          10 :         if (cmp == 0) {
    1682           7 :                 goto open_keytab;
    1683             :         }
    1684             : 
    1685           3 :         cmp = strncmp(keytab_name_req, "WRFILE:/", 8);
    1686           3 :         if (cmp == 0) {
    1687           0 :                 goto open_keytab;
    1688             :         }
    1689             : 
    1690           3 :         DBG_WARNING("ERROR: Invalid keytab name: %s\n", keytab_name_req);
    1691             : 
    1692           0 :         return KRB5_KT_BADNAME;
    1693             : 
    1694         136 : open_keytab:
    1695         136 :         return smb_krb5_kt_open_relative(context,
    1696             :                                          keytab_name_req,
    1697             :                                          write_access,
    1698             :                                          keytab);
    1699             : }
    1700             : 
    1701             : /**
    1702             :  * @brief Get a key table name.
    1703             :  *
    1704             :  * @param[in]  mem_ctx The talloc context to use for allocation.
    1705             :  *
    1706             :  * @param[in]  context The library context.
    1707             :  *
    1708             :  * @param[in]  keytab The key table to get the name from.
    1709             :  *
    1710             :  * @param[in]  keytab_name A talloc'ed string of the key table name.
    1711             :  *
    1712             :  * The talloc'ed name string needs to be freed with talloc_free().
    1713             :  *
    1714             :  * @return 0 on success, a Kerberos error code otherwise.
    1715             :  */
    1716           0 : krb5_error_code smb_krb5_kt_get_name(TALLOC_CTX *mem_ctx,
    1717             :                                      krb5_context context,
    1718             :                                      krb5_keytab keytab,
    1719             :                                      const char **keytab_name)
    1720             : {
    1721           0 :         char keytab_string[MAX_KEYTAB_NAME_LEN];
    1722           0 :         krb5_error_code ret = 0;
    1723             : 
    1724           0 :         ret = krb5_kt_get_name(context, keytab,
    1725             :                                keytab_string, MAX_KEYTAB_NAME_LEN - 2);
    1726           0 :         if (ret) {
    1727           0 :                 return ret;
    1728             :         }
    1729             : 
    1730           0 :         *keytab_name = talloc_strdup(mem_ctx, keytab_string);
    1731           0 :         if (!*keytab_name) {
    1732           0 :                 return ENOMEM;
    1733             :         }
    1734             : 
    1735           0 :         return ret;
    1736             : }
    1737             : 
    1738             : /**
    1739             :  * @brief Seek and delete old entries in a keytab based on the passed
    1740             :  *        principal.
    1741             :  *
    1742             :  * @param[in]  context       The KRB5 context to use.
    1743             :  *
    1744             :  * @param[in]  keytab        The keytab to operate on.
    1745             :  *
    1746             :  * @param[in]  keep_old_kvno Keep the entries with the previous kvno.
    1747             :  *
    1748             :  * @param[in]  kvno          The kvno to use.
    1749             :  *
    1750             :  * @param[in]  enctype_only  Only evaluate the enctype argument if true
    1751             :  *
    1752             :  * @param[in]  enctype       Only search for entries with the specified enctype
    1753             :  *
    1754             :  * @param[in]  princ_s       The principal as a string to search for.
    1755             :  *
    1756             :  * @param[in]  princ         The principal as a krb5_principal to search for.
    1757             :  *
    1758             :  * @param[in]  flush         Whether to flush the complete keytab.
    1759             :  *
    1760             :  * @retval 0 on Success
    1761             :  *
    1762             :  * @return An appropriate KRB5 error code.
    1763             :  */
    1764         568 : krb5_error_code smb_krb5_kt_seek_and_delete_old_entries(krb5_context context,
    1765             :                                                         krb5_keytab keytab,
    1766             :                                                         bool keep_old_kvno,
    1767             :                                                         krb5_kvno kvno,
    1768             :                                                         bool enctype_only,
    1769             :                                                         krb5_enctype enctype,
    1770             :                                                         const char *princ_s,
    1771             :                                                         krb5_principal princ,
    1772             :                                                         bool flush)
    1773             : {
    1774           0 :         krb5_error_code ret;
    1775           0 :         krb5_kt_cursor cursor;
    1776           0 :         krb5_keytab_entry kt_entry;
    1777         568 :         char *ktprinc = NULL;
    1778         568 :         krb5_kvno old_kvno = kvno - 1;
    1779           0 :         TALLOC_CTX *tmp_ctx;
    1780             : 
    1781         568 :         if (flush) {
    1782           0 :                 SMB_ASSERT(!keep_old_kvno);
    1783           0 :                 SMB_ASSERT(!enctype_only);
    1784           0 :                 SMB_ASSERT(princ_s == NULL);
    1785           0 :                 SMB_ASSERT(princ == NULL);
    1786             :         } else {
    1787         568 :                 SMB_ASSERT(princ_s != NULL);
    1788         568 :                 SMB_ASSERT(princ != NULL);
    1789             :         }
    1790             : 
    1791         568 :         ZERO_STRUCT(cursor);
    1792         568 :         ZERO_STRUCT(kt_entry);
    1793             : 
    1794             :         /*
    1795             :          * Start with talloc_new() and only then call krb5_kt_start_seq_get().
    1796             :          * If any of them fails, the cleanup code is simpler.
    1797             :          */
    1798         568 :         tmp_ctx = talloc_new(NULL);
    1799         568 :         if (tmp_ctx == NULL) {
    1800           0 :                 return ENOMEM;
    1801             :         }
    1802             : 
    1803         568 :         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    1804         568 :         if (ret == KRB5_KT_END || ret == ENOENT ) {
    1805             :                 /* no entries */
    1806           8 :                 talloc_free(tmp_ctx);
    1807           8 :                 return 0;
    1808             :         }
    1809             : 
    1810         560 :         DEBUG(3, (__location__ ": Will try to delete old keytab entries\n"));
    1811       17204 :         while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
    1812       16644 :                 bool name_ok = false;
    1813           0 :                 krb5_enctype kt_entry_enctype =
    1814       16644 :                         smb_krb5_kt_get_enctype_from_entry(&kt_entry);
    1815             : 
    1816       16644 :                 if (princ_s != NULL) {
    1817       16644 :                         ret = smb_krb5_unparse_name(tmp_ctx, context,
    1818       16644 :                                                     kt_entry.principal,
    1819             :                                                     &ktprinc);
    1820       16644 :                         if (ret) {
    1821           0 :                                 DEBUG(1, (__location__
    1822             :                                           ": smb_krb5_unparse_name failed "
    1823             :                                           "(%s)\n", error_message(ret)));
    1824           0 :                                 goto out;
    1825             :                         }
    1826             : 
    1827             : #ifdef HAVE_KRB5_KT_COMPARE
    1828        8322 :                         name_ok = krb5_kt_compare(context, &kt_entry,
    1829             :                                                   princ, 0, 0);
    1830             : #else
    1831        8322 :                         name_ok = (strcmp(ktprinc, princ_s) == 0);
    1832             : #endif
    1833             : 
    1834       16644 :                         if (!name_ok) {
    1835       15006 :                                 DEBUG(10, (__location__ ": ignoring keytab "
    1836             :                                            "entry principal %s, kvno = %d\n",
    1837             :                                            ktprinc, kt_entry.vno));
    1838             : 
    1839             :                                 /* Not a match,
    1840             :                                  * just free this entry and continue. */
    1841       15006 :                                 ret = smb_krb5_kt_free_entry(context,
    1842             :                                                              &kt_entry);
    1843       15006 :                                 ZERO_STRUCT(kt_entry);
    1844       15006 :                                 if (ret) {
    1845           0 :                                         DEBUG(1, (__location__
    1846             :                                                   ": smb_krb5_kt_free_entry "
    1847             :                                                   "failed (%s)\n",
    1848             :                                                   error_message(ret)));
    1849           0 :                                         goto out;
    1850             :                                 }
    1851             : 
    1852       15006 :                                 TALLOC_FREE(ktprinc);
    1853       15006 :                                 continue;
    1854             :                         }
    1855             : 
    1856        1638 :                         TALLOC_FREE(ktprinc);
    1857             :                 }
    1858             : 
    1859             :                 /*------------------------------------------------------------
    1860             :                  * Save the entries with kvno - 1. This is what microsoft does
    1861             :                  * to allow people with existing sessions that have kvno - 1
    1862             :                  * to still work. Otherwise, when the password for the machine
    1863             :                  * changes, all kerberized sessions will 'break' until either
    1864             :                  * the client reboots or the client's session key expires and
    1865             :                  * they get a new session ticket with the new kvno.
    1866             :                  * Some keytab files only store the kvno in 8bits, limit
    1867             :                  * the compare accordingly.
    1868             :                  */
    1869             : 
    1870        1638 :                 if (keep_old_kvno && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
    1871           0 :                         DEBUG(5, (__location__ ": Saving previous (kvno %d) "
    1872             :                                   "entry for principal: %s.\n",
    1873             :                                   old_kvno,
    1874             :                                   princ_s != NULL ? princ_s : "UNKNOWN"));
    1875           0 :                         continue;
    1876             :                 }
    1877             : 
    1878        1638 :                 if (enctype_only &&
    1879        1596 :                     ((kt_entry.vno & 0xff) == (kvno & 0xff)) &&
    1880             :                     (kt_entry_enctype != enctype))
    1881             :                 {
    1882        1248 :                         DEBUG(5, (__location__ ": Saving entry with kvno [%d] "
    1883             :                                   "enctype [%d] for principal: %s.\n",
    1884             :                                   kvno, kt_entry_enctype,
    1885             :                                   princ_s != NULL ? princ_s : "UNKNOWN"));
    1886        1248 :                         continue;
    1887             :                 }
    1888             : 
    1889         390 :                 DEBUG(5, (__location__ ": Found old entry for principal: %s "
    1890             :                           "(kvno %d) - trying to remove it.\n",
    1891             :                           princ_s != NULL ? princ_s : "UNKNOWN",
    1892             :                           kt_entry.vno));
    1893             : 
    1894         390 :                 ret = krb5_kt_end_seq_get(context, keytab, &cursor);
    1895         390 :                 ZERO_STRUCT(cursor);
    1896         390 :                 if (ret) {
    1897           0 :                         DEBUG(1, (__location__ ": krb5_kt_end_seq_get() "
    1898             :                                   "failed (%s)\n", error_message(ret)));
    1899           0 :                         goto out;
    1900             :                 }
    1901         390 :                 ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
    1902         390 :                 if (ret) {
    1903           0 :                         DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
    1904             :                                   "failed (%s)\n", error_message(ret)));
    1905           0 :                         goto out;
    1906             :                 }
    1907             : 
    1908         390 :                 DEBUG(5, (__location__ ": removed old entry for principal: "
    1909             :                           "%s (kvno %d).\n",
    1910             :                           princ_s != NULL ? princ_s : "UNKNOWN",
    1911             :                           kt_entry.vno));
    1912             : 
    1913         390 :                 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    1914         390 :                 if (ret) {
    1915           0 :                         DEBUG(1, (__location__ ": krb5_kt_start_seq() failed "
    1916             :                                   "(%s)\n", error_message(ret)));
    1917           0 :                         goto out;
    1918             :                 }
    1919         390 :                 ret = smb_krb5_kt_free_entry(context, &kt_entry);
    1920         390 :                 ZERO_STRUCT(kt_entry);
    1921         390 :                 if (ret) {
    1922           0 :                         DEBUG(1, (__location__ ": krb5_kt_remove_entry() "
    1923             :                                   "failed (%s)\n", error_message(ret)));
    1924           0 :                         goto out;
    1925             :                 }
    1926             :         }
    1927             : 
    1928         560 : out:
    1929         560 :         talloc_free(tmp_ctx);
    1930         560 :         if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
    1931          49 :                 smb_krb5_kt_free_entry(context, &kt_entry);
    1932             :         }
    1933         560 :         if (!all_zero((uint8_t *)&cursor, sizeof(cursor))) {
    1934         560 :                 krb5_kt_end_seq_get(context, keytab, &cursor);
    1935             :         }
    1936         560 :         return ret;
    1937             : }
    1938             : 
    1939             : /**
    1940             :  * @brief Add a keytab entry for the given principal
    1941             :  *
    1942             :  * @param[in]  context       The krb5 context to use.
    1943             :  *
    1944             :  * @param[in]  keytab        The keytab to add the entry to.
    1945             :  *
    1946             :  * @param[in]  kvno          The kvno to use.
    1947             :  *
    1948             :  * @param[in]  princ_s       The principal as a string.
    1949             :  *
    1950             :  * @param[in]  salt_principal The salt principal to salt the password with.
    1951             :  *                            Only needed for keys which support salting.
    1952             :  *                            If no salt is used set no_salt to false and
    1953             :  *                            pass NULL here.
    1954             :  *
    1955             :  * @param[in]  enctype        The encryption type of the keytab entry.
    1956             :  *
    1957             :  * @param[in]  password       The password of the keytab entry.
    1958             :  *
    1959             :  * @retval 0 on Success
    1960             :  *
    1961             :  * @return A corresponding KRB5 error code.
    1962             :  *
    1963             :  * @see smb_krb5_kt_open()
    1964             :  */
    1965         552 : krb5_error_code smb_krb5_kt_add_password(krb5_context context,
    1966             :                                          krb5_keytab keytab,
    1967             :                                          krb5_kvno kvno,
    1968             :                                          const char *princ_s,
    1969             :                                          const char *salt_principal,
    1970             :                                          krb5_enctype enctype,
    1971             :                                          krb5_data *password)
    1972             : {
    1973           0 :         krb5_error_code ret;
    1974           0 :         krb5_keytab_entry kt_entry;
    1975         552 :         krb5_principal princ = NULL;
    1976           0 :         krb5_keyblock *keyp;
    1977         552 :         krb5_principal salt_princ = NULL;
    1978             : 
    1979         552 :         ZERO_STRUCT(kt_entry);
    1980             : 
    1981         552 :         ret = smb_krb5_parse_name(context, princ_s, &princ);
    1982         552 :         if (ret) {
    1983           0 :                 DEBUG(1, (__location__ ": smb_krb5_parse_name(%s) "
    1984             :                           "failed (%s)\n", princ_s, error_message(ret)));
    1985           0 :                 goto out;
    1986             :         }
    1987             : 
    1988             :         /* Seek and delete old keytab entries */
    1989         552 :         ret = smb_krb5_kt_seek_and_delete_old_entries(context,
    1990             :                                                       keytab,
    1991             :                                                       true, /* keep_old_kvno */
    1992             :                                                       kvno,
    1993             :                                                       true, /* enctype_only */
    1994             :                                                       enctype,
    1995             :                                                       princ_s,
    1996             :                                                       princ,
    1997             :                                                       false); /* flush */
    1998         552 :         if (ret) {
    1999           0 :                 goto out;
    2000             :         }
    2001             : 
    2002             :         /* If we get here, we have deleted all the old entries with kvno's
    2003             :          * not equal to the current kvno-1. */
    2004             : 
    2005         552 :         keyp = KRB5_KT_KEY(&kt_entry);
    2006             : 
    2007             :         /* Now add keytab entries for all encryption types */
    2008         552 :         ret = smb_krb5_parse_name(context, salt_principal, &salt_princ);
    2009         552 :         if (ret) {
    2010           0 :                 DBG_WARNING("krb5_parse_name(%s) failed (%s)\n",
    2011             :                             salt_principal, error_message(ret));
    2012           0 :                 goto out;
    2013             :         }
    2014             : 
    2015         552 :         ret = smb_krb5_create_key_from_string(context,
    2016             :                                               salt_princ,
    2017             :                                               NULL,
    2018             :                                               password,
    2019             :                                               enctype,
    2020             :                                               keyp);
    2021         552 :         krb5_free_principal(context, salt_princ);
    2022         552 :         if (ret != 0) {
    2023           0 :                 goto out;
    2024             :         }
    2025             : 
    2026         552 :         kt_entry.principal = princ;
    2027         552 :         kt_entry.vno       = kvno;
    2028             : 
    2029         552 :         DEBUG(3, (__location__ ": adding keytab entry for (%s) with "
    2030             :                   "encryption type (%d) and version (%d)\n",
    2031             :                   princ_s, enctype, kt_entry.vno));
    2032         552 :         ret = krb5_kt_add_entry(context, keytab, &kt_entry);
    2033         552 :         krb5_free_keyblock_contents(context, keyp);
    2034         552 :         ZERO_STRUCT(kt_entry);
    2035         552 :         if (ret) {
    2036           0 :                 DEBUG(1, (__location__ ": adding entry to keytab "
    2037             :                           "failed (%s)\n", error_message(ret)));
    2038           0 :                 goto out;
    2039             :         }
    2040             : 
    2041         552 : out:
    2042         552 :         if (princ) {
    2043         552 :                 krb5_free_principal(context, princ);
    2044             :         }
    2045             : 
    2046         552 :         return ret;
    2047             : }
    2048             : 
    2049             : #if defined(HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE) && \
    2050             :     defined(HAVE_KRB5_GET_CREDS_OPT_ALLOC) && \
    2051             :     defined(HAVE_KRB5_GET_CREDS)
    2052           0 : static krb5_error_code smb_krb5_get_credentials_for_user_opt(krb5_context context,
    2053             :                                                              krb5_ccache ccache,
    2054             :                                                              krb5_principal me,
    2055             :                                                              krb5_principal server,
    2056             :                                                              krb5_principal impersonate_princ,
    2057             :                                                              krb5_creds **out_creds)
    2058             : {
    2059           0 :         krb5_error_code ret;
    2060           0 :         krb5_get_creds_opt opt;
    2061             : 
    2062           0 :         ret = krb5_get_creds_opt_alloc(context, &opt);
    2063           0 :         if (ret) {
    2064           0 :                 goto done;
    2065             :         }
    2066           0 :         krb5_get_creds_opt_add_options(context, opt, KRB5_GC_FORWARDABLE);
    2067             : 
    2068           0 :         if (impersonate_princ) {
    2069           0 :                 ret = krb5_get_creds_opt_set_impersonate(context, opt,
    2070             :                                                          impersonate_princ);
    2071           0 :                 if (ret) {
    2072           0 :                         goto done;
    2073             :                 }
    2074             :         }
    2075             : 
    2076           0 :         ret = krb5_get_creds(context, opt, ccache, server, out_creds);
    2077           0 :         if (ret) {
    2078           0 :                 goto done;
    2079             :         }
    2080             : 
    2081           0 :  done:
    2082           0 :         if (opt) {
    2083           0 :                 krb5_get_creds_opt_free(context, opt);
    2084             :         }
    2085           0 :         return ret;
    2086             : }
    2087             : #endif /* HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE */
    2088             : 
    2089             : #ifdef HAVE_KRB5_GET_CREDENTIALS_FOR_USER
    2090             : 
    2091             : #if !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER
    2092             : krb5_error_code KRB5_CALLCONV
    2093             : krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
    2094             :                               krb5_ccache ccache, krb5_creds *in_creds,
    2095             :                               krb5_data *subject_cert,
    2096             :                               krb5_creds **out_creds);
    2097             : #endif /* !HAVE_DECL_KRB5_GET_CREDENTIALS_FOR_USER */
    2098             : 
    2099           0 : static krb5_error_code smb_krb5_get_credentials_for_user(krb5_context context,
    2100             :                                                          krb5_ccache ccache,
    2101             :                                                          krb5_principal me,
    2102             :                                                          krb5_principal server,
    2103             :                                                          krb5_principal impersonate_princ,
    2104             :                                                          krb5_creds **out_creds)
    2105             : {
    2106             :         krb5_error_code ret;
    2107             :         krb5_creds in_creds;
    2108             : 
    2109           0 :         ZERO_STRUCT(in_creds);
    2110             : 
    2111           0 :         if (impersonate_princ) {
    2112             : 
    2113           0 :                 in_creds.server = me;
    2114           0 :                 in_creds.client = impersonate_princ;
    2115             : 
    2116           0 :                 ret = krb5_get_credentials_for_user(context,
    2117             :                                                     0, /* krb5_flags options */
    2118             :                                                     ccache,
    2119             :                                                     &in_creds,
    2120             :                                                     NULL, /* krb5_data *subject_cert */
    2121             :                                                     out_creds);
    2122             :         } else {
    2123           0 :                 in_creds.client = me;
    2124           0 :                 in_creds.server = server;
    2125             : 
    2126           0 :                 ret = krb5_get_credentials(context, 0, ccache,
    2127             :                                            &in_creds, out_creds);
    2128             :         }
    2129             : 
    2130           0 :         return ret;
    2131             : }
    2132             : #endif /* HAVE_KRB5_GET_CREDENTIALS_FOR_USER */
    2133             : 
    2134             : /*
    2135             :  * smb_krb5_get_credentials
    2136             :  *
    2137             :  * @brief Get krb5 credentials for a server
    2138             :  *
    2139             :  * @param[in] context           An initialized krb5_context
    2140             :  * @param[in] ccache            An initialized krb5_ccache
    2141             :  * @param[in] me                The krb5_principal of the caller
    2142             :  * @param[in] server            The krb5_principal of the requested service
    2143             :  * @param[in] impersonate_princ The krb5_principal of a user to impersonate as (optional)
    2144             :  * @param[out] out_creds        The returned krb5_creds structure
    2145             :  * @return krb5_error_code
    2146             :  *
    2147             :  */
    2148           0 : krb5_error_code smb_krb5_get_credentials(krb5_context context,
    2149             :                                          krb5_ccache ccache,
    2150             :                                          krb5_principal me,
    2151             :                                          krb5_principal server,
    2152             :                                          krb5_principal impersonate_princ,
    2153             :                                          krb5_creds **out_creds)
    2154             : {
    2155           0 :         krb5_error_code ret;
    2156           0 :         krb5_creds *creds = NULL;
    2157             : 
    2158           0 :         if (out_creds != NULL) {
    2159           0 :                 *out_creds = NULL;
    2160             :         }
    2161             : 
    2162           0 :         if (impersonate_princ) {
    2163             : #ifdef HAVE_KRB5_GET_CREDS_OPT_SET_IMPERSONATE /* Heimdal */
    2164           0 :                 ret = smb_krb5_get_credentials_for_user_opt(context, ccache, me, server, impersonate_princ, &creds);
    2165             : #elif defined(HAVE_KRB5_GET_CREDENTIALS_FOR_USER) /* MIT */
    2166           0 :                 ret = smb_krb5_get_credentials_for_user(context, ccache, me, server, impersonate_princ, &creds);
    2167             : #else
    2168             :                 ret = ENOTSUP;
    2169             : #endif
    2170             :         } else {
    2171           0 :                 krb5_creds in_creds;
    2172             : 
    2173           0 :                 ZERO_STRUCT(in_creds);
    2174             : 
    2175           0 :                 in_creds.client = me;
    2176           0 :                 in_creds.server = server;
    2177             : 
    2178           0 :                 ret = krb5_get_credentials(context, 0, ccache,
    2179             :                                            &in_creds, &creds);
    2180             :         }
    2181           0 :         if (ret) {
    2182           0 :                 goto done;
    2183             :         }
    2184             : 
    2185           0 :         if (out_creds) {
    2186           0 :                 *out_creds = creds;
    2187             :         }
    2188             : 
    2189           0 :  done:
    2190           0 :         if (creds && ret) {
    2191           0 :                 krb5_free_creds(context, creds);
    2192             :         }
    2193             : 
    2194           0 :         return ret;
    2195             : }
    2196             : 
    2197             : /**
    2198             :  * @brief Initialize a krb5_keyblock with the given data.
    2199             :  *
    2200             :  * Initializes a new keyblock, allocates the contents for the key and
    2201             :  * copies the data into the keyblock.
    2202             :  *
    2203             :  * @param[in]  context  The library context
    2204             :  *
    2205             :  * @param[in]  enctype  The encryption type.
    2206             :  *
    2207             :  * @param[in]  data     The date to initialize the keyblock with.
    2208             :  *
    2209             :  * @param[in]  length   The length of the keyblock.
    2210             :  *
    2211             :  * @param[in]  key      Newly allocated keyblock structure.
    2212             :  *
    2213             :  * The key date must be freed using krb5_free_keyblock_contents() when it is
    2214             :  * no longer needed.
    2215             :  *
    2216             :  * @return 0 on success, a Kerberos error code otherwise.
    2217             :  */
    2218      861484 : krb5_error_code smb_krb5_keyblock_init_contents(krb5_context context,
    2219             :                                                 krb5_enctype enctype,
    2220             :                                                 const void *data,
    2221             :                                                 size_t length,
    2222             :                                                 krb5_keyblock *key)
    2223             : {
    2224             : #if defined(HAVE_KRB5_KEYBLOCK_INIT)
    2225      859890 :         return krb5_keyblock_init(context, enctype, data, length, key);
    2226             : #else
    2227        1594 :         memset(key, 0, sizeof(krb5_keyblock));
    2228        1594 :         KRB5_KEY_DATA(key) = SMB_MALLOC(length);
    2229        1594 :         if (NULL == KRB5_KEY_DATA(key)) {
    2230           0 :                 return ENOMEM;
    2231             :         }
    2232        1594 :         memcpy(KRB5_KEY_DATA(key), data, length);
    2233        1594 :         KRB5_KEY_LENGTH(key) = length;
    2234        1594 :         KRB5_KEY_TYPE(key) = enctype;
    2235        1594 :         return 0;
    2236             : #endif
    2237             : }
    2238             : 
    2239             : /**
    2240             :  * @brief Simulate a kinit by putting the tgt in the given credential cache.
    2241             :  *
    2242             :  * This function uses a keyblock rather than needing the original password.
    2243             :  *
    2244             :  * @param[in]  ctx      The library context
    2245             :  *
    2246             :  * @param[in]  cc       The credential cache to put the tgt in.
    2247             :  *
    2248             :  * @param[in]  principal The client princial
    2249             :  *
    2250             :  * @param[in]  keyblock  The keyblock to use.
    2251             :  *
    2252             :  * @param[in]  target_service The service name of the initial credentials (or NULL).
    2253             :  *
    2254             :  * @param[in]  krb_options Initial credential options.
    2255             :  *
    2256             :  * @param[in]  expire_time    A pointer to store the expiration time of the
    2257             :  *                            credentials (or NULL).
    2258             :  *
    2259             :  * @param[in]  kdc_time       A pointer to store the time when the ticket becomes
    2260             :  *                            valid (or NULL).
    2261             :  *
    2262             :  * @return 0 on success, a Kerberos error code otherwise.
    2263             :  */
    2264          18 : krb5_error_code smb_krb5_kinit_keyblock_ccache(krb5_context ctx,
    2265             :                                                krb5_ccache cc,
    2266             :                                                krb5_principal principal,
    2267             :                                                krb5_keyblock *keyblock,
    2268             :                                                const char *target_service,
    2269             :                                                krb5_get_init_creds_opt *krb_options,
    2270             :                                                time_t *expire_time,
    2271             :                                                time_t *kdc_time)
    2272             : {
    2273          18 :         krb5_error_code code = 0;
    2274           3 :         krb5_creds my_creds;
    2275             : 
    2276             : #if defined(HAVE_KRB5_GET_INIT_CREDS_KEYBLOCK)
    2277          14 :         code = krb5_get_init_creds_keyblock(ctx, &my_creds, principal,
    2278             :                                             keyblock, 0, target_service,
    2279             :                                             krb_options);
    2280             : #elif defined(HAVE_KRB5_GET_INIT_CREDS_KEYTAB)
    2281             : {
    2282             : #define SMB_CREDS_KEYTAB "MEMORY:tmp_kinit_keyblock_ccache"
    2283           4 :         char tmp_name[64] = {0};
    2284             :         krb5_keytab_entry entry;
    2285             :         krb5_keytab keytab;
    2286             :         int rc;
    2287             : 
    2288           4 :         memset(&entry, 0, sizeof(entry));
    2289           4 :         entry.principal = principal;
    2290           4 :         *(KRB5_KT_KEY(&entry)) = *keyblock;
    2291             : 
    2292           4 :         rc = snprintf(tmp_name, sizeof(tmp_name),
    2293             :                       "%s-%p",
    2294             :                       SMB_CREDS_KEYTAB,
    2295             :                       &my_creds);
    2296           4 :         if (rc < 0) {
    2297           0 :                 return KRB5_KT_BADNAME;
    2298             :         }
    2299           4 :         code = krb5_kt_resolve(ctx, tmp_name, &keytab);
    2300           4 :         if (code) {
    2301           0 :                 return code;
    2302             :         }
    2303             : 
    2304           4 :         code = krb5_kt_add_entry(ctx, keytab, &entry);
    2305           4 :         if (code) {
    2306           0 :                 (void)krb5_kt_close(ctx, keytab);
    2307           0 :                 goto done;
    2308             :         }
    2309             : 
    2310           4 :         code = krb5_get_init_creds_keytab(ctx, &my_creds, principal,
    2311             :                                           keytab, 0, target_service,
    2312             :                                           krb_options);
    2313           4 :         (void)krb5_kt_close(ctx, keytab);
    2314             : }
    2315             : #else
    2316             : #error krb5_get_init_creds_keyblock not available!
    2317             : #endif
    2318          18 :         if (code) {
    2319           1 :                 return code;
    2320             :         }
    2321             : 
    2322             : #ifndef SAMBA4_USES_HEIMDAL /* MIT */
    2323             :         /*
    2324             :          * We need to store the principal as returned from the KDC to the
    2325             :          * credentials cache. If we don't do that the KRB5 library is not
    2326             :          * able to find the tickets it is looking for
    2327             :          */
    2328           4 :         principal = my_creds.client;
    2329             : #endif
    2330          17 :         code = krb5_cc_initialize(ctx, cc, principal);
    2331          17 :         if (code) {
    2332           0 :                 goto done;
    2333             :         }
    2334             : 
    2335          17 :         code = krb5_cc_store_cred(ctx, cc, &my_creds);
    2336          17 :         if (code) {
    2337           0 :                 goto done;
    2338             :         }
    2339             : 
    2340          17 :         if (expire_time) {
    2341           0 :                 *expire_time = (time_t) my_creds.times.endtime;
    2342             :         }
    2343             : 
    2344          17 :         if (kdc_time) {
    2345          17 :                 *kdc_time = (time_t) my_creds.times.starttime;
    2346             :         }
    2347             : 
    2348          14 :         code = 0;
    2349          17 : done:
    2350          17 :         krb5_free_cred_contents(ctx, &my_creds);
    2351          17 :         return code;
    2352             : }
    2353             : 
    2354             : /**
    2355             :  * @brief Simulate a kinit by putting the tgt in the given credential cache.
    2356             :  *
    2357             :  * @param[in]  ctx      The library context
    2358             :  *
    2359             :  * @param[in]  cc       The credential cache to put the tgt in.
    2360             :  *
    2361             :  * @param[in]  principal The client princial
    2362             :  *
    2363             :  * @param[in]  password  The password (or NULL).
    2364             :  *
    2365             :  * @param[in]  target_service The service name of the initial credentials (or NULL).
    2366             :  *
    2367             :  * @param[in]  krb_options Initial credential options.
    2368             :  *
    2369             :  * @param[in]  expire_time    A pointer to store the expiration time of the
    2370             :  *                            credentials (or NULL).
    2371             :  *
    2372             :  * @param[in]  kdc_time       A pointer to store the time when the ticket becomes
    2373             :  *                            valid (or NULL).
    2374             :  *
    2375             :  * @return 0 on success, a Kerberos error code otherwise.
    2376             :  */
    2377       15433 : krb5_error_code smb_krb5_kinit_password_ccache(krb5_context ctx,
    2378             :                                                krb5_ccache cc,
    2379             :                                                krb5_principal principal,
    2380             :                                                const char *password,
    2381             :                                                const char *target_service,
    2382             :                                                krb5_get_init_creds_opt *krb_options,
    2383             :                                                time_t *expire_time,
    2384             :                                                time_t *kdc_time)
    2385             : {
    2386       15433 :         krb5_error_code code = 0;
    2387         589 :         krb5_creds my_creds;
    2388             : 
    2389       15433 :         code = krb5_get_init_creds_password(ctx, &my_creds, principal,
    2390             :                                             password, NULL, NULL, 0,
    2391             :                                             target_service, krb_options);
    2392       15433 :         if (code) {
    2393        1412 :                 return code;
    2394             :         }
    2395             : 
    2396             :         /*
    2397             :          * We need to store the principal as returned from the KDC to the
    2398             :          * credentials cache. If we don't do that the KRB5 library is not
    2399             :          * able to find the tickets it is looking for
    2400             :          */
    2401       14021 :         principal = my_creds.client;
    2402       14021 :         code = krb5_cc_initialize(ctx, cc, principal);
    2403       14021 :         if (code) {
    2404           0 :                 goto done;
    2405             :         }
    2406             : 
    2407       14021 :         code = krb5_cc_store_cred(ctx, cc, &my_creds);
    2408       14021 :         if (code) {
    2409           0 :                 goto done;
    2410             :         }
    2411             : 
    2412       14021 :         if (expire_time) {
    2413           0 :                 *expire_time = (time_t) my_creds.times.endtime;
    2414             :         }
    2415             : 
    2416       14021 :         if (kdc_time) {
    2417       14021 :                 *kdc_time = (time_t) my_creds.times.starttime;
    2418             :         }
    2419             : 
    2420       13432 :         code = 0;
    2421       14021 : done:
    2422       14021 :         krb5_free_cred_contents(ctx, &my_creds);
    2423       14021 :         return code;
    2424             : }
    2425             : 
    2426             : #ifdef SAMBA4_USES_HEIMDAL
    2427             : /**
    2428             :  * @brief Simulate a kinit by putting the tgt in the given credential cache.
    2429             :  *
    2430             :  * @param[in]  ctx      The library context
    2431             :  *
    2432             :  * @param[in]  cc       The credential cache to store the tgt in.
    2433             :  *
    2434             :  * @param[in]  principal The initial client princial.
    2435             :  *
    2436             :  * @param[in]  password  The password (or NULL).
    2437             :  *
    2438             :  * @param[in]  impersonate_principal The impersonation principal (or NULL).
    2439             :  *
    2440             :  * @param[in]  self_service The local service for S4U2Self if
    2441             :  *                          impersonate_principal is specified).
    2442             :  *
    2443             :  * @param[in]  target_service The service name of the initial credentials
    2444             :  *                            (kpasswd/REALM or a remote service). It defaults
    2445             :  *                            to the krbtgt if NULL.
    2446             :  *
    2447             :  * @param[in]  krb_options Initial credential options.
    2448             :  *
    2449             :  * @param[in]  expire_time    A pointer to store the expiration time of the
    2450             :  *                            credentials (or NULL).
    2451             :  *
    2452             :  * @param[in]  kdc_time       A pointer to store the time when the ticket becomes
    2453             :  *                            valid (or NULL).
    2454             :  *
    2455             :  * @return 0 on success, a Kerberos error code otherwise.
    2456             :  */
    2457          35 : krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx,
    2458             :                                            krb5_ccache store_cc,
    2459             :                                            krb5_principal init_principal,
    2460             :                                            const char *init_password,
    2461             :                                            krb5_principal impersonate_principal,
    2462             :                                            const char *self_service,
    2463             :                                            const char *target_service,
    2464             :                                            krb5_get_init_creds_opt *krb_options,
    2465             :                                            time_t *expire_time,
    2466             :                                            time_t *kdc_time)
    2467             : {
    2468          35 :         krb5_error_code code = 0;
    2469           0 :         krb5_get_creds_opt options;
    2470           0 :         krb5_principal store_principal;
    2471           0 :         krb5_creds store_creds;
    2472           0 :         krb5_creds *s4u2self_creds;
    2473           0 :         Ticket s4u2self_ticket;
    2474           0 :         size_t s4u2self_ticketlen;
    2475           0 :         krb5_creds *s4u2proxy_creds;
    2476           0 :         krb5_principal self_princ;
    2477           0 :         bool s4u2proxy;
    2478           0 :         krb5_principal target_princ;
    2479           0 :         krb5_ccache tmp_cc;
    2480           0 :         const char *self_realm;
    2481          35 :         const char *client_realm = NULL;
    2482          35 :         krb5_principal blacklist_principal = NULL;
    2483          35 :         krb5_principal whitelist_principal = NULL;
    2484             : 
    2485          35 :         code = krb5_get_init_creds_password(ctx, &store_creds,
    2486             :                                             init_principal,
    2487             :                                             init_password,
    2488             :                                             NULL, NULL,
    2489             :                                             0,
    2490             :                                             NULL,
    2491             :                                             krb_options);
    2492          35 :         if (code != 0) {
    2493           0 :                 return code;
    2494             :         }
    2495             : 
    2496          35 :         store_principal = init_principal;
    2497             : 
    2498             :         /*
    2499             :          * We are trying S4U2Self now:
    2500             :          *
    2501             :          * As we do not want to expose our TGT in the
    2502             :          * krb5_ccache, which is also holds the impersonated creds.
    2503             :          *
    2504             :          * Some low level krb5/gssapi function might use the TGT
    2505             :          * identity and let the client act as our machine account.
    2506             :          *
    2507             :          * We need to avoid that and use a temporary krb5_ccache
    2508             :          * in order to pass our TGT to the krb5_get_creds() function.
    2509             :          */
    2510          35 :         code = smb_krb5_cc_new_unique_memory(ctx, NULL, NULL, &tmp_cc);
    2511          35 :         if (code != 0) {
    2512           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2513           0 :                 return code;
    2514             :         }
    2515             : 
    2516          35 :         code = krb5_cc_initialize(ctx, tmp_cc, store_creds.client);
    2517          35 :         if (code != 0) {
    2518           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2519           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2520           0 :                 return code;
    2521             :         }
    2522             : 
    2523          35 :         code = krb5_cc_store_cred(ctx, tmp_cc, &store_creds);
    2524          35 :         if (code != 0) {
    2525           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2526           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2527           0 :                 return code;
    2528             :         }
    2529             : 
    2530             :         /*
    2531             :          * we need to remember the client principal of our
    2532             :          * TGT and make sure the KDC does not return this
    2533             :          * in the impersonated tickets. This can happen
    2534             :          * if the KDC does not support S4U2Self and S4U2Proxy.
    2535             :          */
    2536          35 :         blacklist_principal = store_creds.client;
    2537          35 :         store_creds.client = NULL;
    2538          35 :         krb5_free_cred_contents(ctx, &store_creds);
    2539             : 
    2540             :         /*
    2541             :          * Check if we also need S4U2Proxy or if S4U2Self is
    2542             :          * enough in order to get a ticket for the target.
    2543             :          */
    2544          35 :         if (target_service == NULL) {
    2545          20 :                 s4u2proxy = false;
    2546          15 :         } else if (strcmp(target_service, self_service) == 0) {
    2547           3 :                 s4u2proxy = false;
    2548             :         } else {
    2549          12 :                 s4u2proxy = true;
    2550             :         }
    2551             : 
    2552             :         /*
    2553             :          * For S4U2Self we need our own service principal,
    2554             :          * which belongs to our own realm (available on
    2555             :          * our client principal).
    2556             :          */
    2557          35 :         self_realm = krb5_principal_get_realm(ctx, init_principal);
    2558             : 
    2559          35 :         code = krb5_parse_name(ctx, self_service, &self_princ);
    2560          35 :         if (code != 0) {
    2561           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2562           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2563           0 :                 return code;
    2564             :         }
    2565             : 
    2566          35 :         code = krb5_principal_set_realm(ctx, self_princ, self_realm);
    2567          35 :         if (code != 0) {
    2568           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2569           0 :                 krb5_free_principal(ctx, self_princ);
    2570           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2571           0 :                 return code;
    2572             :         }
    2573             : 
    2574          35 :         code = krb5_get_creds_opt_alloc(ctx, &options);
    2575          35 :         if (code != 0) {
    2576           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2577           0 :                 krb5_free_principal(ctx, self_princ);
    2578           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2579           0 :                 return code;
    2580             :         }
    2581             : 
    2582          35 :         if (s4u2proxy) {
    2583             :                 /*
    2584             :                  * If we want S4U2Proxy, we need the forwardable flag
    2585             :                  * on the S4U2Self ticket.
    2586             :                  */
    2587          12 :                 krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
    2588             :         }
    2589             : 
    2590          35 :         code = krb5_get_creds_opt_set_impersonate(ctx, options,
    2591             :                                                   impersonate_principal);
    2592          35 :         if (code != 0) {
    2593           0 :                 krb5_get_creds_opt_free(ctx, options);
    2594           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2595           0 :                 krb5_free_principal(ctx, self_princ);
    2596           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2597           0 :                 return code;
    2598             :         }
    2599             : 
    2600          35 :         code = krb5_get_creds(ctx, options, tmp_cc,
    2601             :                               self_princ, &s4u2self_creds);
    2602          35 :         krb5_get_creds_opt_free(ctx, options);
    2603          35 :         krb5_free_principal(ctx, self_princ);
    2604          35 :         if (code != 0) {
    2605           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2606           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2607           0 :                 return code;
    2608             :         }
    2609             : 
    2610          35 :         if (!s4u2proxy) {
    2611          23 :                 krb5_cc_destroy(ctx, tmp_cc);
    2612             : 
    2613             :                 /*
    2614             :                  * Now make sure we store the impersonated principal
    2615             :                  * and creds instead of the TGT related stuff
    2616             :                  * in the krb5_ccache of the caller.
    2617             :                  */
    2618          23 :                 code = krb5_copy_creds_contents(ctx, s4u2self_creds,
    2619             :                                                 &store_creds);
    2620          23 :                 krb5_free_creds(ctx, s4u2self_creds);
    2621          23 :                 if (code != 0) {
    2622           0 :                         return code;
    2623             :                 }
    2624             : 
    2625             :                 /*
    2626             :                  * It's important to store the principal the KDC
    2627             :                  * returned, as otherwise the caller would not find
    2628             :                  * the S4U2Self ticket in the krb5_ccache lookup.
    2629             :                  */
    2630          23 :                 store_principal = store_creds.client;
    2631          23 :                 goto store;
    2632             :         }
    2633             : 
    2634             :         /*
    2635             :          * We are trying S4U2Proxy:
    2636             :          *
    2637             :          * We need the ticket from the S4U2Self step
    2638             :          * and our TGT in order to get the delegated ticket.
    2639             :          */
    2640          12 :         code = decode_Ticket((const uint8_t *)s4u2self_creds->ticket.data,
    2641          12 :                              s4u2self_creds->ticket.length,
    2642             :                              &s4u2self_ticket,
    2643             :                              &s4u2self_ticketlen);
    2644          12 :         if (code != 0) {
    2645           0 :                 krb5_free_creds(ctx, s4u2self_creds);
    2646           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2647           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2648           0 :                 return code;
    2649             :         }
    2650             : 
    2651             :         /*
    2652             :          * we need to remember the client principal of the
    2653             :          * S4U2Self stage and as it needs to match the one we
    2654             :          * will get for the S4U2Proxy stage. We need this
    2655             :          * in order to detect KDCs which does not support S4U2Proxy.
    2656             :          */
    2657          12 :         whitelist_principal = s4u2self_creds->client;
    2658          12 :         s4u2self_creds->client = NULL;
    2659          12 :         krb5_free_creds(ctx, s4u2self_creds);
    2660             : 
    2661             :         /*
    2662             :          * For S4U2Proxy we also got a target service principal,
    2663             :          * which also belongs to our own realm (available on
    2664             :          * our client principal).
    2665             :          */
    2666          12 :         code = krb5_parse_name(ctx, target_service, &target_princ);
    2667          12 :         if (code != 0) {
    2668           0 :                 free_Ticket(&s4u2self_ticket);
    2669           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2670           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2671           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2672           0 :                 return code;
    2673             :         }
    2674             : 
    2675          12 :         code = krb5_principal_set_realm(ctx, target_princ, self_realm);
    2676          12 :         if (code != 0) {
    2677           0 :                 free_Ticket(&s4u2self_ticket);
    2678           0 :                 krb5_free_principal(ctx, target_princ);
    2679           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2680           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2681           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2682           0 :                 return code;
    2683             :         }
    2684             : 
    2685          12 :         code = krb5_get_creds_opt_alloc(ctx, &options);
    2686          12 :         if (code != 0) {
    2687           0 :                 free_Ticket(&s4u2self_ticket);
    2688           0 :                 krb5_free_principal(ctx, target_princ);
    2689           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2690           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2691           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2692           0 :                 return code;
    2693             :         }
    2694             : 
    2695          12 :         krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
    2696          12 :         krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_CONSTRAINED_DELEGATION);
    2697             : 
    2698          12 :         code = krb5_get_creds_opt_set_ticket(ctx, options, &s4u2self_ticket);
    2699          12 :         free_Ticket(&s4u2self_ticket);
    2700          12 :         if (code != 0) {
    2701           0 :                 krb5_get_creds_opt_free(ctx, options);
    2702           0 :                 krb5_free_principal(ctx, target_princ);
    2703           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2704           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2705           0 :                 krb5_cc_destroy(ctx, tmp_cc);
    2706           0 :                 return code;
    2707             :         }
    2708             : 
    2709          12 :         code = krb5_get_creds(ctx, options, tmp_cc,
    2710             :                               target_princ, &s4u2proxy_creds);
    2711          12 :         krb5_get_creds_opt_free(ctx, options);
    2712          12 :         krb5_free_principal(ctx, target_princ);
    2713          12 :         krb5_cc_destroy(ctx, tmp_cc);
    2714          12 :         if (code != 0) {
    2715           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2716           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2717           0 :                 return code;
    2718             :         }
    2719             : 
    2720             :         /*
    2721             :          * Now make sure we store the impersonated principal
    2722             :          * and creds instead of the TGT related stuff
    2723             :          * in the krb5_ccache of the caller.
    2724             :          */
    2725          12 :         code = krb5_copy_creds_contents(ctx, s4u2proxy_creds,
    2726             :                                         &store_creds);
    2727          12 :         krb5_free_creds(ctx, s4u2proxy_creds);
    2728          12 :         if (code != 0) {
    2729           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2730           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2731           0 :                 return code;
    2732             :         }
    2733             : 
    2734             :         /*
    2735             :          * It's important to store the principal the KDC
    2736             :          * returned, as otherwise the caller would not find
    2737             :          * the S4U2Self ticket in the krb5_ccache lookup.
    2738             :          */
    2739          12 :         store_principal = store_creds.client;
    2740             : 
    2741          35 :  store:
    2742          70 :         if (blacklist_principal &&
    2743          35 :             krb5_principal_compare(ctx, store_creds.client, blacklist_principal)) {
    2744           0 :                 char *sp = NULL;
    2745           0 :                 char *ip = NULL;
    2746             : 
    2747           0 :                 code = krb5_unparse_name(ctx, blacklist_principal, &sp);
    2748           0 :                 if (code != 0) {
    2749           0 :                         sp = NULL;
    2750             :                 }
    2751           0 :                 code = krb5_unparse_name(ctx, impersonate_principal, &ip);
    2752           0 :                 if (code != 0) {
    2753           0 :                         ip = NULL;
    2754             :                 }
    2755           0 :                 DBG_WARNING("KDC returned self principal[%s] while impersonating [%s]\n",
    2756             :                             sp?sp:"<no memory>",
    2757             :                             ip?ip:"<no memory>");
    2758             : 
    2759           0 :                 SAFE_FREE(sp);
    2760           0 :                 SAFE_FREE(ip);
    2761             : 
    2762           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2763           0 :                 krb5_free_principal(ctx, blacklist_principal);
    2764           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2765           0 :                 return KRB5_FWD_BAD_PRINCIPAL;
    2766             :         }
    2767          35 :         if (blacklist_principal) {
    2768          35 :                 krb5_free_principal(ctx, blacklist_principal);
    2769             :         }
    2770             : 
    2771          47 :         if (whitelist_principal &&
    2772          12 :             !krb5_principal_compare(ctx, store_creds.client, whitelist_principal)) {
    2773           0 :                 char *sp = NULL;
    2774           0 :                 char *ep = NULL;
    2775             : 
    2776           0 :                 code = krb5_unparse_name(ctx, store_creds.client, &sp);
    2777           0 :                 if (code != 0) {
    2778           0 :                         sp = NULL;
    2779             :                 }
    2780           0 :                 code = krb5_unparse_name(ctx, whitelist_principal, &ep);
    2781           0 :                 if (code != 0) {
    2782           0 :                         ep = NULL;
    2783             :                 }
    2784           0 :                 DBG_WARNING("KDC returned wrong principal[%s] we expected [%s]\n",
    2785             :                             sp?sp:"<no memory>",
    2786             :                             ep?ep:"<no memory>");
    2787             : 
    2788           0 :                 SAFE_FREE(sp);
    2789           0 :                 SAFE_FREE(ep);
    2790             : 
    2791           0 :                 krb5_free_principal(ctx, whitelist_principal);
    2792           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2793           0 :                 return KRB5_FWD_BAD_PRINCIPAL;
    2794             :         }
    2795          35 :         if (whitelist_principal) {
    2796          12 :                 krb5_free_principal(ctx, whitelist_principal);
    2797             :         }
    2798             : 
    2799          35 :         code = krb5_cc_initialize(ctx, store_cc, store_principal);
    2800          35 :         if (code != 0) {
    2801           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2802           0 :                 return code;
    2803             :         }
    2804             : 
    2805          35 :         code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
    2806          35 :         if (code != 0) {
    2807           0 :                 krb5_free_cred_contents(ctx, &store_creds);
    2808           0 :                 return code;
    2809             :         }
    2810             : 
    2811          35 :         client_realm = krb5_principal_get_realm(ctx, store_creds.client);
    2812          35 :         if (client_realm != NULL) {
    2813             :                 /*
    2814             :                  * Because the CANON flag doesn't have any impact
    2815             :                  * on the impersonate_principal => store_creds.client
    2816             :                  * realm mapping. We need to store the credentials twice,
    2817             :                  * once with the returned realm and once with the
    2818             :                  * realm of impersonate_principal.
    2819             :                  */
    2820          35 :                 code = krb5_principal_set_realm(ctx, store_creds.server,
    2821             :                                                 client_realm);
    2822          35 :                 if (code != 0) {
    2823           0 :                         krb5_free_cred_contents(ctx, &store_creds);
    2824           0 :                         return code;
    2825             :                 }
    2826             : 
    2827          35 :                 code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
    2828          35 :                 if (code != 0) {
    2829           0 :                         krb5_free_cred_contents(ctx, &store_creds);
    2830           0 :                         return code;
    2831             :                 }
    2832             :         }
    2833             : 
    2834          35 :         if (expire_time) {
    2835           0 :                 *expire_time = (time_t) store_creds.times.endtime;
    2836             :         }
    2837             : 
    2838          35 :         if (kdc_time) {
    2839          35 :                 *kdc_time = (time_t) store_creds.times.starttime;
    2840             :         }
    2841             : 
    2842          35 :         krb5_free_cred_contents(ctx, &store_creds);
    2843             : 
    2844          35 :         return 0;
    2845             : }
    2846             : 
    2847             : #else /* MIT */
    2848             : 
    2849           0 : static bool princ_compare_no_dollar(krb5_context ctx,
    2850             :                                     krb5_principal a,
    2851             :                                     krb5_principal b)
    2852             : {
    2853           0 :         krb5_principal mod = NULL;
    2854             :         bool cmp;
    2855             : 
    2856           0 :         if (a->length == 1 && b->length == 1 &&
    2857           0 :             a->data[0].length != 0 && b->data[0].length != 0 &&
    2858           0 :             a->data[0].data[a->data[0].length - 1] !=
    2859           0 :             b->data[0].data[b->data[0].length - 1]) {
    2860           0 :                 if (a->data[0].data[a->data[0].length - 1] == '$') {
    2861           0 :                         mod = a;
    2862           0 :                         mod->data[0].length--;
    2863           0 :                 } else if (b->data[0].data[b->data[0].length - 1] == '$') {
    2864           0 :                         mod = b;
    2865           0 :                         mod->data[0].length--;
    2866             :                 }
    2867             :         }
    2868             : 
    2869           0 :         cmp = krb5_principal_compare_flags(ctx,
    2870             :                                            a,
    2871             :                                            b,
    2872             :                                            KRB5_PRINCIPAL_COMPARE_CASEFOLD);
    2873           0 :         if (mod != NULL) {
    2874           0 :                 mod->data[0].length++;
    2875             :         }
    2876             : 
    2877           0 :         return cmp;
    2878             : }
    2879             : 
    2880           0 : krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx,
    2881             :                                            krb5_ccache store_cc,
    2882             :                                            krb5_principal init_principal,
    2883             :                                            const char *init_password,
    2884             :                                            krb5_principal impersonate_principal,
    2885             :                                            const char *self_service,
    2886             :                                            const char *target_service,
    2887             :                                            krb5_get_init_creds_opt *krb_options,
    2888             :                                            time_t *expire_time,
    2889             :                                            time_t *kdc_time)
    2890             : {
    2891             :         krb5_error_code code;
    2892           0 :         krb5_principal self_princ = NULL;
    2893           0 :         krb5_principal target_princ = NULL;
    2894           0 :         krb5_creds *store_creds = NULL;
    2895           0 :         krb5_creds *s4u2self_creds = NULL;
    2896           0 :         krb5_creds *s4u2proxy_creds = NULL;
    2897           0 :         krb5_creds init_creds = {0};
    2898           0 :         krb5_creds mcreds = {0};
    2899           0 :         krb5_flags options = KRB5_GC_NO_STORE;
    2900             :         krb5_ccache tmp_cc;
    2901           0 :         bool s4u2proxy = false;
    2902             :         bool ok;
    2903             : 
    2904           0 :         code = smb_krb5_cc_new_unique_memory(ctx, NULL, NULL, &tmp_cc);
    2905           0 :         if (code != 0) {
    2906           0 :                 return code;
    2907             :         }
    2908             : 
    2909           0 :         code = krb5_get_init_creds_password(ctx,
    2910             :                                             &init_creds,
    2911             :                                             init_principal,
    2912             :                                             init_password,
    2913             :                                             NULL,
    2914             :                                             NULL,
    2915             :                                             0,
    2916             :                                             NULL,
    2917             :                                             krb_options);
    2918           0 :         if (code != 0) {
    2919           0 :                 goto done;
    2920             :         }
    2921             : 
    2922           0 :         code = krb5_cc_initialize(ctx, tmp_cc, init_creds.client);
    2923           0 :         if (code != 0) {
    2924           0 :                 goto done;
    2925             :         }
    2926             : 
    2927           0 :         code = krb5_cc_store_cred(ctx, tmp_cc, &init_creds);
    2928           0 :         if (code != 0) {
    2929           0 :                 goto done;
    2930             :         }
    2931             : 
    2932             :         /*
    2933             :          * Check if we also need S4U2Proxy or if S4U2Self is
    2934             :          * enough in order to get a ticket for the target.
    2935             :          */
    2936           0 :         if (target_service == NULL) {
    2937           0 :                 s4u2proxy = false;
    2938           0 :         } else if (strcmp(target_service, self_service) == 0) {
    2939           0 :                 s4u2proxy = false;
    2940             :         } else {
    2941           0 :                 s4u2proxy = true;
    2942             :         }
    2943             : 
    2944           0 :         code = krb5_parse_name(ctx, self_service, &self_princ);
    2945           0 :         if (code != 0) {
    2946           0 :                 goto done;
    2947             :         }
    2948             : 
    2949             :         /*
    2950             :          * MIT lacks aliases support in S4U, for S4U2Self we require the tgt
    2951             :          * client and the request server to be the same principal name.
    2952             :          */
    2953           0 :         ok = princ_compare_no_dollar(ctx, init_creds.client, self_princ);
    2954           0 :         if (!ok) {
    2955           0 :                 code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    2956           0 :                 goto done;
    2957             :         }
    2958             : 
    2959           0 :         mcreds.client = impersonate_principal;
    2960           0 :         mcreds.server = init_creds.client;
    2961             : 
    2962           0 :         code = krb5_get_credentials_for_user(ctx, options, tmp_cc, &mcreds,
    2963             :                                              NULL, &s4u2self_creds);
    2964           0 :         if (code != 0) {
    2965           0 :                 goto done;
    2966             :         }
    2967             : 
    2968           0 :         if (s4u2proxy) {
    2969           0 :                 code = krb5_parse_name(ctx, target_service, &target_princ);
    2970           0 :                 if (code != 0) {
    2971           0 :                         goto done;
    2972             :                 }
    2973             : 
    2974           0 :                 mcreds.client = init_creds.client;
    2975           0 :                 mcreds.server = target_princ;
    2976           0 :                 mcreds.second_ticket = s4u2self_creds->ticket;
    2977             : 
    2978           0 :                 code = krb5_get_credentials(ctx, options |
    2979             :                                             KRB5_GC_CONSTRAINED_DELEGATION,
    2980             :                                             tmp_cc, &mcreds, &s4u2proxy_creds);
    2981           0 :                 if (code != 0) {
    2982           0 :                         goto done;
    2983             :                 }
    2984             : 
    2985             :                 /* Check KDC support of S4U2Proxy extension */
    2986           0 :                 if (!krb5_principal_compare(ctx, s4u2self_creds->client,
    2987           0 :                                             s4u2proxy_creds->client)) {
    2988           0 :                         code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
    2989           0 :                         goto done;
    2990             :                 }
    2991             : 
    2992           0 :                 store_creds = s4u2proxy_creds;
    2993             :         } else {
    2994           0 :                 store_creds = s4u2self_creds;;
    2995             : 
    2996             :                 /* We need to save the ticket with the requested server name
    2997             :                  * or the caller won't be able to find it in cache. */
    2998           0 :                 if (!krb5_principal_compare(ctx, self_princ,
    2999           0 :                         store_creds->server)) {
    3000           0 :                         krb5_free_principal(ctx, store_creds->server);
    3001           0 :                         store_creds->server = NULL;
    3002           0 :                         code = krb5_copy_principal(ctx, self_princ,
    3003             :                                                    &store_creds->server);
    3004           0 :                         if (code != 0) {
    3005           0 :                                 goto done;
    3006             :                         }
    3007             :                 }
    3008             :         }
    3009             : 
    3010           0 :         code = krb5_cc_initialize(ctx, store_cc, store_creds->client);
    3011           0 :         if (code != 0) {
    3012           0 :                 goto done;
    3013             :         }
    3014             : 
    3015           0 :         code = krb5_cc_store_cred(ctx, store_cc, store_creds);
    3016           0 :         if (code != 0) {
    3017           0 :                 goto done;
    3018             :         }
    3019             : 
    3020           0 :         if (expire_time) {
    3021           0 :                 *expire_time = (time_t) store_creds->times.endtime;
    3022             :         }
    3023             : 
    3024           0 :         if (kdc_time) {
    3025           0 :                 *kdc_time = (time_t) store_creds->times.starttime;
    3026             :         }
    3027             : 
    3028           0 : done:
    3029           0 :         krb5_cc_destroy(ctx, tmp_cc);
    3030           0 :         krb5_free_cred_contents(ctx, &init_creds);
    3031           0 :         krb5_free_creds(ctx, s4u2self_creds);
    3032           0 :         krb5_free_creds(ctx, s4u2proxy_creds);
    3033           0 :         krb5_free_principal(ctx, self_princ);
    3034           0 :         krb5_free_principal(ctx, target_princ);
    3035             : 
    3036           0 :         return code;
    3037             : }
    3038             : #endif
    3039             : 
    3040             : #if !defined(HAVE_KRB5_MAKE_PRINCIPAL) && defined(HAVE_KRB5_BUILD_PRINCIPAL_ALLOC_VA)
    3041             : /**
    3042             :  * @brief Create a principal name using a variable argument list.
    3043             :  *
    3044             :  * @param[in]  context  The library context.
    3045             :  *
    3046             :  * @param[inout]  principal A pointer to the principal structure.
    3047             :  *
    3048             :  * @param[in]  _realm    The realm to use. If NULL then the function will
    3049             :  *                       get the default realm name.
    3050             :  *
    3051             :  * @param[in]  ...       A list of 'char *' components, ending with NULL.
    3052             :  *
    3053             :  * Use krb5_free_principal() to free the principal when it is no longer needed.
    3054             :  *
    3055             :  * @return 0 on success, a Kerberos error code otherwise.
    3056             :  */
    3057        2687 : krb5_error_code smb_krb5_make_principal(krb5_context context,
    3058             :                                         krb5_principal *principal,
    3059             :                                         const char *_realm, ...)
    3060             : {
    3061             :         krb5_error_code code;
    3062             :         bool free_realm;
    3063             :         char *realm;
    3064             :         va_list ap;
    3065             : 
    3066        2687 :         if (_realm) {
    3067        2687 :                 realm = discard_const_p(char, _realm);
    3068        2687 :                 free_realm = false;
    3069             :         } else {
    3070           0 :                 code = krb5_get_default_realm(context, &realm);
    3071           0 :                 if (code) {
    3072           0 :                         return code;
    3073             :                 }
    3074           0 :                 free_realm = true;
    3075             :         }
    3076             : 
    3077        2687 :         va_start(ap, _realm);
    3078        2687 :         code = krb5_build_principal_alloc_va(context, principal,
    3079        2687 :                                              strlen(realm), realm,
    3080             :                                              ap);
    3081        2687 :         va_end(ap);
    3082             : 
    3083        2687 :         if (free_realm) {
    3084           0 :                 krb5_free_default_realm(context, realm);
    3085             :         }
    3086             : 
    3087        2687 :         return code;
    3088             : }
    3089             : #endif
    3090             : 
    3091             : #if !defined(HAVE_KRB5_CC_GET_LIFETIME) && defined(HAVE_KRB5_CC_RETRIEVE_CRED)
    3092             : /**
    3093             :  * @brief Get the lifetime of the initial ticket in the cache.
    3094             :  *
    3095             :  * @param[in]  context  The kerberos context.
    3096             :  *
    3097             :  * @param[in]  id       The credential cache to get the ticket lifetime.
    3098             :  *
    3099             :  * @param[out] t        A pointer to a time value to store the lifetime.
    3100             :  *
    3101             :  * @return              0 on success, a krb5_error_code on error.
    3102             :  */
    3103         559 : krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
    3104             :                                          krb5_ccache id,
    3105             :                                          time_t *t)
    3106             : {
    3107             :         krb5_cc_cursor cursor;
    3108             :         krb5_error_code kerr;
    3109             :         krb5_creds cred;
    3110         559 :         krb5_timestamp endtime = 0;
    3111             :         krb5_timestamp now;
    3112             : 
    3113         559 :         *t = 0;
    3114             : 
    3115         559 :         kerr = krb5_timeofday(context, &now);
    3116         559 :         if (kerr) {
    3117           0 :                 return kerr;
    3118             :         }
    3119             : 
    3120         559 :         kerr = krb5_cc_start_seq_get(context, id, &cursor);
    3121         559 :         if (kerr) {
    3122           0 :                 return kerr;
    3123             :         }
    3124             : 
    3125         869 :         while ((kerr = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
    3126         857 :                 if (krb5_is_config_principal(context, cred.server)) {
    3127         298 :                         krb5_free_cred_contents(context, &cred);
    3128         298 :                         continue;
    3129             :                 }
    3130             : 
    3131             : #ifndef HAVE_FLAGS_IN_KRB5_CREDS
    3132         559 :                 if (cred.ticket_flags & TKT_FLG_INITIAL) {
    3133             : #else
    3134             :                 if (cred.flags.b.initial) {
    3135             : #endif
    3136         547 :                         if (now < cred.times.endtime) {
    3137         547 :                                 endtime = cred.times.endtime;
    3138             :                         }
    3139         547 :                         krb5_free_cred_contents(context, &cred);
    3140         547 :                         break;
    3141             :                 }
    3142             : 
    3143          12 :                 if (cred.times.endtime <= now) {
    3144             :                         /* already expired */
    3145           0 :                         krb5_free_cred_contents(context, &cred);
    3146           0 :                         continue;
    3147             :                 }
    3148             : 
    3149             :                 /**
    3150             :                  * If there was no krbtgt, use the shortest lifetime of
    3151             :                  * service tickets that have yet to expire.  If all
    3152             :                  * credentials are expired, krb5_cc_get_lifetime() will fail.
    3153             :                  */
    3154          12 :                 if (endtime == 0 || cred.times.endtime < endtime) {
    3155          12 :                         endtime = cred.times.endtime;
    3156             :                 }
    3157          12 :                 krb5_free_cred_contents(context, &cred);
    3158             :         }
    3159             : 
    3160         559 :         if (now < endtime) {
    3161         559 :                 *t = (time_t) (endtime - now);
    3162         559 :                 kerr = 0;
    3163             :         }
    3164             : 
    3165         559 :         krb5_cc_end_seq_get(context, id, &cursor);
    3166             : 
    3167         559 :         return kerr;
    3168             : }
    3169             : #endif /* HAVE_KRB5_CC_GET_LIFETIME */
    3170             : 
    3171             : #if !defined(HAVE_KRB5_FREE_CHECKSUM_CONTENTS) && defined(HAVE_FREE_CHECKSUM)
    3172          12 : void smb_krb5_free_checksum_contents(krb5_context ctx, krb5_checksum *cksum)
    3173             : {
    3174          12 :         free_Checksum(cksum);
    3175          12 : }
    3176             : #endif
    3177             : 
    3178             : /**
    3179             :  * @brief Compute a checksum operating on a keyblock.
    3180             :  *
    3181             :  * This function computes a checksum over a PAC using the keyblock for a keyed
    3182             :  * checksum.
    3183             :  *
    3184             :  * @param[in]  mem_ctx A talloc context to allocate the signature on.
    3185             :  *
    3186             :  * @param[in]  pac_data The PAC as input.
    3187             :  *
    3188             :  * @param[in]  context  The library context.
    3189             :  *
    3190             :  * @param[in]  keyblock Encryption key for a keyed checksum.
    3191             :  *
    3192             :  * @param[out] sig_type The checksum type
    3193             :  *
    3194             :  * @param[out] sig_blob The talloc'ed checksum
    3195             :  *
    3196             :  * The caller must free the sig_blob with talloc_free() when it is not needed
    3197             :  * anymore.
    3198             :  *
    3199             :  * @return 0 on success, a Kerberos error code otherwise.
    3200             :  */
    3201          12 : krb5_error_code smb_krb5_make_pac_checksum(TALLOC_CTX *mem_ctx,
    3202             :                                            DATA_BLOB *pac_data,
    3203             :                                            krb5_context context,
    3204             :                                            const krb5_keyblock *keyblock,
    3205             :                                            uint32_t *sig_type,
    3206             :                                            DATA_BLOB *sig_blob)
    3207             : {
    3208          12 :         krb5_error_code ret;
    3209          12 :         krb5_checksum cksum;
    3210             : #if defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CREATE_CHECKSUM)
    3211          12 :         krb5_crypto crypto;
    3212             : 
    3213             : 
    3214          12 :         ret = krb5_crypto_init(context,
    3215             :                                keyblock,
    3216             :                                0,
    3217             :                                &crypto);
    3218          12 :         if (ret) {
    3219           0 :                 DEBUG(0,("krb5_crypto_init() failed: %s\n",
    3220             :                           smb_get_krb5_error_message(context, ret, mem_ctx)));
    3221           0 :                 return ret;
    3222             :         }
    3223          24 :         ret = krb5_create_checksum(context,
    3224             :                                    crypto,
    3225             :                                    KRB5_KU_OTHER_CKSUM,
    3226             :                                    0,
    3227          12 :                                    pac_data->data,
    3228             :                                    pac_data->length,
    3229             :                                    &cksum);
    3230          12 :         if (ret) {
    3231           0 :                 DEBUG(2, ("PAC Verification failed: %s\n",
    3232             :                           smb_get_krb5_error_message(context, ret, mem_ctx)));
    3233             :         }
    3234             : 
    3235          12 :         krb5_crypto_destroy(context, crypto);
    3236             : 
    3237          12 :         if (ret) {
    3238           0 :                 return ret;
    3239             :         }
    3240             : 
    3241          12 :         *sig_type = cksum.cksumtype;
    3242          12 :         *sig_blob = data_blob_talloc(mem_ctx,
    3243             :                                         cksum.checksum.data,
    3244             :                                         cksum.checksum.length);
    3245             : #elif defined(HAVE_KRB5_C_MAKE_CHECKSUM)
    3246             :         krb5_data input;
    3247             : 
    3248           0 :         input.data = (char *)pac_data->data;
    3249           0 :         input.length = pac_data->length;
    3250             : 
    3251           0 :         ret = krb5_c_make_checksum(context,
    3252             :                                    0,
    3253             :                                    keyblock,
    3254             :                                    KRB5_KEYUSAGE_APP_DATA_CKSUM,
    3255             :                                    &input,
    3256             :                                    &cksum);
    3257           0 :         if (ret) {
    3258           0 :                 DEBUG(2, ("PAC Verification failed: %s\n",
    3259             :                           smb_get_krb5_error_message(context, ret, mem_ctx)));
    3260           0 :                 return ret;
    3261             :         }
    3262             : 
    3263           0 :         *sig_type = cksum.checksum_type;
    3264           0 :         *sig_blob = data_blob_talloc(mem_ctx,
    3265             :                                         cksum.contents,
    3266             :                                         cksum.length);
    3267             : 
    3268             : #else
    3269             : #error krb5_create_checksum or krb5_c_make_checksum not available
    3270             : #endif /* HAVE_KRB5_C_MAKE_CHECKSUM */
    3271          12 :         smb_krb5_free_checksum_contents(context, &cksum);
    3272             : 
    3273          12 :         return 0;
    3274             : }
    3275             : 
    3276             : 
    3277             : /**
    3278             :  * @brief Get realm of a principal
    3279             :  *
    3280             :  * @param[in] mem_ctx   The talloc ctx to put the result on
    3281             :  *
    3282             :  * @param[in] context   The library context
    3283             :  *
    3284             :  * @param[in] principal The principal to get the realm from.
    3285             :  *
    3286             :  * @return A talloced string with the realm or NULL if an error occurred.
    3287             :  */
    3288      645758 : char *smb_krb5_principal_get_realm(TALLOC_CTX *mem_ctx,
    3289             :                                    krb5_context context,
    3290             :                                    krb5_const_principal principal)
    3291             : {
    3292             : #ifdef HAVE_KRB5_PRINCIPAL_GET_REALM /* Heimdal */
    3293      632697 :         const char *realm = NULL;
    3294             : 
    3295      632697 :         realm = krb5_principal_get_realm(context, principal);
    3296      632697 :         if (realm == NULL) {
    3297           0 :                 return NULL;
    3298             :         }
    3299             : 
    3300      632697 :         return talloc_strdup(mem_ctx, realm);
    3301             : #elif defined(krb5_princ_realm) /* MIT */
    3302       13061 :         const krb5_data *realm = NULL;
    3303             : 
    3304       13061 :         realm = krb5_princ_realm(context, principal);
    3305       13061 :         if (realm == NULL) {
    3306           0 :                 return NULL;
    3307             :         }
    3308             : 
    3309       13061 :         return talloc_strndup(mem_ctx, realm->data, realm->length);
    3310             : #else
    3311             : #error UNKNOWN_GET_PRINC_REALM_FUNCTIONS
    3312             : #endif
    3313             : }
    3314             : 
    3315             : /**
    3316             :  * @brief Get realm of a principal
    3317             :  *
    3318             :  * @param[in] context   The library context
    3319             :  *
    3320             :  * @param[in] principal The principal to set the realm
    3321             :  *
    3322             :  * @param[in] realm     The realm as a string to set.
    3323             :  *
    3324             :  * @return 0 on success, a Kerberos error code otherwise.
    3325             :  */
    3326      227358 : krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
    3327             :                                              krb5_principal principal,
    3328             :                                              const char *realm)
    3329             : {
    3330             : #ifdef HAVE_KRB5_PRINCIPAL_SET_REALM /* Heimdal */
    3331      221562 :         return krb5_principal_set_realm(context, principal, realm);
    3332             : #elif defined(krb5_princ_realm) && defined(krb5_princ_set_realm) /* MIT */
    3333             :         krb5_error_code ret;
    3334             :         krb5_data data;
    3335             :         krb5_data *old_data;
    3336             : 
    3337        5796 :         old_data = krb5_princ_realm(context, principal);
    3338             : 
    3339        5796 :         ret = smb_krb5_copy_data_contents(&data,
    3340             :                                           realm,
    3341             :                                           strlen(realm));
    3342        5796 :         if (ret) {
    3343           0 :                 return ret;
    3344             :         }
    3345             : 
    3346             :         /* free realm before setting */
    3347        5796 :         free(old_data->data);
    3348             : 
    3349        5796 :         krb5_princ_set_realm(context, principal, &data);
    3350             : 
    3351        5796 :         return ret;
    3352             : #else
    3353             : #error UNKNOWN_PRINC_SET_REALM_FUNCTION
    3354             : #endif
    3355             : }
    3356             : 
    3357             : 
    3358             : /**
    3359             :  * @brief Get the realm from the service hostname.
    3360             :  *
    3361             :  * This function will look for a domain realm mapping in the [domain_realm]
    3362             :  * section of the krb5.conf first and fallback to extract the realm from
    3363             :  * the provided service hostname. As a last resort it will return the
    3364             :  * provided client_realm.
    3365             :  *
    3366             :  * @param[in]  mem_ctx     The talloc context
    3367             :  *
    3368             :  * @param[in]  hostname    The service hostname
    3369             :  *
    3370             :  * @param[in]  client_realm  If we can not find a mapping, fall back to
    3371             :  *                           this realm.
    3372             :  *
    3373             :  * @return The realm to use for the service hostname, NULL if a fatal error
    3374             :  *         occurred.
    3375             :  */
    3376       24327 : char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
    3377             :                                        const char *hostname,
    3378             :                                        const char *client_realm)
    3379             : {
    3380             : #if defined(HAVE_KRB5_REALM_TYPE)
    3381             :         /* Heimdal. */
    3382       24298 :         krb5_realm *realm_list = NULL;
    3383             : #else
    3384             :         /* MIT */
    3385          29 :         char **realm_list = NULL;
    3386             : #endif
    3387       24327 :         char *realm = NULL;
    3388        1042 :         krb5_error_code kerr;
    3389       24327 :         krb5_context ctx = NULL;
    3390             : 
    3391       24327 :         kerr = smb_krb5_init_context_common(&ctx);
    3392       24327 :         if (kerr) {
    3393           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
    3394             :                         error_message(kerr));
    3395           0 :                 return NULL;
    3396             :         }
    3397             : 
    3398       24327 :         kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
    3399       24327 :         if (kerr == KRB5_ERR_HOST_REALM_UNKNOWN) {
    3400           0 :                 realm_list = NULL;
    3401           0 :                 kerr = 0;
    3402             :         }
    3403       24327 :         if (kerr != 0) {
    3404           0 :                 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
    3405             :                         "failed %s\n",
    3406             :                         hostname ? hostname : "(NULL)",
    3407             :                         error_message(kerr) ));
    3408           0 :                 goto out;
    3409             :         }
    3410             : 
    3411       24327 :         if (realm_list != NULL &&
    3412       24327 :             realm_list[0] != NULL &&
    3413       24327 :             realm_list[0][0] != '\0') {
    3414       24298 :                 realm = talloc_strdup(mem_ctx, realm_list[0]);
    3415       24298 :                 if (realm == NULL) {
    3416           0 :                         goto out;
    3417             :                 }
    3418             :         } else {
    3419          29 :                 const char *p = NULL;
    3420             : 
    3421             :                 /*
    3422             :                  * "dc6.samba2003.example.com"
    3423             :                  * returns a realm of "SAMBA2003.EXAMPLE.COM"
    3424             :                  *
    3425             :                  * "dc6." returns realm as NULL
    3426             :                  */
    3427          29 :                 p = strchr_m(hostname, '.');
    3428          29 :                 if (p != NULL && p[1] != '\0') {
    3429          28 :                         realm = talloc_strdup_upper(mem_ctx, p + 1);
    3430          28 :                         if (realm == NULL) {
    3431           0 :                                 goto out;
    3432             :                         }
    3433             :                 }
    3434             :         }
    3435             : 
    3436       23285 :         if (realm == NULL) {
    3437           1 :                 realm = talloc_strdup(mem_ctx, client_realm);
    3438             :         }
    3439             : 
    3440       24326 :   out:
    3441             : 
    3442       24327 :         if (ctx) {
    3443       24327 :                 if (realm_list) {
    3444       24327 :                         krb5_free_host_realm(ctx, realm_list);
    3445       24327 :                         realm_list = NULL;
    3446             :                 }
    3447       24327 :                 krb5_free_context(ctx);
    3448       24327 :                 ctx = NULL;
    3449             :         }
    3450       23285 :         return realm;
    3451             : }
    3452             : 
    3453             : /**
    3454             :  * @brief Get an error string from a Kerberos error code.
    3455             :  *
    3456             :  * @param[in]  context  The library context.
    3457             :  *
    3458             :  * @param[in]  code     The Kerberos error code.
    3459             :  *
    3460             :  * @param[in]  mem_ctx  The talloc context to allocate the error string on.
    3461             :  *
    3462             :  * @return A talloc'ed error string or NULL if an error occurred.
    3463             :  *
    3464             :  * The caller must free the returned error string with talloc_free() if not
    3465             :  * needed anymore
    3466             :  */
    3467       15795 : char *smb_get_krb5_error_message(krb5_context context,
    3468             :                                  krb5_error_code code,
    3469             :                                  TALLOC_CTX *mem_ctx)
    3470             : {
    3471           0 :         char *ret;
    3472             : 
    3473             : #if defined(HAVE_KRB5_GET_ERROR_MESSAGE) && defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
    3474             :         const char *context_error = krb5_get_error_message(context, code);
    3475             :         if (context_error) {
    3476             :                 ret = talloc_asprintf(mem_ctx, "%s: %s",
    3477             :                                         error_message(code), context_error);
    3478             :                 krb5_free_error_message(context, context_error);
    3479             :                 return ret;
    3480             :         }
    3481             : #endif
    3482       15795 :         ret = talloc_strdup(mem_ctx, error_message(code));
    3483       15795 :         return ret;
    3484             : }
    3485             : 
    3486             : /**
    3487             :  * @brief Return the type of a krb5_principal
    3488             :  *
    3489             :  * @param[in]  context  The library context.
    3490             :  *
    3491             :  * @param[in]  principal The principal to get the type from.
    3492             :  *
    3493             :  * @return The integer type of the principal.
    3494             :  */
    3495      240499 : int smb_krb5_principal_get_type(krb5_context context,
    3496             :                                 krb5_const_principal principal)
    3497             : {
    3498             : #ifdef HAVE_KRB5_PRINCIPAL_GET_TYPE /* Heimdal */
    3499      240286 :         return krb5_principal_get_type(context, principal);
    3500             : #elif defined(krb5_princ_type) /* MIT */
    3501         213 :         return krb5_princ_type(context, principal);
    3502             : #else
    3503             : #error  UNKNOWN_PRINC_GET_TYPE_FUNCTION
    3504             : #endif
    3505             : }
    3506             : 
    3507             : /**
    3508             :  * @brief Set the type of a principal
    3509             :  *
    3510             :  * @param[in]  context  The library context
    3511             :  *
    3512             :  * @param[inout] principal The principal to set the type for.
    3513             :  *
    3514             :  * @param[in]  type     The principal type to set.
    3515             :  */
    3516       45299 : void smb_krb5_principal_set_type(krb5_context context,
    3517             :                                  krb5_principal principal,
    3518             :                                  int type)
    3519             : {
    3520             : #ifdef HAVE_KRB5_PRINCIPAL_SET_TYPE /* Heimdal */
    3521       45299 :         krb5_principal_set_type(context, principal, type);
    3522             : #elif defined(krb5_princ_type) /* MIT */
    3523           0 :         krb5_princ_type(context, principal) = type;
    3524             : #else
    3525             : #error  UNKNOWN_PRINC_SET_TYPE_FUNCTION
    3526             : #endif
    3527       45299 : }
    3528             : 
    3529             : /**
    3530             :  * @brief Check if a principal is a TGS
    3531             :  *
    3532             :  * @param[in]  context  The library context
    3533             :  *
    3534             :  * @param[inout] principal The principal to check.
    3535             :  *
    3536             :  * @returns 1 if equal, 0 if not and -1 on error.
    3537             :  */
    3538      257479 : int smb_krb5_principal_is_tgs(krb5_context context,
    3539             :                               krb5_const_principal principal)
    3540             : {
    3541      257479 :         char *p = NULL;
    3542      257479 :         int eq = 1;
    3543      257479 :         krb5_error_code ret = 0;
    3544             : 
    3545      257479 :         if (krb5_princ_size(context, principal) > 2) {
    3546         340 :                 return 0;
    3547             :         }
    3548             : 
    3549      257139 :         ret = smb_krb5_principal_get_comp_string(NULL, context, principal, 0, &p);
    3550      257139 :         if (ret == ENOENT) {
    3551           0 :                 return 0;
    3552      257139 :         } else if (ret) {
    3553           0 :                 return -1;
    3554             :         }
    3555             : 
    3556      257139 :         eq = strcmp(p, KRB5_TGS_NAME) == 0;
    3557             : 
    3558      257139 :         talloc_free(p);
    3559             : 
    3560      257139 :         return eq;
    3561             : }
    3562             : 
    3563             : #if !defined(HAVE_KRB5_WARNX)
    3564             : /**
    3565             :  * @brief Log a Kerberos message
    3566             :  *
    3567             :  * It sends the message to com_err.
    3568             :  *
    3569             :  * @param[in]  context  The library context
    3570             :  *
    3571             :  * @param[in]  fmt      The message format
    3572             :  *
    3573             :  * @param[in]  ...      The message arguments
    3574             :  *
    3575             :  * @return 0 on success.
    3576             :  */
    3577           0 : krb5_error_code krb5_warnx(krb5_context context, const char *fmt, ...)
    3578             : {
    3579             :         va_list args;
    3580             : 
    3581           0 :         va_start(args, fmt);
    3582           0 :         com_err_va("samba-kdc", errno, fmt, args);
    3583           0 :         va_end(args);
    3584             : 
    3585           0 :         return 0;
    3586             : }
    3587             : #endif
    3588             : 
    3589             : /**
    3590             :  * @brief Copy a credential cache.
    3591             :  *
    3592             :  * @param[in]  context  The library context.
    3593             :  *
    3594             :  * @param[in]  incc     Credential cache to be copied.
    3595             :  *
    3596             :  * @param[inout] outcc  Copy of credential cache to be filled in.
    3597             :  *
    3598             :  * @return 0 on success, a Kerberos error code otherwise.
    3599             :  */
    3600         320 : krb5_error_code smb_krb5_cc_copy_creds(krb5_context context,
    3601             :                                        krb5_ccache incc, krb5_ccache outcc)
    3602             : {
    3603             : #ifdef HAVE_KRB5_CC_COPY_CACHE /* Heimdal */
    3604         204 :         return krb5_cc_copy_cache(context, incc, outcc);
    3605             : #elif defined(HAVE_KRB5_CC_COPY_CREDS)
    3606             :         krb5_error_code ret;
    3607         116 :         krb5_principal princ = NULL;
    3608             : 
    3609         116 :         ret = krb5_cc_get_principal(context, incc, &princ);
    3610         116 :         if (ret != 0) {
    3611           0 :                 return ret;
    3612             :         }
    3613         116 :         ret = krb5_cc_initialize(context, outcc, princ);
    3614         116 :         krb5_free_principal(context, princ);
    3615         116 :         if (ret != 0) {
    3616           0 :                 return ret;
    3617             :         }
    3618         116 :         return krb5_cc_copy_creds(context, incc, outcc);
    3619             : #else
    3620             : #error UNKNOWN_KRB5_CC_COPY_CACHE_OR_CREDS_FUNCTION
    3621             : #endif
    3622             : }
    3623             : 
    3624             : /**********************************************************
    3625             :  * ADS KRB5 CALLS
    3626             :  **********************************************************/
    3627             : 
    3628           0 : static bool ads_cleanup_expired_creds(krb5_context context,
    3629             :                                       krb5_ccache  ccache,
    3630             :                                       krb5_creds  *credsp)
    3631             : {
    3632           0 :         krb5_error_code retval;
    3633           0 :         const char *cc_type = krb5_cc_get_type(context, ccache);
    3634             : 
    3635           0 :         DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
    3636             :                   cc_type, krb5_cc_get_name(context, ccache),
    3637             :                   http_timestring(talloc_tos(), credsp->times.endtime)));
    3638             : 
    3639             :         /* we will probably need new tickets if the current ones
    3640             :            will expire within 10 seconds.
    3641             :         */
    3642           0 :         if (credsp->times.endtime >= (time(NULL) + 10))
    3643           0 :                 return false;
    3644             : 
    3645             :         /* heimdal won't remove creds from a file ccache, and
    3646             :            perhaps we shouldn't anyway, since internally we
    3647             :            use memory ccaches, and a FILE one probably means that
    3648             :            we're using creds obtained outside of our executable
    3649             :         */
    3650           0 :         if (strequal(cc_type, "FILE")) {
    3651           0 :                 DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
    3652           0 :                 return false;
    3653             :         }
    3654             : 
    3655           0 :         retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
    3656           0 :         if (retval) {
    3657           0 :                 DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
    3658             :                           error_message(retval)));
    3659             :                 /* If we have an error in this, we want to display it,
    3660             :                    but continue as though we deleted it */
    3661             :         }
    3662           0 :         return true;
    3663             : }
    3664             : 
    3665             : /* Allocate and setup the auth context into the state we need. */
    3666             : 
    3667           0 : static krb5_error_code ads_setup_auth_context(krb5_context context,
    3668             :                                               krb5_auth_context *auth_context)
    3669             : {
    3670           0 :         krb5_error_code retval;
    3671             : 
    3672           0 :         retval = krb5_auth_con_init(context, auth_context );
    3673           0 :         if (retval) {
    3674           0 :                 DEBUG(1,("krb5_auth_con_init failed (%s)\n",
    3675             :                         error_message(retval)));
    3676           0 :                 return retval;
    3677             :         }
    3678             : 
    3679             :         /* Ensure this is an addressless ticket. */
    3680           0 :         retval = krb5_auth_con_setaddrs(context, *auth_context, NULL, NULL);
    3681           0 :         if (retval) {
    3682           0 :                 DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n",
    3683             :                         error_message(retval)));
    3684             :         }
    3685             : 
    3686           0 :         return retval;
    3687             : }
    3688             : 
    3689             : #if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
    3690           0 : static krb5_error_code ads_create_gss_checksum(krb5_data *in_data, /* [inout] */
    3691             :                                                uint32_t gss_flags)
    3692             : {
    3693           0 :         unsigned int orig_length = in_data->length;
    3694           0 :         unsigned int base_cksum_size = GSSAPI_CHECKSUM_SIZE;
    3695           0 :         char *gss_cksum = NULL;
    3696             : 
    3697           0 :         if (orig_length) {
    3698             :                 /* Extra length field for delegated ticket. */
    3699           0 :                 base_cksum_size += 4;
    3700             :         }
    3701             : 
    3702           0 :         if ((unsigned int)base_cksum_size + orig_length <
    3703             :                         (unsigned int)base_cksum_size) {
    3704           0 :                 return EINVAL;
    3705             :         }
    3706             : 
    3707           0 :         gss_cksum = (char *)SMB_MALLOC(base_cksum_size + orig_length);
    3708           0 :         if (gss_cksum == NULL) {
    3709           0 :                 return ENOMEM;
    3710             :         }
    3711             : 
    3712           0 :         memset(gss_cksum, '\0', base_cksum_size + orig_length);
    3713           0 :         SIVAL(gss_cksum, 0, GSSAPI_BNDLENGTH);
    3714             : 
    3715             :         /*
    3716             :          * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes.
    3717             :          * This matches the behavior of heimdal and mit.
    3718             :          *
    3719             :          * And it is needed to work against some closed source
    3720             :          * SMB servers.
    3721             :          *
    3722             :          * See bug #7883
    3723             :          */
    3724           0 :         memset(&gss_cksum[4], 0x00, GSSAPI_BNDLENGTH);
    3725             : 
    3726           0 :         SIVAL(gss_cksum, 20, gss_flags);
    3727             : 
    3728           0 :         if (orig_length && in_data->data != NULL) {
    3729           0 :                 SSVAL(gss_cksum, 24, 1); /* The Delegation Option identifier */
    3730           0 :                 SSVAL(gss_cksum, 26, orig_length);
    3731             :                 /* Copy the kerberos KRB_CRED data */
    3732           0 :                 memcpy(gss_cksum + 28, in_data->data, orig_length);
    3733           0 :                 free(in_data->data);
    3734           0 :                 in_data->data = NULL;
    3735           0 :                 in_data->length = 0;
    3736             :         }
    3737           0 :         in_data->data = gss_cksum;
    3738           0 :         in_data->length = base_cksum_size + orig_length;
    3739           0 :         return 0;
    3740             : }
    3741             : #endif
    3742             : 
    3743             : /*
    3744             :  * We can't use krb5_mk_req because w2k wants the service to be in a particular
    3745             :  * format.
    3746             :  */
    3747           0 : static krb5_error_code ads_krb5_mk_req(krb5_context context,
    3748             :                                        krb5_auth_context *auth_context,
    3749             :                                        const krb5_flags ap_req_options,
    3750             :                                        const char *principal,
    3751             :                                        krb5_ccache ccache,
    3752             :                                        krb5_data *outbuf,
    3753             :                                        time_t *expire_time,
    3754             :                                        const char *impersonate_princ_s)
    3755             : {
    3756           0 :         krb5_error_code retval;
    3757           0 :         krb5_principal server;
    3758           0 :         krb5_principal impersonate_princ = NULL;
    3759           0 :         krb5_creds *credsp;
    3760           0 :         krb5_creds creds;
    3761           0 :         krb5_data in_data;
    3762           0 :         bool creds_ready = false;
    3763           0 :         int i = 0, maxtries = 3;
    3764           0 :         bool ok;
    3765             : 
    3766           0 :         ZERO_STRUCT(in_data);
    3767             : 
    3768           0 :         retval = smb_krb5_parse_name(context, principal, &server);
    3769           0 :         if (retval != 0) {
    3770           0 :                 DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
    3771           0 :                 return retval;
    3772             :         }
    3773             : 
    3774           0 :         if (impersonate_princ_s) {
    3775           0 :                 retval = smb_krb5_parse_name(context, impersonate_princ_s,
    3776             :                                              &impersonate_princ);
    3777           0 :                 if (retval) {
    3778           0 :                         DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", impersonate_princ_s));
    3779           0 :                         goto cleanup_princ;
    3780             :                 }
    3781             :         }
    3782             : 
    3783             :         /* obtain ticket & session key */
    3784           0 :         ZERO_STRUCT(creds);
    3785           0 :         if ((retval = krb5_copy_principal(context, server, &creds.server))) {
    3786           0 :                 DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n",
    3787             :                          error_message(retval)));
    3788           0 :                 goto cleanup_princ;
    3789             :         }
    3790             : 
    3791           0 :         retval = krb5_cc_get_principal(context, ccache, &creds.client);
    3792           0 :         if (retval != 0) {
    3793             :                 /* This can commonly fail on smbd startup with no ticket in the cache.
    3794             :                  * Report at higher level than 1. */
    3795           0 :                 DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
    3796             :                          error_message(retval)));
    3797           0 :                 goto cleanup_creds;
    3798             :         }
    3799             : 
    3800           0 :         while (!creds_ready && (i < maxtries)) {
    3801             : 
    3802           0 :                 retval = smb_krb5_get_credentials(context,
    3803             :                                                   ccache,
    3804             :                                                   creds.client,
    3805             :                                                   creds.server,
    3806             :                                                   impersonate_princ,
    3807             :                                                   &credsp);
    3808           0 :                 if (retval != 0) {
    3809           0 :                         DBG_WARNING("smb_krb5_get_credentials failed for %s "
    3810             :                                     "(%s)\n",
    3811             :                                     principal,
    3812             :                                     error_message(retval));
    3813           0 :                         goto cleanup_creds;
    3814             :                 }
    3815             : 
    3816             :                 /* cope with ticket being in the future due to clock skew */
    3817           0 :                 if ((unsigned)credsp->times.starttime > time(NULL)) {
    3818           0 :                         time_t t = time(NULL);
    3819           0 :                         int time_offset =(int)((unsigned)credsp->times.starttime-t);
    3820           0 :                         DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
    3821           0 :                         krb5_set_real_time(context, t + time_offset + 1, 0);
    3822             :                 }
    3823             : 
    3824           0 :                 ok = ads_cleanup_expired_creds(context, ccache, credsp);
    3825           0 :                 if (!ok) {
    3826           0 :                         creds_ready = true;
    3827             :                 }
    3828             : 
    3829           0 :                 i++;
    3830             :         }
    3831             : 
    3832           0 :         DBG_DEBUG("Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
    3833             :                   principal,
    3834             :                   krb5_cc_get_type(context, ccache),
    3835             :                   krb5_cc_get_name(context, ccache),
    3836             :                   http_timestring(talloc_tos(),
    3837             :                                   (unsigned)credsp->times.endtime),
    3838             :                   (unsigned)credsp->times.endtime);
    3839             : 
    3840           0 :         if (expire_time) {
    3841           0 :                 *expire_time = (time_t)credsp->times.endtime;
    3842             :         }
    3843             : 
    3844             :         /* Allocate the auth_context. */
    3845           0 :         retval = ads_setup_auth_context(context, auth_context);
    3846           0 :         if (retval != 0) {
    3847           0 :                 DBG_WARNING("ads_setup_auth_context failed (%s)\n",
    3848             :                             error_message(retval));
    3849           0 :                 goto cleanup_creds;
    3850             :         }
    3851             : 
    3852             : #if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
    3853             :         {
    3854           0 :                 uint32_t gss_flags = 0;
    3855             : 
    3856           0 :                 if (credsp->ticket_flags & TKT_FLG_OK_AS_DELEGATE) {
    3857             :                         /*
    3858             :                          * Fetch a forwarded TGT from the KDC so that we can
    3859             :                          * hand off a 2nd ticket as part of the kerberos
    3860             :                          * exchange.
    3861             :                          */
    3862             : 
    3863           0 :                         DBG_INFO("Server marked as OK to delegate to, building "
    3864             :                                  "forwardable TGT\n");
    3865             : 
    3866           0 :                         retval = krb5_auth_con_setuseruserkey(context,
    3867             :                                         *auth_context,
    3868           0 :                                         &credsp->keyblock );
    3869           0 :                         if (retval != 0) {
    3870           0 :                                 DBG_WARNING("krb5_auth_con_setuseruserkey "
    3871             :                                             "failed (%s)\n",
    3872             :                                             error_message(retval));
    3873           0 :                                 goto cleanup_creds;
    3874             :                         }
    3875             : 
    3876             :                         /* Must use a subkey for forwarded tickets. */
    3877           0 :                         retval = krb5_auth_con_setflags(context,
    3878             :                                                         *auth_context,
    3879             :                                                         KRB5_AUTH_CONTEXT_USE_SUBKEY);
    3880           0 :                         if (retval != 0) {
    3881           0 :                                 DBG_WARNING("krb5_auth_con_setflags failed (%s)\n",
    3882             :                                             error_message(retval));
    3883           0 :                                 goto cleanup_creds;
    3884             :                         }
    3885             : 
    3886           0 :                         retval = krb5_fwd_tgt_creds(context,/* Krb5 context [in] */
    3887             :                                 *auth_context,  /* Authentication context [in] */
    3888             :                                 discard_const_p(char, KRB5_TGS_NAME),  /* Ticket service name ("krbtgt") [in] */
    3889           0 :                                 credsp->client, /* Client principal for the tgt [in] */
    3890           0 :                                 credsp->server, /* Server principal for the tgt [in] */
    3891             :                                 ccache,         /* Credential cache to use for storage [in] */
    3892             :                                 1,              /* Turn on for "Forwardable ticket" [in] */
    3893             :                                 &in_data );     /* Resulting response [out] */
    3894             : 
    3895           0 :                         if (retval) {
    3896           0 :                                 DBG_INFO("krb5_fwd_tgt_creds failed (%s)\n",
    3897             :                                          error_message(retval));
    3898             : 
    3899             :                                 /*
    3900             :                                  * This is not fatal. Delete the *auth_context and continue
    3901             :                                  * with krb5_mk_req_extended to get a non-forwardable ticket.
    3902             :                                  */
    3903             : 
    3904           0 :                                 if (in_data.data) {
    3905           0 :                                         free( in_data.data );
    3906           0 :                                         in_data.data = NULL;
    3907           0 :                                         in_data.length = 0;
    3908             :                                 }
    3909           0 :                                 krb5_auth_con_free(context, *auth_context);
    3910           0 :                                 *auth_context = NULL;
    3911           0 :                                 retval = ads_setup_auth_context(context, auth_context);
    3912           0 :                                 if (retval != 0) {
    3913           0 :                                         DBG_WARNING("ads_setup_auth_context failed (%s)\n",
    3914             :                                                     error_message(retval));
    3915           0 :                                         goto cleanup_creds;
    3916             :                                 }
    3917             :                         } else {
    3918             :                                 /* We got a delegated ticket. */
    3919           0 :                                 gss_flags |= GSS_C_DELEG_FLAG;
    3920             :                         }
    3921             :                 }
    3922             : 
    3923             :                 /* Frees and reallocates in_data into a GSS checksum blob. */
    3924           0 :                 retval = ads_create_gss_checksum(&in_data, gss_flags);
    3925           0 :                 if (retval != 0) {
    3926           0 :                         goto cleanup_data;
    3927             :                 }
    3928             : 
    3929             :                 /* We always want GSS-checksum types. */
    3930           0 :                 retval = krb5_auth_con_set_req_cksumtype(context, *auth_context, GSSAPI_CHECKSUM );
    3931           0 :                 if (retval != 0) {
    3932           0 :                         DEBUG(1,("krb5_auth_con_set_req_cksumtype failed (%s)\n",
    3933             :                                 error_message(retval)));
    3934           0 :                         goto cleanup_data;
    3935             :                 }
    3936             :         }
    3937             : #endif
    3938             : 
    3939           0 :         retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
    3940             :                                       &in_data, credsp, outbuf);
    3941           0 :         if (retval != 0) {
    3942           0 :                 DBG_WARNING("krb5_mk_req_extended failed (%s)\n",
    3943             :                             error_message(retval));
    3944             :         }
    3945             : 
    3946             : #if defined(TKT_FLG_OK_AS_DELEGATE ) && defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY) && defined(KRB5_AUTH_CONTEXT_USE_SUBKEY) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
    3947           0 : cleanup_data:
    3948             : #endif
    3949             : 
    3950           0 :         if (in_data.data) {
    3951           0 :                 free( in_data.data );
    3952           0 :                 in_data.length = 0;
    3953             :         }
    3954             : 
    3955           0 :         krb5_free_creds(context, credsp);
    3956             : 
    3957           0 : cleanup_creds:
    3958           0 :         krb5_free_cred_contents(context, &creds);
    3959             : 
    3960           0 : cleanup_princ:
    3961           0 :         krb5_free_principal(context, server);
    3962           0 :         if (impersonate_princ) {
    3963           0 :                 krb5_free_principal(context, impersonate_princ);
    3964             :         }
    3965             : 
    3966           0 :         return retval;
    3967             : }
    3968             : 
    3969             : /*
    3970             :   get a kerberos5 ticket for the given service
    3971             : */
    3972           0 : int ads_krb5_cli_get_ticket(TALLOC_CTX *mem_ctx,
    3973             :                             const char *principal,
    3974             :                             time_t time_offset,
    3975             :                             DATA_BLOB *ticket,
    3976             :                             DATA_BLOB *session_key_krb5,
    3977             :                             uint32_t extra_ap_opts, const char *ccname,
    3978             :                             time_t *tgs_expire,
    3979             :                             const char *impersonate_princ_s)
    3980             : {
    3981           0 :         krb5_error_code retval;
    3982           0 :         krb5_data packet;
    3983           0 :         krb5_context context = NULL;
    3984           0 :         krb5_ccache ccdef = NULL;
    3985           0 :         krb5_auth_context auth_context = NULL;
    3986           0 :         krb5_enctype enc_types[] = {
    3987             :                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
    3988             :                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
    3989             :                 ENCTYPE_ARCFOUR_HMAC,
    3990             :                 ENCTYPE_NULL};
    3991           0 :         bool ok;
    3992             : 
    3993           0 :         if (ccname == NULL) {
    3994           0 :                 DBG_ERR("No explicit ccache given for service [%s], "
    3995             :                         "impersonating [%s]\n",
    3996             :                         principal, impersonate_princ_s);
    3997           0 :                 retval = EINVAL;
    3998           0 :                 goto failed;
    3999             :         }
    4000             : 
    4001           0 :         DBG_DEBUG("Getting ticket for service [%s] using creds from [%s] "
    4002             :                   "and impersonating [%s]\n",
    4003             :                   principal, ccname, impersonate_princ_s);
    4004             : 
    4005           0 :         retval = smb_krb5_init_context_common(&context);
    4006           0 :         if (retval != 0) {
    4007           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
    4008             :                         error_message(retval));
    4009           0 :                 goto failed;
    4010             :         }
    4011             : 
    4012           0 :         if (time_offset != 0) {
    4013           0 :                 krb5_set_real_time(context, time(NULL) + time_offset, 0);
    4014             :         }
    4015             : 
    4016           0 :         retval = krb5_cc_resolve(context, ccname, &ccdef);
    4017           0 :         if (retval != 0) {
    4018           0 :                 DBG_WARNING("krb5_cc_resolve(%s) failed (%s)\n",
    4019             :                             ccname, error_message(retval));
    4020           0 :                 goto failed;
    4021             :         }
    4022             : 
    4023           0 :         retval = krb5_set_default_tgs_ktypes(context, enc_types);
    4024           0 :         if (retval != 0) {
    4025           0 :                 DBG_WARNING("krb5_set_default_tgs_ktypes failed (%s)\n",
    4026             :                             error_message(retval));
    4027           0 :                 goto failed;
    4028             :         }
    4029             : 
    4030           0 :         retval = ads_krb5_mk_req(context,
    4031             :                                  &auth_context,
    4032           0 :                                  AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
    4033             :                                  principal,
    4034             :                                  ccdef,
    4035             :                                  &packet,
    4036             :                                  tgs_expire,
    4037             :                                  impersonate_princ_s);
    4038           0 :         if (retval != 0) {
    4039           0 :                 goto failed;
    4040             :         }
    4041             : 
    4042           0 :         ok = smb_krb5_get_smb_session_key(mem_ctx,
    4043             :                                           context,
    4044             :                                           auth_context,
    4045             :                                           session_key_krb5,
    4046             :                                           false);
    4047           0 :         if (!ok) {
    4048           0 :                 retval = ENOMEM;
    4049           0 :                 goto failed;
    4050             :         }
    4051             : 
    4052           0 :         *ticket = data_blob_talloc(mem_ctx, packet.data, packet.length);
    4053             : 
    4054           0 :         smb_krb5_free_data_contents(context, &packet);
    4055             : 
    4056           0 : failed:
    4057             : 
    4058           0 :         if (context) {
    4059           0 :                 if (ccdef) {
    4060           0 :                         krb5_cc_close(context, ccdef);
    4061             :                 }
    4062           0 :                 if (auth_context) {
    4063           0 :                         krb5_auth_con_free(context, auth_context);
    4064             :                 }
    4065           0 :                 krb5_free_context(context);
    4066             :         }
    4067             : 
    4068           0 :         return retval;
    4069             : }
    4070             : 
    4071             : #ifndef SAMBA4_USES_HEIMDAL /* MITKRB5 tracing callback */
    4072      321964 : static void smb_krb5_trace_cb(krb5_context ctx,
    4073             : #ifdef HAVE_KRB5_TRACE_INFO
    4074             :                               const krb5_trace_info *info,
    4075             : #elif defined(HAVE_KRB5_TRACE_INFO_STRUCT)
    4076             :                               const struct krb5_trace_info *info,
    4077             : #else
    4078             : #error unknown krb5_trace_info
    4079             : #endif
    4080             :                               void *data)
    4081             : {
    4082      321964 :         if (info != NULL) {
    4083      234635 :                 DBGC_DEBUG(DBGC_KERBEROS, "%s", info->message);
    4084             :         }
    4085      321964 : }
    4086             : #endif
    4087             : 
    4088      515260 : krb5_error_code smb_krb5_init_context_common(krb5_context *_krb5_context)
    4089             : {
    4090       14329 :         krb5_error_code ret;
    4091       14329 :         krb5_context krb5_ctx;
    4092             : 
    4093      515260 :         initialize_krb5_error_table();
    4094             : 
    4095      515260 :         ret = krb5_init_context(&krb5_ctx);
    4096      515260 :         if (ret) {
    4097           0 :                 DBG_ERR("Krb5 context initialization failed (%s)\n",
    4098             :                          error_message(ret));
    4099           0 :                 return ret;
    4100             :         }
    4101             : 
    4102             :         /* The MIT Kerberos build relies on using the system krb5.conf file.
    4103             :          * If you really want to use another file please set KRB5_CONFIG
    4104             :          * accordingly. */
    4105             : #ifndef SAMBA4_USES_HEIMDAL
    4106       87630 :         ret = krb5_set_trace_callback(krb5_ctx, smb_krb5_trace_cb, NULL);
    4107       87630 :         if (ret) {
    4108           0 :                 DBG_ERR("Failed to set MIT kerberos trace callback! (%s)\n",
    4109             :                         error_message(ret));
    4110             :         }
    4111             : #endif
    4112             : 
    4113             : #ifdef SAMBA4_USES_HEIMDAL
    4114             :         /* Set options in kerberos */
    4115      427630 :         krb5_set_dns_canonicalize_hostname(krb5_ctx, false);
    4116             : #endif
    4117             : 
    4118      515260 :         *_krb5_context = krb5_ctx;
    4119      515260 :         return 0;
    4120             : }
    4121             : 
    4122             : /*
    4123             :  * This should only be used in code that
    4124             :  * really wants to touch the global default ccache!
    4125             :  */
    4126       99014 : krb5_error_code smb_force_krb5_cc_default(krb5_context ctx, krb5_ccache *id)
    4127             : {
    4128             : #undef krb5_cc_default
    4129       99014 :         return krb5_cc_default(ctx, id);
    4130             : #define krb5_cc_default __ERROR__XX__NEVER_USE_krb5_cc_default__;
    4131             : }
    4132             : 
    4133             : /*
    4134             :  * This should only be used in code that
    4135             :  * really wants to touch the global default ccache!
    4136             :  */
    4137           0 : const char *smb_force_krb5_cc_default_name(krb5_context ctx)
    4138             : {
    4139             : #undef krb5_cc_default_name
    4140           0 :         return krb5_cc_default_name(ctx);
    4141             : #define krb5_cc_default_name __ERROR__XX__NEVER_USE_krb5_cc_default_name__;
    4142             : }
    4143             : 
    4144             : #else /* HAVE_KRB5 */
    4145             : /* This saves a few linking headaches */
    4146             : int ads_krb5_cli_get_ticket(TALLOC_CTX *mem_ctx,
    4147             :                             const char *principal,
    4148             :                             time_t time_offset,
    4149             :                             DATA_BLOB *ticket,
    4150             :                             DATA_BLOB *session_key_krb5,
    4151             :                             uint32_t extra_ap_opts, const char *ccname,
    4152             :                             time_t *tgs_expire,
    4153             :                             const char *impersonate_princ_s)
    4154             : {
    4155             :          DEBUG(0,("NO KERBEROS SUPPORT\n"));
    4156             :          return 1;
    4157             : }
    4158             : 
    4159             : #endif /* HAVE_KRB5 */

Generated by: LCOV version 1.14