2 Unix SMB/CIFS implementation.
4 server side dcerpc core code
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan (metze) Metzmacher 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "librpc/gen_ndr/ndr_epmapper.h"
26 #include "librpc/gen_ndr/ndr_oxidresolver.h"
27 #include "auth/auth.h"
28 #include "dlinklist.h"
29 #include "rpc_server/dcerpc_server.h"
32 see if two endpoints match
34 static BOOL
endpoints_match(const struct dcerpc_binding
*ep1
,
35 const struct dcerpc_binding
*ep2
)
37 if (ep1
->transport
!= ep2
->transport
) {
41 if (!ep1
->endpoint
|| !ep2
->endpoint
) {
42 return ep1
->endpoint
== ep2
->endpoint
;
45 if (strcasecmp(ep1
->endpoint
, ep2
->endpoint
) != 0)
52 find an endpoint in the dcesrv_context
54 static struct dcesrv_endpoint
*find_endpoint(struct dcesrv_context
*dce_ctx
,
55 const struct dcerpc_binding
*ep_description
)
57 struct dcesrv_endpoint
*ep
;
58 for (ep
=dce_ctx
->endpoint_list
; ep
; ep
=ep
->next
) {
59 if (endpoints_match(&ep
->ep_description
, ep_description
)) {
67 find a registered context_id from a bind or alter_context
69 static struct dcesrv_connection_context
*dcesrv_find_context(struct dcesrv_connection
*conn
,
72 struct dcesrv_connection_context
*c
;
73 for (c
=conn
->contexts
;c
;c
=c
->next
) {
74 if (c
->context_id
== context_id
) return c
;
80 see if a uuid and if_version match to an interface
82 static BOOL
interface_match(const struct dcesrv_interface
*if1
,
83 const struct dcesrv_interface
*if2
)
85 if (if1
->if_version
!= if2
->if_version
) {
89 if (strcmp(if1
->uuid
, if2
->uuid
)==0) {
97 find the interface operations on an endpoint
99 static const struct dcesrv_interface
*find_interface(const struct dcesrv_endpoint
*endpoint
,
100 const struct dcesrv_interface
*iface
)
102 struct dcesrv_if_list
*ifl
;
103 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
104 if (interface_match(&(ifl
->iface
), iface
)) {
105 return &(ifl
->iface
);
112 see if a uuid and if_version match to an interface
114 static BOOL
interface_match_by_uuid(const struct dcesrv_interface
*iface
,
115 const char *uuid
, uint32_t if_version
)
117 if (iface
->if_version
!= if_version
) {
121 if (strcmp(iface
->uuid
, uuid
)==0) {
129 find the interface operations on an endpoint by uuid
131 static const struct dcesrv_interface
*find_interface_by_uuid(const struct dcesrv_endpoint
*endpoint
,
132 const char *uuid
, uint32_t if_version
)
134 struct dcesrv_if_list
*ifl
;
135 for (ifl
=endpoint
->interface_list
; ifl
; ifl
=ifl
->next
) {
136 if (interface_match_by_uuid(&(ifl
->iface
), uuid
, if_version
)) {
137 return &(ifl
->iface
);
144 find a call that is pending in our call list
146 static struct dcesrv_call_state
*dcesrv_find_call(struct dcesrv_connection
*dce_conn
, uint16_t call_id
)
148 struct dcesrv_call_state
*c
;
149 for (c
=dce_conn
->call_list
;c
;c
=c
->next
) {
150 if (c
->pkt
.call_id
== call_id
) {
158 register an interface on an endpoint
160 NTSTATUS
dcesrv_interface_register(struct dcesrv_context
*dce_ctx
,
162 const struct dcesrv_interface
*iface
,
163 const struct security_descriptor
*sd
)
165 struct dcesrv_endpoint
*ep
;
166 struct dcesrv_if_list
*ifl
;
167 struct dcerpc_binding binding
;
171 status
= dcerpc_parse_binding(dce_ctx
, ep_name
, &binding
);
173 if (NT_STATUS_IS_ERR(status
)) {
174 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name
));
178 /* check if this endpoint exists
180 if ((ep
=find_endpoint(dce_ctx
, &binding
))==NULL
) {
181 ep
= talloc_p(dce_ctx
, struct dcesrv_endpoint
);
183 return NT_STATUS_NO_MEMORY
;
186 ep
->ep_description
= binding
;
190 /* see if the interface is already registered on te endpoint */
191 if (find_interface(ep
, iface
)!=NULL
) {
192 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
193 iface
->name
, ep_name
));
194 return NT_STATUS_OBJECT_NAME_COLLISION
;
197 /* talloc a new interface list element */
198 ifl
= talloc_p(dce_ctx
, struct dcesrv_if_list
);
200 return NT_STATUS_NO_MEMORY
;
203 /* copy the given interface struct to the one on the endpoints interface list */
204 memcpy(&(ifl
->iface
),iface
, sizeof(struct dcesrv_interface
));
206 /* if we have a security descriptor given,
207 * we should see if we can set it up on the endpoint
210 /* if there's currently no security descriptor given on the endpoint
213 if (ep
->sd
== NULL
) {
214 ep
->sd
= security_descriptor_copy(dce_ctx
, sd
);
217 /* if now there's no security descriptor given on the endpoint
218 * something goes wrong, either we failed to copy the security descriptor
219 * or there was already one on the endpoint
221 if (ep
->sd
!= NULL
) {
222 DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
223 " on endpoint '%s'\n",
224 iface
->name
, ep_name
));
225 if (add_ep
) free(ep
);
227 return NT_STATUS_OBJECT_NAME_COLLISION
;
231 /* finally add the interface on the endpoint */
232 DLIST_ADD(ep
->interface_list
, ifl
);
234 /* if it's a new endpoint add it to the dcesrv_context */
236 DLIST_ADD(dce_ctx
->endpoint_list
, ep
);
239 DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
240 iface
->name
, ep_name
));
245 static NTSTATUS
dcesrv_inherited_session_key(struct dcesrv_connection
*p
,
246 DATA_BLOB
*session_key
)
248 if (p
->auth_state
.session_info
->session_key
.length
) {
249 *session_key
= p
->auth_state
.session_info
->session_key
;
252 return NT_STATUS_NO_USER_SESSION_KEY
;
255 NTSTATUS
dcesrv_generic_session_key(struct dcesrv_connection
*p
,
256 DATA_BLOB
*session_key
)
258 /* this took quite a few CPU cycles to find ... */
259 session_key
->data
= discard_const_p(uint8_t, "SystemLibraryDTC");
260 session_key
->length
= 16;
265 fetch the user session key - may be default (above) or the SMB session key
267 NTSTATUS
dcesrv_fetch_session_key(struct dcesrv_connection
*p
,
268 DATA_BLOB
*session_key
)
270 return p
->auth_state
.session_key(p
, session_key
);
275 destroy a link to an endpoint
277 static int dcesrv_endpoint_destructor(void *ptr
)
279 struct dcesrv_connection
*p
= ptr
;
281 while (p
->contexts
) {
282 struct dcesrv_connection_context
*c
= p
->contexts
;
284 DLIST_REMOVE(p
->contexts
, c
);
287 c
->iface
->unbind(c
, c
->iface
);
298 connect to a dcerpc endpoint
300 NTSTATUS
dcesrv_endpoint_connect(struct dcesrv_context
*dce_ctx
,
301 const struct dcesrv_endpoint
*ep
,
302 struct dcesrv_connection
**p
)
304 *p
= talloc_p(dce_ctx
, struct dcesrv_connection
);
306 return NT_STATUS_NO_MEMORY
;
309 (*p
)->dce_ctx
= dce_ctx
;
311 (*p
)->contexts
= NULL
;
312 (*p
)->call_list
= NULL
;
313 (*p
)->cli_max_recv_frag
= 0;
314 (*p
)->partial_input
= data_blob(NULL
, 0);
315 (*p
)->auth_state
.auth_info
= NULL
;
316 (*p
)->auth_state
.gensec_security
= NULL
;
317 (*p
)->auth_state
.session_info
= NULL
;
318 (*p
)->auth_state
.session_key
= dcesrv_generic_session_key
;
319 (*p
)->srv_conn
= NULL
;
321 talloc_set_destructor(*p
, dcesrv_endpoint_destructor
);
327 search and connect to a dcerpc endpoint
329 NTSTATUS
dcesrv_endpoint_search_connect(struct dcesrv_context
*dce_ctx
,
330 const struct dcerpc_binding
*ep_description
,
331 struct auth_session_info
*session_info
,
332 struct dcesrv_connection
**dce_conn_p
)
335 const struct dcesrv_endpoint
*ep
;
337 /* make sure this endpoint exists */
338 ep
= find_endpoint(dce_ctx
, ep_description
);
340 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
343 status
= dcesrv_endpoint_connect(dce_ctx
, ep
, dce_conn_p
);
344 if (!NT_STATUS_IS_OK(status
)) {
348 (*dce_conn_p
)->auth_state
.session_info
= talloc_reference((*dce_conn_p
), session_info
);
349 (*dce_conn_p
)->auth_state
.session_key
= dcesrv_inherited_session_key
;
351 /* TODO: check security descriptor of the endpoint here
352 * if it's a smb named pipe
353 * if it's failed free dce_conn_p
360 static void dcesrv_init_hdr(struct dcerpc_packet
*pkt
)
363 pkt
->rpc_vers_minor
= 0;
364 if (lp_rpc_big_endian()) {
367 pkt
->drep
[0] = DCERPC_DREP_LE
;
375 return a dcerpc fault
377 static NTSTATUS
dcesrv_fault(struct dcesrv_call_state
*call
, uint32_t fault_code
)
379 struct dcerpc_packet pkt
;
380 struct dcesrv_call_reply
*rep
;
383 /* setup a bind_ack */
384 dcesrv_init_hdr(&pkt
);
386 pkt
.call_id
= call
->pkt
.call_id
;
387 pkt
.ptype
= DCERPC_PKT_FAULT
;
388 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
389 pkt
.u
.fault
.alloc_hint
= 0;
390 pkt
.u
.fault
.context_id
= 0;
391 pkt
.u
.fault
.cancel_count
= 0;
392 pkt
.u
.fault
.status
= fault_code
;
394 rep
= talloc_p(call
, struct dcesrv_call_reply
);
396 return NT_STATUS_NO_MEMORY
;
399 status
= dcerpc_push_auth(&rep
->data
, call
, &pkt
, NULL
);
400 if (!NT_STATUS_IS_OK(status
)) {
404 dcerpc_set_frag_length(&rep
->data
, rep
->data
.length
);
406 DLIST_ADD_END(call
->replies
, rep
, struct dcesrv_call_reply
*);
407 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
414 return a dcerpc bind_nak
416 static NTSTATUS
dcesrv_bind_nak(struct dcesrv_call_state
*call
, uint32_t reason
)
418 struct dcerpc_packet pkt
;
419 struct dcesrv_call_reply
*rep
;
422 /* setup a bind_nak */
423 dcesrv_init_hdr(&pkt
);
425 pkt
.call_id
= call
->pkt
.call_id
;
426 pkt
.ptype
= DCERPC_PKT_BIND_NAK
;
427 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
428 pkt
.u
.bind_nak
.reject_reason
= reason
;
429 pkt
.u
.bind_nak
.num_versions
= 0;
431 rep
= talloc_p(call
, struct dcesrv_call_reply
);
433 return NT_STATUS_NO_MEMORY
;
436 status
= dcerpc_push_auth(&rep
->data
, call
, &pkt
, NULL
);
437 if (!NT_STATUS_IS_OK(status
)) {
441 dcerpc_set_frag_length(&rep
->data
, rep
->data
.length
);
443 DLIST_ADD_END(call
->replies
, rep
, struct dcesrv_call_reply
*);
444 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
451 handle a bind request
453 static NTSTATUS
dcesrv_bind(struct dcesrv_call_state
*call
)
455 const char *uuid
, *transfer_syntax
;
456 uint32_t if_version
, transfer_syntax_version
;
457 struct dcerpc_packet pkt
;
458 struct dcesrv_call_reply
*rep
;
460 uint32_t result
=0, reason
=0;
462 const struct dcesrv_interface
*iface
;
464 if (call
->pkt
.u
.bind
.num_contexts
!= 1 ||
465 call
->pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
< 1) {
466 return dcesrv_bind_nak(call
, 0);
469 context_id
= call
->pkt
.u
.bind
.ctx_list
[0].context_id
;
471 /* you can't bind twice on one context */
472 if (dcesrv_find_context(call
->conn
, context_id
) != NULL
) {
473 return dcesrv_bind_nak(call
, 0);
476 if_version
= call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.if_version
;
477 uuid
= GUID_string(call
, &call
->pkt
.u
.bind
.ctx_list
[0].abstract_syntax
.uuid
);
479 return dcesrv_bind_nak(call
, 0);
482 transfer_syntax_version
= call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].if_version
;
483 transfer_syntax
= GUID_string(call
,
484 &call
->pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
[0].uuid
);
485 if (!transfer_syntax
||
486 strcasecmp(NDR_GUID
, transfer_syntax
) != 0 ||
487 NDR_GUID_VERSION
!= transfer_syntax_version
) {
488 /* we only do NDR encoded dcerpc */
489 return dcesrv_bind_nak(call
, 0);
492 iface
= find_interface_by_uuid(call
->conn
->endpoint
, uuid
, if_version
);
494 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid
, if_version
));
495 /* we don't know about that interface */
496 result
= DCERPC_BIND_PROVIDER_REJECT
;
497 reason
= DCERPC_BIND_REASON_ASYNTAX
;
501 /* add this context to the list of available context_ids */
502 struct dcesrv_connection_context
*context
= talloc(call
->conn
,
503 struct dcesrv_connection_context
);
504 if (context
== NULL
) {
505 return dcesrv_bind_nak(call
, 0);
507 context
->conn
= call
->conn
;
508 context
->iface
= iface
;
509 context
->context_id
= context_id
;
510 context
->private = NULL
;
511 context
->handles
= NULL
;
512 DLIST_ADD(call
->conn
->contexts
, context
);
513 call
->context
= context
;
516 if (call
->conn
->cli_max_recv_frag
== 0) {
517 call
->conn
->cli_max_recv_frag
= call
->pkt
.u
.bind
.max_recv_frag
;
520 /* handle any authentication that is being requested */
521 if (!dcesrv_auth_bind(call
)) {
522 /* TODO: work out the right reject code */
523 return dcesrv_bind_nak(call
, 0);
526 /* setup a bind_ack */
527 dcesrv_init_hdr(&pkt
);
529 pkt
.call_id
= call
->pkt
.call_id
;
530 pkt
.ptype
= DCERPC_PKT_BIND_ACK
;
531 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
532 pkt
.u
.bind_ack
.max_xmit_frag
= 0x2000;
533 pkt
.u
.bind_ack
.max_recv_frag
= 0x2000;
534 pkt
.u
.bind_ack
.assoc_group_id
= call
->pkt
.u
.bind
.assoc_group_id
;
536 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
537 pkt
.u
.bind_ack
.secondary_address
= talloc_asprintf(call
, "\\PIPE\\%s", iface
->name
);
539 pkt
.u
.bind_ack
.secondary_address
= "";
541 pkt
.u
.bind_ack
.num_results
= 1;
542 pkt
.u
.bind_ack
.ctx_list
= talloc_p(call
, struct dcerpc_ack_ctx
);
543 if (!pkt
.u
.bind_ack
.ctx_list
) {
544 return NT_STATUS_NO_MEMORY
;
546 pkt
.u
.bind_ack
.ctx_list
[0].result
= result
;
547 pkt
.u
.bind_ack
.ctx_list
[0].reason
= reason
;
548 GUID_from_string(NDR_GUID
, &pkt
.u
.bind_ack
.ctx_list
[0].syntax
.uuid
);
549 pkt
.u
.bind_ack
.ctx_list
[0].syntax
.if_version
= NDR_GUID_VERSION
;
550 pkt
.u
.bind_ack
.auth_info
= data_blob(NULL
, 0);
552 if (!dcesrv_auth_bind_ack(call
, &pkt
)) {
553 return dcesrv_bind_nak(call
, 0);
557 status
= iface
->bind(call
, iface
);
558 if (!NT_STATUS_IS_OK(status
)) {
559 DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
560 uuid
, if_version
, nt_errstr(status
)));
561 return dcesrv_bind_nak(call
, 0);
565 rep
= talloc(call
, struct dcesrv_call_reply
);
567 return NT_STATUS_NO_MEMORY
;
570 status
= dcerpc_push_auth(&rep
->data
, call
, &pkt
,
571 call
->conn
->auth_state
.auth_info
);
572 if (!NT_STATUS_IS_OK(status
)) {
576 dcerpc_set_frag_length(&rep
->data
, rep
->data
.length
);
578 DLIST_ADD_END(call
->replies
, rep
, struct dcesrv_call_reply
*);
579 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
586 handle a auth3 request
588 static NTSTATUS
dcesrv_auth3(struct dcesrv_call_state
*call
)
590 /* handle the auth3 in the auth code */
591 if (!dcesrv_auth_auth3(call
)) {
592 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
597 /* we don't send a reply to a auth3 request, except by a
603 handle a bind request
605 static NTSTATUS
dcesrv_alter(struct dcesrv_call_state
*call
)
607 struct dcerpc_packet pkt
;
608 struct dcesrv_call_reply
*rep
;
610 uint32_t result
=0, reason
=0;
612 /* handle any authentication that is being requested */
613 if (!dcesrv_auth_alter(call
)) {
614 /* TODO: work out the right reject code */
615 return dcesrv_bind_nak(call
, 0);
618 /* setup a alter_ack */
619 dcesrv_init_hdr(&pkt
);
621 pkt
.call_id
= call
->pkt
.call_id
;
622 pkt
.ptype
= DCERPC_PKT_ALTER_RESP
;
623 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
624 pkt
.u
.alter_resp
.max_xmit_frag
= 0x2000;
625 pkt
.u
.alter_resp
.max_recv_frag
= 0x2000;
626 pkt
.u
.alter_resp
.assoc_group_id
= call
->pkt
.u
.bind
.assoc_group_id
;
627 pkt
.u
.alter_resp
.secondary_address
= NULL
;
628 pkt
.u
.alter_resp
.num_results
= 1;
629 pkt
.u
.alter_resp
.ctx_list
= talloc_p(call
, struct dcerpc_ack_ctx
);
630 if (!pkt
.u
.alter_resp
.ctx_list
) {
631 return NT_STATUS_NO_MEMORY
;
633 pkt
.u
.alter_resp
.ctx_list
[0].result
= result
;
634 pkt
.u
.alter_resp
.ctx_list
[0].reason
= reason
;
635 GUID_from_string(NDR_GUID
, &pkt
.u
.alter_resp
.ctx_list
[0].syntax
.uuid
);
636 pkt
.u
.alter_resp
.ctx_list
[0].syntax
.if_version
= NDR_GUID_VERSION
;
637 pkt
.u
.alter_resp
.auth_info
= data_blob(NULL
, 0);
639 if (!dcesrv_auth_alter_ack(call
, &pkt
)) {
640 return dcesrv_bind_nak(call
, 0);
643 rep
= talloc_p(call
, struct dcesrv_call_reply
);
645 return NT_STATUS_NO_MEMORY
;
648 status
= dcerpc_push_auth(&rep
->data
, call
, &pkt
,
649 call
->conn
->auth_state
.auth_info
);
650 if (!NT_STATUS_IS_OK(status
)) {
654 dcerpc_set_frag_length(&rep
->data
, rep
->data
.length
);
656 DLIST_ADD_END(call
->replies
, rep
, struct dcesrv_call_reply
*);
657 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
663 handle a dcerpc request packet
665 static NTSTATUS
dcesrv_request(struct dcesrv_call_state
*call
)
667 struct ndr_pull
*pull
;
668 struct ndr_push
*push
;
672 uint32_t total_length
;
673 struct dcesrv_connection_context
*context
;
675 call
->fault_code
= 0;
677 context
= dcesrv_find_context(call
->conn
, call
->pkt
.u
.request
.context_id
);
678 if (context
== NULL
) {
679 return dcesrv_fault(call
, DCERPC_FAULT_UNK_IF
);
682 call
->context
= context
;
684 pull
= ndr_pull_init_blob(&call
->pkt
.u
.request
.stub_and_verifier
, call
);
686 return NT_STATUS_NO_MEMORY
;
689 if (call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_ORPC
) {
690 pull
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
693 if (!(call
->pkt
.drep
[0] & DCERPC_DREP_LE
)) {
694 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
697 /* unravel the NDR for the packet */
698 status
= context
->iface
->ndr_pull(call
, call
, pull
, &r
);
699 if (!NT_STATUS_IS_OK(status
)) {
700 return dcesrv_fault(call
, call
->fault_code
);
703 if (pull
->offset
!= pull
->data_size
) {
704 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n",
705 pull
->data_size
- pull
->offset
));
706 dump_data(10, pull
->data
+pull
->offset
, pull
->data_size
- pull
->offset
);
709 /* call the dispatch function */
710 status
= context
->iface
->dispatch(call
, call
, r
);
711 if (!NT_STATUS_IS_OK(status
)) {
712 return dcesrv_fault(call
, call
->fault_code
);
715 /* form the reply NDR */
716 push
= ndr_push_init_ctx(call
);
718 return NT_STATUS_NO_MEMORY
;
721 /* carry over the pointer count to the reply in case we are
722 using full pointer. See NDR specification for full
724 push
->ptr_count
= pull
->ptr_count
;
726 if (lp_rpc_big_endian()) {
727 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
730 status
= context
->iface
->ndr_push(call
, call
, push
, r
);
731 if (!NT_STATUS_IS_OK(status
)) {
732 return dcesrv_fault(call
, call
->fault_code
);
735 stub
= ndr_push_blob(push
);
737 total_length
= stub
.length
;
741 struct dcesrv_call_reply
*rep
;
742 struct dcerpc_packet pkt
;
744 rep
= talloc(call
, struct dcesrv_call_reply
);
746 return NT_STATUS_NO_MEMORY
;
749 length
= stub
.length
;
750 if (length
+ DCERPC_RESPONSE_LENGTH
> call
->conn
->cli_max_recv_frag
) {
751 /* the 32 is to cope with signing data */
752 length
= call
->conn
->cli_max_recv_frag
-
753 (DCERPC_MAX_SIGN_SIZE
+DCERPC_RESPONSE_LENGTH
);
756 /* form the dcerpc response packet */
757 dcesrv_init_hdr(&pkt
);
759 pkt
.call_id
= call
->pkt
.call_id
;
760 pkt
.ptype
= DCERPC_PKT_RESPONSE
;
762 if (stub
.length
== total_length
) {
763 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
765 if (length
== stub
.length
) {
766 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
768 pkt
.u
.response
.alloc_hint
= stub
.length
;
769 pkt
.u
.response
.context_id
= call
->pkt
.u
.request
.context_id
;
770 pkt
.u
.response
.cancel_count
= 0;
771 pkt
.u
.response
.stub_and_verifier
.data
= stub
.data
;
772 pkt
.u
.response
.stub_and_verifier
.length
= length
;
774 if (!dcesrv_auth_response(call
, &rep
->data
, &pkt
)) {
775 return dcesrv_fault(call
, DCERPC_FAULT_OTHER
);
778 dcerpc_set_frag_length(&rep
->data
, rep
->data
.length
);
780 DLIST_ADD_END(call
->replies
, rep
, struct dcesrv_call_reply
*);
783 stub
.length
-= length
;
784 } while (stub
.length
!= 0);
786 DLIST_ADD_END(call
->conn
->call_list
, call
, struct dcesrv_call_state
*);
793 work out if we have a full packet yet
795 static BOOL
dce_full_packet(const DATA_BLOB
*data
)
797 if (data
->length
< DCERPC_FRAG_LEN_OFFSET
+2) {
800 if (dcerpc_get_frag_length(data
) > data
->length
) {
807 we might have consumed only part of our input - advance past that part
809 static void dce_partial_advance(struct dcesrv_connection
*dce_conn
, uint32_t offset
)
813 if (dce_conn
->partial_input
.length
== offset
) {
814 data_blob_free(&dce_conn
->partial_input
);
818 blob
= dce_conn
->partial_input
;
819 dce_conn
->partial_input
= data_blob(blob
.data
+ offset
,
820 blob
.length
- offset
);
821 data_blob_free(&blob
);
825 process some input to a dcerpc endpoint server.
827 NTSTATUS
dcesrv_input_process(struct dcesrv_connection
*dce_conn
)
829 struct ndr_pull
*ndr
;
831 struct dcesrv_call_state
*call
;
834 call
= talloc(dce_conn
, struct dcesrv_call_state
);
836 talloc_free(dce_conn
->partial_input
.data
);
837 return NT_STATUS_NO_MEMORY
;
839 call
->conn
= dce_conn
;
840 call
->replies
= NULL
;
841 call
->context
= NULL
;
843 blob
= dce_conn
->partial_input
;
844 blob
.length
= dcerpc_get_frag_length(&blob
);
846 ndr
= ndr_pull_init_blob(&blob
, call
);
848 talloc_free(dce_conn
->partial_input
.data
);
850 return NT_STATUS_NO_MEMORY
;
853 if (!(CVAL(blob
.data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
854 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
857 status
= ndr_pull_dcerpc_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &call
->pkt
);
858 if (!NT_STATUS_IS_OK(status
)) {
859 talloc_free(dce_conn
->partial_input
.data
);
864 /* we have to check the signing here, before combining the
866 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
867 !dcesrv_auth_request(call
, &blob
)) {
868 dce_partial_advance(dce_conn
, blob
.length
);
869 return dcesrv_fault(call
, DCERPC_FAULT_LOGON_FAILURE
);
872 dce_partial_advance(dce_conn
, blob
.length
);
874 /* see if this is a continued packet */
875 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
876 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_FIRST
)) {
877 struct dcesrv_call_state
*call2
= call
;
880 /* we only allow fragmented requests, no other packet types */
881 if (call
->pkt
.ptype
!= DCERPC_PKT_REQUEST
) {
882 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
885 /* this is a continuation of an existing call - find the call then
886 tack it on the end */
887 call
= dcesrv_find_call(dce_conn
, call2
->pkt
.call_id
);
889 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
892 if (call
->pkt
.ptype
!= call2
->pkt
.ptype
) {
893 /* trying to play silly buggers are we? */
894 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
897 alloc_size
= call
->pkt
.u
.request
.stub_and_verifier
.length
+
898 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
899 if (call
->pkt
.u
.request
.alloc_hint
> alloc_size
) {
900 alloc_size
= call
->pkt
.u
.request
.alloc_hint
;
903 call
->pkt
.u
.request
.stub_and_verifier
.data
=
905 call
->pkt
.u
.request
.stub_and_verifier
.data
,
906 uint8_t, alloc_size
);
907 if (!call
->pkt
.u
.request
.stub_and_verifier
.data
) {
908 return dcesrv_fault(call2
, DCERPC_FAULT_OTHER
);
910 memcpy(call
->pkt
.u
.request
.stub_and_verifier
.data
+
911 call
->pkt
.u
.request
.stub_and_verifier
.length
,
912 call2
->pkt
.u
.request
.stub_and_verifier
.data
,
913 call2
->pkt
.u
.request
.stub_and_verifier
.length
);
914 call
->pkt
.u
.request
.stub_and_verifier
.length
+=
915 call2
->pkt
.u
.request
.stub_and_verifier
.length
;
917 call
->pkt
.pfc_flags
|= (call2
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
);
922 /* this may not be the last pdu in the chain - if its isn't then
923 just put it on the call_list and wait for the rest */
924 if (call
->pkt
.ptype
== DCERPC_PKT_REQUEST
&&
925 !(call
->pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
926 DLIST_ADD_END(dce_conn
->call_list
, call
, struct dcesrv_call_state
*);
930 switch (call
->pkt
.ptype
) {
931 case DCERPC_PKT_BIND
:
932 status
= dcesrv_bind(call
);
934 case DCERPC_PKT_AUTH3
:
935 status
= dcesrv_auth3(call
);
937 case DCERPC_PKT_ALTER
:
938 status
= dcesrv_alter(call
);
940 case DCERPC_PKT_REQUEST
:
941 status
= dcesrv_request(call
);
944 status
= NT_STATUS_INVALID_PARAMETER
;
948 /* if we are going to be sending a reply then add
949 it to the list of pending calls. We add it to the end to keep the call
950 list in the order we will answer */
951 if (!NT_STATUS_IS_OK(status
)) {
960 provide some input to a dcerpc endpoint server. This passes data
961 from a dcerpc client into the server
963 NTSTATUS
dcesrv_input(struct dcesrv_connection
*dce_conn
, const DATA_BLOB
*data
)
967 dce_conn
->partial_input
.data
= talloc_realloc(dce_conn
,
968 dce_conn
->partial_input
.data
,
970 dce_conn
->partial_input
.length
+ data
->length
);
971 if (!dce_conn
->partial_input
.data
) {
972 return NT_STATUS_NO_MEMORY
;
974 memcpy(dce_conn
->partial_input
.data
+ dce_conn
->partial_input
.length
,
975 data
->data
, data
->length
);
976 dce_conn
->partial_input
.length
+= data
->length
;
978 while (dce_full_packet(&dce_conn
->partial_input
)) {
979 status
= dcesrv_input_process(dce_conn
);
980 if (!NT_STATUS_IS_OK(status
)) {
989 retrieve some output from a dcerpc server
990 The caller supplies a function that will be called to do the
993 The first argument to write_fn() will be 'private', the second will
994 be a pointer to a buffer containing the data to be sent and the 3rd
995 will be the number of bytes to be sent.
997 write_fn() should return the number of bytes successfully written.
999 this will return STATUS_BUFFER_OVERFLOW if there is more to be read
1000 from the current fragment
1002 NTSTATUS
dcesrv_output(struct dcesrv_connection
*dce_conn
,
1004 ssize_t (*write_fn
)(void *, DATA_BLOB
*))
1006 struct dcesrv_call_state
*call
;
1007 struct dcesrv_call_reply
*rep
;
1010 call
= dce_conn
->call_list
;
1011 if (!call
|| !call
->replies
) {
1012 return NT_STATUS_FOOBAR
;
1014 rep
= call
->replies
;
1016 nwritten
= write_fn(private, &rep
->data
);
1017 if (nwritten
== -1) {
1018 /* TODO: hmm, how do we cope with this? destroy the
1019 connection perhaps? */
1020 return NT_STATUS_UNSUCCESSFUL
;
1023 rep
->data
.length
-= nwritten
;
1024 rep
->data
.data
+= nwritten
;
1026 if (rep
->data
.length
== 0) {
1027 /* we're done with this section of the call */
1028 DLIST_REMOVE(call
->replies
, rep
);
1030 return STATUS_BUFFER_OVERFLOW
;
1033 if (call
->replies
== NULL
) {
1034 /* we're done with the whole call */
1035 DLIST_REMOVE(dce_conn
->call_list
, call
);
1039 return NT_STATUS_OK
;
1044 write_fn() for dcesrv_output_blob()
1046 static ssize_t
dcesrv_output_blob_write_fn(void *private, DATA_BLOB
*out
)
1048 DATA_BLOB
*blob
= private;
1049 if (out
->length
< blob
->length
) {
1050 blob
->length
= out
->length
;
1052 memcpy(blob
->data
, out
->data
, blob
->length
);
1053 return blob
->length
;
1057 a simple wrapper for dcesrv_output() for when we want to output
1060 NTSTATUS
dcesrv_output_blob(struct dcesrv_connection
*dce_conn
,
1063 return dcesrv_output(dce_conn
, blob
, dcesrv_output_blob_write_fn
);
1067 initialise the dcerpc server context
1069 NTSTATUS
dcesrv_init_context(TALLOC_CTX
*mem_ctx
, struct dcesrv_context
**dce_ctx
)
1072 const char **endpoint_servers
= lp_dcerpc_endpoint_servers();
1074 (*dce_ctx
) = talloc_p(mem_ctx
, struct dcesrv_context
);
1076 return NT_STATUS_NO_MEMORY
;
1079 (*dce_ctx
)->endpoint_list
= NULL
;
1081 if (!endpoint_servers
) {
1082 DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
1083 return NT_STATUS_OK
;
1086 for (i
=0;endpoint_servers
[i
];i
++) {
1088 const struct dcesrv_endpoint_server
*ep_server
;
1090 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1092 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1093 return NT_STATUS_UNSUCCESSFUL
;
1096 ret
= ep_server
->init_server(*dce_ctx
, ep_server
);
1097 if (!NT_STATUS_IS_OK(ret
)) {
1098 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers
[i
]));
1103 return NT_STATUS_OK
;
1106 static void dcesrv_init(struct server_service
*service
, const struct model_ops
*model_ops
)
1108 struct dcesrv_context
*dce_ctx
;
1110 const char **endpoint_servers
= lp_dcerpc_endpoint_servers();
1112 DEBUG(1,("dcesrv_init\n"));
1114 if (!endpoint_servers
) {
1115 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1119 dce_ctx
= talloc_p(service
, struct dcesrv_context
);
1121 DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
1125 ZERO_STRUCTP(dce_ctx
);
1126 dce_ctx
->endpoint_list
= NULL
;
1128 for (i
=0;endpoint_servers
[i
];i
++) {
1130 const struct dcesrv_endpoint_server
*ep_server
;
1132 ep_server
= dcesrv_ep_server_byname(endpoint_servers
[i
]);
1134 DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers
[i
]));
1138 ret
= ep_server
->init_server(dce_ctx
, ep_server
);
1139 if (!NT_STATUS_IS_OK(ret
)) {
1140 DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers
[i
]));
1145 dcesrv_sock_init(service
, model_ops
, dce_ctx
);
1150 static void dcesrv_accept(struct server_connection
*srv_conn
)
1152 dcesrv_sock_accept(srv_conn
);
1155 static void dcesrv_recv(struct server_connection
*srv_conn
,
1156 struct timeval t
, uint16_t flags
)
1158 dcesrv_sock_recv(srv_conn
, t
, flags
);
1161 static void dcesrv_send(struct server_connection
*srv_conn
,
1162 struct timeval t
, uint16_t flags
)
1164 dcesrv_sock_send(srv_conn
, t
, flags
);
1167 static void dcesrv_close(struct server_connection
*srv_conn
, const char *reason
)
1169 dcesrv_sock_close(srv_conn
, reason
);
1173 static void dcesrv_exit(struct server_service
*service
, const char *reason
)
1175 dcesrv_sock_exit(service
, reason
);
1179 /* the list of currently registered DCERPC endpoint servers.
1181 static struct ep_server
{
1182 struct dcesrv_endpoint_server
*ep_server
;
1183 } *ep_servers
= NULL
;
1184 static int num_ep_servers
;
1187 register a DCERPC endpoint server.
1189 The 'name' can be later used by other backends to find the operations
1190 structure for this backend.
1192 The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1194 NTSTATUS
dcerpc_register_ep_server(const void *_ep_server
)
1196 const struct dcesrv_endpoint_server
*ep_server
= _ep_server
;
1198 if (dcesrv_ep_server_byname(ep_server
->name
) != NULL
) {
1199 /* its already registered! */
1200 DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
1202 return NT_STATUS_OBJECT_NAME_COLLISION
;
1205 ep_servers
= realloc_p(ep_servers
, struct ep_server
, num_ep_servers
+1);
1207 smb_panic("out of memory in dcerpc_register");
1210 ep_servers
[num_ep_servers
].ep_server
= smb_xmemdup(ep_server
, sizeof(*ep_server
));
1211 ep_servers
[num_ep_servers
].ep_server
->name
= smb_xstrdup(ep_server
->name
);
1215 DEBUG(3,("DCERPC endpoint server '%s' registered\n",
1218 return NT_STATUS_OK
;
1222 return the operations structure for a named backend of the specified type
1224 const struct dcesrv_endpoint_server
*dcesrv_ep_server_byname(const char *name
)
1228 for (i
=0;i
<num_ep_servers
;i
++) {
1229 if (strcmp(ep_servers
[i
].ep_server
->name
, name
) == 0) {
1230 return ep_servers
[i
].ep_server
;
1238 return the DCERPC module version, and the size of some critical types
1239 This can be used by endpoint server modules to either detect compilation errors, or provide
1240 multiple implementations for different smbd compilation options in one module
1242 const struct dcesrv_critical_sizes
*dcerpc_module_version(void)
1244 static const struct dcesrv_critical_sizes critical_sizes
= {
1245 DCERPC_MODULE_VERSION
,
1246 sizeof(struct dcesrv_context
),
1247 sizeof(struct dcesrv_endpoint
),
1248 sizeof(struct dcesrv_endpoint_server
),
1249 sizeof(struct dcesrv_interface
),
1250 sizeof(struct dcesrv_if_list
),
1251 sizeof(struct dcesrv_connection
),
1252 sizeof(struct dcesrv_call_state
),
1253 sizeof(struct dcesrv_auth
),
1254 sizeof(struct dcesrv_handle
)
1257 return &critical_sizes
;
1260 static const struct server_service_ops dcesrv_ops
= {
1262 .service_init
= dcesrv_init
,
1263 .accept_connection
= dcesrv_accept
,
1264 .recv_handler
= dcesrv_recv
,
1265 .send_handler
= dcesrv_send
,
1266 .idle_handler
= NULL
,
1267 .close_connection
= dcesrv_close
,
1268 .service_exit
= dcesrv_exit
,
1271 const struct server_service_ops
*dcesrv_get_ops(void)
1276 NTSTATUS
server_service_rpc_init(void)
1278 return NT_STATUS_OK
;