*/
#include "includes.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/gen_ndr/ndr_oxidresolver.h"
+#include "auth/auth.h"
+#include "dlinklist.h"
+#include "rpc_server/dcerpc_server.h"
/*
see if two endpoints match
*/
-static BOOL endpoints_match(const struct dcesrv_ep_description *ep1,
- const struct dcesrv_ep_description *ep2)
+static BOOL endpoints_match(const struct dcerpc_binding *ep1,
+ const struct dcerpc_binding *ep2)
{
- if (ep1->type != ep2->type) {
+ if (ep1->transport != ep2->transport) {
return False;
}
- switch (ep1->type) {
- case ENDPOINT_SMB:
- if (strcasecmp(ep1->info.smb_pipe,ep2->info.smb_pipe)==0) {
- return True;
- }
- break;
- case ENDPOINT_TCP:
- if (ep1->info.tcp_port == ep2->info.tcp_port) {
- return True;
- }
- break;
+ if (!ep1->endpoint || !ep2->endpoint) {
+ return ep1->endpoint == ep2->endpoint;
}
- return False;
+ if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0)
+ return False;
+
+ return True;
}
/*
find an endpoint in the dcesrv_context
*/
static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
- const struct dcesrv_ep_description *ep_description)
+ const struct dcerpc_binding *ep_description)
{
struct dcesrv_endpoint *ep;
for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
static BOOL interface_match(const struct dcesrv_interface *if1,
const struct dcesrv_interface *if2)
{
- if (if1->ndr->if_version != if2->ndr->if_version) {
+ if (if1->if_version != if2->if_version) {
return False;
}
- if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
+ if (strcmp(if1->uuid, if2->uuid)==0) {
return True;
}
static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
const char *uuid, uint32_t if_version)
{
- if (iface->ndr->if_version != if_version) {
+ if (iface->if_version != if_version) {
return False;
}
- if (strcmp(iface->ndr->uuid, uuid)==0) {
+ if (strcmp(iface->uuid, uuid)==0) {
return True;
}
const struct dcesrv_interface *iface,
const struct security_descriptor *sd)
{
- struct dcesrv_ep_description ep_description;
struct dcesrv_endpoint *ep;
struct dcesrv_if_list *ifl;
- BOOL tcp;
+ struct dcerpc_binding binding;
BOOL add_ep = False;
+ NTSTATUS status;
+
+ status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
- tcp = (strncasecmp(ep_name, "TCP-", 4) == 0);
-
- if (tcp) {
- ep_description.type = ENDPOINT_TCP;
- ep_description.info.tcp_port = atoi(ep_name+4);
- } else {
- ep_description.type = ENDPOINT_SMB;
- ep_description.info.smb_pipe = ep_name;
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
+ return status;
}
/* check if this endpoint exists
*/
- if ((ep=find_endpoint(dce_ctx, &ep_description))==NULL) {
+ if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
if (!ep) {
return NT_STATUS_NO_MEMORY;
}
ZERO_STRUCTP(ep);
- if (tcp) {
- ep->ep_description.type = ENDPOINT_TCP;
- ep->ep_description.info.tcp_port = atoi(ep_name+4);
- } else {
- ep->ep_description.type = ENDPOINT_SMB;
- ep->ep_description.info.smb_pipe = smb_xstrdup(ep_name);
- }
+ ep->ep_description = binding;
add_ep = True;
}
/* see if the interface is already registered on te endpoint */
if (find_interface(ep, iface)!=NULL) {
DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
- iface->ndr->name, ep_name));
+ iface->name, ep_name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
* we try to set it
*/
if (ep->sd == NULL) {
- ep->sd = copy_security_descriptor(dce_ctx, sd);
+ ep->sd = security_descriptor_copy(dce_ctx, sd);
}
/* if now there's no security descriptor given on the endpoint
if (ep->sd != NULL) {
DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
" on endpoint '%s'\n",
- iface->ndr->name, ep_name));
+ iface->name, ep_name));
if (add_ep) free(ep);
free(ifl);
return NT_STATUS_OBJECT_NAME_COLLISION;
}
DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
- iface->ndr->name, ep_name));
+ iface->name, ep_name));
return NT_STATUS_OK;
}
DATA_BLOB *session_key)
{
/* this took quite a few CPU cycles to find ... */
- session_key->data = "SystemLibraryDTC";
+ session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
session_key->length = 16;
return NT_STATUS_OK;
}
}
+/*
+ destroy a link to an endpoint
+*/
+static int dcesrv_endpoint_destructor(void *ptr)
+{
+ struct dcesrv_connection *p = ptr;
+ if (p->iface) {
+ p->iface->unbind(p, p->iface);
+ }
+
+ /* destroy any handles */
+ while (p->handles) {
+ dcesrv_handle_destroy(p, p->handles);
+ }
+
+ if (p->auth_state.gensec_security) {
+ talloc_free(p->auth_state.gensec_security);
+ p->auth_state.gensec_security = NULL;
+ }
+
+ return 0;
+}
+
+
/*
connect to a dcerpc endpoint
*/
(*p)->auth_state.session_key = dcesrv_generic_session_key;
(*p)->srv_conn = NULL;
+ talloc_set_destructor(*p, dcesrv_endpoint_destructor);
+
return NT_STATUS_OK;
}
search and connect to a dcerpc endpoint
*/
NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
- const struct dcesrv_ep_description *ep_description,
+ const struct dcerpc_binding *ep_description,
struct auth_session_info *session_info,
struct dcesrv_connection **dce_conn_p)
{
}
-/*
- disconnect a link to an endpoint
-*/
-void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
-{
- if (p->iface) {
- p->iface->unbind(p, p->iface);
- }
-
- /* destroy any handles */
- while (p->handles) {
- dcesrv_handle_destroy(p, p->handles);
- }
-
- if (p->auth_state.gensec_security) {
- gensec_end(&p->auth_state.gensec_security);
- }
-
- talloc_free(p);
-}
-
static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
{
pkt->rpc_vers = 5;
pkt.u.bind_ack.max_xmit_frag = 0x2000;
pkt.u.bind_ack.max_recv_frag = 0x2000;
pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
- if (call->conn->iface && call->conn->iface->ndr) {
+ if (call->conn->iface) {
+ /* FIXME: Use pipe name as specified by endpoint instead of interface name */
pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s",
- call->conn->iface->ndr->name);
+ call->conn->iface->name);
} else {
pkt.u.bind_ack.secondary_address = "";
}
return NT_STATUS_OK;
}
+/*
+ handle a bind request
+*/
+static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
+{
+ struct dcerpc_packet pkt;
+ struct dcesrv_call_reply *rep;
+ NTSTATUS status;
+ uint32_t result=0, reason=0;
+
+ /* handle any authentication that is being requested */
+ if (!dcesrv_auth_alter(call)) {
+ /* TODO: work out the right reject code */
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ /* setup a alter_ack */
+ dcesrv_init_hdr(&pkt);
+ pkt.auth_length = 0;
+ pkt.call_id = call->pkt.call_id;
+ pkt.ptype = DCERPC_PKT_ALTER_ACK;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt.u.alter_ack.max_xmit_frag = 0x2000;
+ pkt.u.alter_ack.max_recv_frag = 0x2000;
+ pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
+ pkt.u.alter_ack.secondary_address = NULL;
+ pkt.u.alter_ack.num_results = 1;
+ pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
+ if (!pkt.u.alter_ack.ctx_list) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pkt.u.alter_ack.ctx_list[0].result = result;
+ pkt.u.alter_ack.ctx_list[0].reason = reason;
+ GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid);
+ pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
+ pkt.u.alter_ack.auth_info = data_blob(NULL, 0);
+
+ if (!dcesrv_auth_alter_ack(call, &pkt)) {
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ rep = talloc_p(call, struct dcesrv_call_reply);
+ if (!rep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_push_auth(&rep->data, call, &pkt,
+ call->conn->auth_state.auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dcerpc_set_frag_length(&rep->data, rep->data.length);
+
+ DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
+ DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+
+ return NT_STATUS_OK;
+}
/*
handle a dcerpc request packet
{
struct ndr_pull *pull;
struct ndr_push *push;
- uint16_t opnum;
void *r;
NTSTATUS status;
DATA_BLOB stub;
uint32_t total_length;
+ call->fault_code = 0;
if (!call->conn->iface) {
return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
}
- opnum = call->pkt.u.request.opnum;
-
- if (opnum >= call->conn->iface->ndr->num_calls) {
- return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
- }
-
pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
if (!pull) {
return NT_STATUS_NO_MEMORY;
}
- r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
- if (!r) {
- return NT_STATUS_NO_MEMORY;
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
+ pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
}
if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
}
/* unravel the NDR for the packet */
- status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
+ status = call->conn->iface->ndr_pull(call, call, pull, &r);
if (!NT_STATUS_IS_OK(status)) {
- dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
- &call->pkt.u.request.stub_and_verifier);
- return dcesrv_fault(call, DCERPC_FAULT_NDR);
+ return dcesrv_fault(call, call->fault_code);
}
if (pull->offset != pull->data_size) {
dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
}
- call->fault_code = 0;
-
/* call the dispatch function */
status = call->conn->iface->dispatch(call, call, r);
if (!NT_STATUS_IS_OK(status)) {
- dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN,
- &call->pkt.u.request.stub_and_verifier);
return dcesrv_fault(call, call->fault_code);
}
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}
- status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
+ status = call->conn->iface->ndr_push(call, call, push, r);
if (!NT_STATUS_IS_OK(status)) {
- return dcesrv_fault(call, DCERPC_FAULT_NDR);
+ return dcesrv_fault(call, call->fault_code);
}
stub = ndr_push_blob(push);
dce_partial_advance(dce_conn, blob.length);
/* see if this is a continued packet */
- if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
struct dcesrv_call_state *call2 = call;
uint32_t alloc_size;
/* this may not be the last pdu in the chain - if its isn't then
just put it on the call_list and wait for the rest */
- if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
return NT_STATUS_OK;
}
case DCERPC_PKT_AUTH3:
status = dcesrv_auth3(call);
break;
+ case DCERPC_PKT_ALTER:
+ status = dcesrv_alter(call);
+ break;
case DCERPC_PKT_REQUEST:
status = dcesrv_request(call);
break;
struct dcesrv_call_state *call;
struct dcesrv_call_reply *rep;
ssize_t nwritten;
- NTSTATUS status = NT_STATUS_OK;
call = dce_conn->call_list;
if (!call || !call->replies) {
/* we're done with this section of the call */
DLIST_REMOVE(call->replies, rep);
} else {
- status = STATUS_BUFFER_OVERFLOW;
+ return STATUS_BUFFER_OVERFLOW;
}
if (call->replies == NULL) {
talloc_free(call);
}
- return status;
+ return NT_STATUS_OK;
}
}
}
- dcesrv_tcp_init(service, model_ops, dce_ctx);
+ dcesrv_sock_init(service, model_ops, dce_ctx);
return;
}
static void dcesrv_accept(struct server_connection *srv_conn)
{
- dcesrv_tcp_accept(srv_conn);
+ dcesrv_sock_accept(srv_conn);
}
-static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
+static void dcesrv_recv(struct server_connection *srv_conn,
+ struct timeval t, uint16_t flags)
{
- dcesrv_tcp_recv(srv_conn, t, flags);
+ dcesrv_sock_recv(srv_conn, t, flags);
}
-static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
+static void dcesrv_send(struct server_connection *srv_conn,
+ struct timeval t, uint16_t flags)
{
- dcesrv_tcp_send(srv_conn, t, flags);
-}
-
-static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
-{
- dcesrv_tcp_idle(srv_conn, t);
+ dcesrv_sock_send(srv_conn, t, flags);
}
static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
{
- dcesrv_tcp_close(srv_conn, reason);
+ dcesrv_sock_close(srv_conn, reason);
return;
}
static void dcesrv_exit(struct server_service *service, const char *reason)
{
- dcesrv_tcp_exit(service, reason);
+ dcesrv_sock_exit(service, reason);
return;
}
/* the list of currently registered DCERPC endpoint servers.
*/
-static struct {
+static struct ep_server {
struct dcesrv_endpoint_server *ep_server;
} *ep_servers = NULL;
static int num_ep_servers;
The 'type' is used to specify whether this is for a disk, printer or IPC$ share
*/
-static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
+NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
{
const struct dcesrv_endpoint_server *ep_server = _ep_server;
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
+ ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
if (!ep_servers) {
smb_panic("out of memory in dcerpc_register");
}
sizeof(struct dcesrv_context),
sizeof(struct dcesrv_endpoint),
sizeof(struct dcesrv_endpoint_server),
- sizeof(struct dcesrv_ep_description),
sizeof(struct dcesrv_interface),
sizeof(struct dcesrv_if_list),
sizeof(struct dcesrv_connection),
return &critical_sizes;
}
-/*
- initialise the DCERPC subsystem
-*/
-BOOL subsystem_dcerpc_init(void)
-{
- NTSTATUS status;
-
- status = register_subsystem("dcerpc", dcerpc_register_ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- return False;
- }
-
- /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */
- static_init_dcerpc;
-
- DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
- return True;
-}
-
static const struct server_service_ops dcesrv_ops = {
.name = "rpc",
.service_init = dcesrv_init,
.accept_connection = dcesrv_accept,
.recv_handler = dcesrv_recv,
.send_handler = dcesrv_send,
- .idle_handler = dcesrv_idle,
+ .idle_handler = NULL,
.close_connection = dcesrv_close,
.service_exit = dcesrv_exit,
};