1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-11 00: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_syntax_id transfer_syntaxes[num_transfer_syntaxes];
} dcerpc_ctx_list; } 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 { typedef struct {
uint16 max_xmit_frag; uint16 max_xmit_frag;
uint16 max_recv_frag; uint16 max_recv_frag;

View File

@@ -50,6 +50,11 @@
*/ */
#define ascstr_noterm [flag(STR_NOTERM|STR_ASCII|STR_SIZE4|STR_LEN4)] string #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_NOALIGN LIBNDR_FLAG_NOALIGN
#define NDR_REMAINING LIBNDR_FLAG_REMAINING #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; (*s) = as;
break; 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: default:
return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
ndr->flags & LIBNDR_STRING_FLAGS); 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; ndr->offset += c_len + 1;
break; 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: default:
return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n",
ndr->flags & LIBNDR_STRING_FLAGS); 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]; uint8_t full_session_key[16];
struct schannel_state *schannel_state; struct schannel_state *schannel_state;
const char *workgroup, *workstation; const char *workgroup, *workstation;
struct dcerpc_bind_schannel bind_schannel;
memcpy(full_session_key, session_key, 8); memcpy(full_session_key, session_key, 8);
memset(full_session_key+8, 0, 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->auth_info->auth_context_id = random();
p->security_state = NULL; p->security_state = NULL;
p->auth_info->credentials = data_blob_talloc(p->mem_ctx, /* TODO: what are these?? */
NULL, bind_schannel.unknown1 = 0;
8 + bind_schannel.unknown2 = 3;
strlen(workgroup)+1 + bind_schannel.domain = workgroup;
strlen(workstation)+1); bind_schannel.hostname = workstation;
if (!p->auth_info->credentials.data) {
return NT_STATUS_NO_MEMORY;
}
/* oh, this is ugly! */ status = ndr_push_struct_blob(&p->auth_info->credentials, p->mem_ctx, &bind_schannel,
SIVAL(p->auth_info->credentials.data, 0, 0); (ndr_push_flags_fn_t)ndr_push_dcerpc_bind_schannel);
SIVAL(p->auth_info->credentials.data, 4, 3); if (!NT_STATUS_IS_OK(status)) {
memcpy(p->auth_info->credentials.data+8, workgroup, strlen(workgroup)+1); goto done;
memcpy(p->auth_info->credentials.data+8+strlen(workgroup)+1, }
workstation, strlen(workstation)+1);
/* send the authenticated bind request */ /* send the authenticated bind request */
status = dcerpc_bind_byuuid(p, p->mem_ctx, uuid, version); 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; (*p)->flags = binding->flags;
if (binding->flags & DCERPC_SCHANNEL) { 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) { if (!trust_password) {
DEBUG(0,("Unable to fetch machine password\n")); DEBUG(0,("Unable to fetch machine password\n"));
goto done; goto done;
@@ -635,9 +635,9 @@ NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p,
/* /*
create a secondary dcerpc connection on SMB 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 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, NTSTATUS dcerpc_secondary_smb(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
const char *pipe_name, const char *pipe_name,

View File

@@ -126,6 +126,7 @@ ADD_OBJ_FILES = \
rpc_server/dcesrv_auth.o \ rpc_server/dcesrv_auth.o \
rpc_server/dcesrv_crypto.o \ rpc_server/dcesrv_crypto.o \
rpc_server/dcesrv_crypto_ntlmssp.o \ rpc_server/dcesrv_crypto_ntlmssp.o \
rpc_server/dcesrv_crypto_schannel.o \
rpc_server/handles.o rpc_server/handles.o
# #
# End SUBSYSTEM DCERPC # End SUBSYSTEM DCERPC

View File

@@ -97,7 +97,7 @@ struct dcesrv_handle {
struct dcesrv_crypto_ops { struct dcesrv_crypto_ops {
const char *name; const char *name;
uint8 auth_type; 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, NTSTATUS (*update)(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out); const DATA_BLOB in, DATA_BLOB *out);
NTSTATUS (*session_info)(struct dcesrv_auth *auth, struct auth_session_info **session_info); 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; 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)) { if (!NT_STATUS_IS_OK(status)) {
return False; return False;
} }

View File

@@ -68,9 +68,9 @@ NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn,
/* /*
start crypto state 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) const struct dcesrv_crypto_ops *dcesrv_crypto_backend_bytype(uint8_t auth_type)
{ {
switch (auth_type) { switch (auth_type) {
#if 0
case DCERPC_AUTH_TYPE_SCHANNEL: case DCERPC_AUTH_TYPE_SCHANNEL:
return dcesrv_crypto_schannel_get_ops(); return dcesrv_crypto_schannel_get_ops();
#endif
case DCERPC_AUTH_TYPE_NTLMSSP: case DCERPC_AUTH_TYPE_NTLMSSP:
return dcesrv_crypto_ntlmssp_get_ops(); return dcesrv_crypto_ntlmssp_get_ops();
} }

View File

@@ -22,8 +22,7 @@
*/ */
/* /*
this provides a crypto interface to the various backends (such as this provides the NTLMSSP backend for server side rpc
NTLMSSP and SCHANNEL) for the rpc server code
*/ */
#include "includes.h" #include "includes.h"
@@ -32,11 +31,15 @@
/* /*
start crypto state 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; struct auth_ntlmssp_state *ntlmssp = NULL;
NTSTATUS status; 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); status = auth_ntlmssp_start(&ntlmssp);
auth->crypto_ctx.private_data = 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_value(ldb, &msg, "sessionKey", &val);
ldb_msg_add_string(ldb, &msg, "expiry", s); ldb_msg_add_string(ldb, &msg, "expiry", s);
ldb_delete(ldb, msg.dn);
ret = ldb_add(ldb, &msg); ret = ldb_add(ldb, &msg);
ldb_close(ldb);
if (ret != 0) { 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; return NT_STATUS_INTERNAL_DB_CORRUPTION;
} }
ldb_close(ldb);
return NT_STATUS_OK; return NT_STATUS_OK;
} }
@@ -110,13 +114,20 @@ NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx,
struct ldb_message **res; struct ldb_message **res;
int ret; int ret;
const struct ldb_val *val; const struct ldb_val *val;
char *expr=NULL;
ldb = schannel_db_connect(mem_ctx); ldb = schannel_db_connect(mem_ctx);
if (ldb == NULL) { if (ldb == NULL) {
return NT_STATUS_NO_MEMORY; 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) { if (ret != 1) {
ldb_close(ldb); ldb_close(ldb);
return NT_STATUS_INVALID_HANDLE; return NT_STATUS_INVALID_HANDLE;