summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2010-07-24 13:02:57 -0400
committerSimo Sorce <idra@samba.org>2010-07-28 12:42:15 -0400
commit7eaa15af2c5b544946bfb2b8c522ba9677527972 (patch)
treedf6035a0a06adf47653b8c001e673677aebf71a5
parent1abcbd70aed327ae5233423ce74662241fa9d21a (diff)
downloadsamba-7eaa15af2c5b544946bfb2b8c522ba9677527972.tar.gz
samba-7eaa15af2c5b544946bfb2b8c522ba9677527972.tar.bz2
samba-7eaa15af2c5b544946bfb2b8c522ba9677527972.zip
s3-dcerpc: Add sign/seal with gssapi
-rw-r--r--source3/configure.in3
-rw-r--r--source3/librpc/rpc/dcerpc_gssapi.c222
-rw-r--r--source3/librpc/rpc/dcerpc_gssapi.h10
-rw-r--r--source3/librpc/rpc/dcerpc_helpers.c86
-rw-r--r--source3/rpc_client/cli_pipe.c18
5 files changed, 332 insertions, 7 deletions
diff --git a/source3/configure.in b/source3/configure.in
index 905ad23efc..4b92cd677e 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -3749,7 +3749,7 @@ if test x"$with_ads_support" != x"no"; then
# now check for gssapi headers. This is also done here to allow for
# different kerberos include paths
- AC_CHECK_HEADERS(gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h com_err.h)
+ AC_CHECK_HEADERS(gssapi.h gssapi/gssapi_generic.h gssapi/gssapi.h gssapi/gssapi_ext.h com_err.h)
##################################################################
# we might need the k5crypto and com_err libraries on some systems
@@ -3774,6 +3774,7 @@ if test x"$with_ads_support" != x"no"; then
# now see if we can find the gssapi libs in standard paths
if test x"$have_gssapi" != x"yes"; then
AC_CHECK_LIB_EXT(gssapi_krb5, KRB5_LIBS,gss_display_status,[],[],have_gssapi=yes)
+ AC_CHECK_FUNC_EXT(gss_wrap_iov, $KRB5_LIBS)
fi
AC_CHECK_FUNC_EXT(krb5_set_real_time, $KRB5_LIBS)
diff --git a/source3/librpc/rpc/dcerpc_gssapi.c b/source3/librpc/rpc/dcerpc_gssapi.c
index d415369207..8c0ad6a8b3 100644
--- a/source3/librpc/rpc/dcerpc_gssapi.c
+++ b/source3/librpc/rpc/dcerpc_gssapi.c
@@ -22,6 +22,7 @@
#include "includes.h"
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
#include "dcerpc_gssapi.h"
#ifdef HAVE_GSSAPI_H
@@ -413,3 +414,224 @@ DATA_BLOB gse_get_session_key(struct gse_context *gse_ctx)
}
#endif /* HAVE_GSSAPI_H */
+
+#ifdef HAVE_GSS_WRAP_IOV
+
+size_t gse_get_signature_length(struct gse_context *gse_ctx,
+ int seal, size_t payload_size)
+{
+ OM_uint32 gss_min, gss_maj;
+ gss_iov_buffer_desc iov[2];
+ uint8_t fakebuf[payload_size];
+ int sealed;
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = NULL;
+ iov[0].buffer.length = 0;
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.value = fakebuf;
+ iov[1].buffer.length = payload_size;
+
+ gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gss_ctx,
+ seal, GSS_C_QOP_DEFAULT,
+ &sealed, iov, 2);
+ if (gss_maj) {
+ DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
+ gse_errstr(talloc_tos(), gss_maj, gss_min)));
+ return 0;
+ }
+
+ return iov[0].buffer.length;
+}
+
+NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ OM_uint32 gss_min, gss_maj;
+ gss_iov_buffer_desc iov[2];
+ int req_seal = 1; /* setting to 1 means we request sign+seal */
+ int sealed;
+ NTSTATUS status;
+
+ /* allocate the memory ourselves so we do not need to talloc_memdup */
+ signature->length = gse_get_signature_length(gse_ctx, 1, data->length);
+ if (!signature->length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ signature->data = talloc_size(mem_ctx, signature->length);
+ if (!signature->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = signature->data;
+ iov[0].buffer.length = signature->length;
+
+ /* data is encrypted in place, which is ok */
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.value = data->data;
+ iov[1].buffer.length = data->length;
+
+ gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gss_ctx,
+ req_seal, GSS_C_QOP_DEFAULT,
+ &sealed, iov, 2);
+ if (gss_maj) {
+ DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
+ gse_errstr(talloc_tos(), gss_maj, gss_min)));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ if (!sealed) {
+ DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+ DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
+ (int)iov[1].buffer.length, (int)iov[0].buffer.length));
+
+done:
+ return status;
+}
+
+NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ OM_uint32 gss_min, gss_maj;
+ gss_iov_buffer_desc iov[2];
+ int sealed;
+ NTSTATUS status;
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[0].buffer.value = signature->data;
+ iov[0].buffer.length = signature->length;
+
+ /* data is decrypted in place, which is ok */
+ iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[1].buffer.value = data->data;
+ iov[1].buffer.length = data->length;
+
+ gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gss_ctx,
+ &sealed, NULL, iov, 2);
+ if (gss_maj) {
+ DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
+ gse_errstr(talloc_tos(), gss_maj, gss_min)));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ if (!sealed) {
+ DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+ DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
+ (int)iov[1].buffer.length, (int)iov[0].buffer.length));
+
+done:
+ return status;
+}
+
+NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ OM_uint32 gss_min, gss_maj;
+ gss_buffer_desc in_data = { 0, NULL };
+ gss_buffer_desc out_data = { 0, NULL};
+ NTSTATUS status;
+
+ in_data.value = data->data;
+ in_data.length = data->length;
+
+ gss_maj = gss_get_mic(&gss_min, gse_ctx->gss_ctx,
+ GSS_C_QOP_DEFAULT,
+ &in_data, &out_data);
+ if (gss_maj) {
+ DEBUG(0, ("gss_get_mic failed with [%s]\n",
+ gse_errstr(talloc_tos(), gss_maj, gss_min)));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ *signature = data_blob_talloc(mem_ctx,
+ out_data.value, out_data.length);
+ if (!signature->data) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ if (out_data.value) {
+ gss_maj = gss_release_buffer(&gss_min, &out_data);
+ }
+ return status;
+}
+
+NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ OM_uint32 gss_min, gss_maj;
+ gss_buffer_desc in_data = { 0, NULL };
+ gss_buffer_desc in_token = { 0, NULL};
+ NTSTATUS status;
+
+ in_data.value = data->data;
+ in_data.length = data->length;
+ in_token.value = signature->data;
+ in_token.length = signature->length;
+
+ gss_maj = gss_verify_mic(&gss_min, gse_ctx->gss_ctx,
+ &in_data, &in_token, NULL);
+ if (gss_maj) {
+ DEBUG(0, ("gss_verify_mic failed with [%s]\n",
+ gse_errstr(talloc_tos(), gss_maj, gss_min)));
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ return status;
+}
+
+#else /* HAVE_GSS_WRAP_IOV */
+
+size_t gse_get_signature_length(struct gse_context *gse_ctx,
+ int seal, size_t payload_size)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+#endif /* HAVE_GSS_WRAP_IOV */
diff --git a/source3/librpc/rpc/dcerpc_gssapi.h b/source3/librpc/rpc/dcerpc_gssapi.h
index ea44e9e383..6367990ac1 100644
--- a/source3/librpc/rpc/dcerpc_gssapi.h
+++ b/source3/librpc/rpc/dcerpc_gssapi.h
@@ -45,4 +45,14 @@ NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
bool gse_require_more_processing(struct gse_context *gse_ctx);
DATA_BLOB gse_get_session_key(struct gse_context *gse_ctx);
+size_t gse_get_signature_length(struct gse_context *gse_ctx,
+ int seal, size_t payload_size);
+NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature);
+NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature);
+NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature);
+NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
+ DATA_BLOB *data, DATA_BLOB *signature);
#endif /* _CLI_PIPE_GSSAPI_H_ */
diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c
index be076d8645..4dc3d7f81f 100644
--- a/source3/librpc/rpc/dcerpc_helpers.c
+++ b/source3/librpc/rpc/dcerpc_helpers.c
@@ -26,6 +26,7 @@
#include "../libcli/auth/spnego.h"
#include "../libcli/auth/ntlmssp.h"
#include "ntlmssp_wrap.h"
+#include "librpc/rpc/dcerpc_gssapi.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_PARSE
@@ -371,6 +372,55 @@ static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
return NT_STATUS_OK;
}
+/*******************************************************************
+ Create and add the gssapi sign/seal auth data.
+ ********************************************************************/
+
+static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
+ enum dcerpc_AuthLevel auth_level,
+ DATA_BLOB *rpc_out)
+{
+ DATA_BLOB data;
+ DATA_BLOB auth_blob;
+ NTSTATUS status;
+
+ if (!gse_ctx) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data.data = rpc_out->data + DCERPC_RESPONSE_LENGTH;
+ data.length = rpc_out->length - DCERPC_RESPONSE_LENGTH
+ - DCERPC_AUTH_TRAILER_LENGTH;
+
+ switch (auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gse_seal(talloc_tos(), gse_ctx, &data, &auth_blob);
+ break;
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ status = gse_sign(talloc_tos(), gse_ctx, &data, &auth_blob);
+ break;
+ default:
+ status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to process packet: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ /* Finally attach the blob. */
+ if (!data_blob_append(NULL, rpc_out,
+ auth_blob.data, auth_blob.length)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&auth_blob);
+
+ return NT_STATUS_OK;
+}
+
/**
* @brief Append an auth footer according to what is the current mechanism
*
@@ -443,6 +493,11 @@ NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
auth->auth_level,
rpc_out);
break;
+ case DCERPC_AUTH_TYPE_KRB5:
+ status = add_gssapi_auth_footer(auth->a_u.gssapi_state,
+ auth->auth_level,
+ rpc_out);
+ break;
default:
status = NT_STATUS_INVALID_PARAMETER;
break;
@@ -617,6 +672,37 @@ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
}
break;
+ case DCERPC_AUTH_TYPE_KRB5:
+
+ 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;
+ }
+ break;
+
default:
DEBUG(0, ("process_request_pdu: "
"unknown auth type %u set.\n",
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 4a3229d7cc..8588875506 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -1257,6 +1257,7 @@ static NTSTATUS calculate_data_len_tosend(struct rpc_pipe_client *cli,
uint32_t *p_ss_padding)
{
uint32_t data_space, data_len;
+ size_t max_len;
switch (cli->auth->auth_level) {
case DCERPC_AUTH_LEVEL_NONE:
@@ -1272,6 +1273,10 @@ static NTSTATUS calculate_data_len_tosend(struct rpc_pipe_client *cli,
case DCERPC_AUTH_LEVEL_INTEGRITY:
case DCERPC_AUTH_LEVEL_PRIVACY:
+ max_len = cli->max_xmit_frag
+ - DCERPC_REQUEST_LENGTH
+ - DCERPC_AUTH_TRAILER_LENGTH;
+
/* Treat the same for all authenticated rpc requests. */
switch(cli->auth->auth_type) {
case DCERPC_AUTH_TYPE_SPNEGO:
@@ -1280,7 +1285,7 @@ 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; /* no signing */
+ *p_auth_len = 0; /* TODO */
break;
default:
return NT_STATUS_INVALID_PARAMETER;
@@ -1292,16 +1297,17 @@ static NTSTATUS calculate_data_len_tosend(struct rpc_pipe_client *cli,
*p_auth_len = NL_AUTH_SIGNATURE_SIZE;
break;
case DCERPC_AUTH_TYPE_KRB5:
- *p_auth_len = 0; /* no signing */
+ *p_auth_len = gse_get_signature_length(
+ cli->auth->a_u.gssapi_state,
+ (cli->auth->auth_level ==
+ DCERPC_AUTH_LEVEL_PRIVACY),
+ max_len);
break;
default:
return NT_STATUS_INVALID_PARAMETER;
}
- data_space = cli->max_xmit_frag
- - DCERPC_REQUEST_LENGTH
- - DCERPC_AUTH_TRAILER_LENGTH
- - *p_auth_len;
+ data_space = max_len - *p_auth_len;
data_len = MIN(data_space, data_left);
*p_ss_padding = 0;