s3-dcerpc: add sign/seal support when using SPNEGO/KRB5
authorSimo Sorce <idra@samba.org>
Thu, 29 Jul 2010 20:34:39 +0000 (16:34 -0400)
committerSimo Sorce <idra@samba.org>
Fri, 30 Jul 2010 18:55:27 +0000 (14:55 -0400)
source3/librpc/rpc/dcerpc_helpers.c
source3/librpc/rpc/dcerpc_spnego.c
source3/librpc/rpc/dcerpc_spnego.h
source3/rpc_client/cli_pipe.c

index 4dc3d7f81f2ebdede9c3f0ac7ce6b8a8919a063c..592832bdd8085d127cda0e434d752d1fd7f3fcf1 100644 (file)
@@ -27,6 +27,7 @@
 #include "../libcli/auth/ntlmssp.h"
 #include "ntlmssp_wrap.h"
 #include "librpc/rpc/dcerpc_gssapi.h"
+#include "librpc/rpc/dcerpc_spnego.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_PARSE
@@ -308,6 +309,39 @@ static NTSTATUS add_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
        return NT_STATUS_OK;
 }
 
+/*******************************************************************
+ Check/unseal the NTLMSSP auth data. (Unseal in place).
+ ********************************************************************/
+
+static NTSTATUS get_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
+                                       enum dcerpc_AuthLevel auth_level,
+                                       DATA_BLOB *data, DATA_BLOB *full_pkt,
+                                       DATA_BLOB *auth_token)
+{
+       switch (auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               /* Data portion is encrypted. */
+               return auth_ntlmssp_unseal_packet(auth_state,
+                                                 data->data,
+                                                 data->length,
+                                                 full_pkt->data,
+                                                 full_pkt->length,
+                                                 auth_token);
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               /* Data is signed. */
+               return auth_ntlmssp_check_packet(auth_state,
+                                                data->data,
+                                                data->length,
+                                                full_pkt->data,
+                                                full_pkt->length,
+                                                auth_token);
+
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+}
+
 /*******************************************************************
  Create and add the schannel sign/seal auth data.
  ********************************************************************/
@@ -372,6 +406,38 @@ static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
        return NT_STATUS_OK;
 }
 
+/*******************************************************************
+ Check/unseal the Schannel auth data. (Unseal in place).
+ ********************************************************************/
+
+static NTSTATUS get_schannel_auth_footer(TALLOC_CTX *mem_ctx,
+                                        struct schannel_state *auth_state,
+                                        enum dcerpc_AuthLevel auth_level,
+                                        DATA_BLOB *data, DATA_BLOB *full_pkt,
+                                        DATA_BLOB *auth_token)
+{
+       switch (auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               /* Data portion is encrypted. */
+               return netsec_incoming_packet(auth_state,
+                                               mem_ctx, true,
+                                               data->data,
+                                               data->length,
+                                               auth_token);
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               /* Data is signed. */
+               return netsec_incoming_packet(auth_state,
+                                               mem_ctx, false,
+                                               data->data,
+                                               data->length,
+                                               auth_token);
+
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+}
+
 /*******************************************************************
  Create and add the gssapi sign/seal auth data.
  ********************************************************************/
@@ -421,6 +487,79 @@ static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
        return NT_STATUS_OK;
 }
 
+/*******************************************************************
+ Check/unseal the gssapi auth data. (Unseal in place).
+ ********************************************************************/
+
+static NTSTATUS get_gssapi_auth_footer(TALLOC_CTX *mem_ctx,
+                                       struct gse_context *gse_ctx,
+                                       enum dcerpc_AuthLevel auth_level,
+                                       DATA_BLOB *data, DATA_BLOB *full_pkt,
+                                       DATA_BLOB *auth_token)
+{
+       /* TODO: pass in full_pkt when
+        * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
+       switch (auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               /* Data portion is encrypted. */
+               return gse_unseal(mem_ctx, gse_ctx,
+                                 data, auth_token);
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               /* Data is signed. */
+               return gse_sigcheck(mem_ctx, gse_ctx,
+                                   data, auth_token);
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+}
+
+/*******************************************************************
+ Create and add the spnego-negotiated sign/seal auth data.
+ ********************************************************************/
+
+static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx,
+                                       enum dcerpc_AuthLevel auth_level,
+                                       DATA_BLOB *rpc_out)
+{
+       enum dcerpc_AuthType auth_type;
+       struct gse_context *gse_ctx;
+       void *auth_ctx;
+       NTSTATUS status;
+
+       if (!spnego_ctx) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       status = spnego_get_negotiated_mech(spnego_ctx,
+                                           &auth_type, &auth_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       switch (auth_type) {
+       case DCERPC_AUTH_TYPE_KRB5:
+               gse_ctx = talloc_get_type(auth_ctx, struct gse_context);
+               if (!gse_ctx) {
+                       status = NT_STATUS_INTERNAL_ERROR;
+                       break;
+               }
+               status = add_gssapi_auth_footer(gse_ctx,
+                                               auth_level, rpc_out);
+               break;
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+               status = NT_STATUS_NOT_IMPLEMENTED;
+               break;
+
+       default:
+               status = NT_STATUS_INTERNAL_ERROR;
+               break;
+       }
+
+       return status;
+}
+
 /**
 * @brief   Append an auth footer according to what is the current mechanism
 *
@@ -480,7 +619,9 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
                break;
        case DCERPC_AUTH_TYPE_SPNEGO:
                if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
-                       return NT_STATUS_INVALID_PARAMETER;
+                       return add_spnego_auth_footer(auth->a_u.spnego_state,
+                                                     auth->auth_level,
+                                                     rpc_out);
                }
                /* fall thorugh */
        case DCERPC_AUTH_TYPE_NTLMSSP:
@@ -591,49 +732,44 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
 
        case DCERPC_AUTH_TYPE_SPNEGO:
                if (auth->spnego_type != PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
-                       DEBUG(0, ("Currently only NTLMSSP is supported "
-                                 "with SPNEGO\n"));
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-               /* fall through */
-       case DCERPC_AUTH_TYPE_NTLMSSP:
-
-               DEBUG(10, ("NTLMSSP auth\n"));
-
-               if (!auth->a_u.auth_ntlmssp_state) {
-                       DEBUG(0, ("Invalid auth level, "
-                                 "failed to process packet auth.\n"));
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
+                       enum dcerpc_AuthType auth_type;
+                       struct gse_context *gse_ctx;
+                       void *auth_ctx;
 
-               switch (auth->auth_level) {
-               case DCERPC_AUTH_LEVEL_PRIVACY:
-                       status = auth_ntlmssp_unseal_packet(
-                                       auth->a_u.auth_ntlmssp_state,
-                                       data.data, data.length,
-                                       full_pkt.data, full_pkt.length,
-                                       &auth_info.credentials);
+                       status = spnego_get_negotiated_mech(
+                                               auth->a_u.spnego_state,
+                                               &auth_type, &auth_ctx);
                        if (!NT_STATUS_IS_OK(status)) {
                                return status;
                        }
-                       memcpy(pkt_trailer->data, data.data, data.length);
-                       break;
+                       gse_ctx = talloc_get_type(auth_ctx,
+                                                 struct gse_context);
+                       if (!gse_ctx) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
 
-               case DCERPC_AUTH_LEVEL_INTEGRITY:
-                       status = auth_ntlmssp_check_packet(
-                                       auth->a_u.auth_ntlmssp_state,
-                                       data.data, data.length,
-                                       full_pkt.data, full_pkt.length,
-                                       &auth_info.credentials);
+                       DEBUG(10, ("KRB5 auth\n"));
+
+                       status = get_gssapi_auth_footer(pkt, gse_ctx,
+                                               auth->auth_level,
+                                               &data, &full_pkt,
+                                               &auth_info.credentials);
                        if (!NT_STATUS_IS_OK(status)) {
                                return status;
                        }
                        break;
+               }
+               /* fall through */
+       case DCERPC_AUTH_TYPE_NTLMSSP:
 
-               default:
-                       DEBUG(0, ("Invalid auth level, "
-                                 "failed to process packet auth.\n"));
-                       return NT_STATUS_INVALID_PARAMETER;
+               DEBUG(10, ("NTLMSSP auth\n"));
+
+               status = get_ntlmssp_auth_footer(auth->a_u.auth_ntlmssp_state,
+                                                auth->auth_level,
+                                                &data, &full_pkt,
+                                                &auth_info.credentials);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
                break;
 
@@ -641,34 +777,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
 
                DEBUG(10, ("SCHANNEL auth\n"));
 
-               switch (auth->auth_level) {
-               case DCERPC_AUTH_LEVEL_PRIVACY:
-                       status = netsec_incoming_packet(
-                                       auth->a_u.schannel_auth,
-                                       pkt, true,
-                                       data.data, data.length,
-                                       &auth_info.credentials);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               return status;
-                       }
-                       memcpy(pkt_trailer->data, data.data, data.length);
-                       break;
-
-               case DCERPC_AUTH_LEVEL_INTEGRITY:
-                       status = netsec_incoming_packet(
-                                       auth->a_u.schannel_auth,
-                                       pkt, false,
-                                       data.data, data.length,
-                                       &auth_info.credentials);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               return status;
-                       }
-                       break;
-
-               default:
-                       DEBUG(0, ("Invalid auth level, "
-                                 "failed to process packet auth.\n"));
-                       return NT_STATUS_INVALID_PARAMETER;
+               status = get_schannel_auth_footer(pkt,
+                                                 auth->a_u.schannel_auth,
+                                                 auth->auth_level,
+                                                 &data, &full_pkt,
+                                                 &auth_info.credentials);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
                break;
 
@@ -676,30 +791,13 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
 
                DEBUG(10, ("KRB5 auth\n"));
 
-               switch (auth->auth_level) {
-               case DCERPC_AUTH_LEVEL_PRIVACY:
-                       status = gse_unseal(pkt, auth->a_u.gssapi_state,
-                                           &data, &auth_info.credentials);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               return status;
-                       }
-                       memcpy(pkt_trailer->data, data.data, data.length);
-                       break;
-
-               case DCERPC_AUTH_LEVEL_INTEGRITY:
-                       /* TODO: pass in full_pkt when
-                        * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
-                       status = gse_sigcheck(pkt, auth->a_u.gssapi_state,
-                                             &data, &auth_info.credentials);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               return status;
-                       }
-                       break;
-
-               default:
-                       DEBUG(0, ("Invalid auth level, "
-                                 "failed to process packet auth.\n"));
-                       return NT_STATUS_INVALID_PARAMETER;
+               status = get_gssapi_auth_footer(pkt,
+                                               auth->a_u.gssapi_state,
+                                               auth->auth_level,
+                                               &data, &full_pkt,
+                                               &auth_info.credentials);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
                break;
 
@@ -710,6 +808,14 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       /* TODO: remove later
+        * this is still needed because in the server code the
+        * pkt_trailer actually has a copy of the raw data, and they
+        * are still both used in later calls */
+       if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+               memcpy(pkt_trailer->data, data.data, data.length);
+       }
+
        *pad_len = auth_info.auth_pad_length;
        data_blob_free(&auth_info.credentials);
        return NT_STATUS_OK;
index 51d294de5e3c5a04a44a53d69c276f5794908678..e733469ac32dbe5c339f682b2062085f0ce8cd57 100644 (file)
@@ -233,3 +233,22 @@ bool spnego_require_more_processing(struct spnego_context *sp_ctx)
        }
 }
 
+NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
+                                   enum dcerpc_AuthType *auth_type,
+                                   void **auth_context)
+{
+       switch (sp_ctx->auth_type) {
+       case DCERPC_AUTH_TYPE_KRB5:
+               *auth_context = sp_ctx->mech_ctx.gssapi_state;
+               break;
+       case DCERPC_AUTH_TYPE_NTLMSSP:
+               *auth_context = sp_ctx->mech_ctx.auth_ntlmssp_state;
+               break;
+       default:
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       *auth_type = sp_ctx->auth_type;
+       return NT_STATUS_OK;
+}
+
index 7f48f39498f7159a5b91eb18ff65ddfc17edb265..08458b246f74a8960d4553d1c958ee24bf9db8ea 100644 (file)
@@ -39,4 +39,8 @@ NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
 
 bool spnego_require_more_processing(struct spnego_context *sp_ctx);
 
+NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
+                                   enum dcerpc_AuthType *auth_type,
+                                   void **auth_context);
+
 #endif /* _DCERPC_SPENGO_H_ */
index 6dc2cd69afd750757501f807dcfb7e436718ea86..e41966f6fb6f64bbc35c0205cce4873d6ca4d08c 100644 (file)
@@ -1305,6 +1305,10 @@ static NTSTATUS calculate_data_len_tosend(struct rpc_pipe_client *cli,
 {
        uint32_t data_space, data_len;
        size_t max_len;
+       struct gse_context *gse_ctx;
+       enum dcerpc_AuthType auth_type;
+       void *auth_ctx;
+       NTSTATUS status;
 
        switch (cli->auth->auth_level) {
        case DCERPC_AUTH_LEVEL_NONE:
@@ -1332,11 +1336,26 @@ static NTSTATUS calculate_data_len_tosend(struct rpc_pipe_client *cli,
                                *p_auth_len = NTLMSSP_SIG_SIZE;
                                break;
                        case PIPE_AUTH_TYPE_SPNEGO_KRB5:
-                               *p_auth_len = 0; /* TODO */
+                               status = spnego_get_negotiated_mech(
+                                               cli->auth->a_u.spnego_state,
+                                               &auth_type, &auth_ctx);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       return status;
+                               }
+                               gse_ctx = talloc_get_type(auth_ctx,
+                                                         struct gse_context);
+                               if (!gse_ctx) {
+                                       return NT_STATUS_INVALID_PARAMETER;
+                               }
+                               *p_auth_len = gse_get_signature_length(gse_ctx,
+                                               (cli->auth->auth_level ==
+                                                 DCERPC_AUTH_LEVEL_PRIVACY),
+                                               max_len);
                                break;
                        default:
                                return NT_STATUS_INVALID_PARAMETER;
                        }
+                       break;
                case DCERPC_AUTH_TYPE_NTLMSSP:
                        *p_auth_len = NTLMSSP_SIG_SIZE;
                        break;