r21997: Implement the server side of gss seal negotiate.
authorJeremy Allison <jra@samba.org>
Wed, 28 Mar 2007 01:11:27 +0000 (01:11 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:18:58 +0000 (12:18 -0500)
Jeremy.
(This used to be commit 6b923acfee59e39eea69e9e9a00f1f6118ed4270)

source3/libsmb/smb_seal.c
source3/smbd/seal.c

index ed2c66013e8d29c5cd782e05068de2ac67e71f40..891673ed154af20a56057c4116db197246f123e5 100644 (file)
@@ -332,8 +332,12 @@ 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);
+       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
index d5b956c53d8311142f6416a1cc284515b07a18c6..0a093d21ab2f3063e90b7e909dfbd7e40085c528 100644 (file)
@@ -97,7 +97,7 @@ static NTSTATUS get_gss_creds(const char *service,
                                gss_cred_id_t *p_srv_cred)
 {
        OM_uint32 ret;
-        OM_uint32 min;
+       OM_uint32 min;
        gss_name_t srv_name;
        gss_buffer_desc input_name;
        char *host_princ_s = NULL;
@@ -141,6 +141,8 @@ static NTSTATUS get_gss_creds(const char *service,
 
 /******************************************************************************
  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_srv_trans_enc_ctx *ec)
@@ -160,6 +162,18 @@ static NTSTATUS make_auth_gss(struct smb_srv_trans_enc_ctx *ec)
                }
        }
 
+       ec->es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
+       if (!ec->es->s.gss_state) {
+               OM_uint32 min;
+               gss_release_cred(&min, &srv_cred);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ZERO_STRUCTP(ec->es->s.gss_state);
+       ec->es->s.gss_state->creds = srv_cred;
+
+       /* No context yet. */
+       ec->es->s.gss_state->gss_ctx = GSS_C_NO_CONTEXT;
+
        return NT_STATUS_OK;
 }
 #endif
@@ -197,19 +211,21 @@ static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec)
  Create a server encryption context.
 ******************************************************************************/
 
-static struct smb_srv_trans_enc_ctx *make_srv_encryption_context(enum smb_trans_enc_type smb_enc_type)
+static NTSTATUS make_srv_encryption_context(enum smb_trans_enc_type smb_enc_type, struct smb_srv_trans_enc_ctx **pp_ec)
 {
        struct smb_srv_trans_enc_ctx *ec;
 
+       *pp_ec = NULL;
+
        ec = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx);
        if (!ec) {
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
        ZERO_STRUCTP(partial_srv_trans_enc_ctx);
        ec->es = SMB_MALLOC_P(struct smb_trans_enc_state);
        if (!ec->es) {
                SAFE_FREE(ec);
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
        ZERO_STRUCTP(ec->es);
        ec->es->smb_enc_type = smb_enc_type;
@@ -219,7 +235,7 @@ static struct smb_srv_trans_enc_ctx *make_srv_encryption_context(enum smb_trans_
                                NTSTATUS status = make_auth_ntlmssp(ec);
                                if (!NT_STATUS_IS_OK(status)) {
                                        srv_free_encryption_context(&ec);
-                                       return NULL;
+                                       return status;
                                }
                        }
                        break;
@@ -231,16 +247,17 @@ static struct smb_srv_trans_enc_ctx *make_srv_encryption_context(enum smb_trans_
                                NTSTATUS status = make_auth_gss(ec);
                                if (!NT_STATUS_IS_OK(status)) {
                                        srv_free_encryption_context(&ec);
-                                       return NULL;
+                                       return status;
                                }
                        }
                        break;
 #endif
                default:
                        srv_free_encryption_context(&ec);
-                       return NULL;
+                       return NT_STATUS_INVALID_PARAMETER;
        }
-       return ec;
+       *pp_ec = ec;
+       return NT_STATUS_OK;
 }
 
 /******************************************************************************
@@ -308,14 +325,68 @@ NTSTATUS srv_encrypt_buffer(char *buf, char **buf_out)
 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
 static NTSTATUS srv_enc_spnego_gss_negotiate(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;
+
        if (!partial_srv_trans_enc_ctx) {
-               partial_srv_trans_enc_ctx = make_srv_encryption_context(SMB_TRANS_ENC_GSS);
-               if (!partial_srv_trans_enc_ctx) {
-                       return NT_STATUS_NO_MEMORY;
+               NTSTATUS status = make_srv_encryption_context(SMB_TRANS_ENC_GSS, &partial_srv_trans_enc_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
+       gss_state = partial_srv_trans_enc_ctx->es->s.gss_state;
+
+       in_buf.value = secblob.data;
+       in_buf.length = secblob.length;
+
+       out_buf.value = NULL;
+       out_buf.length = 0;
+
+       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. */
+
+       if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
+               return gss_err_to_ntstatus(ret, min);
+       }
+
+       /* 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;
                }
        }
 
-       return NT_STATUS_NOT_SUPPORTED;
+       SAFE_FREE(*ppdata);
+       *ppdata = memdup(out_buf.value, out_buf.length);
+       if (!*ppdata) {
+               gss_release_buffer(&min, &out_buf);
+               return NT_STATUS_NO_MEMORY;
+       }
+       *p_data_size = out_buf.length;
+       gss_release_buffer(&min, &out_buf);
+
+       if (ret != GSS_S_CONTINUE_NEEDED) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       } else {
+               return NT_STATUS_OK;
+       }
 }
 #endif
 
@@ -330,9 +401,9 @@ static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_si
        DATA_BLOB chal = data_blob(NULL, 0);
        DATA_BLOB response = data_blob(NULL, 0);
 
-       partial_srv_trans_enc_ctx = make_srv_encryption_context(SMB_TRANS_ENC_NTLM);
-       if (!partial_srv_trans_enc_ctx) {
-               return NT_STATUS_NO_MEMORY;
+       status = make_srv_encryption_context(SMB_TRANS_ENC_NTLM, &partial_srv_trans_enc_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, secblob, &chal);