1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-07 12:23:51 +03:00

r1030: added server side schannel support

This commit is contained in:
Andrew Tridgell
2004-06-05 05:01:38 +00:00
committed by Gerald (Jerry) Carter
parent ee6c17f373
commit 2ac79dfba0
12 changed files with 248 additions and 29 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;