#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "auth/auth.h"
#include "auth/gensec/gensec.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
#include "rpc_server/dcerpc_server.h"
#include "rpc_server/dcerpc_server_proto.h"
#include "librpc/rpc/dcerpc_proto.h"
#include "libcli/security/security.h"
#include "param/param.h"
+#define SAMBA_ASSOC_GROUP 0x12345678
+
extern const struct dcesrv_interface dcesrv_mgmt_interface;
/*
return NT_STATUS_OK;
}
-static NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
- DATA_BLOB *session_key)
+NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
+ DATA_BLOB *session_key)
{
if (p->auth_state.session_info->session_key.length) {
*session_key = p->auth_state.session_info->session_key;
/*
fetch the user session key - may be default (above) or the SMB session key
+
+ The key is always truncated to 16 bytes
*/
_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
DATA_BLOB *session_key)
{
- return p->auth_state.session_key(p, session_key);
+ NTSTATUS status = p->auth_state.session_key(p, session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ session_key->length = MIN(session_key->length, 16);
+
+ return NT_STATUS_OK;
}
p->endpoint = ep;
p->contexts = NULL;
p->call_list = NULL;
+ p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
p->incoming_fragmented_call_list = NULL;
p->pending_call_list = NULL;
p->cli_max_recv_frag = 0;
{
struct ncacn_packet pkt;
struct data_blob_list_item *rep;
+ uint8_t zeros[4];
NTSTATUS status;
/* setup a bind_ack */
pkt.u.fault.cancel_count = 0;
pkt.u.fault.status = fault_code;
+ ZERO_STRUCT(zeros);
+ pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
+
rep = talloc(call, struct data_blob_list_item);
if (!rep) {
return NT_STATUS_NO_MEMORY;
uint32_t result=0, reason=0;
uint32_t context_id;
const struct dcesrv_interface *iface;
-
- if (call->pkt.u.bind.assoc_group_id != 0) {
+ uint32_t extra_flags = 0;
+
+ /*
+ * Association groups allow policy handles to be shared across
+ * multiple client connections. We don't implement this yet.
+ *
+ * So we just allow 0 if the client wants to create a new
+ * association group.
+ *
+ * And we allow the 0x12345678 value, we give away as
+ * assoc_group_id back to the clients
+ */
+ if (call->pkt.u.bind.assoc_group_id != 0 &&
+ lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
+ call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
return dcesrv_bind_nak(call, 0);
}
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
+ /*
+ * we need to send a non zero assoc_group_id here to make longhorn happy,
+ * it also matches samba3
+ */
+ context->assoc_group_id = SAMBA_ASSOC_GROUP;
context->private = NULL;
context->handles = NULL;
DLIST_ADD(call->conn->contexts, context);
call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
}
+ if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
+ lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
+ call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
+ extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+ }
+
/* handle any authentication that is being requested */
if (!dcesrv_auth_bind(call)) {
return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
pkt.auth_length = 0;
pkt.call_id = call->pkt.call_id;
pkt.ptype = DCERPC_PKT_BIND_ACK;
- pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
pkt.u.bind_ack.max_xmit_frag = 0x2000;
pkt.u.bind_ack.max_recv_frag = 0x2000;
- /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
- pkt.u.bind_ack.assoc_group_id = 0x12345678;
+ pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
if (iface) {
/* FIXME: Use pipe name as specified by endpoint instead of interface name */
pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
}
}
+ /* the iface->bind() might change the assoc_group_id */
+ pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
+
rep = talloc(call, struct data_blob_list_item);
if (!rep) {
return NT_STATUS_NO_MEMORY;
struct dcesrv_connection_context *context;
const struct dcesrv_interface *iface;
struct GUID uuid, *transfer_syntax_uuid;
+ NTSTATUS status;
if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
context->conn = call->conn;
context->iface = iface;
context->context_id = context_id;
+ context->assoc_group_id = SAMBA_ASSOC_GROUP;
context->private = NULL;
context->handles = NULL;
DLIST_ADD(call->conn->contexts, context);
call->context = context;
+ if (iface) {
+ status = iface->bind(call, iface);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
return NT_STATUS_OK;
}
context_id = call->pkt.u.alter.ctx_list[0].context_id;
/* see if they are asking for a new interface */
- if (result == 0 &&
- dcesrv_find_context(call->conn, context_id) == NULL) {
- status = dcesrv_alter_new_context(call, context_id);
- if (!NT_STATUS_IS_OK(status)) {
- result = DCERPC_BIND_PROVIDER_REJECT;
- reason = DCERPC_BIND_REASON_ASYNTAX;
+ if (result == 0) {
+ call->context = dcesrv_find_context(call->conn, context_id);
+ if (!call->context) {
+ status = dcesrv_alter_new_context(call, context_id);
+ if (!NT_STATUS_IS_OK(status)) {
+ result = DCERPC_BIND_PROVIDER_REJECT;
+ reason = DCERPC_BIND_REASON_ASYNTAX;
+ }
}
}
+ if (result == 0 &&
+ call->pkt.u.alter.assoc_group_id != 0 &&
+ lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
+ call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
+ /* TODO: work out what to return here */
+ result = DCERPC_BIND_PROVIDER_REJECT;
+ reason = DCERPC_BIND_REASON_ASYNTAX;
+ }
+
/* setup a alter_resp */
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
pkt.auth_length = 0;
pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
pkt.u.alter_resp.max_xmit_frag = 0x2000;
pkt.u.alter_resp.max_recv_frag = 0x2000;
- pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
+ if (result == 0) {
+ pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
+ } else {
+ pkt.u.alter_resp.assoc_group_id = 0;
+ }
pkt.u.alter_resp.num_results = 1;
pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
if (!pkt.u.alter_resp.ctx_list) {
call->context = context;
call->ndr_pull = pull;
- if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
- pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
- }
-
if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
pull->flags |= LIBNDR_FLAG_BIGENDIAN;
}
struct ndr_push *push;
NTSTATUS status;
DATA_BLOB stub;
- uint32_t total_length;
+ uint32_t total_length, chunk_size;
struct dcesrv_connection_context *context = call->context;
+ size_t sig_size = 0;
/* call the reply function */
status = context->iface->reply(call, call, call->r);
total_length = stub.length;
+ /* we can write a full max_recv_frag size, minus the dcerpc
+ request header size */
+ chunk_size = call->conn->cli_max_recv_frag;
+ chunk_size -= DCERPC_REQUEST_LENGTH;
+ if (call->conn->auth_state.auth_info &&
+ call->conn->auth_state.gensec_security) {
+ sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
+ call->conn->cli_max_recv_frag);
+ if (sig_size) {
+ chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+ chunk_size -= sig_size;
+ }
+ }
+ chunk_size -= (chunk_size % 16);
+
do {
uint32_t length;
struct data_blob_list_item *rep;
rep = talloc(call, struct data_blob_list_item);
NT_STATUS_HAVE_NO_MEMORY(rep);
- length = stub.length;
- if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
- /* the 32 is to cope with signing data */
- length = call->conn->cli_max_recv_frag -
- (DCERPC_MAX_SIGN_SIZE+DCERPC_RESPONSE_LENGTH);
- }
+ length = MIN(chunk_size, stub.length);
/* form the dcerpc response packet */
dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
pkt.u.response.stub_and_verifier.data = stub.data;
pkt.u.response.stub_and_verifier.length = length;
- if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
+ if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
return dcesrv_fault(call, DCERPC_FAULT_OTHER);
}
ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
}
+ if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+
ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
talloc_free(dce_conn->partial_input.data);