diff options
-rw-r--r-- | source3/include/client.h | 9 | ||||
-rw-r--r-- | source3/include/includes.h | 4 | ||||
-rw-r--r-- | source3/include/trans2.h | 1 | ||||
-rw-r--r-- | source3/libsmb/smb_seal.c | 33 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 4 | ||||
-rw-r--r-- | source3/smbd/seal.c | 86 |
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: |