LCOV - code coverage report
Current view: top level - lib/krb5_wrap - krb5_samba.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 593 1374 43.2 %
Date: 2024-02-14 10:14:15 Functions: 41 58 70.7 %

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

Generated by: LCOV version 1.14