LCOV - code coverage report
Current view: top level - source4/auth/gensec - gensec_gssapi.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 611 790 77.3 %
Date: 2024-01-11 09:59:51 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Kerberos backend for GENSEC
       5             :    
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       7             :    Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include <tevent.h>
      26             : #include "lib/util/tevent_ntstatus.h"
      27             : #include "lib/events/events.h"
      28             : #include "system/kerberos.h"
      29             : #include "system/gssapi.h"
      30             : #include "auth/kerberos/kerberos.h"
      31             : #include "librpc/gen_ndr/krb5pac.h"
      32             : #include "auth/auth.h"
      33             : #include <ldb.h>
      34             : #include "auth/auth_sam.h"
      35             : #include "librpc/gen_ndr/dcerpc.h"
      36             : #include "auth/credentials/credentials.h"
      37             : #include "auth/credentials/credentials_krb5.h"
      38             : #include "auth/gensec/gensec.h"
      39             : #include "auth/gensec/gensec_internal.h"
      40             : #include "auth/gensec/gensec_proto.h"
      41             : #include "auth/gensec/gensec_toplevel_proto.h"
      42             : #include "param/param.h"
      43             : #include "auth/session_proto.h"
      44             : #include "gensec_gssapi.h"
      45             : #include "lib/util/util_net.h"
      46             : #include "auth/kerberos/pac_utils.h"
      47             : #include "auth/kerberos/gssapi_helper.h"
      48             : #include "lib/util/smb_strtox.h"
      49             : 
      50             : #ifndef gss_mech_spnego
      51             : gss_OID_desc spnego_mech_oid_desc =
      52             :                 { 6, discard_const_p(void, "\x2b\x06\x01\x05\x05\x02") };
      53             : #define gss_mech_spnego (&spnego_mech_oid_desc)
      54             : #endif
      55             : 
      56             : _PUBLIC_ NTSTATUS gensec_gssapi_init(TALLOC_CTX *);
      57             : 
      58             : static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
      59             : static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
      60             : static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size);
      61             : 
      62       79982 : static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
      63             : {
      64        3187 :         OM_uint32 min_stat;
      65             : 
      66       79982 :         if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
      67          88 :                 gss_release_cred(&min_stat,
      68             :                                  &gensec_gssapi_state->delegated_cred_handle);
      69             :         }
      70             : 
      71       79982 :         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
      72       61463 :                 gss_delete_sec_context(&min_stat,
      73             :                                        &gensec_gssapi_state->gssapi_context,
      74             :                                        GSS_C_NO_BUFFER);
      75             :         }
      76             : 
      77       79982 :         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
      78       30027 :                 gss_release_name(&min_stat,
      79             :                                  &gensec_gssapi_state->server_name);
      80             :         }
      81       79982 :         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
      82       31461 :                 gss_release_name(&min_stat,
      83             :                                  &gensec_gssapi_state->client_name);
      84             :         }
      85             : 
      86       79982 :         return 0;
      87             : }
      88             : 
      89       30085 : static NTSTATUS gensec_gssapi_setup_server_principal(TALLOC_CTX *mem_ctx,
      90             :                                                      const char *target_principal,
      91             :                                                      const char *service,
      92             :                                                      const char *hostname,
      93             :                                                      const char *realm,
      94             :                                                      const gss_OID mech,
      95             :                                                      char **pserver_principal,
      96             :                                                      gss_name_t *pserver_name)
      97             : {
      98       30085 :         char *server_principal = NULL;
      99        1035 :         gss_buffer_desc name_token;
     100        1035 :         gss_OID name_type;
     101       30085 :         OM_uint32 maj_stat, min_stat = 0;
     102             : 
     103       30085 :         if (target_principal != NULL) {
     104         219 :                 server_principal = talloc_strdup(mem_ctx, target_principal);
     105         219 :                 name_type = GSS_C_NULL_OID;
     106             :         } else {
     107       29866 :                 server_principal = talloc_asprintf(mem_ctx,
     108             :                                                    "%s/%s@%s",
     109             :                                                    service, hostname, realm);
     110       29866 :                 name_type = GSS_C_NT_USER_NAME;
     111             :         }
     112       30085 :         if (server_principal == NULL) {
     113           0 :                 return NT_STATUS_NO_MEMORY;
     114             :         }
     115             : 
     116       30085 :         name_token.value = (uint8_t *)server_principal;
     117       30085 :         name_token.length = strlen(server_principal);
     118             : 
     119       30085 :         maj_stat = gss_import_name(&min_stat,
     120             :                                    &name_token,
     121             :                                    name_type,
     122             :                                    pserver_name);
     123       30085 :         if (maj_stat) {
     124           0 :                 DBG_WARNING("GSS Import name of %s failed: %s\n",
     125             :                             server_principal,
     126             :                             gssapi_error_string(mem_ctx,
     127             :                                                 maj_stat,
     128             :                                                 min_stat,
     129             :                                                 mech));
     130           0 :                 TALLOC_FREE(server_principal);
     131           0 :                 return NT_STATUS_INVALID_PARAMETER;
     132             :         }
     133             : 
     134       30085 :         *pserver_principal = server_principal;
     135             : 
     136       30085 :         return NT_STATUS_OK;
     137             : }
     138             : 
     139       80002 : static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
     140             : {
     141        3192 :         struct gensec_gssapi_state *gensec_gssapi_state;
     142        3192 :         krb5_error_code ret;
     143             : #ifdef SAMBA4_USES_HEIMDAL
     144        3192 :         const char *realm;
     145             : #endif
     146             : 
     147       80002 :         gensec_gssapi_state = talloc_zero(gensec_security, struct gensec_gssapi_state);
     148       80002 :         if (!gensec_gssapi_state) {
     149           0 :                 return NT_STATUS_NO_MEMORY;
     150             :         }
     151             : 
     152       80002 :         gensec_security->private_data = gensec_gssapi_state;
     153             : 
     154       80002 :         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
     155             : 
     156             :         /* TODO: Fill in channel bindings */
     157       80002 :         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
     158             : 
     159       80002 :         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
     160       80002 :         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
     161             :         
     162       80002 :         gensec_gssapi_state->gss_want_flags = 0;
     163       80002 :         gensec_gssapi_state->expire_time = GENSEC_EXPIRE_TIME_INFINITY;
     164             : 
     165       80002 :         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation_by_kdc_policy", true)) {
     166       80002 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_POLICY_FLAG;
     167             :         }
     168       80002 :         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "mutual", true)) {
     169       80002 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_MUTUAL_FLAG;
     170             :         }
     171       80002 :         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "delegation", false)) {
     172           0 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_DELEG_FLAG;
     173             :         }
     174       80002 :         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "replay", true)) {
     175       80002 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_REPLAY_FLAG;
     176             :         }
     177       80002 :         if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "sequence", true)) {
     178       80002 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_SEQUENCE_FLAG;
     179             :         }
     180             : 
     181       80002 :         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
     182       33980 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG;
     183             :         }
     184       80002 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
     185       24296 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG;
     186             :         }
     187       80002 :         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
     188       22903 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_INTEG_FLAG;
     189       22903 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_CONF_FLAG;
     190             :         }
     191       80002 :         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
     192        8763 :                 gensec_gssapi_state->gss_want_flags |= GSS_C_DCE_STYLE;
     193             :         }
     194             : 
     195       80002 :         gensec_gssapi_state->gss_got_flags = 0;
     196             : 
     197       80002 :         switch (gensec_security->ops->auth_type) {
     198           0 :         case DCERPC_AUTH_TYPE_SPNEGO:
     199           0 :                 gensec_gssapi_state->gss_oid = gss_mech_spnego;
     200           0 :                 break;
     201       80002 :         case DCERPC_AUTH_TYPE_KRB5:
     202             :         default:
     203       80002 :                 gensec_gssapi_state->gss_oid =
     204             :                         discard_const_p(void, gss_mech_krb5);
     205       80002 :                 break;
     206             :         }
     207             : 
     208       83194 :         ret = smb_krb5_init_context(gensec_gssapi_state,
     209       80002 :                                     gensec_security->settings->lp_ctx,
     210             :                                     &gensec_gssapi_state->smb_krb5_context);
     211       80002 :         if (ret) {
     212           0 :                 DEBUG(1,("gensec_gssapi_start: smb_krb5_init_context failed (%s)\n",
     213             :                          error_message(ret)));
     214           0 :                 talloc_free(gensec_gssapi_state);
     215           0 :                 return NT_STATUS_INTERNAL_ERROR;
     216             :         }
     217             : 
     218       80002 :         gensec_gssapi_state->client_cred = NULL;
     219       80002 :         gensec_gssapi_state->server_cred = NULL;
     220             : 
     221       80002 :         gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
     222             : 
     223       80002 :         gensec_gssapi_state->sasl = false;
     224       80002 :         gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
     225       80002 :         gensec_gssapi_state->sasl_protection = 0;
     226             : 
     227        3192 :         gensec_gssapi_state->max_wrap_buf_size
     228       80002 :                 = gensec_setting_int(gensec_security->settings, "gensec_gssapi", "max wrap buf size", 65536);
     229       80002 :         gensec_gssapi_state->gss_exchange_count = 0;
     230       80002 :         gensec_gssapi_state->sig_size = 0;
     231             : 
     232       80002 :         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destructor);
     233             : 
     234             : #ifdef SAMBA4_USES_HEIMDAL
     235       58745 :         realm = lpcfg_realm(gensec_security->settings->lp_ctx);
     236       58745 :         if (realm != NULL) {
     237       58745 :                 ret = gsskrb5_set_default_realm(realm);
     238       58745 :                 if (ret) {
     239           0 :                         DEBUG(1,("gensec_gssapi_start: gsskrb5_set_default_realm failed\n"));
     240           0 :                         talloc_free(gensec_gssapi_state);
     241           0 :                         return NT_STATUS_INTERNAL_ERROR;
     242             :                 }
     243             :         }
     244             : 
     245             :         /* don't do DNS lookups of any kind, it might/will fail for a netbios name */
     246       58745 :         ret = gsskrb5_set_dns_canonicalize(false);
     247       58745 :         if (ret) {
     248           0 :                 DEBUG(1,("gensec_gssapi_start: gsskrb5_set_dns_canonicalize failed\n"));
     249           0 :                 talloc_free(gensec_gssapi_state);
     250           0 :                 return NT_STATUS_INTERNAL_ERROR;
     251             :         }
     252             : #endif
     253       80002 :         return NT_STATUS_OK;
     254             : }
     255             : 
     256       48556 : static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
     257             : {
     258        2157 :         NTSTATUS nt_status;
     259        2157 :         int ret;
     260        2157 :         struct gensec_gssapi_state *gensec_gssapi_state;
     261        2157 :         struct cli_credentials *machine_account;
     262        2157 :         struct gssapi_creds_container *gcc;
     263             : 
     264       48556 :         nt_status = gensec_gssapi_start(gensec_security);
     265       48556 :         if (!NT_STATUS_IS_OK(nt_status)) {
     266           0 :                 return nt_status;
     267             :         }
     268             : 
     269       48556 :         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     270             : 
     271       48556 :         machine_account = gensec_get_credentials(gensec_security);
     272             :         
     273       48556 :         if (!machine_account) {
     274           0 :                 DEBUG(3, ("No machine account credentials specified\n"));
     275           0 :                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
     276             :         } else {
     277       50713 :                 ret = cli_credentials_get_server_gss_creds(machine_account, 
     278       48556 :                                                            gensec_security->settings->lp_ctx, &gcc);
     279       48556 :                 if (ret) {
     280           0 :                         DEBUG(1, ("Acquiring acceptor credentials failed: %s\n",
     281             :                                   error_message(ret)));
     282           0 :                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
     283             :                 }
     284             :         }
     285             : 
     286       48556 :         gensec_gssapi_state->server_cred = gcc;
     287       48556 :         return NT_STATUS_OK;
     288             : 
     289             : }
     290             : 
     291         121 : static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_security)
     292             : {
     293           0 :         NTSTATUS nt_status;
     294           0 :         struct gensec_gssapi_state *gensec_gssapi_state;
     295         121 :         nt_status = gensec_gssapi_server_start(gensec_security);
     296             : 
     297         121 :         if (NT_STATUS_IS_OK(nt_status)) {
     298         121 :                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     299         121 :                 gensec_gssapi_state->sasl = true;
     300             :         }
     301         121 :         return nt_status;
     302             : }
     303             : 
     304       60585 : static NTSTATUS gensec_gssapi_client_creds(struct gensec_security *gensec_security,
     305             :                                            struct tevent_context *ev)
     306             : {
     307        1915 :         struct gensec_gssapi_state *gensec_gssapi_state;
     308        1915 :         struct gssapi_creds_container *gcc;
     309       60585 :         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
     310        1915 :         const char *error_string;
     311        1915 :         int ret;
     312             : 
     313       60585 :         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     314             : 
     315             :         /* Only run this the first time the update() call is made */
     316       60585 :         if (gensec_gssapi_state->client_cred) {
     317       29139 :                 return NT_STATUS_OK;
     318             :         }
     319             : 
     320       32481 :         ret = cli_credentials_get_client_gss_creds(creds,
     321             :                                                    ev,
     322       31446 :                                                    gensec_security->settings->lp_ctx, &gcc, &error_string);
     323       31446 :         switch (ret) {
     324       29044 :         case 0:
     325       30079 :                 break;
     326           2 :         case EINVAL:
     327           2 :                 DEBUG(3, ("Cannot obtain client GSS credentials we need to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
     328        1367 :                 return NT_STATUS_INVALID_PARAMETER;
     329         167 :         case KRB5KDC_ERR_PREAUTH_FAILED:
     330             :         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
     331             :         case KRB5KRB_AP_ERR_BAD_INTEGRITY:
     332         167 :                 DEBUG(1, ("Wrong username or password: %s\n", error_string));
     333         167 :                 return NT_STATUS_LOGON_FAILURE;
     334          20 :         case KRB5KDC_ERR_CLIENT_REVOKED:
     335          20 :                 DEBUG(1, ("Account locked out: %s\n", error_string));
     336          20 :                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
     337        1175 :         case KRB5_REALM_UNKNOWN:
     338             :         case KRB5_KDC_UNREACH:
     339        1175 :                 DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", gensec_gssapi_state->target_principal, error_string));
     340        1175 :                 return NT_STATUS_NO_LOGON_SERVERS;
     341           0 :         case KRB5_CC_NOTFOUND:
     342             :         case KRB5_CC_END:
     343           0 :                 DEBUG(2, ("Error obtaining ticket we require to contact %s: (possibly due to clock skew between us and the KDC) %s\n", gensec_gssapi_state->target_principal, error_string));
     344           0 :                 return NT_STATUS_TIME_DIFFERENCE_AT_DC;
     345           3 :         default:
     346           3 :                 DEBUG(1, ("Acquiring initiator credentials failed: %s\n", error_string));
     347           3 :                 return NT_STATUS_UNSUCCESSFUL;
     348             :         }
     349             : 
     350       30079 :         gensec_gssapi_state->client_cred = gcc;
     351       30079 :         if (!talloc_reference(gensec_gssapi_state, gcc)) {
     352           0 :                 return NT_STATUS_NO_MEMORY;
     353             :         }
     354             : 
     355       30079 :         return NT_STATUS_OK;
     356             : }
     357             : 
     358       42294 : static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
     359             : {
     360        1041 :         struct gensec_gssapi_state *gensec_gssapi_state;
     361       42294 :         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
     362        1041 :         NTSTATUS nt_status;
     363       42294 :         const char *target_principal = NULL;
     364       42294 :         const char *hostname = gensec_get_target_hostname(gensec_security);
     365       42294 :         const char *service = gensec_get_target_service(gensec_security);
     366       42294 :         const char *realm = cli_credentials_get_realm(creds);
     367             : 
     368       42294 :         target_principal = gensec_get_target_principal(gensec_security);
     369       42294 :         if (target_principal != NULL) {
     370         219 :                 goto do_start;
     371             :         }
     372             : 
     373       42075 :         if (!hostname) {
     374         269 :                 DEBUG(3, ("No hostname for target computer passed in, cannot use kerberos for this connection\n"));
     375         269 :                 return NT_STATUS_INVALID_PARAMETER;
     376             :         }
     377       41806 :         if (is_ipaddress(hostname)) {
     378       10123 :                 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
     379       10123 :                 return NT_STATUS_INVALID_PARAMETER;
     380             :         }
     381       31683 :         if (strcmp(hostname, "localhost") == 0) {
     382           0 :                 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
     383           0 :                 return NT_STATUS_INVALID_PARAMETER;
     384             :         }
     385             : 
     386       31683 :         if (realm == NULL) {
     387         456 :                 char *cred_name = cli_credentials_get_unparsed_name(creds,
     388             :                                                                 gensec_security);
     389         456 :                 DEBUG(3, ("cli_credentials(%s) without realm, "
     390             :                           "cannot use kerberos for this connection %s/%s\n",
     391             :                           cred_name, service, hostname));
     392         456 :                 TALLOC_FREE(cred_name);
     393         456 :                 return NT_STATUS_INVALID_PARAMETER;
     394             :         }
     395             : 
     396       31227 : do_start:
     397             : 
     398       31446 :         nt_status = gensec_gssapi_start(gensec_security);
     399       31446 :         if (!NT_STATUS_IS_OK(nt_status)) {
     400           0 :                 return nt_status;
     401             :         }
     402             : 
     403       31446 :         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     404             : 
     405       31446 :         if (cli_credentials_get_impersonate_principal(creds)) {
     406          45 :                 gensec_gssapi_state->gss_want_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG);
     407             :         }
     408             : 
     409       31446 :         return NT_STATUS_OK;
     410             : }
     411             : 
     412         139 : static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
     413             : {
     414           0 :         NTSTATUS nt_status;
     415           0 :         struct gensec_gssapi_state *gensec_gssapi_state;
     416         139 :         nt_status = gensec_gssapi_client_start(gensec_security);
     417             : 
     418         139 :         if (NT_STATUS_IS_OK(nt_status)) {
     419         139 :                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     420         139 :                 gensec_gssapi_state->sasl = true;
     421             :         }
     422         139 :         return nt_status;
     423             : }
     424             : 
     425       96693 : static NTSTATUS gensec_gssapi_update_internal(struct gensec_security *gensec_security,
     426             :                                               TALLOC_CTX *out_mem_ctx,
     427             :                                               struct tevent_context *ev,
     428             :                                               const DATA_BLOB in, DATA_BLOB *out)
     429             : {
     430        2892 :         struct gensec_gssapi_state *gensec_gssapi_state
     431       96693 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
     432        2892 :         NTSTATUS nt_status;
     433        2892 :         OM_uint32 maj_stat, min_stat;
     434        2892 :         OM_uint32 min_stat2;
     435       96693 :         gss_buffer_desc input_token = { 0, NULL };
     436       96693 :         gss_buffer_desc output_token = { 0, NULL };
     437       96693 :         struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security);
     438       96693 :         const char *target_principal = gensec_get_target_principal(gensec_security);
     439       96693 :         const char *hostname = gensec_get_target_hostname(gensec_security);
     440       96693 :         const char *service = gensec_get_target_service(gensec_security);
     441       96693 :         gss_OID gss_oid_p = NULL;
     442       96693 :         OM_uint32 time_req = 0;
     443       96693 :         OM_uint32 time_rec = 0;
     444        2892 :         struct timeval tv;
     445             : 
     446       96693 :         time_req = gensec_setting_int(gensec_security->settings,
     447             :                                       "gensec_gssapi", "requested_life_time",
     448             :                                       time_req);
     449             : 
     450       96693 :         input_token.length = in.length;
     451       96693 :         input_token.value = in.data;
     452             : 
     453       96693 :         switch (gensec_gssapi_state->sasl_state) {
     454       96348 :         case STAGE_GSS_NEG:
     455             :         {
     456       96348 :                 switch (gensec_security->gensec_role) {
     457       60585 :                 case GENSEC_CLIENT:
     458             :                 {
     459       60585 :                         const char *client_realm = NULL;
     460             : #ifdef SAMBA4_USES_HEIMDAL
     461        1915 :                         struct gsskrb5_send_to_kdc send_to_kdc;
     462        1915 :                         krb5_error_code ret;
     463             : #else
     464       15232 :                         bool fallback = false;
     465             : #endif
     466             : 
     467       60585 :                         nt_status = gensec_gssapi_client_creds(gensec_security, ev);
     468       60585 :                         if (!NT_STATUS_IS_OK(nt_status)) {
     469        1367 :                                 return nt_status;
     470             :                         }
     471             : 
     472             : #ifdef SAMBA4_USES_HEIMDAL
     473       44235 :                         send_to_kdc.func = smb_krb5_send_and_recv_func;
     474       44235 :                         send_to_kdc.ptr = ev;
     475             : 
     476       44235 :                         min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
     477       44235 :                         if (min_stat) {
     478           0 :                                 DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
     479           0 :                                 return NT_STATUS_INTERNAL_ERROR;
     480             :                         }
     481             : #endif
     482             : 
     483             :                         /*
     484             :                          * With credentials for
     485             :                          * administrator@FOREST1.EXAMPLE.COM this patch changes
     486             :                          * the target_principal for the ldap service of host
     487             :                          * dc2.forest2.example.com from
     488             :                          *
     489             :                          *   ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM
     490             :                          *
     491             :                          * to
     492             :                          *
     493             :                          *   ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM
     494             :                          *
     495             :                          * Typically
     496             :                          * ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM
     497             :                          * should be used in order to allow the KDC of
     498             :                          * FOREST1.EXAMPLE.COM to generate a referral ticket
     499             :                          * for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM.
     500             :                          *
     501             :                          * The problem is that KDCs only return such referral
     502             :                          * tickets if there's a forest trust between
     503             :                          * FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM. If
     504             :                          * there's only an external domain trust between
     505             :                          * FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC
     506             :                          * of FOREST1.EXAMPLE.COM will respond with
     507             :                          * S_PRINCIPAL_UNKNOWN when being asked for
     508             :                          * ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM.
     509             :                          *
     510             :                          * In the case of an external trust the client can
     511             :                          * still ask explicitly for
     512             :                          * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and
     513             :                          * the KDC of FOREST1.EXAMPLE.COM will generate it.
     514             :                          *
     515             :                          * From there the client can use the
     516             :                          * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM
     517             :                          * ticket and ask a KDC of FOREST2.EXAMPLE.COM for a
     518             :                          * service ticket for
     519             :                          * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM.
     520             :                          *
     521             :                          * With Heimdal we'll get the fallback on
     522             :                          * S_PRINCIPAL_UNKNOWN behavior when we pass
     523             :                          * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM as
     524             :                          * target principal. As _krb5_get_cred_kdc_any() first
     525             :                          * calls get_cred_kdc_referral() (which always starts
     526             :                          * with the client realm) and falls back to
     527             :                          * get_cred_kdc_capath() (which starts with the given
     528             :                          * realm).
     529             :                          *
     530             :                          * MIT krb5 only tries the given realm of the target
     531             :                          * principal, if we want to autodetect support for
     532             :                          * transitive forest trusts, would have to do the
     533             :                          * fallback ourself.
     534             :                          */
     535       59218 :                         client_realm = cli_credentials_get_realm(cli_creds);
     536             : #ifndef SAMBA4_USES_HEIMDAL
     537       14983 :                         if (gensec_gssapi_state->server_name == NULL) {
     538        7655 :                                 nt_status = gensec_gssapi_setup_server_principal(gensec_gssapi_state,
     539             :                                                                                  target_principal,
     540             :                                                                                  service,
     541             :                                                                                  hostname,
     542             :                                                                                  client_realm,
     543             :                                                                                  gensec_gssapi_state->gss_oid,
     544             :                                                                                  &gensec_gssapi_state->target_principal,
     545             :                                                                                  &gensec_gssapi_state->server_name);
     546        7655 :                                 if (!NT_STATUS_IS_OK(nt_status)) {
     547           0 :                                         return nt_status;
     548             :                                 }
     549             : 
     550        7655 :                                 maj_stat = gss_init_sec_context(&min_stat,
     551        7655 :                                                                 gensec_gssapi_state->client_cred->creds,
     552             :                                                                 &gensec_gssapi_state->gssapi_context,
     553             :                                                                 gensec_gssapi_state->server_name,
     554             :                                                                 gensec_gssapi_state->gss_oid,
     555             :                                                                 gensec_gssapi_state->gss_want_flags,
     556             :                                                                 time_req,
     557             :                                                                 gensec_gssapi_state->input_chan_bindings,
     558             :                                                                 &input_token,
     559             :                                                                 &gss_oid_p,
     560             :                                                                 &output_token,
     561             :                                                                 &gensec_gssapi_state->gss_got_flags, /* ret flags */
     562             :                                                                 &time_rec);
     563        7655 :                                 if (maj_stat != GSS_S_FAILURE) {
     564        7648 :                                         goto init_sec_context_done;
     565             :                                 }
     566           7 :                                 if (min_stat != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
     567           0 :                                         goto init_sec_context_done;
     568             :                                 }
     569           7 :                                 if (target_principal != NULL) {
     570           0 :                                         goto init_sec_context_done;
     571             :                                 }
     572             : 
     573           7 :                                 fallback = true;
     574           7 :                                 TALLOC_FREE(gensec_gssapi_state->target_principal);
     575           7 :                                 gss_release_name(&min_stat2, &gensec_gssapi_state->server_name);
     576             :                         }
     577             : #endif /* !SAMBA4_USES_HEIMDAL */
     578       51570 :                         if (gensec_gssapi_state->server_name == NULL) {
     579       22431 :                                 const char *server_realm = NULL;
     580             : 
     581       22431 :                                 server_realm = smb_krb5_get_realm_from_hostname(gensec_gssapi_state,
     582             :                                                                                 hostname,
     583             :                                                                                 client_realm);
     584       22431 :                                 if (server_realm == NULL) {
     585           0 :                                         return NT_STATUS_NO_MEMORY;
     586             :                                 }
     587             : 
     588             : #ifndef SAMBA4_USES_HEIMDAL
     589          14 :                                 if (fallback &&
     590           7 :                                     strequal(client_realm, server_realm)) {
     591           1 :                                         goto init_sec_context_done;
     592             :                                 }
     593             : #endif /* !SAMBA4_USES_HEIMDAL */
     594             : 
     595       22430 :                                 nt_status = gensec_gssapi_setup_server_principal(gensec_gssapi_state,
     596             :                                                                                  target_principal,
     597             :                                                                                  service,
     598             :                                                                                  hostname,
     599             :                                                                                  server_realm,
     600             :                                                                                  gensec_gssapi_state->gss_oid,
     601             :                                                                                  &gensec_gssapi_state->target_principal,
     602             :                                                                                  &gensec_gssapi_state->server_name);
     603       22430 :                                 if (!NT_STATUS_IS_OK(nt_status)) {
     604           0 :                                         return nt_status;
     605             :                                 }
     606             :                         }
     607             : 
     608       53484 :                         maj_stat = gss_init_sec_context(&min_stat, 
     609       51569 :                                                         gensec_gssapi_state->client_cred->creds,
     610             :                                                         &gensec_gssapi_state->gssapi_context, 
     611       44235 :                                                         gensec_gssapi_state->server_name, 
     612             :                                                         gensec_gssapi_state->gss_oid,
     613             :                                                         gensec_gssapi_state->gss_want_flags, 
     614             :                                                         time_req,
     615             :                                                         gensec_gssapi_state->input_chan_bindings,
     616             :                                                         &input_token, 
     617             :                                                         &gss_oid_p,
     618             :                                                         &output_token, 
     619             :                                                         &gensec_gssapi_state->gss_got_flags, /* ret flags */
     620             :                                                         &time_rec);
     621       51569 :                         goto init_sec_context_done;
     622             :                         /* JUMP! */
     623       59218 : init_sec_context_done:
     624       59218 :                         if (gss_oid_p) {
     625       59215 :                                 gensec_gssapi_state->gss_oid = gss_oid_p;
     626             :                         }
     627             : 
     628             : #ifdef SAMBA4_USES_HEIMDAL
     629       44235 :                         send_to_kdc.func = smb_krb5_send_and_recv_func;
     630       44235 :                         send_to_kdc.ptr = NULL;
     631             : 
     632       44235 :                         ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
     633       44235 :                         if (ret) {
     634           0 :                                 DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
     635           0 :                                 return NT_STATUS_INTERNAL_ERROR;
     636             :                         }
     637             : #endif
     638       59218 :                         break;
     639             :                 }
     640       35763 :                 case GENSEC_SERVER:
     641             :                 {
     642       36740 :                         maj_stat = gss_accept_sec_context(&min_stat, 
     643             :                                                           &gensec_gssapi_state->gssapi_context, 
     644       35763 :                                                           gensec_gssapi_state->server_cred->creds,
     645             :                                                           &input_token, 
     646             :                                                           gensec_gssapi_state->input_chan_bindings,
     647             :                                                           &gensec_gssapi_state->client_name, 
     648             :                                                           &gss_oid_p,
     649             :                                                           &output_token, 
     650             :                                                           &gensec_gssapi_state->gss_got_flags, 
     651             :                                                           &time_rec,
     652             :                                                           &gensec_gssapi_state->delegated_cred_handle);
     653       35763 :                         if (gss_oid_p) {
     654       35118 :                                 gensec_gssapi_state->gss_oid = gss_oid_p;
     655             :                         }
     656       34786 :                         break;
     657             :                 }
     658           0 :                 default:
     659           0 :                         return NT_STATUS_INVALID_PARAMETER;
     660             :                         
     661             :                 }
     662             : 
     663       94981 :                 gensec_gssapi_state->gss_exchange_count++;
     664             : 
     665       94981 :                 if (maj_stat == GSS_S_COMPLETE) {
     666       60569 :                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
     667       60569 :                         gss_release_buffer(&min_stat2, &output_token);
     668             :                         
     669       60569 :                         if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
     670       58200 :                             gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
     671       29893 :                                 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
     672             :                         } else {
     673       30676 :                                 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
     674             :                         }
     675             : 
     676       60569 :                         tv = timeval_current_ofs(time_rec, 0);
     677       60569 :                         gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);
     678             : 
     679             :                         /* We may have been invoked as SASL, so there
     680             :                          * is more work to do */
     681       60569 :                         if (gensec_gssapi_state->sasl) {
     682         230 :                                 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
     683         230 :                                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
     684             :                         } else {
     685       60339 :                                 gensec_gssapi_state->sasl_state = STAGE_DONE;
     686             : 
     687       60339 :                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
     688       40092 :                                         DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
     689       20247 :                                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
     690       19901 :                                         DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
     691             :                                 } else {
     692         346 :                                         DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
     693             :                                 }
     694             : 
     695       60339 :                                 return NT_STATUS_OK;
     696             :                         }
     697       34412 :                 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
     698       34383 :                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
     699       34383 :                         gss_release_buffer(&min_stat2, &output_token);
     700             :                         
     701       34383 :                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     702          29 :                 } else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
     703           0 :                         gss_cred_id_t creds = NULL;
     704           0 :                         gss_name_t name;
     705           0 :                         gss_buffer_desc buffer;
     706           0 :                         OM_uint32 lifetime = 0;
     707           0 :                         gss_cred_usage_t usage;
     708           0 :                         const char *role = NULL;
     709             : 
     710           0 :                         switch (gensec_security->gensec_role) {
     711           0 :                         case GENSEC_CLIENT:
     712           0 :                                 creds = gensec_gssapi_state->client_cred->creds;
     713           0 :                                 role = "client";
     714           0 :                                 break;
     715           0 :                         case GENSEC_SERVER:
     716           0 :                                 creds = gensec_gssapi_state->server_cred->creds;
     717           0 :                                 role = "server";
     718           0 :                                 break;
     719             :                         }
     720             : 
     721           0 :                         DBG_ERR("GSS %s Update(krb5)(%d) failed, credentials "
     722             :                                 "expired during GSSAPI handshake!\n",
     723             :                                 role,
     724             :                                 gensec_gssapi_state->gss_exchange_count);
     725             : 
     726           0 :                         maj_stat = gss_inquire_cred(&min_stat, 
     727             :                                                     creds,
     728             :                                                     &name, &lifetime, &usage, NULL);
     729             : 
     730           0 :                         if (maj_stat == GSS_S_COMPLETE) {
     731           0 :                                 const char *usage_string = NULL;
     732           0 :                                 switch (usage) {
     733           0 :                                 case GSS_C_BOTH:
     734           0 :                                         usage_string = "GSS_C_BOTH";
     735           0 :                                         break;
     736           0 :                                 case GSS_C_ACCEPT:
     737           0 :                                         usage_string = "GSS_C_ACCEPT";
     738           0 :                                         break;
     739           0 :                                 case GSS_C_INITIATE:
     740           0 :                                         usage_string = "GSS_C_INITIATE";
     741           0 :                                         break;
     742             :                                 }
     743           0 :                                 maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
     744           0 :                                 if (maj_stat) {
     745           0 :                                         buffer.value = NULL;
     746           0 :                                         buffer.length = 0;
     747             :                                 }
     748           0 :                                 if (lifetime > 0) {
     749           0 :                                         DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
     750             :                                                   (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
     751             :                                                   lifetime, usage_string));
     752             :                                 } else {
     753           0 :                                         DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
     754             :                                                   (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
     755             :                                                   usage_string));
     756             :                                 }
     757           0 :                                 gss_release_buffer(&min_stat, &buffer);
     758           0 :                                 gss_release_name(&min_stat, &name);
     759           0 :                         } else if (maj_stat != GSS_S_COMPLETE) {
     760           0 :                                 DEBUG(0, ("inquiry of credential lifetime via GSSAPI gss_inquire_cred failed: %s\n",
     761             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     762             :                         }
     763           0 :                         return NT_STATUS_INVALID_PARAMETER;
     764          29 :                 } else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
     765             :                                              gss_mech_krb5)) {
     766          29 :                         switch (min_stat) {
     767           0 :                         case (OM_uint32)KRB5KRB_AP_ERR_TKT_NYV:
     768           0 :                                 DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
     769             :                                           gensec_gssapi_state->target_principal,
     770             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     771           0 :                                 return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
     772           0 :                         case (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED:
     773           0 :                                 DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
     774             :                                           gensec_gssapi_state->target_principal,
     775             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     776           0 :                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
     777           0 :                         case (OM_uint32)KRB5_KDC_UNREACH:
     778           0 :                                 DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
     779             :                                           gensec_gssapi_state->target_principal,
     780             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     781           0 :                                 return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
     782          12 :                         case (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
     783          12 :                                 DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
     784             :                                           gensec_gssapi_state->target_principal,
     785             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     786          12 :                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
     787           0 :                         case (OM_uint32)KRB5KRB_AP_ERR_MSG_TYPE:
     788             :                                 /* garbage input, possibly from the auto-mech detection */
     789           0 :                                 return NT_STATUS_INVALID_PARAMETER;
     790          17 :                         default:
     791          17 :                                 DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
     792             :                                           gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
     793             :                                           gensec_gssapi_state->gss_exchange_count,
     794             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     795          17 :                                 return NT_STATUS_LOGON_FAILURE;
     796             :                         }
     797             :                 } else {
     798           0 :                         DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
     799             :                                   gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
     800             :                                   gensec_gssapi_state->gss_exchange_count,
     801             :                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     802           0 :                         return NT_STATUS_LOGON_FAILURE;
     803             :                 }
     804           0 :                 break;
     805             :         }
     806             : 
     807             :         /* These last two stages are only done if we were invoked as SASL */
     808         230 :         case STAGE_SASL_SSF_NEG:
     809             :         {
     810         230 :                 switch (gensec_security->gensec_role) {
     811         115 :                 case GENSEC_CLIENT:
     812             :                 {
     813           0 :                         uint8_t maxlength_proposed[4]; 
     814           0 :                         uint8_t maxlength_accepted[4]; 
     815           0 :                         uint8_t security_supported;
     816           0 :                         int conf_state;
     817           0 :                         gss_qop_t qop_state;
     818         115 :                         input_token.length = in.length;
     819         115 :                         input_token.value = in.data;
     820             : 
     821             :                         /* As a client, we have just send a
     822             :                          * zero-length blob to the server (after the
     823             :                          * normal GSSAPI exchange), and it has replied
     824             :                          * with it's SASL negotiation */
     825             :                         
     826         115 :                         maj_stat = gss_unwrap(&min_stat, 
     827          90 :                                               gensec_gssapi_state->gssapi_context, 
     828             :                                               &input_token,
     829             :                                               &output_token, 
     830             :                                               &conf_state,
     831             :                                               &qop_state);
     832         115 :                         if (GSS_ERROR(maj_stat)) {
     833           0 :                                 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
     834             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     835           0 :                                 return NT_STATUS_ACCESS_DENIED;
     836             :                         }
     837             :                         
     838         115 :                         if (output_token.length < 4) {
     839           0 :                                 gss_release_buffer(&min_stat, &output_token);
     840           0 :                                 return NT_STATUS_INVALID_PARAMETER;
     841             :                         }
     842             : 
     843         115 :                         memcpy(maxlength_proposed, output_token.value, 4);
     844         115 :                         gss_release_buffer(&min_stat, &output_token);
     845             : 
     846             :                         /* first byte is the proposed security */
     847         115 :                         security_supported = maxlength_proposed[0];
     848         115 :                         maxlength_proposed[0] = '\0';
     849             :                         
     850             :                         /* Rest is the proposed max wrap length */
     851         115 :                         gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
     852             :                                                                      gensec_gssapi_state->max_wrap_buf_size);
     853         115 :                         gensec_gssapi_state->sasl_protection = 0;
     854         115 :                         if (security_supported & NEG_SEAL) {
     855          21 :                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
     856          21 :                                         gensec_gssapi_state->sasl_protection |= NEG_SEAL;
     857             :                                 }
     858             :                         }
     859         115 :                         if (security_supported & NEG_SIGN) {
     860          21 :                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
     861          21 :                                         gensec_gssapi_state->sasl_protection |= NEG_SIGN;
     862             :                                 }
     863             :                         }
     864         115 :                         if (security_supported & NEG_NONE) {
     865         115 :                                 gensec_gssapi_state->sasl_protection |= NEG_NONE;
     866             :                         }
     867         115 :                         if (gensec_gssapi_state->sasl_protection == 0) {
     868           0 :                                 DEBUG(1, ("Remote server does not support unprotected connections\n"));
     869           0 :                                 return NT_STATUS_ACCESS_DENIED;
     870             :                         }
     871             : 
     872             :                         /* Send back the negotiated max length */
     873             : 
     874         115 :                         RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);
     875             : 
     876         115 :                         maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
     877             :                         
     878         115 :                         input_token.value = maxlength_accepted;
     879         115 :                         input_token.length = sizeof(maxlength_accepted);
     880             : 
     881         115 :                         maj_stat = gss_wrap(&min_stat, 
     882          90 :                                             gensec_gssapi_state->gssapi_context, 
     883             :                                             false,
     884             :                                             GSS_C_QOP_DEFAULT,
     885             :                                             &input_token,
     886             :                                             &conf_state,
     887             :                                             &output_token);
     888         115 :                         if (GSS_ERROR(maj_stat)) {
     889           0 :                                 DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
     890             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     891           0 :                                 return NT_STATUS_ACCESS_DENIED;
     892             :                         }
     893             :                         
     894         115 :                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
     895         115 :                         gss_release_buffer(&min_stat, &output_token);
     896             : 
     897             :                         /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
     898         115 :                         gensec_gssapi_state->sasl_state = STAGE_DONE;
     899             : 
     900         115 :                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
     901          21 :                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
     902          94 :                         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
     903           0 :                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
     904             :                         } else {
     905          94 :                                 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographic protection\n"));
     906             :                         }
     907             : 
     908         115 :                         return NT_STATUS_OK;
     909             :                 }
     910         115 :                 case GENSEC_SERVER:
     911             :                 {
     912           0 :                         uint8_t maxlength_proposed[4]; 
     913         115 :                         uint8_t security_supported = 0x0;
     914           0 :                         int conf_state;
     915             : 
     916             :                         /* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
     917         115 :                         if (in.length != 0) {
     918           0 :                                 DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
     919             :                         }
     920             :                         
     921             :                         /* Give the client some idea what we will support */
     922             :                           
     923         115 :                         RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
     924             :                         /* first byte is the proposed security */
     925         115 :                         maxlength_proposed[0] = '\0';
     926             :                         
     927         115 :                         gensec_gssapi_state->sasl_protection = 0;
     928         115 :                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
     929          21 :                                 security_supported |= NEG_SEAL;
     930             :                         } 
     931         115 :                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
     932          21 :                                 security_supported |= NEG_SIGN;
     933             :                         }
     934         115 :                         if (security_supported == 0) {
     935             :                                 /* If we don't support anything, this must be 0 */
     936          94 :                                 RSIVAL(maxlength_proposed, 0, 0x0);
     937             :                         }
     938             : 
     939             :                         /* TODO:  We may not wish to support this */
     940         115 :                         security_supported |= NEG_NONE;
     941         115 :                         maxlength_proposed[0] = security_supported;
     942             :                         
     943         115 :                         input_token.value = maxlength_proposed;
     944         115 :                         input_token.length = sizeof(maxlength_proposed);
     945             : 
     946         115 :                         maj_stat = gss_wrap(&min_stat, 
     947          90 :                                             gensec_gssapi_state->gssapi_context, 
     948             :                                             false,
     949             :                                             GSS_C_QOP_DEFAULT,
     950             :                                             &input_token,
     951             :                                             &conf_state,
     952             :                                             &output_token);
     953         115 :                         if (GSS_ERROR(maj_stat)) {
     954           0 :                                 DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
     955             :                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     956           0 :                                 return NT_STATUS_ACCESS_DENIED;
     957             :                         }
     958             :                         
     959         115 :                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
     960         115 :                         gss_release_buffer(&min_stat, &output_token);
     961             : 
     962         115 :                         gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
     963         115 :                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
     964             :                 }
     965           0 :                 default:
     966           0 :                         return NT_STATUS_INVALID_PARAMETER;
     967             :                         
     968             :                 }
     969             :         }
     970             :         /* This is s server-only stage */
     971         115 :         case STAGE_SASL_SSF_ACCEPT:
     972             :         {
     973           0 :                 uint8_t maxlength_accepted[4]; 
     974           0 :                 uint8_t security_accepted;
     975           0 :                 int conf_state;
     976           0 :                 gss_qop_t qop_state;
     977         115 :                 input_token.length = in.length;
     978         115 :                 input_token.value = in.data;
     979             :                         
     980         115 :                 maj_stat = gss_unwrap(&min_stat, 
     981          90 :                                       gensec_gssapi_state->gssapi_context, 
     982             :                                       &input_token,
     983             :                                       &output_token, 
     984             :                                       &conf_state,
     985             :                                       &qop_state);
     986         115 :                 if (GSS_ERROR(maj_stat)) {
     987           0 :                         DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
     988             :                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
     989           0 :                         return NT_STATUS_ACCESS_DENIED;
     990             :                 }
     991             :                         
     992         115 :                 if (output_token.length < 4) {
     993           0 :                         gss_release_buffer(&min_stat, &output_token);
     994           0 :                         return NT_STATUS_INVALID_PARAMETER;
     995             :                 }
     996             : 
     997         115 :                 memcpy(maxlength_accepted, output_token.value, 4);
     998         115 :                 gss_release_buffer(&min_stat, &output_token);
     999             :                 
    1000             :                 /* first byte is the proposed security */
    1001         115 :                 security_accepted = maxlength_accepted[0];
    1002         115 :                 maxlength_accepted[0] = '\0';
    1003             : 
    1004             :                 /* Rest is the proposed max wrap length */
    1005         115 :                 gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
    1006             :                                                              gensec_gssapi_state->max_wrap_buf_size);
    1007             : 
    1008         115 :                 gensec_gssapi_state->sasl_protection = 0;
    1009         115 :                 if (security_accepted & NEG_SEAL) {
    1010          21 :                         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
    1011           0 :                                 DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
    1012           0 :                                 return NT_STATUS_ACCESS_DENIED;
    1013             :                         }
    1014          21 :                         gensec_gssapi_state->sasl_protection |= NEG_SEAL;
    1015             :                 }
    1016         115 :                 if (security_accepted & NEG_SIGN) {
    1017          21 :                         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
    1018           0 :                                 DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
    1019           0 :                                 return NT_STATUS_ACCESS_DENIED;
    1020             :                         }
    1021          21 :                         gensec_gssapi_state->sasl_protection |= NEG_SIGN;
    1022             :                 }
    1023         115 :                 if (security_accepted & NEG_NONE) {
    1024         115 :                         gensec_gssapi_state->sasl_protection |= NEG_NONE;
    1025             :                 }
    1026             : 
    1027             :                 /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
    1028         115 :                 gensec_gssapi_state->sasl_state = STAGE_DONE;
    1029         115 :                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
    1030          21 :                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
    1031          94 :                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
    1032           0 :                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
    1033             :                 } else {
    1034          94 :                         DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
    1035             :                 }
    1036             : 
    1037         115 :                 *out = data_blob(NULL, 0);
    1038         115 :                 return NT_STATUS_OK;    
    1039             :         }
    1040           0 :         default:
    1041           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1042             :         }
    1043             : }
    1044             : 
    1045             : struct gensec_gssapi_update_state {
    1046             :         NTSTATUS status;
    1047             :         DATA_BLOB out;
    1048             : };
    1049             : 
    1050       96693 : static struct tevent_req *gensec_gssapi_update_send(TALLOC_CTX *mem_ctx,
    1051             :                                                     struct tevent_context *ev,
    1052             :                                                     struct gensec_security *gensec_security,
    1053             :                                                     const DATA_BLOB in)
    1054             : {
    1055       96693 :         struct tevent_req *req = NULL;
    1056       96693 :         struct gensec_gssapi_update_state *state = NULL;
    1057        2892 :         NTSTATUS status;
    1058             : 
    1059       96693 :         req = tevent_req_create(mem_ctx, &state,
    1060             :                                 struct gensec_gssapi_update_state);
    1061       96693 :         if (req == NULL) {
    1062           0 :                 return NULL;
    1063             :         }
    1064             : 
    1065       96693 :         status = gensec_gssapi_update_internal(gensec_security,
    1066             :                                                state, ev, in,
    1067       96693 :                                                &state->out);
    1068       96693 :         state->status = status;
    1069       96693 :         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
    1070       34728 :                 tevent_req_done(req);
    1071       34728 :                 return tevent_req_post(req, ev);
    1072             :         }
    1073       61965 :         if (tevent_req_nterror(req, status)) {
    1074        1396 :                 return tevent_req_post(req, ev);
    1075             :         }
    1076             : 
    1077       60569 :         tevent_req_done(req);
    1078       60569 :         return tevent_req_post(req, ev);
    1079             : }
    1080             : 
    1081       96693 : static NTSTATUS gensec_gssapi_update_recv(struct tevent_req *req,
    1082             :                                           TALLOC_CTX *out_mem_ctx,
    1083             :                                           DATA_BLOB *out)
    1084             : {
    1085        2892 :         struct gensec_gssapi_update_state *state =
    1086       96693 :                 tevent_req_data(req,
    1087             :                 struct gensec_gssapi_update_state);
    1088        2892 :         NTSTATUS status;
    1089             : 
    1090       96693 :         *out = data_blob_null;
    1091             : 
    1092       96693 :         if (tevent_req_is_nterror(req, &status)) {
    1093        1396 :                 tevent_req_received(req);
    1094        1396 :                 return status;
    1095             :         }
    1096             : 
    1097       95297 :         *out = state->out;
    1098       95297 :         talloc_steal(out_mem_ctx, state->out.data);
    1099       95297 :         status = state->status;
    1100       95297 :         tevent_req_received(req);
    1101       95297 :         return status;
    1102             : }
    1103             : 
    1104      984397 : static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
    1105             :                                    TALLOC_CTX *mem_ctx, 
    1106             :                                    const DATA_BLOB *in, 
    1107             :                                    DATA_BLOB *out)
    1108             : {
    1109         930 :         struct gensec_gssapi_state *gensec_gssapi_state
    1110      984397 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1111         930 :         OM_uint32 maj_stat, min_stat;
    1112         930 :         gss_buffer_desc input_token, output_token;
    1113         930 :         int conf_state;
    1114      984397 :         input_token.length = in->length;
    1115      984397 :         input_token.value = in->data;
    1116             : 
    1117      986257 :         maj_stat = gss_wrap(&min_stat, 
    1118      724850 :                             gensec_gssapi_state->gssapi_context, 
    1119      984397 :                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
    1120             :                             GSS_C_QOP_DEFAULT,
    1121             :                             &input_token,
    1122             :                             &conf_state,
    1123             :                             &output_token);
    1124      984397 :         if (GSS_ERROR(maj_stat)) {
    1125           0 :                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
    1126             :                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
    1127           0 :                 return NT_STATUS_ACCESS_DENIED;
    1128             :         }
    1129             : 
    1130      984397 :         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
    1131      984397 :         gss_release_buffer(&min_stat, &output_token);
    1132             : 
    1133      984397 :         if (gensec_gssapi_state->sasl) {
    1134          12 :                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
    1135          12 :                 if (max_wrapped_size < out->length) {
    1136           0 :                         DEBUG(1, ("gensec_gssapi_wrap: when wrapped, INPUT data (%u) is grew to be larger than SASL negotiated maximum output size (%u > %u)\n",
    1137             :                                   (unsigned)in->length, 
    1138             :                                   (unsigned)out->length, 
    1139             :                                   (unsigned int)max_wrapped_size));
    1140           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1141             :                 }
    1142             :         }
    1143             :         
    1144      984397 :         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
    1145      983877 :             && !conf_state) {
    1146           0 :                 return NT_STATUS_ACCESS_DENIED;
    1147             :         }
    1148      984397 :         return NT_STATUS_OK;
    1149             : }
    1150             : 
    1151      984405 : static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
    1152             :                                      TALLOC_CTX *mem_ctx, 
    1153             :                                      const DATA_BLOB *in, 
    1154             :                                      DATA_BLOB *out)
    1155             : {
    1156         930 :         struct gensec_gssapi_state *gensec_gssapi_state
    1157      984405 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1158         930 :         OM_uint32 maj_stat, min_stat;
    1159         930 :         gss_buffer_desc input_token, output_token;
    1160         930 :         int conf_state;
    1161         930 :         gss_qop_t qop_state;
    1162      984405 :         input_token.length = in->length;
    1163      984405 :         input_token.value = in->data;
    1164             :         
    1165      984405 :         if (gensec_gssapi_state->sasl) {
    1166          12 :                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
    1167          12 :                 if (max_wrapped_size < in->length) {
    1168           0 :                         DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
    1169           0 :                         return NT_STATUS_INVALID_PARAMETER;
    1170             :                 }
    1171             :         }
    1172             :         
    1173             :         /*
    1174             :          * FIXME: input_message_buffer is marked const, but gss_unwrap() may
    1175             :          * modify it (see calls to rrc_rotate() in _gssapi_unwrap_cfx()).
    1176             :          */
    1177      985335 :         maj_stat = gss_unwrap(&min_stat, 
    1178      724853 :                               gensec_gssapi_state->gssapi_context, 
    1179             :                               &input_token,
    1180             :                               &output_token, 
    1181             :                               &conf_state,
    1182             :                               &qop_state);
    1183      984405 :         if (GSS_ERROR(maj_stat)) {
    1184           0 :                 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", 
    1185             :                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
    1186           0 :                 return NT_STATUS_ACCESS_DENIED;
    1187             :         }
    1188             : 
    1189      984405 :         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
    1190      984405 :         gss_release_buffer(&min_stat, &output_token);
    1191             :         
    1192      984405 :         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
    1193      983885 :             && !conf_state) {
    1194           0 :                 return NT_STATUS_ACCESS_DENIED;
    1195             :         }
    1196      984405 :         return NT_STATUS_OK;
    1197             : }
    1198             : 
    1199             : /* Find out the maximum input size negotiated on this connection */
    1200             : 
    1201       33626 : static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security) 
    1202             : {
    1203         244 :         struct gensec_gssapi_state *gensec_gssapi_state
    1204       33626 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1205         244 :         OM_uint32 maj_stat, min_stat;
    1206         244 :         OM_uint32 max_input_size;
    1207             : 
    1208       59016 :         maj_stat = gss_wrap_size_limit(&min_stat, 
    1209       25146 :                                        gensec_gssapi_state->gssapi_context,
    1210       33626 :                                        gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
    1211             :                                        GSS_C_QOP_DEFAULT,
    1212       33626 :                                        gensec_gssapi_state->max_wrap_buf_size,
    1213             :                                        &max_input_size);
    1214       33626 :         if (GSS_ERROR(maj_stat)) {
    1215           0 :                 TALLOC_CTX *mem_ctx = talloc_new(NULL); 
    1216           0 :                 DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n",
    1217             :                           gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
    1218           0 :                 talloc_free(mem_ctx);
    1219           0 :                 return 0;
    1220             :         }
    1221             : 
    1222       33626 :         return max_input_size;
    1223             : }
    1224             : 
    1225             : /* Find out the maximum output size negotiated on this connection */
    1226       33650 : static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security) 
    1227             : {
    1228       33650 :         struct gensec_gssapi_state *gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);;
    1229       33406 :         return gensec_gssapi_state->max_wrap_buf_size;
    1230             : }
    1231             : 
    1232      336294 : static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
    1233             :                                           TALLOC_CTX *mem_ctx, 
    1234             :                                           uint8_t *data, size_t length, 
    1235             :                                           const uint8_t *whole_pdu, size_t pdu_length, 
    1236             :                                           DATA_BLOB *sig)
    1237             : {
    1238        1313 :         struct gensec_gssapi_state *gensec_gssapi_state
    1239      336294 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1240      336294 :         bool hdr_signing = false;
    1241      336294 :         size_t sig_size = 0;
    1242        1313 :         NTSTATUS status;
    1243             : 
    1244      336294 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1245      330710 :                 hdr_signing = true;
    1246             :         }
    1247             : 
    1248      336294 :         sig_size = gensec_gssapi_sig_size(gensec_security, length);
    1249             : 
    1250      336294 :         status = gssapi_seal_packet(gensec_gssapi_state->gssapi_context,
    1251             :                                     gensec_gssapi_state->gss_oid,
    1252             :                                     hdr_signing, sig_size,
    1253             :                                     data, length,
    1254             :                                     whole_pdu, pdu_length,
    1255             :                                     mem_ctx, sig);
    1256      336294 :         if (!NT_STATUS_IS_OK(status)) {
    1257           0 :                 DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu,"
    1258             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1259             :                           hdr_signing, sig_size, length, pdu_length,
    1260             :                           nt_errstr(status)));
    1261           0 :                 return status;
    1262             :         }
    1263             : 
    1264      336294 :         return NT_STATUS_OK;
    1265             : }
    1266             : 
    1267      336258 : static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
    1268             :                                             uint8_t *data, size_t length, 
    1269             :                                             const uint8_t *whole_pdu, size_t pdu_length,
    1270             :                                             const DATA_BLOB *sig)
    1271             : {
    1272        1312 :         struct gensec_gssapi_state *gensec_gssapi_state
    1273      336258 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1274      336258 :         bool hdr_signing = false;
    1275        1312 :         NTSTATUS status;
    1276             : 
    1277      336258 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1278      330674 :                 hdr_signing = true;
    1279             :         }
    1280             : 
    1281      336258 :         status = gssapi_unseal_packet(gensec_gssapi_state->gssapi_context,
    1282             :                                       gensec_gssapi_state->gss_oid,
    1283             :                                       hdr_signing,
    1284             :                                       data, length,
    1285             :                                       whole_pdu, pdu_length,
    1286             :                                       sig);
    1287      336258 :         if (!NT_STATUS_IS_OK(status)) {
    1288           0 :                 DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu,"
    1289             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1290             :                           hdr_signing, sig->length, length, pdu_length,
    1291             :                           nt_errstr(status)));
    1292           0 :                 return status;
    1293             :         }
    1294             : 
    1295      336258 :         return NT_STATUS_OK;
    1296             : }
    1297             : 
    1298       66892 : static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
    1299             :                                           TALLOC_CTX *mem_ctx, 
    1300             :                                           const uint8_t *data, size_t length, 
    1301             :                                           const uint8_t *whole_pdu, size_t pdu_length, 
    1302             :                                           DATA_BLOB *sig)
    1303             : {
    1304         316 :         struct gensec_gssapi_state *gensec_gssapi_state
    1305       66892 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1306       66892 :         bool hdr_signing = false;
    1307         316 :         NTSTATUS status;
    1308             : 
    1309       66892 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1310       52295 :                 hdr_signing = true;
    1311             :         }
    1312             : 
    1313       66892 :         status = gssapi_sign_packet(gensec_gssapi_state->gssapi_context,
    1314             :                                     gensec_gssapi_state->gss_oid,
    1315             :                                     hdr_signing,
    1316             :                                     data, length,
    1317             :                                     whole_pdu, pdu_length,
    1318             :                                     mem_ctx, sig);
    1319       66892 :         if (!NT_STATUS_IS_OK(status)) {
    1320           0 :                 DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
    1321             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1322             :                           hdr_signing, length, pdu_length,
    1323             :                           nt_errstr(status)));
    1324           0 :                 return status;
    1325             :         }
    1326             : 
    1327       66892 :         return NT_STATUS_OK;
    1328             : }
    1329             : 
    1330       66804 : static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
    1331             :                                            const uint8_t *data, size_t length, 
    1332             :                                            const uint8_t *whole_pdu, size_t pdu_length, 
    1333             :                                            const DATA_BLOB *sig)
    1334             : {
    1335         316 :         struct gensec_gssapi_state *gensec_gssapi_state
    1336       66804 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1337       66804 :         bool hdr_signing = false;
    1338         316 :         NTSTATUS status;
    1339             : 
    1340       66804 :         if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1341       52287 :                 hdr_signing = true;
    1342             :         }
    1343             : 
    1344       66804 :         status = gssapi_check_packet(gensec_gssapi_state->gssapi_context,
    1345             :                                      gensec_gssapi_state->gss_oid,
    1346             :                                      hdr_signing,
    1347             :                                      data, length,
    1348             :                                      whole_pdu, pdu_length,
    1349             :                                      sig);
    1350       66804 :         if (!NT_STATUS_IS_OK(status)) {
    1351           6 :                 DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu,"
    1352             :                           "data=%zu,pdu=%zu) failed: %s\n",
    1353             :                           hdr_signing, sig->length, length, pdu_length,
    1354             :                           nt_errstr(status)));
    1355           6 :                 return status;
    1356             :         }
    1357             : 
    1358       66798 :         return NT_STATUS_OK;
    1359             : }
    1360             : 
    1361             : /* Try to figure out what features we actually got on the connection */
    1362     7973580 : static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
    1363             :                                        uint32_t feature) 
    1364             : {
    1365       38634 :         struct gensec_gssapi_state *gensec_gssapi_state
    1366     7973580 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1367     7973580 :         if (feature & GENSEC_FEATURE_SIGN) {
    1368             :                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
    1369     1876498 :                 if (gensec_gssapi_state->sasl 
    1370         468 :                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
    1371         311 :                         return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) 
    1372         311 :                                 && (gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG));
    1373             :                 }
    1374     1876187 :                 return gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG;
    1375             :         }
    1376     6097082 :         if (feature & GENSEC_FEATURE_SEAL) {
    1377             :                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
    1378     4571381 :                 if (gensec_gssapi_state->sasl 
    1379         556 :                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
    1380         399 :                         return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) 
    1381         399 :                                  && (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG));
    1382             :                 }
    1383     4570982 :                 return gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG;
    1384             :         }
    1385     1525701 :         if (feature & GENSEC_FEATURE_SESSION_KEY) {
    1386             :                 /* Only for GSSAPI/Krb5 */
    1387       28723 :                 if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
    1388             :                                       gss_mech_krb5)) {
    1389       27421 :                         return true;
    1390             :                 }
    1391             :         }
    1392     1496978 :         if (feature & GENSEC_FEATURE_DCE_STYLE) {
    1393     1334262 :                 return gensec_gssapi_state->gss_got_flags & GSS_C_DCE_STYLE;
    1394             :         }
    1395      162716 :         if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
    1396         976 :                 NTSTATUS status;
    1397         976 :                 uint32_t keytype;
    1398             : 
    1399       33328 :                 if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) {
    1400          47 :                         return false;
    1401             :                 }
    1402             : 
    1403       33281 :                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "force_new_spnego", false)) {
    1404           0 :                         return true;
    1405             :                 }
    1406       33281 :                 if (gensec_setting_bool(gensec_security->settings, "gensec_gssapi", "disable_new_spnego", false)) {
    1407           0 :                         return false;
    1408             :                 }
    1409             : 
    1410       33281 :                 status = gssapi_get_session_key(gensec_gssapi_state,
    1411             :                                                 gensec_gssapi_state->gssapi_context, NULL, &keytype);
    1412             :                 /* 
    1413             :                  * We should do a proper sig on the mechListMic unless
    1414             :                  * we know we have to be backwards compatible with
    1415             :                  * earlier windows versions.  
    1416             :                  * 
    1417             :                  * Negotiating a non-krb5
    1418             :                  * mech for example should be regarded as having
    1419             :                  * NEW_SPNEGO
    1420             :                  */
    1421       33281 :                 if (NT_STATUS_IS_OK(status)) {
    1422       33281 :                         switch (keytype) {
    1423        2359 :                         case ENCTYPE_DES_CBC_CRC:
    1424             :                         case ENCTYPE_DES_CBC_MD5:
    1425             :                         case ENCTYPE_ARCFOUR_HMAC:
    1426             :                         case ENCTYPE_DES3_CBC_SHA1:
    1427        2359 :                                 return false;
    1428             :                         }
    1429             :                 }
    1430       30922 :                 return true;
    1431             :         }
    1432             :         /* We can always do async (rather than strict request/reply) packets.  */
    1433      129388 :         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
    1434      119235 :                 return true;
    1435             :         }
    1436        8766 :         if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
    1437        8766 :                 return true;
    1438             :         }
    1439           0 :         return false;
    1440             : }
    1441             : 
    1442       23416 : static NTTIME gensec_gssapi_expire_time(struct gensec_security *gensec_security)
    1443             : {
    1444         642 :         struct gensec_gssapi_state *gensec_gssapi_state =
    1445       23416 :                 talloc_get_type_abort(gensec_security->private_data,
    1446             :                 struct gensec_gssapi_state);
    1447             : 
    1448       23416 :         return gensec_gssapi_state->expire_time;
    1449             : }
    1450             : 
    1451             : /*
    1452             :  * Extract the 'session key' needed by SMB signing and ncacn_np
    1453             :  * (for encrypting some passwords).
    1454             :  * 
    1455             :  * This breaks all the abstractions, but what do you expect...
    1456             :  */
    1457       45710 : static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
    1458             :                                           TALLOC_CTX *mem_ctx,
    1459             :                                           DATA_BLOB *session_key) 
    1460             : {
    1461        1532 :         struct gensec_gssapi_state *gensec_gssapi_state
    1462       45710 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1463       45710 :         return gssapi_get_session_key(mem_ctx, gensec_gssapi_state->gssapi_context, session_key, NULL);
    1464             : }
    1465             : 
    1466             : /* Get some basic (and authorization) information about the user on
    1467             :  * this session.  This uses either the PAC (if present) or a local
    1468             :  * database lookup */
    1469       31332 : static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
    1470             :                                            TALLOC_CTX *mem_ctx,
    1471             :                                            struct auth_session_info **_session_info) 
    1472             : {
    1473         881 :         NTSTATUS nt_status;
    1474         881 :         TALLOC_CTX *tmp_ctx;
    1475         881 :         struct gensec_gssapi_state *gensec_gssapi_state
    1476       31332 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1477       31332 :         struct auth_session_info *session_info = NULL;
    1478         881 :         OM_uint32 maj_stat, min_stat;
    1479       31332 :         DATA_BLOB pac_blob, *pac_blob_ptr = NULL;
    1480             : 
    1481         881 :         gss_buffer_desc name_token;
    1482         881 :         char *principal_string;
    1483             :         
    1484       31332 :         tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
    1485       31332 :         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
    1486             : 
    1487       32213 :         maj_stat = gss_display_name (&min_stat,
    1488       23317 :                                      gensec_gssapi_state->client_name,
    1489             :                                      &name_token,
    1490             :                                      NULL);
    1491       31332 :         if (GSS_ERROR(maj_stat)) {
    1492           0 :                 DEBUG(1, ("GSS display_name failed: %s\n",
    1493             :                           gssapi_error_string(tmp_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
    1494           0 :                 talloc_free(tmp_ctx);
    1495           0 :                 return NT_STATUS_FOOBAR;
    1496             :         }
    1497             : 
    1498       32213 :         principal_string = talloc_strndup(tmp_ctx,
    1499       31332 :                                           (const char *)name_token.value,
    1500             :                                           name_token.length);
    1501             : 
    1502       31332 :         gss_release_buffer(&min_stat, &name_token);
    1503             : 
    1504       31332 :         if (!principal_string) {
    1505           0 :                 talloc_free(tmp_ctx);
    1506           0 :                 return NT_STATUS_NO_MEMORY;
    1507             :         }
    1508             : 
    1509       31332 :         nt_status = gssapi_obtain_pac_blob(tmp_ctx,  gensec_gssapi_state->gssapi_context,
    1510             :                                            gensec_gssapi_state->client_name,
    1511             :                                            &pac_blob);
    1512             :         
    1513             :         /* IF we have the PAC - otherwise we need to get this
    1514             :          * data from elsewhere - local ldb, or (TODO) lookup of some
    1515             :          * kind... 
    1516             :          */
    1517       31332 :         if (NT_STATUS_IS_OK(nt_status)) {
    1518       31327 :                 pac_blob_ptr = &pac_blob;
    1519             :         }
    1520       31332 :         nt_status = gensec_generate_session_info_pac(tmp_ctx,
    1521             :                                                      gensec_security,
    1522             :                                                      gensec_gssapi_state->smb_krb5_context,
    1523             :                                                      pac_blob_ptr, principal_string,
    1524             :                                                      gensec_get_remote_address(gensec_security),
    1525             :                                                      &session_info);
    1526       31332 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1527           5 :                 talloc_free(tmp_ctx);
    1528           5 :                 return nt_status;
    1529             :         }
    1530             : 
    1531       31327 :         nt_status = gensec_gssapi_session_key(gensec_security, session_info, &session_info->session_key);
    1532       31327 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1533           0 :                 talloc_free(tmp_ctx);
    1534           0 :                 return nt_status;
    1535             :         }
    1536             : 
    1537       31327 :         if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
    1538       29869 :             gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
    1539         881 :                 krb5_error_code ret;
    1540         881 :                 const char *error_string;
    1541             : 
    1542       29805 :                 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
    1543             : 
    1544             :                 /*
    1545             :                  * Create anonymous credentials for now.
    1546             :                  *
    1547             :                  * We will update them with the provided client gss creds.
    1548             :                  */
    1549       29805 :                 session_info->credentials = cli_credentials_init_anon(session_info);
    1550       29805 :                 if (session_info->credentials == NULL) {
    1551           0 :                         talloc_free(tmp_ctx);
    1552           0 :                         return NT_STATUS_NO_MEMORY;
    1553             :                 }
    1554             : 
    1555       30686 :                 ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
    1556       29805 :                                                            gensec_security->settings->lp_ctx,
    1557             :                                                            gensec_gssapi_state->delegated_cred_handle,
    1558             :                                                            CRED_SPECIFIED, &error_string);
    1559       29805 :                 if (ret) {
    1560           0 :                         talloc_free(tmp_ctx);
    1561           0 :                         DEBUG(2,("Failed to get gss creds: %s\n", error_string));
    1562           0 :                         return NT_STATUS_NO_MEMORY;
    1563             :                 }
    1564             :                 
    1565             :                 /* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
    1566       29805 :                 cli_credentials_set_kerberos_state(session_info->credentials,
    1567             :                                                    CRED_USE_KERBEROS_REQUIRED,
    1568             :                                                    CRED_SPECIFIED);
    1569             : 
    1570             :                 /* It has been taken from this place... */
    1571       29805 :                 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
    1572             :         } else {
    1573        1522 :                 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
    1574             :         }
    1575             : 
    1576       31327 :         *_session_info = talloc_steal(mem_ctx, session_info);
    1577       31327 :         talloc_free(tmp_ctx);
    1578             : 
    1579       31327 :         return NT_STATUS_OK;
    1580             : }
    1581             : 
    1582      456673 : static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
    1583             : {
    1584        2682 :         struct gensec_gssapi_state *gensec_gssapi_state
    1585      456673 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1586        2682 :         size_t sig_size;
    1587             : 
    1588      456673 :         if (gensec_gssapi_state->sig_size > 0) {
    1589      445687 :                 return gensec_gssapi_state->sig_size;
    1590             :         }
    1591             : 
    1592        8490 :         sig_size = gssapi_get_sig_size(gensec_gssapi_state->gssapi_context,
    1593             :                                        gensec_gssapi_state->gss_oid,
    1594             :                                        gensec_gssapi_state->gss_got_flags,
    1595             :                                        data_size);
    1596             : 
    1597        8490 :         gensec_gssapi_state->sig_size = sig_size;
    1598        8490 :         return gensec_gssapi_state->sig_size;
    1599             : }
    1600             : 
    1601       31327 : static const char *gensec_gssapi_final_auth_type(struct gensec_security *gensec_security)
    1602             : {
    1603         881 :         struct gensec_gssapi_state *gensec_gssapi_state
    1604       31327 :                 = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
    1605             :         /* Only return the string for GSSAPI/Krb5 */
    1606       31327 :         if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
    1607             :                               gss_mech_krb5)) {
    1608       30446 :                 return GENSEC_FINAL_AUTH_TYPE_KRB5;
    1609             :         } else {
    1610           0 :                 return "gensec_gssapi: UNKNOWN MECH";
    1611             :         }
    1612             : }
    1613             : 
    1614             : static const char *gensec_gssapi_krb5_oids[] = { 
    1615             :         GENSEC_OID_KERBEROS5_OLD,
    1616             :         GENSEC_OID_KERBEROS5,
    1617             :         NULL 
    1618             : };
    1619             : 
    1620             : static const char *gensec_gssapi_spnego_oids[] = { 
    1621             :         GENSEC_OID_SPNEGO,
    1622             :         NULL 
    1623             : };
    1624             : 
    1625             : /* As a server, this could in theory accept any GSSAPI mech */
    1626             : static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
    1627             :         .name           = "gssapi_spnego",
    1628             :         .sasl_name      = "GSS-SPNEGO",
    1629             :         .auth_type      = DCERPC_AUTH_TYPE_SPNEGO,
    1630             :         .oid            = gensec_gssapi_spnego_oids,
    1631             :         .client_start   = gensec_gssapi_client_start,
    1632             :         .server_start   = gensec_gssapi_server_start,
    1633             :         .magic          = gensec_magic_check_krb5_oid,
    1634             :         .update_send    = gensec_gssapi_update_send,
    1635             :         .update_recv    = gensec_gssapi_update_recv,
    1636             :         .session_key    = gensec_gssapi_session_key,
    1637             :         .session_info   = gensec_gssapi_session_info,
    1638             :         .sign_packet    = gensec_gssapi_sign_packet,
    1639             :         .check_packet   = gensec_gssapi_check_packet,
    1640             :         .seal_packet    = gensec_gssapi_seal_packet,
    1641             :         .unseal_packet  = gensec_gssapi_unseal_packet,
    1642             :         .max_input_size   = gensec_gssapi_max_input_size,
    1643             :         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
    1644             :         .wrap           = gensec_gssapi_wrap,
    1645             :         .unwrap         = gensec_gssapi_unwrap,
    1646             :         .have_feature   = gensec_gssapi_have_feature,
    1647             :         .expire_time    = gensec_gssapi_expire_time,
    1648             :         .final_auth_type = gensec_gssapi_final_auth_type,
    1649             :         .enabled        = false,
    1650             :         .kerberos       = true,
    1651             :         .priority       = GENSEC_GSSAPI
    1652             : };
    1653             : 
    1654             : /* As a server, this could in theory accept any GSSAPI mech */
    1655             : static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
    1656             :         .name           = "gssapi_krb5",
    1657             :         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
    1658             :         .oid            = gensec_gssapi_krb5_oids,
    1659             :         .client_start   = gensec_gssapi_client_start,
    1660             :         .server_start   = gensec_gssapi_server_start,
    1661             :         .magic          = gensec_magic_check_krb5_oid,
    1662             :         .update_send    = gensec_gssapi_update_send,
    1663             :         .update_recv    = gensec_gssapi_update_recv,
    1664             :         .session_key    = gensec_gssapi_session_key,
    1665             :         .session_info   = gensec_gssapi_session_info,
    1666             :         .sig_size       = gensec_gssapi_sig_size,
    1667             :         .sign_packet    = gensec_gssapi_sign_packet,
    1668             :         .check_packet   = gensec_gssapi_check_packet,
    1669             :         .seal_packet    = gensec_gssapi_seal_packet,
    1670             :         .unseal_packet  = gensec_gssapi_unseal_packet,
    1671             :         .max_input_size   = gensec_gssapi_max_input_size,
    1672             :         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
    1673             :         .wrap           = gensec_gssapi_wrap,
    1674             :         .unwrap         = gensec_gssapi_unwrap,
    1675             :         .have_feature   = gensec_gssapi_have_feature,
    1676             :         .expire_time    = gensec_gssapi_expire_time,
    1677             :         .final_auth_type = gensec_gssapi_final_auth_type,
    1678             :         .enabled        = true,
    1679             :         .kerberos       = true,
    1680             :         .priority       = GENSEC_GSSAPI
    1681             : };
    1682             : 
    1683             : /* As a server, this could in theory accept any GSSAPI mech */
    1684             : static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
    1685             :         .name             = "gssapi_krb5_sasl",
    1686             :         .sasl_name        = "GSSAPI",
    1687             :         .client_start     = gensec_gssapi_sasl_client_start,
    1688             :         .server_start     = gensec_gssapi_sasl_server_start,
    1689             :         .update_send      = gensec_gssapi_update_send,
    1690             :         .update_recv      = gensec_gssapi_update_recv,
    1691             :         .session_key      = gensec_gssapi_session_key,
    1692             :         .session_info     = gensec_gssapi_session_info,
    1693             :         .max_input_size   = gensec_gssapi_max_input_size,
    1694             :         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
    1695             :         .wrap             = gensec_gssapi_wrap,
    1696             :         .unwrap           = gensec_gssapi_unwrap,
    1697             :         .have_feature     = gensec_gssapi_have_feature,
    1698             :         .expire_time      = gensec_gssapi_expire_time,
    1699             :         .final_auth_type = gensec_gssapi_final_auth_type,
    1700             :         .enabled          = true,
    1701             :         .kerberos         = true,
    1702             :         .priority         = GENSEC_GSSAPI
    1703             : };
    1704             : 
    1705       51497 : _PUBLIC_ NTSTATUS gensec_gssapi_init(TALLOC_CTX *ctx)
    1706             : {
    1707        1174 :         NTSTATUS ret;
    1708             : 
    1709       51497 :         ret = gensec_register(ctx, &gensec_gssapi_spnego_security_ops);
    1710       51497 :         if (!NT_STATUS_IS_OK(ret)) {
    1711           0 :                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
    1712             :                         gensec_gssapi_spnego_security_ops.name));
    1713           0 :                 return ret;
    1714             :         }
    1715             : 
    1716       51497 :         ret = gensec_register(ctx, &gensec_gssapi_krb5_security_ops);
    1717       51497 :         if (!NT_STATUS_IS_OK(ret)) {
    1718           0 :                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
    1719             :                         gensec_gssapi_krb5_security_ops.name));
    1720           0 :                 return ret;
    1721             :         }
    1722             : 
    1723       51497 :         ret = gensec_register(ctx, &gensec_gssapi_sasl_krb5_security_ops);
    1724       51497 :         if (!NT_STATUS_IS_OK(ret)) {
    1725           0 :                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
    1726             :                         gensec_gssapi_sasl_krb5_security_ops.name));
    1727           0 :                 return ret;
    1728             :         }
    1729             : 
    1730       51497 :         return ret;
    1731             : }

Generated by: LCOV version 1.14