summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/Makefile.in3
-rw-r--r--source3/include/proto.h10
-rw-r--r--source3/librpc/crypto/cli_spnego.c88
-rw-r--r--source3/librpc/crypto/spnego.h23
-rw-r--r--source3/libsmb/clispnego.c79
-rw-r--r--source3/rpc_server/dcesrv_spnego.c308
-rw-r--r--source3/rpc_server/dcesrv_spnego.h37
7 files changed, 542 insertions, 6 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 405fba4a0d..882ad437f5 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -713,7 +713,8 @@ RPC_NCACN_NP = rpc_server/srv_pipe_register.o rpc_server/rpc_ncacn_np.o \
RPC_SERVICE = rpc_server/rpc_server.o
RPC_CRYPTO = rpc_server/dcesrv_ntlmssp.o \
- rpc_server/dcesrv_gssapi.o
+ rpc_server/dcesrv_gssapi.o \
+ rpc_server/dcesrv_spnego.o
RPC_PIPE_OBJ = rpc_server/srv_pipe.o rpc_server/srv_pipe_hnd.o \
$(RPC_NCACN_NP) $(RPC_SERVICE) $(RPC_CRYPTO)
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 3349e028fb..849a062230 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2557,6 +2557,16 @@ bool spnego_parse_auth_response(TALLOC_CTX *ctx,
const char *mechOID,
DATA_BLOB *auth);
+bool spnego_parse_auth_and_mic(TALLOC_CTX *ctx, DATA_BLOB blob,
+ DATA_BLOB *auth, DATA_BLOB *signature);
+DATA_BLOB spnego_gen_auth_response_and_mic(TALLOC_CTX *ctx,
+ NTSTATUS nt_status,
+ const char *mechOID,
+ DATA_BLOB *reply,
+ DATA_BLOB *mechlistMIC);
+bool spnego_mech_list_blob(TALLOC_CTX *mem_ctx,
+ char **oid_list, DATA_BLOB *data);
+
/* The following definitions come from libsmb/clistr.c */
size_t clistr_push_fn(const char *function,
diff --git a/source3/librpc/crypto/cli_spnego.c b/source3/librpc/crypto/cli_spnego.c
index 60e9e8012f..bf58e25d9a 100644
--- a/source3/librpc/crypto/cli_spnego.c
+++ b/source3/librpc/crypto/cli_spnego.c
@@ -1,6 +1,6 @@
/*
* SPNEGO Encapsulation
- * RPC Pipe client routines
+ * Client functions
* Copyright (C) Simo Sorce 2010.
*
* This program is free software; you can redistribute it and/or modify
@@ -348,3 +348,89 @@ DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
return data_blob_null;
}
}
+
+NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature)
+{
+ switch(sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ return gse_sign(mem_ctx,
+ sp_ctx->mech_ctx.gssapi_state,
+ data, signature);
+ case SPNEGO_NTLMSSP:
+ return auth_ntlmssp_sign_packet(
+ sp_ctx->mech_ctx.ntlmssp_state,
+ mem_ctx,
+ data->data, data->length,
+ full_data->data, full_data->length,
+ signature);
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature)
+{
+ switch(sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ return gse_sigcheck(mem_ctx,
+ sp_ctx->mech_ctx.gssapi_state,
+ data, signature);
+ case SPNEGO_NTLMSSP:
+ return auth_ntlmssp_check_packet(
+ sp_ctx->mech_ctx.ntlmssp_state,
+ data->data, data->length,
+ full_data->data, full_data->length,
+ signature);
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature)
+{
+ switch(sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ return gse_seal(mem_ctx,
+ sp_ctx->mech_ctx.gssapi_state,
+ data, signature);
+ case SPNEGO_NTLMSSP:
+ return auth_ntlmssp_seal_packet(
+ sp_ctx->mech_ctx.ntlmssp_state,
+ mem_ctx,
+ data->data, data->length,
+ full_data->data, full_data->length,
+ signature);
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature)
+{
+ switch(sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ return gse_unseal(mem_ctx,
+ sp_ctx->mech_ctx.gssapi_state,
+ data, signature);
+ case SPNEGO_NTLMSSP:
+ return auth_ntlmssp_unseal_packet(
+ sp_ctx->mech_ctx.ntlmssp_state,
+ data->data, data->length,
+ full_data->data, full_data->length,
+ signature);
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
diff --git a/source3/librpc/crypto/spnego.h b/source3/librpc/crypto/spnego.h
index 9512ed6324..68d9243bb0 100644
--- a/source3/librpc/crypto/spnego.h
+++ b/source3/librpc/crypto/spnego.h
@@ -34,8 +34,12 @@ struct spnego_context {
struct gse_context *gssapi_state;
} mech_ctx;
+ char *oid_list[ASN1_MAX_OIDS];
+ char *mech_oid;
+
enum {
SPNEGO_CONV_INIT = 0,
+ SPNEGO_CONV_NEGO,
SPNEGO_CONV_AUTH_MORE,
SPNEGO_CONV_AUTH_CONFIRM,
SPNEGO_CONV_AUTH_DONE
@@ -43,6 +47,7 @@ struct spnego_context {
bool do_sign;
bool do_seal;
+ bool is_dcerpc;
};
NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx,
@@ -75,4 +80,22 @@ NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
struct spnego_context *sp_ctx);
+
+NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature);
+NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature);
+NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature);
+NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
+ struct spnego_context *sp_ctx,
+ DATA_BLOB *data, DATA_BLOB *full_data,
+ DATA_BLOB *signature);
+
#endif /* _CLI_SPENGO_H_ */
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 539b411056..9ef848b59c 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -408,7 +408,8 @@ DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob)
/*
parse a SPNEGO auth packet. This contains the encrypted passwords
*/
-bool spnego_parse_auth(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *auth)
+bool spnego_parse_auth_and_mic(TALLOC_CTX *ctx, DATA_BLOB blob,
+ DATA_BLOB *auth, DATA_BLOB *signature)
{
ssize_t len;
struct spnego_data token;
@@ -429,17 +430,34 @@ bool spnego_parse_auth(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *auth)
*auth = data_blob_talloc(ctx,
token.negTokenTarg.responseToken.data,
token.negTokenTarg.responseToken.length);
+
+ if (!signature) {
+ goto done;
+ }
+
+ *signature = data_blob_talloc(ctx,
+ token.negTokenTarg.mechListMIC.data,
+ token.negTokenTarg.mechListMIC.length);
+
+done:
spnego_free_data(&token);
return true;
}
+bool spnego_parse_auth(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *auth)
+{
+ return spnego_parse_auth_and_mic(ctx, blob, auth, NULL);
+}
+
/*
generate a minimal SPNEGO response packet. Doesn't contain much.
*/
-DATA_BLOB spnego_gen_auth_response(TALLOC_CTX *ctx,
- DATA_BLOB *reply, NTSTATUS nt_status,
- const char *mechOID)
+DATA_BLOB spnego_gen_auth_response_and_mic(TALLOC_CTX *ctx,
+ NTSTATUS nt_status,
+ const char *mechOID,
+ DATA_BLOB *reply,
+ DATA_BLOB *mechlistMIC)
{
ASN1_DATA *data;
DATA_BLOB ret;
@@ -476,6 +494,14 @@ DATA_BLOB spnego_gen_auth_response(TALLOC_CTX *ctx,
asn1_pop_tag(data);
}
+ if (mechlistMIC && mechlistMIC->data != NULL) {
+ asn1_push_tag(data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(data,
+ mechlistMIC->data,
+ mechlistMIC->length);
+ asn1_pop_tag(data);
+ }
+
asn1_pop_tag(data);
asn1_pop_tag(data);
@@ -484,6 +510,13 @@ DATA_BLOB spnego_gen_auth_response(TALLOC_CTX *ctx,
return ret;
}
+DATA_BLOB spnego_gen_auth_response(TALLOC_CTX *ctx, DATA_BLOB *reply,
+ NTSTATUS nt_status, const char *mechOID)
+{
+ return spnego_gen_auth_response_and_mic(ctx, nt_status,
+ mechOID, reply, NULL);
+}
+
/*
parse a SPNEGO auth packet. This contains the encrypted passwords
*/
@@ -558,3 +591,41 @@ bool spnego_parse_auth_response(TALLOC_CTX *ctx,
asn1_free(data);
return True;
}
+
+bool spnego_mech_list_blob(TALLOC_CTX *mem_ctx,
+ char **oid_list, DATA_BLOB *raw_data)
+{
+ ASN1_DATA *data;
+ unsigned int idx;
+
+ if (!oid_list || !oid_list[0] || !raw_data) {
+ return false;
+ }
+
+ data = asn1_init(talloc_tos());
+ if (data == NULL) {
+ return false;
+ }
+
+ asn1_push_tag(data, ASN1_SEQUENCE(0));
+ for (idx = 0; oid_list[idx]; idx++) {
+ asn1_write_OID(data, oid_list[idx]);
+ }
+ asn1_pop_tag(data);
+
+ if (data->has_error) {
+ DEBUG(3, (__location__ " failed at %d\n", (int)data->ofs));
+ asn1_free(data);
+ return false;
+ }
+
+ *raw_data = data_blob_talloc(mem_ctx, data->data, data->length);
+ if (!raw_data->data) {
+ DEBUG(3, (__location__": data_blob_talloc() failed!\n"));
+ asn1_free(data);
+ return false;
+ }
+
+ asn1_free(data);
+ return true;
+}
diff --git a/source3/rpc_server/dcesrv_spnego.c b/source3/rpc_server/dcesrv_spnego.c
new file mode 100644
index 0000000000..4686534a2e
--- /dev/null
+++ b/source3/rpc_server/dcesrv_spnego.c
@@ -0,0 +1,308 @@
+/*
+ * SPNEGO Encapsulation
+ * DCERPC Server functions
+ * Copyright (C) Simo Sorce 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "../libcli/auth/spnego.h"
+#include "dcesrv_ntlmssp.h"
+#include "dcesrv_gssapi.h"
+#include "dcesrv_spnego.h"
+
+static NTSTATUS spnego_init_server(TALLOC_CTX *mem_ctx,
+ bool do_sign, bool do_seal,
+ bool is_dcerpc,
+ struct spnego_context **spnego_ctx)
+{
+ struct spnego_context *sp_ctx = NULL;
+
+ sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
+ if (!sp_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ sp_ctx->do_sign = do_sign;
+ sp_ctx->do_seal = do_seal;
+ sp_ctx->is_dcerpc = is_dcerpc;
+
+ *spnego_ctx = sp_ctx;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS spnego_server_mech_init(struct spnego_context *sp_ctx,
+ DATA_BLOB *token_in,
+ DATA_BLOB *token_out)
+{
+ struct auth_ntlmssp_state *ntlmssp_ctx;
+ struct gse_context *gse_ctx;
+ NTSTATUS status;
+
+ switch (sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ status = gssapi_server_auth_start(sp_ctx,
+ sp_ctx->do_sign,
+ sp_ctx->do_seal,
+ sp_ctx->is_dcerpc,
+ token_in,
+ token_out,
+ &gse_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to init gssapi server "
+ "(%s)\n", nt_errstr(status)));
+ return status;
+ }
+
+ sp_ctx->mech_ctx.gssapi_state = gse_ctx;
+ break;
+
+ case SPNEGO_NTLMSSP:
+ status = ntlmssp_server_auth_start(sp_ctx,
+ sp_ctx->do_sign,
+ sp_ctx->do_seal,
+ sp_ctx->is_dcerpc,
+ token_in,
+ token_out,
+ &ntlmssp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to init ntlmssp server "
+ "(%s)\n", nt_errstr(status)));
+ return status;
+ }
+
+ sp_ctx->mech_ctx.ntlmssp_state = ntlmssp_ctx;
+ break;
+
+ default:
+ DEBUG(3, ("No known mechanisms available\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS spnego_server_step(struct spnego_context *sp_ctx,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *spnego_in,
+ DATA_BLOB *spnego_out)
+{
+ DATA_BLOB token_in = data_blob_null;
+ DATA_BLOB token_out = data_blob_null;
+ DATA_BLOB signature = data_blob_null;
+ DATA_BLOB MICblob = data_blob_null;
+ struct spnego_data sp_in;
+ ssize_t len_in = 0;
+ NTSTATUS status;
+ bool ret;
+
+ len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
+ if (len_in == -1) {
+ DEBUG(1, (__location__ ": invalid SPNEGO blob.\n"));
+ dump_data(10, spnego_in->data, spnego_in->length);
+ status = NT_STATUS_INVALID_PARAMETER;
+ sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
+ goto done;
+ }
+ if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ token_in = sp_in.negTokenTarg.responseToken;
+ signature = sp_in.negTokenTarg.mechListMIC;
+
+ switch (sp_ctx->state) {
+ case SPNEGO_CONV_NEGO:
+ /* still to initialize */
+ status = spnego_server_mech_init(sp_ctx,
+ &token_in,
+ &token_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ /* server always need at least one reply from client */
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
+ break;
+
+ case SPNEGO_CONV_AUTH_MORE:
+
+ switch(sp_ctx->mech) {
+ case SPNEGO_KRB5:
+ status = gssapi_server_step(
+ sp_ctx->mech_ctx.gssapi_state,
+ mem_ctx, &token_in, &token_out);
+ break;
+ case SPNEGO_NTLMSSP:
+ status = ntlmssp_server_step(
+ sp_ctx->mech_ctx.ntlmssp_state,
+ mem_ctx, &token_in, &token_out);
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ break;
+
+ case SPNEGO_CONV_AUTH_DONE:
+ /* we are already done, can't step further */
+ /* fall thorugh and return error */
+ default:
+ /* wrong case */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (NT_STATUS_IS_OK(status) && signature.length != 0) {
+ /* last packet and requires signature check */
+ ret = spnego_mech_list_blob(talloc_tos(),
+ sp_ctx->oid_list, &MICblob);
+ if (ret) {
+ status = spnego_sigcheck(talloc_tos(), sp_ctx,
+ &MICblob, &MICblob,
+ &signature);
+ } else {
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ if (NT_STATUS_IS_OK(status) && signature.length != 0) {
+ /* if signature was good, sign our own packet too */
+ status = spnego_sign(talloc_tos(), sp_ctx,
+ &MICblob, &MICblob, &signature);
+ }
+
+done:
+ *spnego_out = spnego_gen_auth_response_and_mic(mem_ctx, status,
+ sp_ctx->mech_oid,
+ &token_out,
+ &signature);
+ if (!spnego_out->data) {
+ DEBUG(1, ("SPNEGO wrapping failed!\n"));
+ status = NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (NT_STATUS_IS_OK(status) ||
+ !NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
+ }
+
+ data_blob_free(&token_in);
+ data_blob_free(&token_out);
+ return status;
+}
+
+NTSTATUS spnego_server_auth_start(TALLOC_CTX *mem_ctx,
+ bool do_sign,
+ bool do_seal,
+ bool is_dcerpc,
+ DATA_BLOB *spnego_in,
+ DATA_BLOB *spnego_out,
+ struct spnego_context **spnego_ctx)
+{
+ struct spnego_context *sp_ctx;
+ DATA_BLOB token_in = data_blob_null;
+ DATA_BLOB token_out = data_blob_null;
+ unsigned int i;
+ NTSTATUS status;
+ bool ret;
+
+ if (!spnego_in->length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = spnego_init_server(mem_ctx, do_sign, do_seal, is_dcerpc, &sp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ret = spnego_parse_negTokenInit(sp_ctx, *spnego_in,
+ sp_ctx->oid_list, NULL, &token_in);
+ if (!ret) {
+ DEBUG(3, ("Invalid SPNEGO message\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* try for krb auth first */
+ for (i = 0; sp_ctx->oid_list[i] && sp_ctx->mech == SPNEGO_NONE; i++) {
+ if (strcmp(OID_KERBEROS5, sp_ctx->oid_list[i]) == 0 ||
+ strcmp(OID_KERBEROS5_OLD, sp_ctx->oid_list[i]) == 0) {
+
+ if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
+ sp_ctx->mech = SPNEGO_KRB5;
+ sp_ctx->mech_oid = sp_ctx->oid_list[i];
+ }
+ }
+ }
+
+ /* if auth type still undetermined, try for NTLMSSP */
+ for (i = 0; sp_ctx->oid_list[i] && sp_ctx->mech == SPNEGO_NONE; i++) {
+ if (strcmp(OID_NTLMSSP, sp_ctx->oid_list[i]) == 0) {
+ sp_ctx->mech = SPNEGO_NTLMSSP;
+ sp_ctx->mech_oid = sp_ctx->oid_list[i];
+ }
+ }
+
+ if (!sp_ctx->mech_oid) {
+ DEBUG(3, ("No known mechanisms available\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("Client Provided OIDs:\n"));
+ for (i = 0; sp_ctx->oid_list[i]; i++) {
+ DEBUG(10, (" %d: %s\n", i, sp_ctx->oid_list[i]));
+ }
+ DEBUG(10, ("Chosen OID: %s\n", sp_ctx->mech_oid));
+ }
+
+ /* If it is not the first OID, then token_in is not valid for the
+ * choosen mech */
+ if (sp_ctx->mech_oid != sp_ctx->oid_list[0]) {
+ /* request more and send back empty token */
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ sp_ctx->state = SPNEGO_CONV_NEGO;
+ goto done;
+ }
+
+ status = spnego_server_mech_init(sp_ctx, &token_in, &token_out);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ DEBUG(10, ("SPNEGO(%d) auth started\n", sp_ctx->mech));
+
+ /* server always need at least one reply from client */
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
+
+done:
+ *spnego_out = spnego_gen_auth_response(mem_ctx, &token_out,
+ status, sp_ctx->mech_oid);
+ if (!spnego_out->data) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ TALLOC_FREE(sp_ctx);
+ } else {
+ status = NT_STATUS_OK;
+ *spnego_ctx = sp_ctx;
+ }
+
+ data_blob_free(&token_in);
+ data_blob_free(&token_out);
+
+ return status;
+}
diff --git a/source3/rpc_server/dcesrv_spnego.h b/source3/rpc_server/dcesrv_spnego.h
new file mode 100644
index 0000000000..eeb865d805
--- /dev/null
+++ b/source3/rpc_server/dcesrv_spnego.h
@@ -0,0 +1,37 @@
+/*
+ * SPNEGO Encapsulation
+ * Server routines
+ * Copyright (C) Simo Sorce 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DCESRV_SPNEGO_H_
+#define _DCESRV_SPENGO_H_
+
+#include "librpc/crypto/spnego.h"
+
+NTSTATUS spnego_server_auth_start(TALLOC_CTX *mem_ctx,
+ bool do_sign,
+ bool do_seal,
+ bool is_dcerpc,
+ DATA_BLOB *spnego_in,
+ DATA_BLOB *spnego_out,
+ struct spnego_context **spnego_ctx);
+NTSTATUS spnego_server_step(struct spnego_context *sp_ctx,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *spnego_in,
+ DATA_BLOB *spnego_out);
+
+#endif /* _DCESRV_SPENGO_H_ */