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

Generated by: LCOV version 1.13