summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-06-05 05:01:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:56:30 -0500
commit5341ad20e1b8953c9256cd8e04a7e55ba9ef84b5 (patch)
tree9d2c21766becd650905c32b1195d6a0203f93110 /source4
parent4c6f04d83f20ecfe62cd87dadf9b48a898502ea7 (diff)
downloadsamba-5341ad20e1b8953c9256cd8e04a7e55ba9ef84b5.tar.gz
samba-5341ad20e1b8953c9256cd8e04a7e55ba9ef84b5.tar.bz2
samba-5341ad20e1b8953c9256cd8e04a7e55ba9ef84b5.zip
r1030: added server side schannel support
(This used to be commit 2ac79dfba0e64056a680f21d7dd0c007f79d4a70)
Diffstat (limited to 'source4')
-rw-r--r--source4/librpc/idl/dcerpc.idl11
-rw-r--r--source4/librpc/idl/idl_types.h5
-rw-r--r--source4/librpc/ndr/ndr_basic.c23
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c25
-rw-r--r--source4/librpc/rpc/dcerpc_util.c8
-rw-r--r--source4/rpc_server/config.mk1
-rw-r--r--source4/rpc_server/dcerpc_server.h2
-rw-r--r--source4/rpc_server/dcesrv_auth.c2
-rw-r--r--source4/rpc_server/dcesrv_crypto.c6
-rw-r--r--source4/rpc_server/dcesrv_crypto_ntlmssp.c9
-rw-r--r--source4/rpc_server/dcesrv_crypto_schannel.c170
-rw-r--r--source4/rpc_server/netlogon/schannel_state.c15
12 files changed, 248 insertions, 29 deletions
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index 0ee3d7b69b..8805b61da6 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -23,6 +23,17 @@ interface dcerpc
dcerpc_syntax_id transfer_syntaxes[num_transfer_syntaxes];
} dcerpc_ctx_list;
+ /*
+ a schannel bind blob - used in auth_info
+ on a schannel bind
+ */
+ typedef [public] struct {
+ uint32 unknown1;
+ uint32 unknown2;
+ astring domain;
+ astring hostname;
+ } dcerpc_bind_schannel;
+
typedef struct {
uint16 max_xmit_frag;
uint16 max_recv_frag;
diff --git a/source4/librpc/idl/idl_types.h b/source4/librpc/idl/idl_types.h
index 7f1ba48bc8..d36e51f8be 100644
--- a/source4/librpc/idl/idl_types.h
+++ b/source4/librpc/idl/idl_types.h
@@ -50,6 +50,11 @@
*/
#define ascstr_noterm [flag(STR_NOTERM|STR_ASCII|STR_SIZE4|STR_LEN4)] string
+/*
+ a null terminated ascii string
+*/
+#define astring [flag(STR_ASCII|STR_NULLTERM)] string
+
#define NDR_NOALIGN LIBNDR_FLAG_NOALIGN
#define NDR_REMAINING LIBNDR_FLAG_REMAINING
diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c
index f8315b3af0..ea58a77c47 100644
--- a/source4/librpc/ndr/ndr_basic.c
+++ b/source4/librpc/ndr/ndr_basic.c
@@ -497,6 +497,17 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
(*s) = as;
break;
+ case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM:
+ len1 = strnlen(ndr->data+ndr->offset, (ndr->data_size - ndr->offset));
+ if (len1+1 <= ndr->data_size - ndr->offset) {
+ len1++;
+ }
+ NDR_ALLOC_N(ndr, as, (len1+1));
+ NDR_CHECK(ndr_pull_bytes(ndr, as, len1));
+ as[len1] = 0;
+ (*s) = as;
+ break;
+
default:
return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
ndr->flags & LIBNDR_STRING_FLAGS);
@@ -639,6 +650,18 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
ndr->offset += c_len + 1;
break;
+ case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM:
+ NDR_PUSH_NEED_BYTES(ndr, c_len + 1);
+ ret = convert_string(CH_UNIX, CH_DOS,
+ s, s_len+1,
+ ndr->data+ndr->offset, c_len + 1);
+ if (ret == -1) {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character conversion");
+ }
+ ndr->offset += c_len + 1;
+ break;
+
default:
return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
ndr->flags & LIBNDR_STRING_FLAGS);
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index ebfcdf7ff3..c271a94bf0 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -173,6 +173,7 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
uint8_t full_session_key[16];
struct schannel_state *schannel_state;
const char *workgroup, *workstation;
+ struct dcerpc_bind_schannel bind_schannel;
memcpy(full_session_key, session_key, 8);
memset(full_session_key+8, 0, 8);
@@ -203,21 +204,17 @@ NTSTATUS dcerpc_bind_auth_schannel_key(struct dcerpc_pipe *p,
p->auth_info->auth_context_id = random();
p->security_state = NULL;
- p->auth_info->credentials = data_blob_talloc(p->mem_ctx,
- NULL,
- 8 +
- strlen(workgroup)+1 +
- strlen(workstation)+1);
- if (!p->auth_info->credentials.data) {
- return NT_STATUS_NO_MEMORY;
- }
+ /* TODO: what are these?? */
+ bind_schannel.unknown1 = 0;
+ bind_schannel.unknown2 = 3;
+ bind_schannel.domain = workgroup;
+ bind_schannel.hostname = workstation;
- /* oh, this is ugly! */
- SIVAL(p->auth_info->credentials.data, 0, 0);
- SIVAL(p->auth_info->credentials.data, 4, 3);
- memcpy(p->auth_info->credentials.data+8, workgroup, strlen(workgroup)+1);
- memcpy(p->auth_info->credentials.data+8+strlen(workgroup)+1,
- workstation, strlen(workstation)+1);
+ status = ndr_push_struct_blob(&p->auth_info->credentials, p->mem_ctx, &bind_schannel,
+ (ndr_push_flags_fn_t)ndr_push_dcerpc_bind_schannel);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
/* send the authenticated bind request */
status = dcerpc_bind_byuuid(p, p->mem_ctx, uuid, version);
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index d8da1327d5..623d5ec24a 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -483,7 +483,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
(*p)->flags = binding->flags;
if (binding->flags & DCERPC_SCHANNEL) {
- const char *trust_password = secrets_fetch_machine_password();
+ const char *trust_password = NULL; // samdb_fetch_member_password();
if (!trust_password) {
DEBUG(0,("Unable to fetch machine password\n"));
goto done;
@@ -635,9 +635,9 @@ NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p,
/*
- create a secondary dcerpc connection on SMB
- the secondary connection will be on the same SMB connection, but
- use a new fnum
+ create a secondary dcerpc connection from a primary SMB connection
+
+ the secondary connection will be on the same SMB connection, but use a new fnum
*/
NTSTATUS dcerpc_secondary_smb(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
const char *pipe_name,
diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk
index 4a7b17cffb..83bc53f1df 100644
--- a/source4/rpc_server/config.mk
+++ b/source4/rpc_server/config.mk
@@ -126,6 +126,7 @@ ADD_OBJ_FILES = \
rpc_server/dcesrv_auth.o \
rpc_server/dcesrv_crypto.o \
rpc_server/dcesrv_crypto_ntlmssp.o \
+ rpc_server/dcesrv_crypto_schannel.o \
rpc_server/handles.o
#
# End SUBSYSTEM DCERPC
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index bc5376b6ce..f73dbaf4cb 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -97,7 +97,7 @@ struct dcesrv_handle {
struct dcesrv_crypto_ops {
const char *name;
uint8 auth_type;
- NTSTATUS (*start)(struct dcesrv_auth *auth);
+ NTSTATUS (*start)(struct dcesrv_auth *auth, DATA_BLOB *auth_blob);
NTSTATUS (*update)(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out);
NTSTATUS (*session_info)(struct dcesrv_auth *auth, struct auth_session_info **session_info);
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index df1a820039..6d08cca5fc 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -56,7 +56,7 @@ BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
return False;
}
- status = dcesrv_crypto_start(&dce_conn->auth_state);
+ status = dcesrv_crypto_start(&dce_conn->auth_state, &dce_conn->auth_state.auth_info->credentials);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
diff --git a/source4/rpc_server/dcesrv_crypto.c b/source4/rpc_server/dcesrv_crypto.c
index b8dfe46835..31039510ab 100644
--- a/source4/rpc_server/dcesrv_crypto.c
+++ b/source4/rpc_server/dcesrv_crypto.c
@@ -68,9 +68,9 @@ NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn,
/*
start crypto state
*/
-NTSTATUS dcesrv_crypto_start(struct dcesrv_auth *auth)
+NTSTATUS dcesrv_crypto_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
{
- return auth->crypto_ctx.ops->start(auth);
+ return auth->crypto_ctx.ops->start(auth, auth_blob);
}
/*
@@ -138,10 +138,8 @@ void dcesrv_crypto_end(struct dcesrv_auth *auth)
const struct dcesrv_crypto_ops *dcesrv_crypto_backend_bytype(uint8_t auth_type)
{
switch (auth_type) {
-#if 0
case DCERPC_AUTH_TYPE_SCHANNEL:
return dcesrv_crypto_schannel_get_ops();
-#endif
case DCERPC_AUTH_TYPE_NTLMSSP:
return dcesrv_crypto_ntlmssp_get_ops();
}
diff --git a/source4/rpc_server/dcesrv_crypto_ntlmssp.c b/source4/rpc_server/dcesrv_crypto_ntlmssp.c
index 5fb6345599..a0bb153ef2 100644
--- a/source4/rpc_server/dcesrv_crypto_ntlmssp.c
+++ b/source4/rpc_server/dcesrv_crypto_ntlmssp.c
@@ -22,8 +22,7 @@
*/
/*
- this provides a crypto interface to the various backends (such as
- NTLMSSP and SCHANNEL) for the rpc server code
+ this provides the NTLMSSP backend for server side rpc
*/
#include "includes.h"
@@ -32,11 +31,15 @@
/*
start crypto state
*/
-static NTSTATUS dcesrv_crypto_ntlmssp_start(struct dcesrv_auth *auth)
+static NTSTATUS dcesrv_crypto_ntlmssp_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
{
struct auth_ntlmssp_state *ntlmssp = NULL;
NTSTATUS status;
+ /* TODO: we should parse the auth_blob and remember the client
+ hostname and target domain, then check against the auth3
+ bind packet */
+
status = auth_ntlmssp_start(&ntlmssp);
auth->crypto_ctx.private_data = ntlmssp;
diff --git a/source4/rpc_server/dcesrv_crypto_schannel.c b/source4/rpc_server/dcesrv_crypto_schannel.c
new file mode 100644
index 0000000000..a9256fb664
--- /dev/null
+++ b/source4/rpc_server/dcesrv_crypto_schannel.c
@@ -0,0 +1,170 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc authentication code - schannel auth/crypto code
+
+ Copyright (C) Andrew Tridgell 2004
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct srv_schannel_state {
+ TALLOC_CTX *mem_ctx;
+ struct dcerpc_bind_schannel bind_info;
+ struct schannel_state *state;
+};
+
+/*
+ start crypto state
+*/
+static NTSTATUS dcesrv_crypto_schannel_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
+{
+ struct srv_schannel_state *schannel = NULL;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ uint8_t session_key[16];
+
+ mem_ctx = talloc_init("schannel_start");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ schannel = talloc_p(mem_ctx, struct srv_schannel_state);
+ if (!schannel) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ schannel->mem_ctx = mem_ctx;
+
+ /* parse the schannel startup blob */
+ status = ndr_pull_struct_blob(auth_blob, mem_ctx, &schannel->bind_info,
+ (ndr_pull_flags_fn_t)ndr_pull_dcerpc_bind_schannel);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* pull the session key for this client */
+ status = schannel_fetch_session_key(mem_ctx, schannel->bind_info.hostname, session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* start up the schannel server code */
+ status = schannel_start(&schannel->state, session_key, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ auth->crypto_ctx.private_data = schannel;
+
+ return status;
+}
+
+/*
+ update crypto state
+*/
+static NTSTATUS dcesrv_crypto_schannel_update(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
+ const DATA_BLOB in, DATA_BLOB *out)
+{
+ return NT_STATUS_OK;
+}
+
+/*
+ seal a packet
+*/
+static NTSTATUS dcesrv_crypto_schannel_seal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig)
+{
+ struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
+
+ return schannel_seal_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
+}
+
+/*
+ sign a packet
+*/
+static NTSTATUS dcesrv_crypto_schannel_sign(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
+ const uint8_t *data, size_t length, DATA_BLOB *sig)
+{
+ struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
+
+ return schannel_sign_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
+}
+
+/*
+ check a packet signature
+*/
+static NTSTATUS dcesrv_crypto_schannel_check_sig(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
+ const uint8_t *data, size_t length, const DATA_BLOB *sig)
+{
+ struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
+
+ return schannel_check_packet(srv_schannel_state->state, data, length, sig);
+}
+
+/*
+ unseal a packet
+*/
+static NTSTATUS dcesrv_crypto_schannel_unseal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig)
+{
+ struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
+
+ return schannel_unseal_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
+}
+
+/*
+ end crypto state
+*/
+static void dcesrv_crypto_schannel_end(struct dcesrv_auth *auth)
+{
+ struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
+
+ if (srv_schannel_state == NULL) {
+ return;
+ }
+
+ schannel_end(&srv_schannel_state->state);
+
+ talloc_destroy(srv_schannel_state->mem_ctx);
+
+ auth->crypto_ctx.private_data = NULL;
+}
+
+static const struct dcesrv_crypto_ops dcesrv_crypto_schannel_ops = {
+ .name = "schannel",
+ .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
+ .start = dcesrv_crypto_schannel_start,
+ .update = dcesrv_crypto_schannel_update,
+ .seal = dcesrv_crypto_schannel_seal,
+ .sign = dcesrv_crypto_schannel_sign,
+ .check_sig = dcesrv_crypto_schannel_check_sig,
+ .unseal = dcesrv_crypto_schannel_unseal,
+ .end = dcesrv_crypto_schannel_end
+};
+
+/*
+ startup the cryptographic side of an authenticated dcerpc server
+*/
+const struct dcesrv_crypto_ops *dcesrv_crypto_schannel_get_ops(void)
+{
+ return &dcesrv_crypto_schannel_ops;
+}
diff --git a/source4/rpc_server/netlogon/schannel_state.c b/source4/rpc_server/netlogon/schannel_state.c
index f4190f21b4..eaa5013572 100644
--- a/source4/rpc_server/netlogon/schannel_state.c
+++ b/source4/rpc_server/netlogon/schannel_state.c
@@ -88,13 +88,17 @@ NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx,
ldb_msg_add_value(ldb, &msg, "sessionKey", &val);
ldb_msg_add_string(ldb, &msg, "expiry", s);
+ ldb_delete(ldb, msg.dn);
+
ret = ldb_add(ldb, &msg);
- ldb_close(ldb);
if (ret != 0) {
+ DEBUG(1,("Unable to add %s to session key db - %s\n", msg.dn, ldb_errstring(ldb)));
+ ldb_close(ldb);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
+ ldb_close(ldb);
return NT_STATUS_OK;
}
@@ -110,13 +114,20 @@ NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx,
struct ldb_message **res;
int ret;
const struct ldb_val *val;
+ char *expr=NULL;
ldb = schannel_db_connect(mem_ctx);
if (ldb == NULL) {
return NT_STATUS_NO_MEMORY;
}
- ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, "(dn=%s)", NULL, &res);
+ expr = talloc_asprintf(mem_ctx, "(dn=%s)", computer_name);
+ if (expr == NULL) {
+ ldb_close(ldb);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_search(ldb, NULL, LDB_SCOPE_SUBTREE, expr, NULL, &res);
if (ret != 1) {
ldb_close(ldb);
return NT_STATUS_INVALID_HANDLE;