2 Unix SMB/Netbios implementation.
3 Generic infrstructure for RPC Daemons
4 Copyright (C) Simo Sorce 2010
5 Copyright (C) Andrew Bartlett 2011
6 Copyright (C) Andreas Schneider 2011
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "librpc/rpc/dcesrv_core.h"
24 #include "rpc_server/rpc_pipes.h"
25 #include "rpc_server/rpc_server.h"
26 #include "rpc_server/rpc_config.h"
28 #include "librpc/gen_ndr/netlogon.h"
29 #include "librpc/gen_ndr/auth.h"
30 #include "lib/tsocket/tsocket.h"
31 #include "libcli/named_pipe_auth/npa_tstream.h"
32 #include "../auth/auth_sam_reply.h"
34 #include "rpc_server/rpc_ncacn_np.h"
35 #include "rpc_server/srv_pipe_hnd.h"
38 #define DBGC_CLASS DBGC_RPC_SRV
40 /* Start listening on the appropriate unix socket and setup all is needed to
41 * dispatch requests to the pipes rpc implementation */
43 struct dcerpc_ncacn_listen_state {
46 struct tevent_context *ev_ctx;
47 struct messaging_context *msg_ctx;
48 struct dcesrv_context *dce_ctx;
49 struct dcesrv_endpoint *endpoint;
50 dcerpc_ncacn_termination_fn termination_fn;
51 void *termination_data;
55 static void dcesrv_ncacn_listener(
56 struct tevent_context *ev,
57 struct tevent_fd *fde,
61 int dcesrv_setup_ncacn_listener(
63 struct dcesrv_context *dce_ctx,
64 struct tevent_context *ev_ctx,
65 struct messaging_context *msg_ctx,
66 struct dcesrv_endpoint *e,
68 dcerpc_ncacn_termination_fn term_fn,
69 void *termination_data,
70 struct dcerpc_ncacn_listen_state **listen_state)
72 struct dcerpc_ncacn_listen_state *state = NULL;
73 struct tevent_fd *fde = NULL;
76 state = talloc_zero(mem_ctx, struct dcerpc_ncacn_listen_state);
78 DBG_ERR("Out of memory\n");
83 state->ev_ctx = ev_ctx;
84 state->msg_ctx = msg_ctx;
85 state->dce_ctx = dce_ctx;
87 state->termination_fn = term_fn;
88 state->termination_data = termination_data;
90 rc = listen(state->fd, SMBD_LISTEN_BACKLOG);
93 DBG_ERR("listen(%d) failed: %s\n",
99 /* Set server socket to non-blocking for the accept. */
100 rc = set_blocking(state->fd, false);
111 dcesrv_ncacn_listener,
115 DBG_ERR("tevent_add_fd for %d failed: %s\n",
120 tevent_fd_set_auto_close(fde);
123 *listen_state = state;
132 static void dcesrv_ncacn_listener(
133 struct tevent_context *ev,
134 struct tevent_fd *fde,
138 struct dcerpc_ncacn_listen_state *state = talloc_get_type_abort(
139 private_data, struct dcerpc_ncacn_listen_state);
140 struct tsocket_address *cli_addr = NULL, *srv_addr = NULL;
141 struct samba_sockaddr addr = {
142 .sa_socklen = sizeof(struct samba_sockaddr),
147 sd = accept(state->fd, &addr.u.sa, &addr.sa_socklen);
149 if (errno != EINTR) {
150 DBG_ERR("Failed to accept: %s\n", strerror(errno));
154 smb_set_close_on_exec(sd);
156 rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &cli_addr);
161 rc = getsockname(sd, &addr.u.sa, &addr.sa_socklen);
166 rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &srv_addr);
179 state->termination_fn,
180 state->termination_data);
184 TALLOC_FREE(cli_addr);
185 TALLOC_FREE(srv_addr);
191 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
193 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
194 conn->transport.private_data,
195 struct dcerpc_ncacn_conn);
197 if (ncacn_conn->termination_fn != NULL) {
198 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
205 NTSTATUS dcerpc_ncacn_conn_init(TALLOC_CTX *mem_ctx,
206 struct tevent_context *ev_ctx,
207 struct messaging_context *msg_ctx,
208 struct dcesrv_context *dce_ctx,
209 struct dcesrv_endpoint *endpoint,
210 dcerpc_ncacn_termination_fn term_fn,
211 void *termination_data,
212 struct dcerpc_ncacn_conn **out)
214 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
216 ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
217 if (ncacn_conn == NULL) {
218 return NT_STATUS_NO_MEMORY;
221 ncacn_conn->ev_ctx = ev_ctx;
222 ncacn_conn->msg_ctx = msg_ctx;
223 ncacn_conn->dce_ctx = dce_ctx;
224 ncacn_conn->endpoint = endpoint;
225 ncacn_conn->sock = -1;
226 ncacn_conn->termination_fn = term_fn;
227 ncacn_conn->termination_data = termination_data;
235 static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq);
236 static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn);
239 static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
243 void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
244 struct messaging_context *msg_ctx,
245 struct dcesrv_context *dce_ctx,
246 struct dcesrv_endpoint *e,
247 struct tsocket_address **cli_addr,
248 struct tsocket_address **srv_addr,
250 dcerpc_ncacn_termination_fn termination_fn,
251 void *termination_data)
253 enum dcerpc_transport_t transport =
254 dcerpc_binding_get_transport(e->ep_description);
255 struct dcerpc_ncacn_conn *ncacn_conn;
259 DBG_DEBUG("dcerpc_ncacn_accept\n");
261 status = dcerpc_ncacn_conn_init(ev_ctx,
269 if (!NT_STATUS_IS_OK(status)) {
270 DBG_ERR("Failed to initialize dcerpc_ncacn_connection: %s\n",
276 ncacn_conn->sock = s;
278 if ((cli_addr != NULL) && (*cli_addr != NULL)) {
279 ncacn_conn->remote_client_addr = talloc_move(
280 ncacn_conn, cli_addr);
282 if (tsocket_address_is_inet(ncacn_conn->remote_client_addr, "ip")) {
283 ncacn_conn->remote_client_name =
284 tsocket_address_inet_addr_string(ncacn_conn->remote_client_addr,
287 ncacn_conn->remote_client_name =
288 tsocket_address_unix_path(ncacn_conn->remote_client_addr,
292 if (ncacn_conn->remote_client_name == NULL) {
293 DBG_ERR("Out of memory obtaining remote socket address as a string!\n");
294 ncacn_terminate_connection(ncacn_conn, "No memory");
300 if ((srv_addr != NULL) && (*srv_addr != NULL)) {
301 ncacn_conn->local_server_addr = talloc_move(
302 ncacn_conn, srv_addr);
304 if (tsocket_address_is_inet(ncacn_conn->local_server_addr, "ip")) {
305 ncacn_conn->local_server_name =
306 tsocket_address_inet_addr_string(ncacn_conn->local_server_addr,
309 ncacn_conn->local_server_name =
310 tsocket_address_unix_path(ncacn_conn->local_server_addr,
313 if (ncacn_conn->local_server_name == NULL) {
314 DBG_ERR("No memory\n");
315 ncacn_terminate_connection(ncacn_conn, "No memory");
321 rc = set_blocking(s, false);
323 DBG_WARNING("Failed to set dcerpc socket to non-blocking\n");
324 ncacn_terminate_connection(ncacn_conn, strerror(errno));
330 * As soon as we have tstream_bsd_existing_socket set up it will
331 * take care of closing the socket.
333 rc = tstream_bsd_existing_socket(ncacn_conn, s, &ncacn_conn->tstream);
335 DBG_WARNING("Failed to create tstream socket for dcerpc\n");
336 ncacn_terminate_connection(ncacn_conn, "No memory");
341 if (transport == NCACN_NP) {
342 struct tevent_req *subreq = NULL;
343 uint64_t allocation_size = 4096;
344 uint16_t device_state = 0xff | 0x0400 | 0x0100;
345 uint16_t file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
347 subreq = tstream_npa_accept_existing_send(ncacn_conn,
353 if (subreq == NULL) {
354 ncacn_terminate_connection(ncacn_conn, "No memory");
357 tevent_req_set_callback(subreq, dcesrv_ncacn_np_accept_done,
362 dcesrv_ncacn_accept_step2(ncacn_conn);
365 static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq)
367 struct dcerpc_ncacn_conn *ncacn_conn = tevent_req_callback_data(
368 subreq, struct dcerpc_ncacn_conn);
369 struct auth_session_info_transport *session_info_transport = NULL;
370 enum dcerpc_transport_t transport;
374 ret = tstream_npa_accept_existing_recv(subreq, &error, ncacn_conn,
375 &ncacn_conn->tstream,
378 &ncacn_conn->remote_client_addr,
379 &ncacn_conn->remote_client_name,
380 &ncacn_conn->local_server_addr,
381 &ncacn_conn->local_server_name,
382 &session_info_transport);
383 ncacn_conn->session_info = talloc_move(ncacn_conn,
384 &session_info_transport->session_info);
386 if (transport != NCACN_NP) {
387 ncacn_terminate_connection(
389 "Only allow NCACN_NP transport on named pipes\n");
393 if (security_token_is_system(
394 ncacn_conn->session_info->security_token)) {
395 ncacn_terminate_connection(
397 "No system token via NCACN_NP allowed\n");
403 DBG_ERR("Failed to accept named pipe connection: %s\n",
405 ncacn_terminate_connection(ncacn_conn, strerror(errno));
409 dcesrv_ncacn_accept_step2(ncacn_conn);
412 static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn)
414 char *pipe_name = NULL;
418 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
419 ncacn_conn->endpoint->ep_description);
420 const char *endpoint = dcerpc_binding_get_string_option(
421 ncacn_conn->endpoint->ep_description, "endpoint");
422 struct dcesrv_connection *dcesrv_conn = NULL;
427 pipe_name = tsocket_address_string(ncacn_conn->remote_client_addr,
429 if (pipe_name == NULL) {
430 DBG_ERR("No memory\n");
431 ncacn_terminate_connection(ncacn_conn, "No memory");
437 rc = getpeereid(ncacn_conn->sock, &uid, &gid);
439 DEBUG(2, ("Failed to get ncalrpc connecting "
440 "uid - %s!\n", strerror(errno)));
442 if (uid == sec_initial_uid()) {
443 TALLOC_FREE(ncacn_conn->remote_client_addr);
445 rc = tsocket_address_unix_from_path(ncacn_conn,
446 AS_SYSTEM_MAGIC_PATH_TOKEN,
447 &ncacn_conn->remote_client_addr);
449 DBG_ERR("No memory\n");
450 ncacn_terminate_connection(ncacn_conn, "No memory");
454 TALLOC_FREE(ncacn_conn->remote_client_name);
455 ncacn_conn->remote_client_name
456 = tsocket_address_unix_path(ncacn_conn->remote_client_addr,
458 if (ncacn_conn->remote_client_name == NULL) {
459 DBG_ERR("No memory\n");
460 ncacn_terminate_connection(ncacn_conn, "No memory");
468 pipe_name = talloc_strdup(ncacn_conn, endpoint);
469 if (pipe_name == NULL) {
470 DBG_ERR("No memory\n");
471 ncacn_terminate_connection(ncacn_conn, "No memory");
476 DBG_ERR("unknown dcerpc transport: %u!\n", transport);
477 ncacn_terminate_connection(ncacn_conn,
478 "Unknown DCE/RPC transport");
482 if (ncacn_conn->session_info == NULL) {
483 status = make_session_info_anonymous(ncacn_conn,
484 &ncacn_conn->session_info);
485 if (!NT_STATUS_IS_OK(status)) {
486 DBG_ERR("Failed to create anonymous session info: "
487 "%s\n", nt_errstr(status));
488 ncacn_terminate_connection(ncacn_conn,
494 rc = make_base_pipes_struct(ncacn_conn,
498 ncacn_conn->remote_client_addr,
499 ncacn_conn->local_server_addr,
502 const char *errstr = strerror(rc);
503 DBG_ERR("Failed to create pipe struct: %s\n", errstr);
504 ncacn_terminate_connection(ncacn_conn, errstr);
509 * This fills in dcesrv_conn->endpoint with the endpoint
510 * associated with the socket. From this point on we know
511 * which (group of) services we are handling, but not the
512 * specific interface.
514 status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
516 ncacn_conn->endpoint,
517 ncacn_conn->session_info,
519 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
521 if (!NT_STATUS_IS_OK(status)) {
522 DBG_ERR("Failed to connect to endpoint: %s\n",
524 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
527 talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
529 dcesrv_conn->transport.private_data = ncacn_conn;
530 dcesrv_conn->transport.report_output_data =
531 dcesrv_sock_report_output_data;
532 dcesrv_conn->transport.terminate_connection =
533 dcesrv_transport_terminate_connection;
534 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
535 "dcesrv send queue");
536 if (dcesrv_conn->send_queue == NULL) {
537 status = NT_STATUS_NO_MEMORY;
538 DBG_ERR("Failed to create send queue: %s\n",
540 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
544 dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
545 dcesrv_conn->local_address = ncacn_conn->local_server_addr;
546 dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
547 status = dcesrv_connection_loop_start(dcesrv_conn);
548 if (!NT_STATUS_IS_OK(status)) {
549 DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
551 ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
553 DBG_DEBUG("dcerpc_ncacn_accept done\n");
559 NTSTATUS dcesrv_auth_gensec_prepare(
561 struct dcesrv_call_state *call,
562 struct gensec_security **out,
565 struct gensec_security *gensec = NULL;
569 return NT_STATUS_INVALID_PARAMETER;
572 status = auth_generic_prepare(mem_ctx,
573 call->conn->remote_address,
574 call->conn->local_address,
577 if (!NT_STATUS_IS_OK(status)) {
578 DBG_ERR("Failed to prepare gensec: %s\n", nt_errstr(status));
587 void dcesrv_log_successful_authz(
588 struct dcesrv_call_state *call,
591 TALLOC_CTX *frame = talloc_stackframe();
592 struct auth4_context *auth4_context = NULL;
593 struct dcesrv_auth *auth = call->auth_state;
594 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
595 call->conn->endpoint->ep_description);
596 const char *auth_type = derpc_transport_string_by_transport(transport);
597 const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
601 DBG_ERR("No memory");
605 if (transport == NCACN_NP) {
606 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
610 status = make_auth4_context(frame, &auth4_context);
612 if (!NT_STATUS_IS_OK(status)) {
613 DBG_ERR("Unable to make auth context for authz log.\n");
619 * Log the authorization to this RPC interface. This
620 * covered ncacn_np pass-through auth, and anonymous
621 * DCE/RPC (eg epmapper, netlogon etc)
623 log_successful_authz_event(auth4_context->msg_ctx,
624 auth4_context->lp_ctx,
625 call->conn->remote_address,
626 call->conn->local_address,
629 transport_protection,
632 auth->auth_audited = true;
637 static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
640 ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
643 DBG_ERR("Failed to remove assoc_group 0x%08x\n",
649 static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
651 struct dcesrv_connection *conn = call->conn;
652 struct dcesrv_context *dce_ctx = conn->dce_ctx;
653 const struct dcesrv_endpoint *endpoint = conn->endpoint;
654 enum dcerpc_transport_t transport =
655 dcerpc_binding_get_transport(endpoint->ep_description);
656 struct dcesrv_assoc_group *assoc_group = NULL;
659 assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
660 if (assoc_group == NULL) {
661 return NT_STATUS_NO_MEMORY;
664 id = idr_get_new_random(dce_ctx->assoc_groups_idr,
668 TALLOC_FREE(assoc_group);
669 DBG_ERR("Out of association groups!\n");
670 return NT_STATUS_RPC_OUT_OF_RESOURCES;
673 assoc_group->transport = transport;
674 assoc_group->id = id;
675 assoc_group->dce_ctx = dce_ctx;
677 call->conn->assoc_group = assoc_group;
679 talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
684 static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
685 uint32_t assoc_group_id)
687 struct dcesrv_connection *conn = call->conn;
688 const struct dcesrv_endpoint *endpoint = conn->endpoint;
689 enum dcerpc_transport_t transport =
690 dcerpc_binding_get_transport(endpoint->ep_description);
691 struct dcesrv_assoc_group *assoc_group = NULL;
694 /* find an association group given a assoc_group_id */
695 id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
696 if (id_ptr == NULL) {
698 * FIXME If the association group is not found it has
699 * been created in other process (preforking daemons).
700 * Until this is properly fixed we just create a new
701 * association group in this process
703 DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
704 "server process, creating a new one\n",
706 return dcesrv_assoc_group_new(call);
708 assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
710 if (assoc_group->transport != transport) {
712 derpc_transport_string_by_transport(
713 assoc_group->transport);
715 derpc_transport_string_by_transport(
718 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
719 "is not available on transport %s",
720 assoc_group_id, at, ct);
721 return NT_STATUS_UNSUCCESSFUL;
724 conn->assoc_group = talloc_reference(conn, assoc_group);
728 NTSTATUS dcesrv_assoc_group_find(
729 struct dcesrv_call_state *call,
732 uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
734 if (assoc_group_id != 0) {
735 return dcesrv_assoc_group_reference(call, assoc_group_id);
738 /* If not requested by client create a new association group */
739 return dcesrv_assoc_group_new(call);
742 void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
745 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
746 dce_conn->transport.private_data,
747 struct dcerpc_ncacn_conn);
749 ncacn_terminate_connection(ncacn_conn, reason);
752 static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
755 if (reason == NULL) {
756 reason = "Unknown reason";
759 DBG_NOTICE("Terminating connection - '%s'\n", reason);
764 NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
765 const char *pipe_name,
766 struct dcesrv_endpoint **out)
768 struct dcesrv_endpoint *e = NULL;
770 for (e = dce_ctx->endpoint_list; e; e = e->next) {
771 enum dcerpc_transport_t transport =
772 dcerpc_binding_get_transport(e->ep_description);
773 const char *endpoint = NULL;
775 if (transport != NCACN_NP) {
779 endpoint = dcerpc_binding_get_string_option(e->ep_description,
781 if (endpoint == NULL) {
785 if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
789 if (strequal(endpoint, pipe_name)) {
795 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
798 struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
800 struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
801 conn->transport.private_data,
802 struct dcerpc_ncacn_conn);
804 return ncacn_conn->p;
807 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */