1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-30 06:50:24 +03:00

s3-libcli Change krb5 smb sealing to call via gensec and gensec_gse

This also fixes the support for smb sealing with krb5 in make test, as
this now relies on secrets.tdb rather than /etc/krb5.keytab.

Andrew Bartlett

Signed-off-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Andrew Bartlett 2012-01-13 20:34:10 +11:00 committed by Stefan Metzmacher
parent 30b1e72556
commit 06f7105490
5 changed files with 89 additions and 490 deletions

View File

@ -167,150 +167,6 @@ static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec,
return NT_STATUS_OK;
}
/******************************************************************************
Generic code for client and server.
gss-api decrypt an incoming buffer. We insist that the size of the
unwrapped buffer must be smaller or identical to the incoming buffer.
******************************************************************************/
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
{
gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
OM_uint32 ret = 0;
OM_uint32 minor = 0;
int flags_got = 0;
gss_buffer_desc in_buf, out_buf;
size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
if (buf_len < 8) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
in_buf.value = buf + 8;
in_buf.length = buf_len - 8;
ret = gss_unwrap(&minor,
gss_ctx,
&in_buf,
&out_buf,
&flags_got, /* did we get sign+seal ? */
(gss_qop_t *) NULL);
if (ret != GSS_S_COMPLETE) {
NTSTATUS status = NT_STATUS_ACCESS_DENIED;
char *gss_err;
gss_err = gssapi_error_string(talloc_tos(),
ret, minor,
GSS_C_NULL_OID);
DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap failed. "
"Error [%d/%d] - %s - %s\n",
ret, minor, nt_errstr(status),
gss_err ? gss_err : "<unknown>"));
talloc_free(gss_err);
return status;
}
if (out_buf.length > in_buf.length) {
DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
(unsigned int)out_buf.length,
(unsigned int)in_buf.length ));
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_INVALID_PARAMETER;
}
memcpy(buf + 8, out_buf.value, out_buf.length);
/* Reset the length and overwrite the header. */
smb_setlen_nbt(buf, out_buf.length + 4);
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_OK;
}
/******************************************************************************
Generic code for client and server.
gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
******************************************************************************/
static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
uint16_t enc_ctx_num,
char *buf,
char **ppbuf_out)
{
gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
OM_uint32 ret = 0;
OM_uint32 minor = 0;
int flags_got = 0;
gss_buffer_desc in_buf, out_buf;
size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
*ppbuf_out = NULL;
if (buf_len < 8) {
return NT_STATUS_BUFFER_TOO_SMALL;
}
in_buf.value = buf + 8;
in_buf.length = buf_len - 8;
ret = gss_wrap(&minor,
gss_ctx,
true, /* we want sign+seal. */
GSS_C_QOP_DEFAULT,
&in_buf,
&flags_got, /* did we get sign+seal ? */
&out_buf);
if (ret != GSS_S_COMPLETE) {
NTSTATUS status = NT_STATUS_ACCESS_DENIED;
char *gss_err;
gss_err = gssapi_error_string(talloc_tos(),
ret, minor,
GSS_C_NULL_OID);
DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. "
"Error [%d/%d] - %s - %s\n",
ret, minor, nt_errstr(status),
gss_err ? gss_err : "<unknown>"));
talloc_free(gss_err);
return status;
}
if (!flags_got) {
/* Sign+seal not supported. */
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_NOT_SUPPORTED;
}
/* Ya see - this is why I *hate* gss-api. I don't
* want to have to malloc another buffer of the
* same size + 8 bytes just to get a continuous
* header + buffer, but gss won't let me pass in
* a pre-allocated buffer. Bastards (and you know
* who you are....). I might fix this by
* going to "encrypt_and_send" passing in a file
* descriptor and doing scatter-gather write with
* TCP cork on Linux. But I shouldn't have to
* bother :-*(. JRA.
*/
*ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
if (!*ppbuf_out) {
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_NO_MEMORY;
}
memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_OK;
}
#endif
/******************************************************************************
Generic code for client and server.
Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
@ -324,16 +180,7 @@ NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, cha
return NT_STATUS_OK;
}
switch (es->smb_enc_type) {
case SMB_TRANS_ENC_NTLM:
return common_gensec_encrypt_buffer(es->s.gensec_security, es->enc_ctx_num, buffer, buf_out);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
case SMB_TRANS_ENC_GSS:
return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
#endif
default:
return NT_STATUS_NOT_SUPPORTED;
}
return common_gensec_encrypt_buffer(es->s.gensec_security, es->enc_ctx_num, buffer, buf_out);
}
/******************************************************************************
@ -349,38 +196,9 @@ NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
return NT_STATUS_OK;
}
switch (es->smb_enc_type) {
case SMB_TRANS_ENC_NTLM:
return common_gensec_decrypt_buffer(es->s.gensec_security, buf);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
case SMB_TRANS_ENC_GSS:
return common_gss_decrypt_buffer(es->s.gss_state, buf);
#endif
default:
return NT_STATUS_NOT_SUPPORTED;
}
return common_gensec_decrypt_buffer(es->s.gensec_security, buf);
}
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
/******************************************************************************
Shutdown a gss encryption state.
******************************************************************************/
static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
{
OM_uint32 minor = 0;
struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
gss_release_cred(&minor, &gss_state->creds);
}
if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
}
SAFE_FREE(*pp_gss_state);
}
#endif
/******************************************************************************
Shutdown an encryption state.
******************************************************************************/
@ -393,19 +211,9 @@ void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
return;
}
if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
if (es->s.gensec_security) {
TALLOC_FREE(es->s.gensec_security);
}
if (es->s.gensec_security) {
TALLOC_FREE(es->s.gensec_security);
}
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
/* Free the gss context handle. */
if (es->s.gss_state) {
common_free_gss_state(&es->s.gss_state);
}
}
#endif
SAFE_FREE(es);
*pp_es = NULL;
}

View File

@ -49,9 +49,6 @@ struct smb_trans_enc_state {
bool enc_on;
union {
struct gensec_security *gensec_security;
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
struct smb_tran_enc_state_gss *gss_state;
#endif
} s;
};

View File

@ -20,9 +20,6 @@
^samba3.blackbox.rpcclient over ncacn_np with \[spnego,smb2,bigendian\]
^samba3.blackbox.rpcclient over ncacn_np with \[spnego,connect,smb2\]
^samba3.blackbox.rpcclient over ncacn_np with \[spnego,connect,smb2,bigendian\]
# GSSAPI/krb5 encrypted CIFS fails in the test environment at the moment
^samba3.blackbox.smbclient_krb5 -e.smbclient
^samba3.blackbox.smbclient_krb5 old ccache -e.smbclient
# these show that we still have some differences between our system
# with our internal iconv because it passes except when we bypass our
# internal iconv modules

View File

@ -30,6 +30,7 @@
#include "auth_generic.h"
#include "auth/gensec/gensec.h"
#include "../libcli/smb/smbXcli_base.h"
#include "auth/credentials/credentials.h"
/****************************************************************************
Get UNIX extensions version info.
@ -585,16 +586,6 @@ static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type sm
ZERO_STRUCTP(es);
es->smb_enc_type = smb_enc_type;
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
if (smb_enc_type == SMB_TRANS_ENC_GSS) {
es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
if (!es->s.gss_state) {
SAFE_FREE(es);
return NULL;
}
ZERO_STRUCTP(es->s.gss_state);
}
#endif
return es;
}
@ -683,99 +674,33 @@ NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli,
return status;
}
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
#ifndef SMB_GSS_REQUIRED_FLAGS
#define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)
#endif
/******************************************************************************
Get client gss blob to send to a server.
******************************************************************************/
static NTSTATUS make_cli_gss_blob(TALLOC_CTX *ctx,
struct smb_trans_enc_state *es,
const char *service,
const char *host,
struct gensec_security *gensec_security,
NTSTATUS status_in,
DATA_BLOB spnego_blob_in,
DATA_BLOB *p_blob_out)
{
const char *krb_mechs[] = {OID_KERBEROS5, NULL};
OM_uint32 ret;
OM_uint32 min;
gss_name_t srv_name;
gss_buffer_desc input_name;
gss_buffer_desc *p_tok_in;
gss_buffer_desc tok_out, tok_in;
DATA_BLOB blob_out = data_blob_null;
DATA_BLOB blob_in = data_blob_null;
OM_uint32 ret_flags = 0;
NTSTATUS status = NT_STATUS_OK;
memset(&tok_out, '\0', sizeof(tok_out));
/* Guess the realm based on the supplied service, and avoid the GSS libs
doing DNS lookups which may fail.
TODO: Loop with the KDC on some more combinations (local
realm in particular), possibly falling back to
GSS_C_NT_HOSTBASED_SERVICE
*/
input_name.value = kerberos_get_principal_from_service_hostname(talloc_tos(),
service, host);
if (!input_name.value) {
return NT_STATUS_NO_MEMORY;
}
input_name.length = strlen((char *)input_name.value);
ret = gss_import_name(&min, &input_name,
GSS_C_NT_USER_NAME,
&srv_name);
if (ret != GSS_S_COMPLETE) {
TALLOC_FREE(input_name.value);
return map_nt_error_from_gss(ret, min);
}
if (spnego_blob_in.length == 0) {
p_tok_in = GSS_C_NO_BUFFER;
blob_in = spnego_blob_in;
} else {
/* Remove the SPNEGO wrapper */
if (!spnego_parse_auth_response(ctx, spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
status = NT_STATUS_UNSUCCESSFUL;
goto fail;
}
tok_in.value = blob_in.data;
tok_in.length = blob_in.length;
p_tok_in = &tok_in;
}
ret = gss_init_sec_context(&min,
GSS_C_NO_CREDENTIAL, /* Use our default cred. */
&es->s.gss_state->gss_ctx,
srv_name,
GSS_C_NO_OID, /* default OID. */
GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
GSS_C_INDEFINITE, /* requested ticket lifetime. */
NULL, /* no channel bindings */
p_tok_in,
NULL, /* ignore mech type */
&tok_out,
&ret_flags,
NULL); /* ignore time_rec */
status = map_nt_error_from_gss(ret, min);
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
ads_errstr(adss)));
goto fail;
}
if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
status = NT_STATUS_ACCESS_DENIED;
}
blob_out = data_blob_talloc(ctx, tok_out.value, tok_out.length);
status = gensec_update(gensec_security, ctx,
NULL, blob_in, &blob_out);
/* Wrap in an SPNEGO wrapper */
*p_blob_out = spnego_gen_negTokenInit(ctx, krb_mechs, &blob_out, NULL);
@ -784,11 +709,6 @@ static NTSTATUS make_cli_gss_blob(TALLOC_CTX *ctx,
data_blob_free(&blob_out);
data_blob_free(&blob_in);
TALLOC_FREE(input_name.value);
gss_release_name(&min, &srv_name);
if (tok_out.value) {
gss_release_buffer(&min, &tok_out);
}
return status;
}
@ -802,16 +722,41 @@ NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
DATA_BLOB blob_send = data_blob_null;
DATA_BLOB param_out = data_blob_null;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
fstring fqdn;
const char *servicename;
struct auth_generic_state *auth_generic_state;
struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
if (!es) {
return NT_STATUS_NO_MEMORY;
}
servicename = "cifs";
status = make_cli_gss_blob(talloc_tos(), es, servicename, cli_state_remote_name(cli), NT_STATUS_OK, blob_recv, &blob_send);
status = auth_generic_client_prepare(NULL,
&auth_generic_state);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SESSION_KEY);
gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
cli_credentials_set_kerberos_state(auth_generic_state->credentials,
CRED_MUST_USE_KERBEROS);
status = gensec_set_target_service(auth_generic_state->gensec_security, "cifs");
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
status = gensec_set_target_hostname(auth_generic_state->gensec_security,
cli_state_remote_name(cli));
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
if (!NT_STATUS_IS_OK(status = auth_generic_client_start(auth_generic_state, GENSEC_OID_KERBEROS5))) {
goto fail;
}
status = make_cli_gss_blob(talloc_tos(), auth_generic_state->gensec_security, NT_STATUS_OK, blob_recv, &blob_send);
do {
data_blob_free(&blob_recv);
status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
@ -819,25 +764,34 @@ NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
es->enc_ctx_num = SVAL(param_out.data, 0);
}
data_blob_free(&blob_send);
status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, status, blob_recv, &blob_send);
status = make_cli_gss_blob(talloc_tos(), auth_generic_state->gensec_security, status, blob_recv, &blob_send);
} while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
data_blob_free(&blob_recv);
if (NT_STATUS_IS_OK(status)) {
if (!gensec_have_feature(auth_generic_state->gensec_security,
GENSEC_FEATURE_SIGN) ||
!gensec_have_feature(auth_generic_state->gensec_security,
GENSEC_FEATURE_SEAL)) {
status = NT_STATUS_ACCESS_DENIED;
}
}
if (NT_STATUS_IS_OK(status)) {
es->enc_on = true;
/* Replace the old state, if any. */
/* We only need the gensec_security part from here.
* es is a malloc()ed pointer, so we cannot make
* gensec_security a talloc child */
es->s.gensec_security = talloc_move(NULL,
&auth_generic_state->gensec_security);
smb1cli_conn_set_encryption(cli->conn, es);
es = NULL;
}
fail:
common_free_encryption_state(&es);
return status;
}
#else
NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
{
return NT_STATUS_NOT_SUPPORTED;
}
#endif
/********************************************************************
Ensure a connection is encrypted.

View File

@ -86,8 +86,16 @@ static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
/*
* We could be accessing the secrets.tdb or krb5.keytab file here.
* ensure we have permissions to do so.
*/
become_root();
status = gensec_start_mech_by_oid(gensec_security, oid);
unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(gensec_security);
return nt_status_squash(status);
@ -98,114 +106,6 @@ static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
return status;
}
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
/******************************************************************************
Import a name.
******************************************************************************/
static NTSTATUS get_srv_gss_creds(const char *service,
const char *name,
gss_cred_usage_t cred_type,
gss_cred_id_t *p_srv_cred)
{
OM_uint32 ret;
OM_uint32 min;
gss_name_t srv_name;
gss_buffer_desc input_name;
char *host_princ_s = NULL;
NTSTATUS status = NT_STATUS_OK;
gss_OID_desc nt_hostbased_service =
{10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
if (asprintf(&host_princ_s, "%s@%s", service, name) == -1) {
return NT_STATUS_NO_MEMORY;
}
input_name.value = host_princ_s;
input_name.length = strlen(host_princ_s) + 1;
ret = gss_import_name(&min,
&input_name,
&nt_hostbased_service,
&srv_name);
DEBUG(10,("get_srv_gss_creds: imported name %s\n",
host_princ_s ));
if (ret != GSS_S_COMPLETE) {
SAFE_FREE(host_princ_s);
return map_nt_error_from_gss(ret, min);
}
/*
* We're accessing the krb5.keytab file here.
* ensure we have permissions to do so.
*/
become_root();
ret = gss_acquire_cred(&min,
srv_name,
GSS_C_INDEFINITE,
GSS_C_NULL_OID_SET,
cred_type,
p_srv_cred,
NULL,
NULL);
unbecome_root();
if (ret != GSS_S_COMPLETE) {
ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
DEBUG(10,("get_srv_gss_creds: gss_acquire_cred failed with %s\n",
ads_errstr(adss)));
status = map_nt_error_from_gss(ret, min);
}
SAFE_FREE(host_princ_s);
gss_release_name(&min, &srv_name);
return status;
}
/******************************************************************************
Create a gss state.
Try and get the cifs/server@realm principal first, then fall back to
host/server@realm.
******************************************************************************/
static NTSTATUS make_auth_gss(struct smb_trans_enc_state *es)
{
NTSTATUS status;
gss_cred_id_t srv_cred;
fstring fqdn;
name_to_fqdn(fqdn, lp_netbios_name());
strlower_m(fqdn);
status = get_srv_gss_creds("cifs", fqdn, GSS_C_ACCEPT, &srv_cred);
if (!NT_STATUS_IS_OK(status)) {
status = get_srv_gss_creds("host", fqdn, GSS_C_ACCEPT, &srv_cred);
if (!NT_STATUS_IS_OK(status)) {
return nt_status_squash(status);
}
}
es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
if (!es->s.gss_state) {
OM_uint32 min;
gss_release_cred(&min, &srv_cred);
return NT_STATUS_NO_MEMORY;
}
ZERO_STRUCTP(es->s.gss_state);
es->s.gss_state->creds = srv_cred;
/* No context yet. */
es->s.gss_state->gss_ctx = GSS_C_NO_CONTEXT;
return NT_STATUS_OK;
}
#endif
/******************************************************************************
Shutdown a server encryption context.
******************************************************************************/
@ -232,6 +132,8 @@ static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote
enum smb_trans_enc_type smb_enc_type,
struct smb_trans_enc_state **pp_es)
{
NTSTATUS status;
const char *oid;
struct smb_trans_enc_state *es;
*pp_es = NULL;
@ -245,32 +147,21 @@ static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote
es->smb_enc_type = smb_enc_type;
switch (smb_enc_type) {
case SMB_TRANS_ENC_NTLM:
{
NTSTATUS status = make_auth_gensec(remote_address,
es, GENSEC_OID_NTLMSSP);
if (!NT_STATUS_IS_OK(status)) {
srv_free_encryption_context(&es);
return status;
}
}
oid = GENSEC_OID_NTLMSSP;
break;
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
case SMB_TRANS_ENC_GSS:
/* Acquire our credentials by calling gss_acquire_cred here. */
{
NTSTATUS status = make_auth_gss(es);
if (!NT_STATUS_IS_OK(status)) {
srv_free_encryption_context(&es);
return status;
}
}
oid = GENSEC_OID_KERBEROS5;
break;
#endif
default:
srv_free_encryption_context(&es);
return NT_STATUS_INVALID_PARAMETER;
}
status = make_auth_gensec(remote_address,
es, oid);
if (!NT_STATUS_IS_OK(status)) {
srv_free_encryption_context(&es);
return status;
}
*pp_es = es;
return NT_STATUS_OK;
}
@ -338,75 +229,35 @@ NTSTATUS srv_encrypt_buffer(struct smbd_server_connection *sconn, char *buf,
Until success we do everything on the partial enc ctx.
******************************************************************************/
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
static NTSTATUS srv_enc_spnego_gss_negotiate(const struct tsocket_address *remote_address,
unsigned char **ppdata,
size_t *p_data_size,
DATA_BLOB secblob)
{
OM_uint32 ret;
OM_uint32 min;
OM_uint32 flags = 0;
gss_buffer_desc in_buf, out_buf;
struct smb_tran_enc_state_gss *gss_state;
DATA_BLOB auth_reply = data_blob_null;
DATA_BLOB response = data_blob_null;
NTSTATUS status;
DATA_BLOB unwrapped_response = data_blob_null;
DATA_BLOB response = data_blob_null;
if (!partial_srv_trans_enc_ctx) {
status = make_srv_encryption_context(remote_address,
SMB_TRANS_ENC_GSS,
&partial_srv_trans_enc_ctx);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
gss_state = partial_srv_trans_enc_ctx->s.gss_state;
in_buf.value = secblob.data;
in_buf.length = secblob.length;
out_buf.value = NULL;
out_buf.length = 0;
become_root();
ret = gss_accept_sec_context(&min,
&gss_state->gss_ctx,
gss_state->creds,
&in_buf,
GSS_C_NO_CHANNEL_BINDINGS,
NULL,
NULL, /* Ignore oids. */
&out_buf, /* To return. */
&flags,
NULL, /* Ingore time. */
NULL); /* Ignore delegated creds. */
unbecome_root();
status = gss_err_to_ntstatus(ret, min);
if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
status = make_srv_encryption_context(remote_address,
SMB_TRANS_ENC_GSS,
&partial_srv_trans_enc_ctx);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* Ensure we've got sign+seal available. */
if (ret == GSS_S_COMPLETE) {
if ((flags & (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) !=
(GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) {
DEBUG(0,("srv_enc_spnego_gss_negotiate: quality of service not good enough "
"for SMB sealing.\n"));
gss_release_buffer(&min, &out_buf);
return NT_STATUS_ACCESS_DENIED;
}
}
become_root();
auth_reply = data_blob(out_buf.value, out_buf.length);
gss_release_buffer(&min, &out_buf);
status = gensec_update(partial_srv_trans_enc_ctx->s.gensec_security,
talloc_tos(), NULL,
secblob, &unwrapped_response);
/* Wrap in SPNEGO. */
response = spnego_gen_auth_response(talloc_tos(), &auth_reply, status, OID_KERBEROS5);
data_blob_free(&auth_reply);
unbecome_root();
/* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
* for success ... */
response = spnego_gen_auth_response(talloc_tos(), &unwrapped_response, status, OID_KERBEROS5);
data_blob_free(&unwrapped_response);
SAFE_FREE(*ppdata);
*ppdata = (unsigned char *)memdup(response.data, response.length);
@ -414,12 +265,10 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(const struct tsocket_address *remot
status = NT_STATUS_NO_MEMORY;
}
*p_data_size = response.length;
data_blob_free(&response);
return status;
}
#endif
/******************************************************************************
Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out.
@ -500,16 +349,10 @@ static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
if (kerb_mech) {
TALLOC_FREE(kerb_mech);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
status = srv_enc_spnego_gss_negotiate(conn->sconn->remote_address,
ppdata,
p_data_size,
secblob);
#else
/* Currently we don't SPNEGO negotiate
* back to NTLMSSP as we do in sessionsetupX. We should... */
return NT_STATUS_LOGON_FAILURE;
#endif
} else {
status = srv_enc_ntlm_negotiate(conn->sconn->remote_address,
ppdata,