summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/client.h9
-rw-r--r--source3/include/includes.h4
-rw-r--r--source3/include/trans2.h1
-rw-r--r--source3/libsmb/smb_seal.c33
-rw-r--r--source3/smbd/negprot.c4
-rw-r--r--source3/smbd/seal.c86
6 files changed, 128 insertions, 9 deletions
diff --git a/source3/include/client.h b/source3/include/client.h
index 817ab0d540..3185f05ac1 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -81,13 +81,20 @@ struct rpc_pipe_client {
/* Transport encryption state. */
enum smb_trans_enc_type { SMB_TRANS_ENC_NTLM, SMB_TRANS_ENC_GSS };
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+struct smb_tran_enc_state_gss {
+ gss_ctx_id_t gss_ctx;
+ gss_cred_id_t creds;
+};
+#endif
+
struct smb_trans_enc_state {
enum smb_trans_enc_type smb_enc_type;
BOOL enc_on;
union {
NTLMSSP_STATE *ntlmssp_state;
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
- gss_ctx_id_t context_handle;
+ struct smb_tran_enc_state_gss *gss_state;
#endif
} s;
};
diff --git a/source3/include/includes.h b/source3/include/includes.h
index c51da335a2..b4485ba30d 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -1188,10 +1188,10 @@ krb5_error_code smb_krb5_mk_error(krb5_context context,
/* Call for SMB transport encryption. */
#if defined(HAVE_GSSAPI)
-NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf);
+NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf);
#endif
#if defined(HAVE_GSSAPI)
-NTSTATUS common_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **buf_out);
+NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf, char **buf_out);
#endif
#endif /* HAVE_KRB5 */
diff --git a/source3/include/trans2.h b/source3/include/trans2.h
index 32ea7d927f..5f7587d6ea 100644
--- a/source3/include/trans2.h
+++ b/source3/include/trans2.h
@@ -530,6 +530,7 @@ findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x40 /* We can do SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x80 /* We *must* SPNEGO negotiations for encryption. */
#define SMB_QUERY_POSIX_FS_INFO 0x201
diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c
index 95012d629e..f0e79b404c 100644
--- a/source3/libsmb/smb_seal.c
+++ b/source3/libsmb/smb_seal.c
@@ -126,8 +126,9 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, cha
******************************************************************************/
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
- NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
+ 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;
@@ -142,7 +143,7 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, cha
in_buf.length = buf_len - 8;
ret = gss_unwrap(&minor,
- context_handle,
+ gss_ctx,
&in_buf,
&out_buf,
&flags_got, /* did we get sign+seal ? */
@@ -178,8 +179,9 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, cha
******************************************************************************/
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
- NTSTATUS common_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **ppbuf_out)
+ NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state, 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;
@@ -196,7 +198,7 @@ NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, cha
in_buf.length = buf_len - 8;
ret = gss_wrap(&minor,
- context_handle,
+ gss_ctx,
True, /* we want sign+seal. */
GSS_C_QOP_DEFAULT,
&in_buf,
@@ -267,7 +269,7 @@ NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, cha
return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, buffer, buf_out);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
case SMB_TRANS_ENC_GSS:
- return common_gss_encrypt_buffer(es->s.context_handle, buffer, buf_out);
+ return common_gss_encrypt_buffer(es->s.gss_state, buffer, buf_out);
#endif
default:
return NT_STATUS_NOT_SUPPORTED;
@@ -297,13 +299,29 @@ NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
case SMB_TRANS_ENC_GSS:
- return common_gss_decrypt_buffer(es->s.context_handle, buf);
+ return common_gss_decrypt_buffer(es->s.gss_state, buf);
#endif
default:
return NT_STATUS_NOT_SUPPORTED;
}
}
+#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;
+
+ gss_release_cred(&minor, &gss_state->creds);
+ gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
+ SAFE_FREE(*pp_gss_state);
+}
+#endif
+
/******************************************************************************
Shutdown an encryption state.
******************************************************************************/
@@ -324,6 +342,9 @@ void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
#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);
diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c
index bc7c75aab4..e1df08579d 100644
--- a/source3/smbd/negprot.c
+++ b/source3/smbd/negprot.c
@@ -228,6 +228,10 @@ static DATA_BLOB negprot_spnego(void)
name_to_fqdn(myname, global_myname());
strlower_m(myname);
asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm());
+ if (host_princ_s == NULL) {
+ blob = data_blob(NULL, 0);
+ return blob;
+ }
blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);
SAFE_FREE(host_princ_s);
}
diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c
index f95a982f60..fbb0eade52 100644
--- a/source3/smbd/seal.c
+++ b/source3/smbd/seal.c
@@ -85,6 +85,85 @@ static void destroy_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec)
}
}
+#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
+
+/******************************************************************************
+ Import a name.
+******************************************************************************/
+
+static NTSTATUS get_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;
+
+ asprintf(&host_princ_s, "%s@%s", service, name);
+ if (host_princ_s == NULL) {
+ 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,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &srv_name);
+
+ if (ret != GSS_S_COMPLETE) {
+ SAFE_FREE(host_princ_s);
+ return map_nt_error_from_gss(ret, min);
+ }
+
+ ret = gss_acquire_cred(&min,
+ &srv_name,
+ GSS_C_INDEFINITE,
+ GSS_C_NULL_OID_SET,
+ cred_type,
+ p_srv_cred,
+ NULL,
+ NULL);
+
+ if (ret != GSS_S_COMPLETE) {
+ 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.
+******************************************************************************/
+
+static NTSTATUS make_auth_gss(struct smb_srv_trans_enc_ctx *ec)
+{
+ NTSTATUS status;
+ gss_cred_id_t srv_cred;
+ fstring fqdn;
+
+ name_to_fqdn(fqdn, global_myname());
+ strlower_m(fqdn);
+
+ status = get_gss_creds("cifs", fqdn, GSS_C_ACCEPT, &srv_cred);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = get_gss_creds("host", fqdn, GSS_C_ACCEPT, &srv_cred);
+ if (!NT_STATUS_IS_OK(status)) {
+ return nt_status_squash(status);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+#endif
+
/******************************************************************************
Shutdown a server encryption context.
******************************************************************************/
@@ -148,6 +227,13 @@ static struct smb_srv_trans_enc_ctx *make_srv_encryption_context(enum smb_trans_
#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(ec);
+ if (!NT_STATUS_IS_OK(status)) {
+ srv_free_encryption_context(&ec);
+ return NULL;
+ }
+ }
break;
#endif
default: