LCOV - code coverage report
Current view: top level - source3/librpc/crypto - gse.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 574 796 72.1 %
Date: 2024-05-31 13:13:24 Functions: 31 31 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  GSSAPI Security Extensions
       3             :  *  RPC Pipe client and server routines
       4             :  *  Copyright (C) Simo Sorce 2010.
       5             :  *  Copyright (C) Andrew Bartlett 2004-2011.
       6             :  *  Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
       7             :  *
       8             :  *  This program is free software; you can redistribute it and/or modify
       9             :  *  it under the terms of the GNU General Public License as published by
      10             :  *  the Free Software Foundation; either version 3 of the License, or
      11             :  *  (at your option) any later version.
      12             :  *
      13             :  *  This program is distributed in the hope that it will be useful,
      14             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  *  GNU General Public License for more details.
      17             :  *
      18             :  *  You should have received a copy of the GNU General Public License
      19             :  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : /* We support only GSSAPI/KRB5 here */
      23             : 
      24             : #include "includes.h"
      25             : #include <tevent.h>
      26             : #include "lib/util/tevent_ntstatus.h"
      27             : #include "gse.h"
      28             : #include "libads/kerberos_proto.h"
      29             : #include "auth/common_auth.h"
      30             : #include "auth/gensec/gensec.h"
      31             : #include "auth/gensec/gensec_internal.h"
      32             : #include "auth/credentials/credentials.h"
      33             : #include "../librpc/gen_ndr/dcerpc.h"
      34             : #include "param/param.h"
      35             : 
      36             : #if defined(HAVE_KRB5)
      37             : 
      38             : #include "auth/kerberos/pac_utils.h"
      39             : #include "auth/kerberos/gssapi_helper.h"
      40             : #include "gse_krb5.h"
      41             : 
      42             : static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
      43             : static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
      44             :                                   size_t data_size);
      45             : 
      46             : struct gse_context {
      47             :         gss_ctx_id_t gssapi_context;
      48             :         gss_name_t server_name;
      49             :         gss_name_t client_name;
      50             :         OM_uint32 gss_want_flags, gss_got_flags;
      51             :         size_t max_wrap_buf_size;
      52             :         size_t sig_size;
      53             : 
      54             :         gss_cred_id_t delegated_cred_handle;
      55             : 
      56             :         NTTIME expire_time;
      57             : 
      58             :         /* gensec_gse only */
      59             :         krb5_context k5ctx;
      60             :         krb5_ccache ccache;
      61             :         krb5_keytab keytab;
      62             : 
      63             :         gss_OID_desc gss_mech;
      64             :         gss_cred_id_t creds;
      65             : 
      66             :         gss_OID ret_mech;
      67             : 
      68             :         struct gss_channel_bindings_struct _channel_bindings;
      69             :         struct gss_channel_bindings_struct *channel_bindings;
      70             : };
      71             : 
      72             : /* free non talloc dependent contexts */
      73        6301 : static int gse_context_destructor(void *ptr)
      74             : {
      75           0 :         struct gse_context *gse_ctx;
      76           0 :         OM_uint32 gss_min;
      77             : 
      78        6301 :         gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
      79        6301 :         if (gse_ctx->k5ctx) {
      80        6301 :                 if (gse_ctx->ccache) {
      81        2770 :                         krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
      82        2770 :                         gse_ctx->ccache = NULL;
      83             :                 }
      84        6301 :                 if (gse_ctx->keytab) {
      85        3521 :                         krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
      86        3521 :                         gse_ctx->keytab = NULL;
      87             :                 }
      88        6301 :                 krb5_free_context(gse_ctx->k5ctx);
      89        6301 :                 gse_ctx->k5ctx = NULL;
      90             :         }
      91        6301 :         if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) {
      92        3656 :                 (void)gss_delete_sec_context(&gss_min,
      93             :                                                  &gse_ctx->gssapi_context,
      94             :                                                  GSS_C_NO_BUFFER);
      95             :         }
      96        6301 :         if (gse_ctx->server_name) {
      97        2770 :                 (void)gss_release_name(&gss_min,
      98             :                                            &gse_ctx->server_name);
      99             :         }
     100        6301 :         if (gse_ctx->client_name) {
     101         890 :                 (void)gss_release_name(&gss_min,
     102             :                                            &gse_ctx->client_name);
     103             :         }
     104        6301 :         if (gse_ctx->creds) {
     105        6291 :                 (void)gss_release_cred(&gss_min,
     106             :                                            &gse_ctx->creds);
     107             :         }
     108        6301 :         if (gse_ctx->delegated_cred_handle) {
     109           0 :                 (void)gss_release_cred(&gss_min,
     110             :                                            &gse_ctx->delegated_cred_handle);
     111             :         }
     112             : 
     113             :         /* MIT and Heimdal differ as to if you can call
     114             :          * gss_release_oid() on this OID, generated by
     115             :          * gss_{accept,init}_sec_context().  However, as long as the
     116             :          * oid is gss_mech_krb5 (which it always is at the moment),
     117             :          * then this is a moot point, as both declare this particular
     118             :          * OID static, and so no memory is lost.  This assert is in
     119             :          * place to ensure that the programmer who wishes to extend
     120             :          * this code to EAP or other GSS mechanisms determines an
     121             :          * implementation-dependent way of releasing any dynamically
     122             :          * allocated OID */
     123        6301 :         SMB_ASSERT(smb_gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) ||
     124             :                    smb_gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5));
     125             : 
     126        6301 :         return 0;
     127             : }
     128             : 
     129        2798 : static NTSTATUS gse_setup_server_principal(TALLOC_CTX *mem_ctx,
     130             :                                            const char *target_principal,
     131             :                                            const char *service,
     132             :                                            const char *hostname,
     133             :                                            const char *realm,
     134             :                                            char **pserver_principal,
     135             :                                            gss_name_t *pserver_name)
     136             : {
     137        2798 :         char *server_principal = NULL;
     138           0 :         gss_buffer_desc name_token;
     139           0 :         gss_OID name_type;
     140        2798 :         OM_uint32 maj_stat, min_stat = 0;
     141             : 
     142        2798 :         if (target_principal != NULL) {
     143           0 :                 server_principal = talloc_strdup(mem_ctx, target_principal);
     144           0 :                 name_type = GSS_C_NULL_OID;
     145             :         } else {
     146        2798 :                 server_principal = talloc_asprintf(mem_ctx,
     147             :                                                    "%s/%s@%s",
     148             :                                                    service,
     149             :                                                    hostname,
     150             :                                                    realm);
     151        2798 :                 name_type = GSS_C_NT_USER_NAME;
     152             :         }
     153        2798 :         if (server_principal == NULL) {
     154           0 :                 return NT_STATUS_NO_MEMORY;
     155             :         }
     156             : 
     157        2798 :         name_token.value = (uint8_t *)server_principal;
     158        2798 :         name_token.length = strlen(server_principal);
     159             : 
     160        2798 :         maj_stat = gss_import_name(&min_stat,
     161             :                                    &name_token,
     162             :                                    name_type,
     163             :                                    pserver_name);
     164        2798 :         if (maj_stat) {
     165           0 :                 DBG_WARNING("GSS Import name of %s failed: %s\n",
     166             :                             server_principal,
     167             :                             gse_errstr(mem_ctx, maj_stat, min_stat));
     168           0 :                 TALLOC_FREE(server_principal);
     169           0 :                 return NT_STATUS_INVALID_PARAMETER;
     170             :         }
     171             : 
     172        2798 :         *pserver_principal = server_principal;
     173             : 
     174        2798 :         return NT_STATUS_OK;
     175             : }
     176             : 
     177        6339 : static NTSTATUS gse_context_init(struct gensec_security *gensec_security,
     178             :                                  bool do_sign, bool do_seal,
     179             :                                  const struct gss_OID_desc_struct *mech,
     180             :                                  uint32_t add_gss_c_flags,
     181             :                                  struct gse_context **_gse_ctx)
     182             : {
     183           0 :         struct gse_context *gse_ctx;
     184           0 :         krb5_error_code k5ret;
     185           0 :         NTSTATUS status;
     186             : 
     187        6339 :         gse_ctx = talloc_zero(gensec_security, struct gse_context);
     188        6339 :         if (!gse_ctx) {
     189           0 :                 return NT_STATUS_NO_MEMORY;
     190             :         }
     191        6339 :         talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
     192             : 
     193        6339 :         gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
     194        6339 :         gse_ctx->max_wrap_buf_size = UINT16_MAX;
     195             : 
     196        6339 :         memcpy(&gse_ctx->gss_mech, mech, sizeof(gss_OID_desc));
     197             : 
     198        6339 :         gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG |
     199             :                                 GSS_C_DELEG_POLICY_FLAG |
     200             :                                 GSS_C_REPLAY_FLAG |
     201             :                                 GSS_C_SEQUENCE_FLAG;
     202        6339 :         if (do_sign) {
     203        2758 :                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
     204             :         }
     205        6339 :         if (do_seal) {
     206         398 :                 gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG;
     207         398 :                 gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG;
     208             :         }
     209             : 
     210        6339 :         gse_ctx->gss_want_flags |= add_gss_c_flags;
     211             : 
     212        6339 :         if (gensec_security->channel_bindings != NULL) {
     213          24 :                 gse_ctx->_channel_bindings.initiator_addrtype =
     214          24 :                         gensec_security->channel_bindings->initiator_addrtype;
     215          24 :                 gse_ctx->_channel_bindings.initiator_address.value =
     216          24 :                         gensec_security->channel_bindings->initiator_address.data;
     217          24 :                 gse_ctx->_channel_bindings.initiator_address.length =
     218          24 :                         gensec_security->channel_bindings->initiator_address.length;
     219             : 
     220          24 :                 gse_ctx->_channel_bindings.acceptor_addrtype =
     221          24 :                         gensec_security->channel_bindings->acceptor_addrtype;
     222          24 :                 gse_ctx->_channel_bindings.acceptor_address.value =
     223          24 :                         gensec_security->channel_bindings->acceptor_address.data;
     224          24 :                 gse_ctx->_channel_bindings.acceptor_address.length =
     225          24 :                         gensec_security->channel_bindings->acceptor_address.length;
     226             : 
     227          24 :                 gse_ctx->_channel_bindings.application_data.value =
     228          24 :                         gensec_security->channel_bindings->application_data.data;
     229          24 :                 gse_ctx->_channel_bindings.application_data.length =
     230          24 :                         gensec_security->channel_bindings->application_data.length;
     231             : 
     232          24 :                 gse_ctx->channel_bindings =
     233          24 :                         &gse_ctx->_channel_bindings;
     234             :         } else {
     235        6315 :                 gse_ctx->channel_bindings = GSS_C_NO_CHANNEL_BINDINGS;
     236             :         }
     237             : 
     238             :         /* Initialize Kerberos Context */
     239        6339 :         k5ret = smb_krb5_init_context_common(&gse_ctx->k5ctx);
     240        6339 :         if (k5ret) {
     241           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     242             :                         error_message(k5ret));
     243           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     244           0 :                 goto err_out;
     245             :         }
     246             : 
     247             : #ifdef SAMBA4_USES_HEIMDAL
     248        3632 :         k5ret = gsskrb5_set_dns_canonicalize(false);
     249        3632 :         if (k5ret) {
     250           0 :                 DBG_ERR("gsskrb5_set_dns_canonicalize() failed (%s)\n",
     251             :                         error_message(k5ret));
     252           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     253           0 :                 goto err_out;
     254             :         }
     255             : #endif
     256             : 
     257             :         /* TODO: Should we enforce a enc_types list ?
     258             :         ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
     259             :         */
     260             : 
     261        6339 :         *_gse_ctx = gse_ctx;
     262        6339 :         return NT_STATUS_OK;
     263             : 
     264           0 : err_out:
     265           0 :         TALLOC_FREE(gse_ctx);
     266           0 :         return status;
     267             : }
     268             : 
     269        2776 : static NTSTATUS gse_init_client(struct gensec_security *gensec_security,
     270             :                                 bool do_sign, bool do_seal,
     271             :                                 const char *ccache_name,
     272             :                                 const struct gss_OID_desc_struct *mech,
     273             :                                 uint32_t add_gss_c_flags,
     274             :                                 struct gse_context **_gse_ctx)
     275             : {
     276           0 :         struct gse_context *gse_ctx;
     277           0 :         OM_uint32 gss_maj, gss_min;
     278             : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
     279        2776 :         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
     280        2776 :         gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
     281             : #endif
     282           0 :         krb5_error_code k5ret;
     283           0 :         NTSTATUS status;
     284             : 
     285        2776 :         status = gse_context_init(gensec_security,
     286             :                                   do_sign,
     287             :                                   do_seal,
     288             :                                   mech,
     289             :                                   add_gss_c_flags,
     290             :                                   &gse_ctx);
     291        2776 :         if (!NT_STATUS_IS_OK(status)) {
     292           0 :                 return NT_STATUS_NO_MEMORY;
     293             :         }
     294             : 
     295        2776 :         if (ccache_name == NULL) {
     296           0 :                 DBG_ERR("No explicit ccache_name given\n");
     297           0 :                 return NT_STATUS_INTERNAL_ERROR;
     298             :         }
     299             : 
     300        2776 :         k5ret = krb5_cc_resolve(gse_ctx->k5ctx,
     301             :                                 ccache_name,
     302        2776 :                                 &gse_ctx->ccache);
     303        2776 :         if (k5ret) {
     304           0 :                 DBG_WARNING("Failed to resolve credential cache '%s'! (%s)\n",
     305             :                             ccache_name, error_message(k5ret));
     306           0 :                 return NT_STATUS_INTERNAL_ERROR;
     307             :         }
     308             : 
     309             : #ifdef SAMBA4_USES_HEIMDAL
     310             :         {
     311           0 :                 int ret;
     312        1807 :                 bool set_dns_canon = gensec_setting_bool(
     313             :                                 gensec_security->settings,
     314             :                                 "krb5", "set_dns_canonicalize",
     315             :                                 false);
     316        1807 :                 const char *server_realm = lpcfg_realm(
     317        1807 :                                 gensec_security->settings->lp_ctx);
     318        1807 :                 if (server_realm != NULL) {
     319        1807 :                         ret = gsskrb5_set_default_realm(server_realm);
     320        1807 :                         if (ret) {
     321           0 :                                 DBG_ERR("gsskrb5_set_default_realm failed\n");
     322           0 :                                 return NT_STATUS_INTERNAL_ERROR;
     323             :                         }
     324             :                 }
     325             : 
     326             :                 /*
     327             :                  * don't do DNS lookups of any kind, it might/will
     328             :                  * fail for a netbios name
     329             :                  */
     330        1807 :                 ret = gsskrb5_set_dns_canonicalize(set_dns_canon);
     331        1807 :                 if (ret != GSS_S_COMPLETE) {
     332           0 :                         DBG_ERR("gsskrb5_set_dns_canonicalize failed\n");
     333           0 :                         return NT_STATUS_INTERNAL_ERROR;
     334             :                 }
     335             :         }
     336             : #endif
     337             : 
     338             :         /* TODO: get krb5 ticket using username/password, if no valid
     339             :          * one already available in ccache */
     340             : 
     341        2776 :         gss_maj = smb_gss_krb5_import_cred(&gss_min,
     342        2776 :                                            gse_ctx->k5ctx,
     343        2776 :                                            gse_ctx->ccache,
     344             :                                            NULL, /* keytab_principal */
     345             :                                            NULL, /* keytab */
     346        2776 :                                            &gse_ctx->creds);
     347        2776 :         if (gss_maj) {
     348           0 :                 char *ccache = NULL;
     349           0 :                 int kret;
     350             : 
     351           0 :                 kret = krb5_cc_get_full_name(gse_ctx->k5ctx,
     352           0 :                                              gse_ctx->ccache,
     353             :                                              &ccache);
     354           0 :                 if (kret != 0) {
     355           0 :                         ccache = NULL;
     356             :                 }
     357             : 
     358           0 :                 DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
     359             :                           "the caller may retry after a kinit.\n",
     360             :                           ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
     361           0 :                 krb5_free_string(gse_ctx->k5ctx, ccache);
     362           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     363           0 :                 goto err_out;
     364             :         }
     365             : 
     366             : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
     367             :         /*
     368             :          * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
     369             :          *
     370             :          * This allows us to disable SIGN and SEAL for
     371             :          * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY.
     372             :          *
     373             :          * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
     374             :          * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
     375             :          */
     376        2776 :         gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds,
     377             :                                       oid,
     378             :                                       &empty_buffer);
     379        2776 :         if (gss_maj) {
     380           0 :                 DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), "
     381             :                           "failed with [%s]\n",
     382             :                           gse_errstr(gse_ctx, gss_maj, gss_min)));
     383           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     384           0 :                 goto err_out;
     385             :         }
     386             : #endif
     387             : 
     388        2776 :         *_gse_ctx = gse_ctx;
     389        2776 :         return NT_STATUS_OK;
     390             : 
     391           0 : err_out:
     392           0 :         TALLOC_FREE(gse_ctx);
     393           0 :         return status;
     394             : }
     395             : 
     396        5531 : static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
     397             :                                           struct gensec_security *gensec_security,
     398             :                                           const DATA_BLOB *token_in,
     399             :                                           DATA_BLOB *token_out)
     400             : {
     401           0 :         struct gse_context *gse_ctx =
     402        5531 :                 talloc_get_type_abort(gensec_security->private_data,
     403             :                                       struct gse_context);
     404        5531 :         OM_uint32 gss_maj = 0;
     405           0 :         OM_uint32 gss_min;
     406           0 :         gss_buffer_desc in_data;
     407           0 :         gss_buffer_desc out_data;
     408        5531 :         DATA_BLOB blob = data_blob_null;
     409           0 :         NTSTATUS status;
     410        5531 :         OM_uint32 time_rec = 0;
     411           0 :         struct timeval tv;
     412        5531 :         struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security);
     413        5531 :         const char *target_principal = gensec_get_target_principal(gensec_security);
     414        5531 :         const char *hostname = gensec_get_target_hostname(gensec_security);
     415        5531 :         const char *service = gensec_get_target_service(gensec_security);
     416        5531 :         const char *client_realm = cli_credentials_get_realm(cli_creds);
     417        5531 :         char *server_principal = NULL;
     418        5531 :         char *server_realm = NULL;
     419        5531 :         bool fallback = false;
     420        5531 :         OM_uint32 time_req = 0;
     421             : 
     422        5531 :         time_req = gensec_setting_int(gensec_security->settings,
     423             :                                       "gensec_gssapi",
     424             :                                       "requested_life_time",
     425             :                                       time_req);
     426             : 
     427        5531 :         in_data.value = token_in->data;
     428        5531 :         in_data.length = token_in->length;
     429             : 
     430             :         /*
     431             :          * With credentials for administrator@FOREST1.EXAMPLE.COM this patch
     432             :          * changes the target_principal for the ldap service of host
     433             :          * dc2.forest2.example.com from
     434             :          *
     435             :          *   ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM
     436             :          *
     437             :          * to
     438             :          *
     439             :          *   ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM
     440             :          *
     441             :          * Typically ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM should be
     442             :          * used in order to allow the KDC of FOREST1.EXAMPLE.COM to generate a
     443             :          * referral ticket for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM.
     444             :          *
     445             :          * The problem is that KDCs only return such referral tickets if
     446             :          * there's a forest trust between FOREST1.EXAMPLE.COM and
     447             :          * FOREST2.EXAMPLE.COM. If there's only an external domain trust
     448             :          * between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC of
     449             :          * FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN when being
     450             :          * asked for ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM.
     451             :          *
     452             :          * In the case of an external trust the client can still ask explicitly
     453             :          * for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and the KDC of
     454             :          * FOREST1.EXAMPLE.COM will generate it.
     455             :          *
     456             :          * From there the client can use the
     457             :          * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM ticket and ask a KDC
     458             :          * of FOREST2.EXAMPLE.COM for a service ticket for
     459             :          * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM.
     460             :          *
     461             :          * With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
     462             :          * when we pass ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM as
     463             :          * target principal. As _krb5_get_cred_kdc_any() first calls
     464             :          * get_cred_kdc_referral() (which always starts with the client realm)
     465             :          * and falls back to get_cred_kdc_capath() (which starts with the given
     466             :          * realm).
     467             :          *
     468             :          * MIT krb5 only tries the given realm of the target principal, if we
     469             :          * want to autodetect support for transitive forest trusts, would have
     470             :          * to do the fallback ourself.
     471             :          */
     472             : #ifndef SAMBA4_USES_HEIMDAL
     473        1928 :         if (gse_ctx->server_name == NULL) {
     474         969 :                 OM_uint32 gss_min2 = 0;
     475             : 
     476         969 :                 status = gse_setup_server_principal(mem_ctx,
     477             :                                                     target_principal,
     478             :                                                     service,
     479             :                                                     hostname,
     480             :                                                     client_realm,
     481             :                                                     &server_principal,
     482             :                                                     &gse_ctx->server_name);
     483         969 :                 if (!NT_STATUS_IS_OK(status)) {
     484           0 :                         return status;
     485             :                 }
     486             : 
     487        1938 :                 gss_maj = gss_init_sec_context(&gss_min,
     488             :                                                gse_ctx->creds,
     489             :                                                &gse_ctx->gssapi_context,
     490             :                                                gse_ctx->server_name,
     491         969 :                                                &gse_ctx->gss_mech,
     492             :                                                gse_ctx->gss_want_flags,
     493             :                                                time_req,
     494             :                                                gse_ctx->channel_bindings,
     495             :                                                &in_data,
     496             :                                                NULL,
     497             :                                                &out_data,
     498             :                                                &gse_ctx->gss_got_flags,
     499             :                                                &time_rec);
     500         969 :                 if (gss_maj != GSS_S_FAILURE) {
     501         947 :                         goto init_sec_context_done;
     502             :                 }
     503          22 :                 if (gss_min != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
     504           0 :                         goto init_sec_context_done;
     505             :                 }
     506          22 :                 if (target_principal != NULL) {
     507           0 :                         goto init_sec_context_done;
     508             :                 }
     509             : 
     510          22 :                 fallback = true;
     511          22 :                 TALLOC_FREE(server_principal);
     512          22 :                 gss_release_name(&gss_min2, &gse_ctx->server_name);
     513             :         }
     514             : #endif /* !SAMBA4_USES_HEIMDAL */
     515             : 
     516        4584 :         if (gse_ctx->server_name == NULL) {
     517        1829 :                 server_realm = smb_krb5_get_realm_from_hostname(mem_ctx,
     518             :                                                                 hostname,
     519             :                                                                 client_realm);
     520        1829 :                 if (server_realm == NULL) {
     521           0 :                         return NT_STATUS_NO_MEMORY;
     522             :                 }
     523             : 
     524        1851 :                 if (fallback &&
     525          22 :                     strequal(client_realm, server_realm)) {
     526           0 :                         goto init_sec_context_done;
     527             :                 }
     528             : 
     529        1829 :                 status = gse_setup_server_principal(mem_ctx,
     530             :                                                     target_principal,
     531             :                                                     service,
     532             :                                                     hostname,
     533             :                                                     server_realm,
     534             :                                                     &server_principal,
     535             :                                                     &gse_ctx->server_name);
     536        1829 :                 TALLOC_FREE(server_realm);
     537        1829 :                 if (!NT_STATUS_IS_OK(status)) {
     538           0 :                         return status;
     539             :                 }
     540             : 
     541        1829 :                 TALLOC_FREE(server_principal);
     542             :         }
     543             : 
     544        9168 :         gss_maj = gss_init_sec_context(&gss_min,
     545        3603 :                                         gse_ctx->creds,
     546             :                                         &gse_ctx->gssapi_context,
     547        3603 :                                         gse_ctx->server_name,
     548        4584 :                                         &gse_ctx->gss_mech,
     549             :                                         gse_ctx->gss_want_flags,
     550             :                                         time_req,
     551             :                                         gse_ctx->channel_bindings,
     552             :                                         &in_data, NULL, &out_data,
     553             :                                         &gse_ctx->gss_got_flags, &time_rec);
     554        4584 :         goto init_sec_context_done;
     555             :         /* JUMP! */
     556        5531 : init_sec_context_done:
     557             : 
     558        5531 :         switch (gss_maj) {
     559        2755 :         case GSS_S_COMPLETE:
     560             :                 /* we are done with it */
     561        2755 :                 tv = timeval_current_ofs(time_rec, 0);
     562        2755 :                 gse_ctx->expire_time = timeval_to_nttime(&tv);
     563             : 
     564        2755 :                 status = NT_STATUS_OK;
     565        2755 :                 break;
     566        2772 :         case GSS_S_CONTINUE_NEEDED:
     567             :                 /* we will need a third leg */
     568        2772 :                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     569        2772 :                 break;
     570           0 :         case GSS_S_CONTEXT_EXPIRED:
     571             :                 /* Make SPNEGO ignore us, we can't go any further here */
     572           0 :                 DBG_NOTICE("Context expired\n");
     573           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     574           4 :                 goto done;
     575           4 :         case GSS_S_FAILURE:
     576           4 :                 switch (gss_min) {
     577           2 :                 case (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: {
     578           2 :                         gss_buffer_desc name_token = {
     579             :                                 .length = 0,
     580             :                         };
     581             : 
     582           2 :                         gss_maj = gss_display_name(&gss_min,
     583           0 :                                                    gse_ctx->server_name,
     584             :                                                    &name_token,
     585             :                                                    NULL);
     586           2 :                         if (gss_maj == GSS_S_COMPLETE) {
     587           2 :                                 DBG_NOTICE("Server principal %.*s not found\n",
     588             :                                            (int)name_token.length,
     589             :                                            (char *)name_token.value);
     590           2 :                                 gss_release_buffer(&gss_maj, &name_token);
     591             :                         } else {
     592           0 :                                 DBG_NOTICE("Server principal not found\n");
     593             :                         }
     594             : 
     595             :                         /* Make SPNEGO ignore us, we can't go any further here */
     596           2 :                         status = NT_STATUS_INVALID_PARAMETER;
     597           2 :                         goto done;
     598             :                 }
     599           0 :                 case (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED:
     600           0 :                         DBG_NOTICE("Ticket expired\n");
     601             :                         /* Make SPNEGO ignore us, we can't go any further here */
     602           0 :                         status = NT_STATUS_INVALID_PARAMETER;
     603           0 :                         goto done;
     604           0 :                 case (OM_uint32)KRB5KRB_AP_ERR_TKT_NYV:
     605           0 :                         DBG_NOTICE("Clockskew\n");
     606             :                         /* Make SPNEGO ignore us, we can't go any further here */
     607           0 :                         status = NT_STATUS_TIME_DIFFERENCE_AT_DC;
     608           0 :                         goto done;
     609           0 :                 case (OM_uint32)KRB5_KDC_UNREACH:
     610           0 :                         DBG_NOTICE("KDC unreachable\n");
     611             :                         /* Make SPNEGO ignore us, we can't go any further here */
     612           0 :                         status = NT_STATUS_NO_LOGON_SERVERS;
     613           0 :                         goto done;
     614           0 :                 case (OM_uint32)KRB5KRB_AP_ERR_MSG_TYPE:
     615             :                         /* Garbage input, possibly from the auto-mech detection */
     616           0 :                         status = NT_STATUS_INVALID_PARAMETER;
     617           0 :                         goto done;
     618           0 :                 case (OM_uint32)KRB5KDC_ERR_ETYPE_NOSUPP:
     619           0 :                         status = NT_STATUS_KDC_UNKNOWN_ETYPE;
     620           0 :                         goto done;
     621           2 :                 default:
     622           2 :                         DBG_ERR("gss_init_sec_context failed with [%s](%u)\n",
     623             :                                 gse_errstr(talloc_tos(), gss_maj, gss_min),
     624             :                                 gss_min);
     625           2 :                         status = NT_STATUS_LOGON_FAILURE;
     626           2 :                         goto done;
     627             :                 }
     628           0 :                 break;
     629           0 :         default:
     630           0 :                 DBG_ERR("gss_init_sec_context failed with [%s]\n",
     631             :                         gse_errstr(talloc_tos(), gss_maj, gss_min));
     632           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     633           0 :                 goto done;
     634             :         }
     635             : 
     636             :         /* we may be told to return nothing */
     637        5527 :         if (out_data.length) {
     638        2799 :                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
     639        2799 :                 if (!blob.data) {
     640           0 :                         status = NT_STATUS_NO_MEMORY;
     641             :                 }
     642             : 
     643        2799 :                 gss_release_buffer(&gss_min, &out_data);
     644             :         }
     645             : 
     646        2728 : done:
     647        5531 :         *token_out = blob;
     648        5531 :         return status;
     649             : }
     650             : 
     651        3563 : static NTSTATUS gse_init_server(struct gensec_security *gensec_security,
     652             :                                 bool do_sign, bool do_seal,
     653             :                                 const struct gss_OID_desc_struct *mech,
     654             :                                 uint32_t add_gss_c_flags,
     655             :                                 struct gse_context **_gse_ctx)
     656             : {
     657           0 :         struct gse_context *gse_ctx;
     658           0 :         OM_uint32 gss_maj, gss_min;
     659           0 :         krb5_error_code ret;
     660           0 :         NTSTATUS status;
     661             : 
     662        3563 :         status = gse_context_init(gensec_security,
     663             :                                   do_sign,
     664             :                                   do_seal,
     665             :                                   mech,
     666             :                                   add_gss_c_flags,
     667             :                                   &gse_ctx);
     668        3563 :         if (!NT_STATUS_IS_OK(status)) {
     669           0 :                 return NT_STATUS_NO_MEMORY;
     670             :         }
     671             : 
     672        3563 :         ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx,
     673        3563 :                                          &gse_ctx->keytab);
     674        3563 :         if (ret) {
     675          10 :                 status = NT_STATUS_INTERNAL_ERROR;
     676          10 :                 goto done;
     677             :         }
     678             : 
     679             :         /* This creates a GSSAPI cred_id_t with the keytab set */
     680        3553 :         gss_maj = smb_gss_mech_import_cred(&gss_min, gse_ctx->k5ctx,
     681        3553 :                                            NULL, NULL, gse_ctx->keytab,
     682        3553 :                                            &gse_ctx->gss_mech,
     683        3553 :                                            &gse_ctx->creds);
     684             : 
     685        3553 :         if (gss_maj != 0) {
     686           0 :                 DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
     687             :                           gse_errstr(gse_ctx, gss_maj, gss_min)));
     688           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     689           0 :                 goto done;
     690             :         }
     691             : 
     692        3553 :         status = NT_STATUS_OK;
     693             : 
     694        3563 : done:
     695        3563 :         if (!NT_STATUS_IS_OK(status)) {
     696          10 :                 TALLOC_FREE(gse_ctx);
     697             :         }
     698             : 
     699        3563 :         *_gse_ctx = gse_ctx;
     700        3563 :         return status;
     701             : }
     702             : 
     703        1011 : static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
     704             :                                           struct gensec_security *gensec_security,
     705             :                                           const DATA_BLOB *token_in,
     706             :                                           DATA_BLOB *token_out)
     707             : {
     708           0 :         struct gse_context *gse_ctx =
     709        1011 :                 talloc_get_type_abort(gensec_security->private_data,
     710             :                                       struct gse_context);
     711           0 :         OM_uint32 gss_maj, gss_min;
     712           0 :         gss_buffer_desc in_data;
     713           0 :         gss_buffer_desc out_data;
     714        1011 :         DATA_BLOB blob = data_blob_null;
     715           0 :         NTSTATUS status;
     716        1011 :         OM_uint32 time_rec = 0;
     717           0 :         struct timeval tv;
     718             : 
     719        1011 :         in_data.value = token_in->data;
     720        1011 :         in_data.length = token_in->length;
     721             : 
     722        1011 :         gss_maj = gss_accept_sec_context(&gss_min,
     723             :                                          &gse_ctx->gssapi_context,
     724         535 :                                          gse_ctx->creds,
     725             :                                          &in_data,
     726             :                                          gse_ctx->channel_bindings,
     727             :                                          &gse_ctx->client_name,
     728             :                                          &gse_ctx->ret_mech,
     729             :                                          &out_data,
     730             :                                          &gse_ctx->gss_got_flags,
     731             :                                          &time_rec,
     732             :                                          &gse_ctx->delegated_cred_handle);
     733             : #ifdef GSS_C_CHANNEL_BOUND_FLAG
     734         953 :         if (gss_maj == GSS_S_COMPLETE &&
     735         853 :             gensec_security->channel_bindings != NULL &&
     736           0 :             !(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL) &&
     737           0 :             !(gse_ctx->gss_got_flags & GSS_C_CHANNEL_BOUND_FLAG))
     738             :         {
     739             :                 /*
     740             :                  * If we require valid channel bindings
     741             :                  * we need to check the client provided
     742             :                  * them.
     743             :                  *
     744             :                  * We detect this if
     745             :                  * GSS_C_CHANNEL_BOUND_FLAG is given.
     746             :                  *
     747             :                  * Recent heimdal and MIT releases support this
     748             :                  * with older releases (e.g. MIT > 1.19).
     749             :                  *
     750             :                  * It means client with zero channel bindings
     751             :                  * on a server with non-zero channel bindings
     752             :                  * won't generate GSS_S_BAD_BINDINGS directly
     753             :                  * unless KERB_AP_OPTIONS_CBT was also
     754             :                  * provides by the client.
     755             :                  *
     756             :                  * So we need to convert a missing
     757             :                  * GSS_C_CHANNEL_BOUND_FLAG into
     758             :                  * GSS_S_BAD_BINDINGS by default
     759             :                  * (unless GENSEC_FEATURE_CB_OPTIONAL is given).
     760             :                  */
     761           0 :                 gss_maj = GSS_S_BAD_BINDINGS;
     762           0 :                 gss_min = 0;
     763             :         }
     764             : #endif /* GSS_C_CHANNEL_BOUND_FLAG */
     765             : 
     766        1011 :         switch (gss_maj) {
     767         896 :         case GSS_S_COMPLETE:
     768             :                 /* we are done with it */
     769         896 :                 tv = timeval_current_ofs(time_rec, 0);
     770         896 :                 gse_ctx->expire_time = timeval_to_nttime(&tv);
     771             : 
     772         896 :                 status = NT_STATUS_OK;
     773        1011 :                 break;
     774         115 :         case GSS_S_CONTINUE_NEEDED:
     775             :                 /* we will need a third leg */
     776         115 :                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     777         115 :                 break;
     778           0 :         case GSS_S_BAD_BINDINGS:
     779           0 :                 DBG_WARNING("Got GSS_S_BAD_BINDINGS\n");
     780           0 :                 status = NT_STATUS_BAD_BINDINGS;
     781           0 :                 goto done;
     782           0 :         default:
     783           0 :                 DEBUG(1, ("gss_accept_sec_context failed with [%s]\n",
     784             :                           gse_errstr(talloc_tos(), gss_maj, gss_min)));
     785             : 
     786           0 :                 if (gse_ctx->gssapi_context) {
     787           0 :                         gss_delete_sec_context(&gss_min,
     788             :                                                 &gse_ctx->gssapi_context,
     789             :                                                 GSS_C_NO_BUFFER);
     790             :                 }
     791             : 
     792             :                 /*
     793             :                  * If we got an output token, make Windows aware of it
     794             :                  * by telling it that more processing is needed
     795             :                  */
     796           0 :                 if (out_data.length > 0) {
     797           0 :                         status = NT_STATUS_MORE_PROCESSING_REQUIRED;
     798             :                         /* Fall through to handle the out token */
     799             :                 } else {
     800           0 :                         status = NT_STATUS_LOGON_FAILURE;
     801           0 :                         goto done;
     802             :                 }
     803             :         }
     804             : 
     805             :         /* we may be told to return nothing */
     806        1011 :         if (out_data.length) {
     807         896 :                 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
     808         896 :                 if (!blob.data) {
     809           0 :                         status = NT_STATUS_NO_MEMORY;
     810             :                 }
     811         896 :                 gss_release_buffer(&gss_min, &out_data);
     812             :         }
     813             : 
     814             : 
     815         115 : done:
     816        1011 :         *token_out = blob;
     817        1011 :         return status;
     818             : }
     819             : 
     820           2 : static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
     821             : {
     822           0 :         OM_uint32 gss_min, gss_maj;
     823           0 :         gss_buffer_desc msg_min;
     824           0 :         gss_buffer_desc msg_maj;
     825           2 :         OM_uint32 msg_ctx = 0;
     826             : 
     827           2 :         char *errstr = NULL;
     828             : 
     829           2 :         ZERO_STRUCT(msg_min);
     830           2 :         ZERO_STRUCT(msg_maj);
     831             : 
     832           2 :         gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
     833             :                                      GSS_C_NO_OID, &msg_ctx, &msg_maj);
     834           2 :         if (gss_maj) {
     835           0 :                 goto done;
     836             :         }
     837           2 :         errstr = talloc_strndup(mem_ctx,
     838           2 :                                 (char *)msg_maj.value,
     839             :                                         msg_maj.length);
     840           2 :         if (!errstr) {
     841           0 :                 goto done;
     842             :         }
     843           2 :         gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
     844             :                                      (gss_OID)discard_const(gss_mech_krb5),
     845             :                                      &msg_ctx, &msg_min);
     846           2 :         if (gss_maj) {
     847           0 :                 goto done;
     848             :         }
     849             : 
     850           2 :         errstr = talloc_strdup_append_buffer(errstr, ": ");
     851           2 :         if (!errstr) {
     852           0 :                 goto done;
     853             :         }
     854           2 :         errstr = talloc_strndup_append_buffer(errstr,
     855           2 :                                                 (char *)msg_min.value,
     856             :                                                         msg_min.length);
     857           2 :         if (!errstr) {
     858           0 :                 goto done;
     859             :         }
     860             : 
     861           2 : done:
     862           2 :         if (msg_min.value) {
     863           2 :                 gss_release_buffer(&gss_min, &msg_min);
     864             :         }
     865           2 :         if (msg_maj.value) {
     866           2 :                 gss_release_buffer(&gss_min, &msg_maj);
     867             :         }
     868           2 :         return errstr;
     869             : }
     870             : 
     871             : struct gensec_gse_client_prepare_krb5_ccache {
     872             :         krb5_context kctx;
     873             :         krb5_ccache id;
     874             :         char *name;
     875             : };
     876             : 
     877        2355 : static int gensec_gse_client_prepare_krb5_ccache_destructor(
     878             :         struct gensec_gse_client_prepare_krb5_ccache *ccache)
     879             : {
     880        2355 :         if (ccache->id != NULL) {
     881        2355 :                 krb5_cc_destroy(ccache->kctx, ccache->id);
     882        2355 :                 ccache->id = NULL;
     883             :         }
     884             : 
     885        2355 :         if (ccache->kctx != NULL) {
     886        2355 :                 krb5_free_context(ccache->kctx);
     887        2355 :                 ccache->kctx = NULL;
     888             :         }
     889             : 
     890        2355 :         return 0;
     891             : }
     892             : 
     893        2481 : static NTSTATUS gensec_gse_client_prepare_krb5_ccache_create(TALLOC_CTX *mem_ctx,
     894             :                         struct gensec_gse_client_prepare_krb5_ccache **_ccache)
     895             : {
     896        2481 :         struct gensec_gse_client_prepare_krb5_ccache *ccache = NULL;
     897           0 :         int ret;
     898             : 
     899        2481 :         *_ccache = NULL;
     900             : 
     901        2481 :         ccache = talloc_zero(mem_ctx, struct gensec_gse_client_prepare_krb5_ccache);
     902        2481 :         if (ccache == NULL) {
     903           0 :                 return NT_STATUS_NO_MEMORY;
     904             :         }
     905             : 
     906        2481 :         talloc_set_destructor(ccache,
     907             :                 gensec_gse_client_prepare_krb5_ccache_destructor);
     908             : 
     909        2481 :         ret = smb_krb5_init_context_common(&ccache->kctx);
     910        2481 :         if (ret != 0) {
     911           0 :                 TALLOC_FREE(ccache);
     912           0 :                 return krb5_to_nt_status(ret);
     913             :         }
     914             : 
     915        2481 :         ret = smb_krb5_cc_new_unique_memory(ccache->kctx,
     916             :                                             ccache,
     917             :                                             &ccache->name,
     918             :                                             &ccache->id);
     919        2481 :         if (ret != 0) {
     920           0 :                 TALLOC_FREE(ccache);
     921           0 :                 return krb5_to_nt_status(ret);
     922             :         }
     923             : 
     924        2481 :         *_ccache = ccache;
     925        2481 :         return NT_STATUS_OK;
     926             : }
     927             : 
     928        3215 : static NTSTATUS gensec_gse_client_prepare_ccache(struct gensec_security *gensec,
     929             :                                                  const char **_ccache_name)
     930             : {
     931        3215 :         TALLOC_CTX *frame = talloc_stackframe();
     932        3215 :         struct cli_credentials *creds = gensec_get_credentials(gensec);
     933        3215 :         enum credentials_use_kerberos krb5_state = CRED_USE_KERBEROS_REQUIRED;
     934        3215 :         enum credentials_obtained user_obtained = CRED_UNINITIALISED;
     935        3215 :         const char *user_principal = NULL;
     936        3215 :         const char *debug_username = NULL;
     937        3215 :         const char *debug_target = NULL;
     938        3215 :         enum credentials_obtained pass_obtained = CRED_UNINITIALISED;
     939        3215 :         const char *pass = NULL;
     940        3215 :         bool ccache_valid = false;
     941        3215 :         enum credentials_obtained ccache_obtained = CRED_UNINITIALISED;
     942        3215 :         char *e_ccache_name = NULL;
     943        3215 :         struct gensec_gse_client_prepare_krb5_ccache *ccache = NULL;
     944        3215 :         const char *error_string = NULL;
     945        3215 :         char *canon_principal = NULL;
     946        3215 :         char *canon_realm = NULL;
     947           0 :         NTSTATUS status;
     948           0 :         int ret;
     949        3215 :         int dbg_fail_lvl = DBGLVL_NOTICE;
     950        3215 :         bool may_ignore_krb5 = true;
     951             : 
     952        3215 :         debug_username = cli_credentials_get_unparsed_name(creds, frame);
     953        3215 :         debug_target = gensec_get_unparsed_target_principal(gensec, frame);
     954             : 
     955        3215 :         krb5_state = cli_credentials_get_kerberos_state(creds);
     956        3215 :         if (krb5_state == CRED_USE_KERBEROS_REQUIRED) {
     957         417 :                 DBG_DEBUG("Kerberos required username[%s]\n",
     958             :                           debug_username);
     959         417 :                 dbg_fail_lvl = DBGLVL_ERR;
     960         417 :                 may_ignore_krb5 = false;
     961             :         }
     962             : 
     963        3215 :         pass_obtained = cli_credentials_get_password_obtained(creds);
     964        3215 :         ccache_valid = cli_credentials_get_ccache_name_obtained(creds,
     965             :                                                                 gensec,
     966             :                                                                 &e_ccache_name,
     967             :                                                                 &ccache_obtained);
     968        3215 :         if (ccache_valid && ccache_obtained >= pass_obtained) {
     969         726 :                 DBG_INFO("No kinit required for %s to access %s, %s\n",
     970             :                          debug_username, debug_target, e_ccache_name);
     971         726 :                 *_ccache_name = e_ccache_name;
     972         726 :                 TALLOC_FREE(frame);
     973         726 :                 return NT_STATUS_OK;
     974             :         }
     975        2489 :         TALLOC_FREE(e_ccache_name);
     976             : 
     977             :         /*
     978             :          * gensec_kerberos_possible() already checked
     979             :          * cli_credentials_get_principal() worked
     980             :          */
     981        2489 :         user_principal = cli_credentials_get_principal_and_obtained(creds,
     982             :                                                                 frame,
     983             :                                                                 &user_obtained);
     984        2489 :         if (user_principal == NULL) {
     985           0 :                 TALLOC_FREE(frame);
     986           0 :                 return NT_STATUS_NO_MEMORY;
     987             :         }
     988             : 
     989        2489 :         pass = cli_credentials_get_password(creds);
     990        2489 :         if (pass == NULL) {
     991           8 :                 DBG_PREFIX(dbg_fail_lvl, (
     992             :                            "No password for user principal[%s]\n",
     993             :                            user_principal));
     994           8 :                 TALLOC_FREE(frame);
     995           8 :                 if (may_ignore_krb5) {
     996           0 :                         return NT_STATUS_INVALID_PARAMETER;
     997             :                 }
     998           8 :                 return NT_STATUS_WRONG_CREDENTIAL_HANDLE;
     999             :         }
    1000             : 
    1001        2481 :         status = gensec_gse_client_prepare_krb5_ccache_create(creds,
    1002             :                                                               &ccache);
    1003        2481 :         if (!NT_STATUS_IS_OK(status)) {
    1004           0 :                 DBG_ERR("gensec_gse_client_prepare_krb5_ccache_create(): %s\n",
    1005             :                         nt_errstr(status));
    1006           0 :                 TALLOC_FREE(frame);
    1007           0 :                 return status;
    1008             :         }
    1009             :         /* cleanup via frame on error */
    1010        2481 :         talloc_reparent(creds, frame, ccache);
    1011             : 
    1012        2481 :         DBG_INFO("Doing kinit for %s to access %s into %s\n",
    1013             :                  user_principal, debug_target, ccache->name);
    1014             : 
    1015        2481 :         ret = kerberos_kinit_password_ext(user_principal,
    1016             :                                           pass,
    1017             :                                           0,
    1018             :                                           0,
    1019             :                                           0,
    1020        2481 :                                           ccache->name,
    1021             :                                           false,
    1022             :                                           false,
    1023             :                                           0,
    1024             :                                           frame,
    1025             :                                           &canon_principal,
    1026             :                                           &canon_realm,
    1027             :                                           NULL);
    1028        2481 :         if (ret != 0) {
    1029         431 :                 switch (ret) {
    1030          18 :                 case KRB5KDC_ERR_PREAUTH_FAILED:
    1031             :                 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
    1032             :                 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
    1033             :                         /*
    1034             :                          * If the fail to authenticate a
    1035             :                          * valid user
    1036             :                          */
    1037          18 :                         dbg_fail_lvl = DBGLVL_ERR;
    1038          18 :                         may_ignore_krb5 = false;
    1039          18 :                         status = NT_STATUS_LOGON_FAILURE;
    1040          18 :                         break;
    1041           2 :                 case KRB5KDC_ERR_CLIENT_REVOKED:
    1042             :                         /*
    1043             :                          * If the fail to authenticate a
    1044             :                          * valid user
    1045             :                          */
    1046           2 :                         dbg_fail_lvl = DBGLVL_ERR;
    1047           2 :                         may_ignore_krb5 = false;
    1048           2 :                         status = NT_STATUS_ACCOUNT_LOCKED_OUT;
    1049           2 :                         break;
    1050         405 :                 case KRB5_REALM_UNKNOWN:
    1051             :                 case KRB5_KDC_UNREACH:
    1052         405 :                         status = NT_STATUS_NO_LOGON_SERVERS;
    1053         405 :                         break;
    1054           6 :                 default:
    1055           6 :                         status = krb5_to_nt_status(ret);
    1056           6 :                         break;
    1057             :                 }
    1058             : 
    1059         431 :                 DBG_PREFIX(dbg_fail_lvl, (
    1060             :                            "Kinit for %s to access %s failed: %s: %s\n",
    1061             :                            user_principal,
    1062             :                            debug_target,
    1063             :                            error_message(ret), nt_errstr(status)));
    1064         431 :                 TALLOC_FREE(frame);
    1065         431 :                 if (may_ignore_krb5) {
    1066         411 :                         return NT_STATUS_INVALID_PARAMETER;
    1067             :                 }
    1068          20 :                 return status;
    1069             :         }
    1070             : 
    1071        2050 :         ret = cli_credentials_set_ccache(creds,
    1072        2050 :                                          gensec->settings->lp_ctx,
    1073        2050 :                                          ccache->name,
    1074             :                                          CRED_SPECIFIED,
    1075             :                                          &error_string);
    1076        2050 :         if (ret != 0) {
    1077           0 :                 DBG_ERR("cli_credentials_set_ccache(%s) "
    1078             :                         "for %s to access %s failed: %s\n",
    1079             :                         ccache->name,
    1080             :                         user_principal,
    1081             :                         debug_target,
    1082             :                         error_string);
    1083           0 :                 TALLOC_FREE(frame);
    1084           0 :                 return krb5_to_nt_status(ret);
    1085             :         }
    1086             : 
    1087        2050 :         DBG_DEBUG("Successfully kinit as %s (%s) to access %s into %s\n",
    1088             :                   user_principal,
    1089             :                   canon_principal,
    1090             :                   debug_target,
    1091             :                   ccache->name);
    1092             : 
    1093             :         /*
    1094             :          * keep the ccache for the lifetime
    1095             :          * of creds
    1096             :          */
    1097        2050 :         *_ccache_name = ccache->name;
    1098             : 
    1099        2050 :         talloc_move(creds, &ccache);
    1100             : 
    1101        2050 :         TALLOC_FREE(frame);
    1102        2050 :         return NT_STATUS_OK;
    1103             : }
    1104             : 
    1105       17589 : static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
    1106             : {
    1107           0 :         struct gse_context *gse_ctx;
    1108       17589 :         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
    1109           0 :         NTSTATUS nt_status;
    1110       17589 :         OM_uint32 want_flags = 0;
    1111       17589 :         bool do_sign = false, do_seal = false;
    1112       17589 :         const char *ccache_name = NULL;
    1113             : 
    1114       17589 :         nt_status = gensec_kerberos_possible(gensec_security);
    1115       17589 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1116       14374 :                 char *target_name = NULL;
    1117       14374 :                 char *cred_name = NULL;
    1118             : 
    1119       14374 :                 target_name = gensec_get_unparsed_target_principal(gensec_security,
    1120             :                                                                    gensec_security);
    1121       14374 :                 cred_name = cli_credentials_get_unparsed_name(creds,
    1122             :                                                               gensec_security);
    1123             : 
    1124       14374 :                 DBG_NOTICE("Not using kerberos to %s as %s: %s\n",
    1125             :                            target_name, cred_name, nt_errstr(nt_status));
    1126             : 
    1127       14374 :                 TALLOC_FREE(target_name);
    1128       14374 :                 TALLOC_FREE(cred_name);
    1129       14374 :                 return nt_status;
    1130             :         }
    1131             : 
    1132        3215 :         nt_status = gensec_gse_client_prepare_ccache(gensec_security,
    1133             :                                                      &ccache_name);
    1134        3215 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1135         439 :                 return nt_status;
    1136             :         }
    1137             : 
    1138        2776 :         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
    1139        2354 :                 do_sign = true;
    1140             :         }
    1141        2776 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
    1142         406 :                 do_sign = true;
    1143             :         }
    1144        2776 :         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
    1145         380 :                 do_seal = true;
    1146             :         }
    1147        2776 :         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
    1148          27 :                 want_flags |= GSS_C_DCE_STYLE;
    1149             :         }
    1150             : 
    1151             : #ifdef HAVE_CLIENT_GSS_C_CHANNEL_BOUND_FLAG
    1152             :         /*
    1153             :          * We can only use GSS_C_CHANNEL_BOUND_FLAG if the kerberos library
    1154             :          * supports that in order to add KERB_AP_OPTIONS_CBT.
    1155             :          *
    1156             :          * See:
    1157             :          * https://github.com/heimdal/heimdal/pull/1234
    1158             :          * https://github.com/krb5/krb5/pull/1329
    1159             :          */
    1160        1780 :         if (!(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL)) {
    1161        1780 :                 want_flags |= GSS_C_CHANNEL_BOUND_FLAG;
    1162             :         }
    1163             : #endif
    1164             : 
    1165        2776 :         nt_status = gse_init_client(gensec_security,
    1166             :                                     do_sign,
    1167             :                                     do_seal,
    1168             :                                     ccache_name,
    1169             :                                     gss_mech_krb5,
    1170             :                                     want_flags,
    1171             :                                     &gse_ctx);
    1172        2776 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1173           0 :                 return nt_status;
    1174             :         }
    1175        2776 :         gensec_security->private_data = gse_ctx;
    1176        2776 :         return NT_STATUS_OK;
    1177             : }
    1178             : 
    1179        3563 : static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security)
    1180             : {
    1181           0 :         struct gse_context *gse_ctx;
    1182           0 :         NTSTATUS nt_status;
    1183        3563 :         OM_uint32 want_flags = 0;
    1184        3563 :         bool do_sign = false, do_seal = false;
    1185             : 
    1186        3563 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
    1187          18 :                 do_sign = true;
    1188             :         }
    1189        3563 :         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
    1190          18 :                 do_seal = true;
    1191             :         }
    1192        3563 :         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
    1193         115 :                 want_flags |= GSS_C_DCE_STYLE;
    1194             :         }
    1195             : 
    1196        3563 :         nt_status = gse_init_server(gensec_security,
    1197             :                                     do_sign,
    1198             :                                     do_seal,
    1199             :                                     gss_mech_krb5,
    1200             :                                     want_flags,
    1201             :                                     &gse_ctx);
    1202        3563 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1203          10 :                 return nt_status;
    1204             :         }
    1205        3553 :         gensec_security->private_data = gse_ctx;
    1206        3553 :         return NT_STATUS_OK;
    1207             : }
    1208             : 
    1209             : struct gensec_gse_update_state {
    1210             :         NTSTATUS status;
    1211             :         DATA_BLOB out;
    1212             : };
    1213             : 
    1214             : static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
    1215             :                                            TALLOC_CTX *mem_ctx,
    1216             :                                            const DATA_BLOB in,
    1217             :                                            DATA_BLOB *out);
    1218             : 
    1219        6542 : static struct tevent_req *gensec_gse_update_send(TALLOC_CTX *mem_ctx,
    1220             :                                                  struct tevent_context *ev,
    1221             :                                                  struct gensec_security *gensec_security,
    1222             :                                                  const DATA_BLOB in)
    1223             : {
    1224        6542 :         struct tevent_req *req = NULL;
    1225        6542 :         struct gensec_gse_update_state *state = NULL;
    1226           0 :         NTSTATUS status;
    1227             : 
    1228        6542 :         req = tevent_req_create(mem_ctx, &state,
    1229             :                                 struct gensec_gse_update_state);
    1230        6542 :         if (req == NULL) {
    1231           0 :                 return NULL;
    1232             :         }
    1233             : 
    1234        6542 :         status = gensec_gse_update_internal(gensec_security,
    1235             :                                             state, in,
    1236        6542 :                                             &state->out);
    1237        6542 :         state->status = status;
    1238        6542 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
    1239        2887 :                 tevent_req_done(req);
    1240        2887 :                 return tevent_req_post(req, ev);
    1241             :         }
    1242        3655 :         if (tevent_req_nterror(req, status)) {
    1243           4 :                 return tevent_req_post(req, ev);
    1244             :         }
    1245             : 
    1246        3651 :         tevent_req_done(req);
    1247        3651 :         return tevent_req_post(req, ev);
    1248             : }
    1249             : 
    1250        6542 : static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security,
    1251             :                                            TALLOC_CTX *mem_ctx,
    1252             :                                            const DATA_BLOB in,
    1253             :                                            DATA_BLOB *out)
    1254             : {
    1255           0 :         NTSTATUS status;
    1256             : 
    1257        6542 :         switch (gensec_security->gensec_role) {
    1258        5531 :         case GENSEC_CLIENT:
    1259        5531 :                 status = gse_get_client_auth_token(mem_ctx,
    1260             :                                                    gensec_security,
    1261             :                                                    &in, out);
    1262        5531 :                 break;
    1263        1011 :         case GENSEC_SERVER:
    1264        1011 :                 status = gse_get_server_auth_token(mem_ctx,
    1265             :                                                    gensec_security,
    1266             :                                                    &in, out);
    1267        1011 :                 break;
    1268             :         }
    1269        6542 :         if (!NT_STATUS_IS_OK(status)) {
    1270        2891 :                 return status;
    1271             :         }
    1272             : 
    1273        3651 :         return NT_STATUS_OK;
    1274             : }
    1275             : 
    1276        6542 : static NTSTATUS gensec_gse_update_recv(struct tevent_req *req,
    1277             :                                        TALLOC_CTX *out_mem_ctx,
    1278             :                                        DATA_BLOB *out)
    1279             : {
    1280           0 :         struct gensec_gse_update_state *state =
    1281        6542 :                 tevent_req_data(req,
    1282             :                 struct gensec_gse_update_state);
    1283           0 :         NTSTATUS status;
    1284             : 
    1285        6542 :         *out = data_blob_null;
    1286             : 
    1287        6542 :         if (tevent_req_is_nterror(req, &status)) {
    1288           4 :                 tevent_req_received(req);
    1289           4 :                 return status;
    1290             :         }
    1291             : 
    1292        6538 :         *out = state->out;
    1293        6538 :         talloc_steal(out_mem_ctx, state->out.data);
    1294        6538 :         status = state->status;
    1295        6538 :         tevent_req_received(req);
    1296        6538 :         return status;
    1297             : }
    1298             : 
    1299        1572 : static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security,
    1300             :                                 TALLOC_CTX *mem_ctx,
    1301             :                                 const DATA_BLOB *in,
    1302             :                                 DATA_BLOB *out)
    1303             : {
    1304           0 :         struct gse_context *gse_ctx =
    1305        1572 :                 talloc_get_type_abort(gensec_security->private_data,
    1306             :                 struct gse_context);
    1307           0 :         OM_uint32 maj_stat, min_stat;
    1308           0 :         gss_buffer_desc input_token, output_token;
    1309           0 :         int conf_state;
    1310        1572 :         input_token.length = in->length;
    1311        1572 :         input_token.value = in->data;
    1312             : 
    1313        1572 :         maj_stat = gss_wrap(&min_stat,
    1314         814 :                             gse_ctx->gssapi_context,
    1315        1572 :                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
    1316             :                             GSS_C_QOP_DEFAULT,
    1317             :                             &input_token,
    1318             :                             &conf_state,
    1319             :                             &output_token);
    1320        1572 :         if (GSS_ERROR(maj_stat)) {
    1321           0 :                 DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n",
    1322             :                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
    1323           0 :                 return NT_STATUS_ACCESS_DENIED;
    1324             :         }
    1325             : 
    1326        1572 :         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
    1327        1572 :         gss_release_buffer(&min_stat, &output_token);
    1328             : 
    1329        1572 :         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
    1330        1572 :             && !conf_state) {
    1331           0 :                 return NT_STATUS_ACCESS_DENIED;
    1332             :         }
    1333        1572 :         return NT_STATUS_OK;
    1334             : }
    1335             : 
    1336        1272 : static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security,
    1337             :                                      TALLOC_CTX *mem_ctx,
    1338             :                                      const DATA_BLOB *in,
    1339             :                                      DATA_BLOB *out)
    1340             : {
    1341           0 :         struct gse_context *gse_ctx =
    1342        1272 :                 talloc_get_type_abort(gensec_security->private_data,
    1343             :                 struct gse_context);
    1344           0 :         OM_uint32 maj_stat, min_stat;
    1345           0 :         gss_buffer_desc input_token, output_token;
    1346           0 :         int conf_state;
    1347           0 :         gss_qop_t qop_state;
    1348        1272 :         input_token.length = in->length;
    1349        1272 :         input_token.value = in->data;
    1350             : 
    1351        1272 :         maj_stat = gss_unwrap(&min_stat,
    1352         660 :                               gse_ctx->gssapi_context,
    1353             :                               &input_token,
    1354             :                               &output_token,
    1355             :                               &conf_state,
    1356             :                               &qop_state);
    1357        1272 :         if (GSS_ERROR(maj_stat)) {
    1358           0 :                 DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n",
    1359             :                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
    1360           0 :                 return NT_STATUS_ACCESS_DENIED;
    1361             :         }
    1362             : 
    1363        1272 :         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
    1364        1272 :         gss_release_buffer(&min_stat, &output_token);
    1365             : 
    1366        1272 :         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
    1367        1272 :             && !conf_state) {
    1368           0 :                 return NT_STATUS_ACCESS_DENIED;
    1369             :         }
    1370        1272 :         return NT_STATUS_OK;
    1371             : }
    1372             : 
    1373          24 : static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
    1374             :                                        TALLOC_CTX *mem_ctx,
    1375             :                                        uint8_t *data, size_t length,
    1376             :                                        const uint8_t *whole_pdu, size_t pdu_length,
    1377             :                                        DATA_BLOB *sig)
    1378             : {
    1379           0 :         struct gse_context *gse_ctx =
    1380          24 :                 talloc_get_type_abort(gensec_security->private_data,
    1381             :                 struct gse_context);
    1382          24 :         bool hdr_signing = false;
    1383          24 :         size_t sig_size = 0;
    1384           0 :         NTSTATUS status;
    1385             : 
    1386          24 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1387          24 :                 hdr_signing = true;
    1388             :         }
    1389             : 
    1390          24 :         sig_size = gensec_gse_sig_size(gensec_security, length);
    1391             : 
    1392          24 :         status = gssapi_seal_packet(gse_ctx->gssapi_context,
    1393          24 :                                     &gse_ctx->gss_mech,
    1394             :                                     hdr_signing, sig_size,
    1395             :                                     data, length,
    1396             :                                     whole_pdu, pdu_length,
    1397             :                                     mem_ctx, sig);
    1398          24 :         if (!NT_STATUS_IS_OK(status)) {
    1399           0 :                 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
    1400             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1401             :                           hdr_signing, sig_size, length, pdu_length,
    1402             :                           nt_errstr(status)));
    1403           0 :                 return status;
    1404             :         }
    1405             : 
    1406          24 :         return NT_STATUS_OK;
    1407             : }
    1408             : 
    1409          24 : static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
    1410             :                                          uint8_t *data, size_t length,
    1411             :                                          const uint8_t *whole_pdu, size_t pdu_length,
    1412             :                                          const DATA_BLOB *sig)
    1413             : {
    1414           0 :         struct gse_context *gse_ctx =
    1415          24 :                 talloc_get_type_abort(gensec_security->private_data,
    1416             :                 struct gse_context);
    1417          24 :         bool hdr_signing = false;
    1418           0 :         NTSTATUS status;
    1419             : 
    1420          24 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1421          24 :                 hdr_signing = true;
    1422             :         }
    1423             : 
    1424          24 :         status = gssapi_unseal_packet(gse_ctx->gssapi_context,
    1425          24 :                                       &gse_ctx->gss_mech,
    1426             :                                       hdr_signing,
    1427             :                                       data, length,
    1428             :                                       whole_pdu, pdu_length,
    1429             :                                       sig);
    1430          24 :         if (!NT_STATUS_IS_OK(status)) {
    1431           0 :                 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
    1432             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1433             :                           hdr_signing, sig->length, length, pdu_length,
    1434             :                           nt_errstr(status)));
    1435           0 :                 return status;
    1436             :         }
    1437             : 
    1438          24 :         return NT_STATUS_OK;
    1439             : }
    1440             : 
    1441         287 : static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
    1442             :                                        TALLOC_CTX *mem_ctx,
    1443             :                                        const uint8_t *data, size_t length,
    1444             :                                        const uint8_t *whole_pdu, size_t pdu_length,
    1445             :                                        DATA_BLOB *sig)
    1446             : {
    1447           0 :         struct gse_context *gse_ctx =
    1448         287 :                 talloc_get_type_abort(gensec_security->private_data,
    1449             :                 struct gse_context);
    1450         287 :         bool hdr_signing = false;
    1451           0 :         NTSTATUS status;
    1452             : 
    1453         287 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1454         122 :                 hdr_signing = true;
    1455             :         }
    1456             : 
    1457         287 :         status = gssapi_sign_packet(gse_ctx->gssapi_context,
    1458         287 :                                     &gse_ctx->gss_mech,
    1459             :                                     hdr_signing,
    1460             :                                     data, length,
    1461             :                                     whole_pdu, pdu_length,
    1462             :                                     mem_ctx, sig);
    1463         287 :         if (!NT_STATUS_IS_OK(status)) {
    1464           0 :                 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
    1465             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1466             :                           hdr_signing, length, pdu_length,
    1467             :                           nt_errstr(status)));
    1468           0 :                 return status;
    1469             :         }
    1470             : 
    1471         287 :         return NT_STATUS_OK;
    1472             : }
    1473             : 
    1474         254 : static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
    1475             :                                         const uint8_t *data, size_t length,
    1476             :                                         const uint8_t *whole_pdu, size_t pdu_length,
    1477             :                                         const DATA_BLOB *sig)
    1478             : {
    1479           0 :         struct gse_context *gse_ctx =
    1480         254 :                 talloc_get_type_abort(gensec_security->private_data,
    1481             :                 struct gse_context);
    1482         254 :         bool hdr_signing = false;
    1483           0 :         NTSTATUS status;
    1484             : 
    1485         254 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1486         136 :                 hdr_signing = true;
    1487             :         }
    1488             : 
    1489         254 :         status = gssapi_check_packet(gse_ctx->gssapi_context,
    1490         254 :                                      &gse_ctx->gss_mech,
    1491             :                                      hdr_signing,
    1492             :                                      data, length,
    1493             :                                      whole_pdu, pdu_length,
    1494             :                                      sig);
    1495         254 :         if (!NT_STATUS_IS_OK(status)) {
    1496           8 :                 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu"
    1497             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1498             :                           hdr_signing, sig->length, length, pdu_length,
    1499             :                           nt_errstr(status)));
    1500           8 :                 return status;
    1501             :         }
    1502             : 
    1503         246 :         return NT_STATUS_OK;
    1504             : }
    1505             : 
    1506             : /* Try to figure out what features we actually got on the connection */
    1507       19904 : static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
    1508             :                                     uint32_t feature)
    1509             : {
    1510           0 :         struct gse_context *gse_ctx =
    1511       19904 :                 talloc_get_type_abort(gensec_security->private_data,
    1512             :                 struct gse_context);
    1513             : 
    1514       19904 :         if (feature & GENSEC_FEATURE_SESSION_KEY) {
    1515        4666 :                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
    1516             :         }
    1517       15238 :         if (feature & GENSEC_FEATURE_SIGN) {
    1518        5790 :                 return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG;
    1519             :         }
    1520        9448 :         if (feature & GENSEC_FEATURE_SEAL) {
    1521        6263 :                 return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG;
    1522             :         }
    1523        3185 :         if (feature & GENSEC_FEATURE_DCE_STYLE) {
    1524         126 :                 return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE;
    1525             :         }
    1526        3059 :         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
    1527           0 :                 NTSTATUS status;
    1528           0 :                 uint32_t keytype;
    1529             : 
    1530        2759 :                 if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) {
    1531          42 :                         return false;
    1532             :                 }
    1533             : 
    1534        2717 :                 status = gssapi_get_session_key(talloc_tos(),
    1535             :                                                 gse_ctx->gssapi_context, NULL, &keytype);
    1536             :                 /*
    1537             :                  * We should do a proper sig on the mechListMic unless
    1538             :                  * we know we have to be backwards compatible with
    1539             :                  * earlier windows versions.
    1540             :                  *
    1541             :                  * Negotiating a non-krb5
    1542             :                  * mech for example should be regarded as having
    1543             :                  * NEW_SPNEGO
    1544             :                  */
    1545        2717 :                 if (NT_STATUS_IS_OK(status)) {
    1546        2717 :                         switch (keytype) {
    1547          61 :                         case ENCTYPE_DES_CBC_CRC:
    1548             :                         case ENCTYPE_DES_CBC_MD5:
    1549             :                         case ENCTYPE_ARCFOUR_HMAC:
    1550             :                         case ENCTYPE_DES3_CBC_SHA1:
    1551          61 :                                 return false;
    1552             :                         }
    1553             :                 }
    1554        2656 :                 return true;
    1555             :         }
    1556             :         /* We can always do async (rather than strict request/reply) packets.  */
    1557         300 :         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
    1558         171 :                 return true;
    1559             :         }
    1560         129 :         if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1561         129 :                 return true;
    1562             :         }
    1563           0 :         return false;
    1564             : }
    1565             : 
    1566        1065 : static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security)
    1567             : {
    1568           0 :         struct gse_context *gse_ctx =
    1569        1065 :                 talloc_get_type_abort(gensec_security->private_data,
    1570             :                 struct gse_context);
    1571             : 
    1572        1065 :         return gse_ctx->expire_time;
    1573             : }
    1574             : 
    1575             : /*
    1576             :  * Extract the 'session key' needed by SMB signing and ncacn_np
    1577             :  * (for encrypting some passwords).
    1578             :  *
    1579             :  * This breaks all the abstractions, but what do you expect...
    1580             :  */
    1581        3211 : static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
    1582             :                                        TALLOC_CTX *mem_ctx,
    1583             :                                        DATA_BLOB *session_key)
    1584             : {
    1585           0 :         struct gse_context *gse_ctx =
    1586        3211 :                 talloc_get_type_abort(gensec_security->private_data,
    1587             :                 struct gse_context);
    1588             : 
    1589        3211 :         return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
    1590             : }
    1591             : 
    1592             : /* Get some basic (and authorization) information about the user on
    1593             :  * this session.  This uses either the PAC (if present) or a local
    1594             :  * database lookup */
    1595         892 : static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security,
    1596             :                                         TALLOC_CTX *mem_ctx,
    1597             :                                         struct auth_session_info **_session_info)
    1598             : {
    1599           0 :         struct gse_context *gse_ctx =
    1600         892 :                 talloc_get_type_abort(gensec_security->private_data,
    1601             :                 struct gse_context);
    1602           0 :         NTSTATUS nt_status;
    1603           0 :         TALLOC_CTX *tmp_ctx;
    1604         892 :         struct auth_session_info *session_info = NULL;
    1605           0 :         OM_uint32 maj_stat, min_stat;
    1606         892 :         DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
    1607             : 
    1608           0 :         gss_buffer_desc name_token;
    1609           0 :         char *principal_string;
    1610             : 
    1611         892 :         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context");
    1612         892 :         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
    1613             : 
    1614         892 :         maj_stat = gss_display_name(&min_stat,
    1615         468 :                                     gse_ctx->client_name,
    1616             :                                     &name_token,
    1617             :                                     NULL);
    1618         892 :         if (GSS_ERROR(maj_stat)) {
    1619           0 :                 DEBUG(1, ("GSS display_name failed: %s\n",
    1620             :                           gse_errstr(talloc_tos(), maj_stat, min_stat)));
    1621           0 :                 talloc_free(tmp_ctx);
    1622           0 :                 return NT_STATUS_FOOBAR;
    1623             :         }
    1624             : 
    1625         892 :         principal_string = talloc_strndup(tmp_ctx,
    1626         892 :                                           (const char *)name_token.value,
    1627             :                                           name_token.length);
    1628             : 
    1629         892 :         gss_release_buffer(&min_stat, &name_token);
    1630             : 
    1631         892 :         if (!principal_string) {
    1632           0 :                 talloc_free(tmp_ctx);
    1633           0 :                 return NT_STATUS_NO_MEMORY;
    1634             :         }
    1635             : 
    1636         892 :         nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gse_ctx->gssapi_context,
    1637             :                                            gse_ctx->client_name,
    1638             :                                            &pac_blob);
    1639             : 
    1640             :         /* IF we have the PAC - otherwise we need to get this
    1641             :          * data from elsewhere
    1642             :          */
    1643         892 :         if (NT_STATUS_IS_OK(nt_status)) {
    1644         884 :                 pac_blob_ptr = &pac_blob;
    1645             :         }
    1646         892 :         nt_status = gensec_generate_session_info_pac(tmp_ctx,
    1647             :                                                      gensec_security,
    1648             :                                                      NULL,
    1649             :                                                      pac_blob_ptr, principal_string,
    1650             :                                                      gensec_get_remote_address(gensec_security),
    1651             :                                                      &session_info);
    1652         892 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1653          14 :                 talloc_free(tmp_ctx);
    1654          14 :                 return nt_status;
    1655             :         }
    1656             : 
    1657         878 :         nt_status = gensec_gse_session_key(gensec_security, session_info,
    1658         878 :                                            &session_info->session_key);
    1659         878 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1660           0 :                 talloc_free(tmp_ctx);
    1661           0 :                 return nt_status;
    1662             :         }
    1663             : 
    1664         878 :         *_session_info = talloc_move(mem_ctx, &session_info);
    1665         878 :         talloc_free(tmp_ctx);
    1666             : 
    1667         878 :         return NT_STATUS_OK;
    1668             : }
    1669             : 
    1670         300 : static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security)
    1671             : {
    1672           0 :         struct gse_context *gse_ctx =
    1673         300 :                 talloc_get_type_abort(gensec_security->private_data,
    1674             :                 struct gse_context);
    1675           0 :         OM_uint32 maj_stat, min_stat;
    1676           0 :         OM_uint32 max_input_size;
    1677             : 
    1678         454 :         maj_stat = gss_wrap_size_limit(&min_stat,
    1679         154 :                                        gse_ctx->gssapi_context,
    1680         300 :                                        gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
    1681             :                                        GSS_C_QOP_DEFAULT,
    1682         300 :                                        gse_ctx->max_wrap_buf_size,
    1683             :                                        &max_input_size);
    1684         300 :         if (GSS_ERROR(maj_stat)) {
    1685           0 :                 TALLOC_CTX *mem_ctx = talloc_new(NULL);
    1686           0 :                 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
    1687             :                           gse_errstr(mem_ctx, maj_stat, min_stat)));
    1688           0 :                 talloc_free(mem_ctx);
    1689           0 :                 return 0;
    1690             :         }
    1691             : 
    1692         300 :         return max_input_size;
    1693             : }
    1694             : 
    1695             : /* Find out the maximum output size negotiated on this connection */
    1696         300 : static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security)
    1697             : {
    1698           0 :         struct gse_context *gse_ctx =
    1699         300 :                 talloc_get_type_abort(gensec_security->private_data,
    1700             :                 struct gse_context);
    1701         300 :         return gse_ctx->max_wrap_buf_size;
    1702             : }
    1703             : 
    1704         186 : static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
    1705             :                                   size_t data_size)
    1706             : {
    1707           0 :         struct gse_context *gse_ctx =
    1708         186 :                 talloc_get_type_abort(gensec_security->private_data,
    1709             :                 struct gse_context);
    1710             : 
    1711         186 :         if (gse_ctx->sig_size > 0) {
    1712          82 :                 return gse_ctx->sig_size;
    1713             :         }
    1714             : 
    1715         208 :         gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
    1716         104 :                                                 &gse_ctx->gss_mech,
    1717             :                                                 gse_ctx->gss_got_flags,
    1718             :                                                 data_size);
    1719         104 :         return gse_ctx->sig_size;
    1720             : }
    1721             : 
    1722         872 : static const char *gensec_gse_final_auth_type(struct gensec_security *gensec_security)
    1723             : {
    1724           0 :         struct gse_context *gse_ctx =
    1725         872 :                 talloc_get_type_abort(gensec_security->private_data,
    1726             :                 struct gse_context);
    1727             : 
    1728             :         /* Only return the string for GSSAPI/Krb5 */
    1729         872 :         if (smb_gss_oid_equal(&gse_ctx->gss_mech,
    1730             :                               gss_mech_krb5)) {
    1731         872 :                 return GENSEC_FINAL_AUTH_TYPE_KRB5;
    1732             :         } else {
    1733           0 :                 return "gensec_gse: UNKNOWN MECH";
    1734             :         }
    1735             : }
    1736             : 
    1737             : static const char *gensec_gse_krb5_oids[] = {
    1738             :         GENSEC_OID_KERBEROS5_OLD,
    1739             :         GENSEC_OID_KERBEROS5,
    1740             :         NULL
    1741             : };
    1742             : 
    1743             : static const struct gensec_security_ops gensec_gse_krb5_security_ops = {
    1744             :         .name           = "gse_krb5",
    1745             :         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
    1746             :         .oid            = gensec_gse_krb5_oids,
    1747             :         .client_start   = gensec_gse_client_start,
    1748             :         .server_start   = gensec_gse_server_start,
    1749             :         .magic          = gensec_magic_check_krb5_oid,
    1750             :         .update_send    = gensec_gse_update_send,
    1751             :         .update_recv    = gensec_gse_update_recv,
    1752             :         .session_key    = gensec_gse_session_key,
    1753             :         .session_info   = gensec_gse_session_info,
    1754             :         .sig_size       = gensec_gse_sig_size,
    1755             :         .sign_packet    = gensec_gse_sign_packet,
    1756             :         .check_packet   = gensec_gse_check_packet,
    1757             :         .seal_packet    = gensec_gse_seal_packet,
    1758             :         .unseal_packet  = gensec_gse_unseal_packet,
    1759             :         .max_input_size   = gensec_gse_max_input_size,
    1760             :         .max_wrapped_size = gensec_gse_max_wrapped_size,
    1761             :         .wrap           = gensec_gse_wrap,
    1762             :         .unwrap         = gensec_gse_unwrap,
    1763             :         .have_feature   = gensec_gse_have_feature,
    1764             :         .expire_time    = gensec_gse_expire_time,
    1765             :         .final_auth_type  = gensec_gse_final_auth_type,
    1766             :         .enabled        = true,
    1767             :         .kerberos       = true,
    1768             :         .priority       = GENSEC_GSSAPI
    1769             : };
    1770             : 
    1771      120652 : const struct gensec_security_ops *gensec_gse_security_by_oid(
    1772             :         const char *oid_string)
    1773             : {
    1774           0 :         int cmp;
    1775             : 
    1776      120652 :         cmp = strcmp(oid_string, GENSEC_OID_KERBEROS5);
    1777      120652 :         if (cmp == 0) {
    1778      120652 :                 return &gensec_gse_krb5_security_ops;
    1779             :         }
    1780             : 
    1781           0 :         return NULL;
    1782             : }
    1783             : #endif /* HAVE_KRB5 */

Generated by: LCOV version 1.14