1
0
mirror of https://github.com/samba-team/samba.git synced 2025-11-30 20:23:49 +03:00
Files
samba-mirror/source/rpc_server/dcesrv_crypto_schannel.c
Andrew Tridgell a35459387d r1136: - added IDL for netr_LogonGetDomainInfo()
- added workstation to auth_session_info in rpc servers

- added session key fetch hook in crypto backends in dcesrv

- store and fetch seed as well as a session key in schannel ldb

- when a client uses schannel to setup a netlogon pipe connection we
  also need to setup the credentials from the schannel negotiation so
  credentials chaining works

- added server side netr_LogonGetDomainInfo() call
2007-10-10 12:56:39 -05:00

240 lines
6.4 KiB
C

/*
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 schannel_bind bind_info;
struct schannel_state *state;
};
static NTSTATUS schannel_setup_session_info(struct srv_schannel_state *schannel,
const char *account_name,
struct auth_session_info **session_info)
{
TALLOC_CTX *mem_ctx;
mem_ctx = talloc_init("schannel_setup");
if (mem_ctx == NULL) {
return NT_STATUS_NO_MEMORY;
}
(*session_info) = talloc_p(mem_ctx, struct auth_session_info);
if (*session_info == NULL) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
ZERO_STRUCTP(*session_info);
(*session_info)->workstation = talloc_strdup(mem_ctx, account_name);
if ((*session_info)->workstation == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* TODO: fill in the rest of the session_info structure */
return NT_STATUS_OK;
}
/*
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;
const char *account_name;
struct schannel_bind_ack ack;
struct creds_CredentialState creds;
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_schannel_bind);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
}
if (schannel->bind_info.bind_type == 23) {
account_name = schannel->bind_info.u.info23.account_name;
} else {
account_name = schannel->bind_info.u.info3.account_name;
}
/* pull the session key for this client */
status = schannel_fetch_session_key(mem_ctx, account_name, &creds);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
}
/* start up the schannel server code */
status = schannel_start(&schannel->state, creds.session_key, False);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
}
status = schannel_setup_session_info(schannel, account_name,
&auth->session_info);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
}
auth->crypto_ctx.private_data = schannel;
ack.unknown1 = 1;
ack.unknown2 = 0;
ack.unknown3 = 0x6c0000;
status = ndr_push_struct_blob(auth_blob, mem_ctx, &ack,
(ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return NT_STATUS_INVALID_PARAMETER;
}
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);
}
/*
get the session key
*/
static NTSTATUS dcesrv_crypto_schannel_session_key(struct dcesrv_auth *auth, uint8_t session_key[16])
{
struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
memcpy(session_key, srv_schannel_state->state->session_key, 16);
return NT_STATUS_OK;
}
/*
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,
.session_key = dcesrv_crypto_schannel_session_key,
.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;
}