X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Frpc_server%2Fservice_rpc.c;h=f7d1a9f3c7df105fb34122ce4d3e0e444e1fd136;hb=d6777a66c0dbd0c356059644b57070d4587d83ea;hp=2ef8591c320a97144d7a737a7e040479f9125a28;hpb=f84093df863eb00238a6be1caba59d926f18e7a5;p=samba.git diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c index 2ef8591c320..f7d1a9f3c7d 100644 --- a/source4/rpc_server/service_rpc.c +++ b/source4/rpc_server/service_rpc.c @@ -24,409 +24,22 @@ #include "includes.h" #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 "lib/events/events.h" -#include "smbd/service_task.h" -#include "smbd/service_stream.h" -#include "smbd/service.h" +#include "rpc_server/dcerpc_server_proto.h" #include "system/filesys.h" -#include "libcli/security/security.h" -#include "lib/socket/socket.h" #include "lib/messaging/irpc.h" #include "system/network.h" #include "lib/socket/netif.h" #include "param/param.h" +#include "../lib/tsocket/tsocket.h" +#include "librpc/rpc/dcerpc_proto.h" +#include "../lib/util/tevent_ntstatus.h" +#include "libcli/raw/smb.h" +#include "../libcli/named_pipe_auth/npa_tstream.h" +#include "smbd/process_model.h" -struct dcesrv_socket_context { - const struct dcesrv_endpoint *endpoint; - struct dcesrv_context *dcesrv_ctx; -}; - -/* - write_fn callback for dcesrv_output() -*/ -static NTSTATUS dcerpc_write_fn(void *private_data, DATA_BLOB *out, size_t *nwritten) -{ - NTSTATUS status; - struct socket_context *sock = talloc_get_type(private_data, struct socket_context); - size_t sendlen; - - status = socket_send(sock, out, &sendlen); - NT_STATUS_IS_ERR_RETURN(status); - - *nwritten = sendlen; - return status; -} - -static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dce_conn->transport.private_data, - struct stream_connection); - - stream_terminate_connection(srv_conn, reason); -} - -static void dcesrv_sock_report_output_data(struct dcesrv_connection *dcesrv_conn) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - if (srv_conn && srv_conn->event.fde) { - EVENT_FD_WRITEABLE(srv_conn->event.fde); - } -} - -static struct socket_address *dcesrv_sock_get_my_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - return socket_get_my_addr(srv_conn->socket, mem_ctx); -} - -static struct socket_address *dcesrv_sock_get_peer_addr(struct dcesrv_connection *dcesrv_conn, TALLOC_CTX *mem_ctx) -{ - struct stream_connection *srv_conn; - srv_conn = talloc_get_type(dcesrv_conn->transport.private_data, - struct stream_connection); - - return socket_get_peer_addr(srv_conn->socket, mem_ctx); -} - -static void dcesrv_sock_accept(struct stream_connection *srv_conn) -{ - NTSTATUS status; - struct dcesrv_socket_context *dcesrv_sock = - talloc_get_type(srv_conn->private, struct dcesrv_socket_context); - struct dcesrv_connection *dcesrv_conn = NULL; - - if (!srv_conn->session_info) { - status = auth_anonymous_session_info(srv_conn, - srv_conn->event.ctx, - srv_conn->lp_ctx, - &srv_conn->session_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcesrv_sock_accept: auth_anonymous_session_info failed: %s\n", - nt_errstr(status))); - stream_terminate_connection(srv_conn, nt_errstr(status)); - return; - } - } - - status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, - srv_conn, - dcesrv_sock->endpoint, - srv_conn->session_info, - srv_conn->event.ctx, - srv_conn->msg_ctx, - srv_conn->server_id, - DCESRV_CALL_STATE_FLAG_MAY_ASYNC, - &dcesrv_conn); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", - nt_errstr(status))); - stream_terminate_connection(srv_conn, nt_errstr(status)); - return; - } - - dcesrv_conn->transport.private_data = srv_conn; - dcesrv_conn->transport.report_output_data = dcesrv_sock_report_output_data; - dcesrv_conn->transport.get_my_addr = dcesrv_sock_get_my_addr; - dcesrv_conn->transport.get_peer_addr = dcesrv_sock_get_peer_addr; - - srv_conn->private = dcesrv_conn; - - irpc_add_name(srv_conn->msg_ctx, "rpc_server"); - - return; -} - -static void dcesrv_sock_recv(struct stream_connection *conn, uint16_t flags) -{ - NTSTATUS status; - struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); - DATA_BLOB tmp_blob; - size_t nread; - - if (dce_conn->processing) { - EVENT_FD_NOT_READABLE(conn->event.fde); - return; - } - - tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000); - if (tmp_blob.data == NULL) { - dcesrv_terminate_connection(dce_conn, "out of memory"); - return; - } - - status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread); - if (NT_STATUS_IS_ERR(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - if (nread == 0) { - talloc_free(tmp_blob.data); - return; - } - - tmp_blob.length = nread; - - dce_conn->processing = true; - status = dcesrv_input(dce_conn, &tmp_blob); - dce_conn->processing = false; - talloc_free(tmp_blob.data); - - EVENT_FD_READABLE(conn->event.fde); - - if (!NT_STATUS_IS_OK(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - - if (dce_conn->call_list && dce_conn->call_list->replies) { - EVENT_FD_WRITEABLE(conn->event.fde); - } -} - -static void dcesrv_sock_send(struct stream_connection *conn, uint16_t flags) -{ - struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); - NTSTATUS status; - - status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn); - if (NT_STATUS_IS_ERR(status)) { - dcesrv_terminate_connection(dce_conn, "eof on socket"); - return; - } - - if (!dce_conn->call_list || !dce_conn->call_list->replies) { - EVENT_FD_NOT_WRITEABLE(conn->event.fde); - } -} - - -static const struct stream_server_ops dcesrv_stream_ops = { - .name = "rpc", - .accept_connection = dcesrv_sock_accept, - .recv_handler = dcesrv_sock_recv, - .send_handler = dcesrv_sock_send, -}; - - - -static NTSTATUS dcesrv_add_ep_unix(struct dcesrv_context *dce_ctx, - struct loadparm_context *lp_ctx, - struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 1; - NTSTATUS status; - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, lp_ctx, - model_ops, &dcesrv_stream_ops, - "unix", e->ep_description->endpoint, &port, - lp_socket_options(lp_ctx), - dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", - e->ep_description->endpoint, nt_errstr(status))); - } - - return status; -} - -static NTSTATUS dcesrv_add_ep_ncalrpc(struct dcesrv_context *dce_ctx, - struct loadparm_context *lp_ctx, - struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 1; - char *full_path; - NTSTATUS status; - - if (!e->ep_description->endpoint) { - /* No identifier specified: use DEFAULT. - * DO NOT hardcode this value anywhere else. Rather, specify - * no endpoint and let the epmapper worry about it. */ - e->ep_description->endpoint = talloc_strdup(dce_ctx, "DEFAULT"); - } - - full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(lp_ctx), - e->ep_description->endpoint); - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, lp_ctx, - model_ops, &dcesrv_stream_ops, - "unix", full_path, &port, - lp_socket_options(lp_ctx), - dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n", - e->ep_description->endpoint, full_path, nt_errstr(status))); - } - return status; -} - - -/* - add a socket address to the list of events, one event per dcerpc endpoint -*/ -static NTSTATUS add_socket_rpc_pipe_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - struct dcesrv_socket_context *dcesrv_sock; - NTSTATUS status; - - if (e->ep_description->endpoint == NULL) { - DEBUG(0, ("Endpoint mandatory for named pipes\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = NT_STATUS_OK; -#if 0 - - status = stream_setup_smb_pipe(event_ctx, model_ops, &dcesrv_stream_ops, - e->ep_description->endpoint, dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", - e->ep_description->endpoint, nt_errstr(status))); - } -#endif - return status; -} - -static NTSTATUS dcesrv_add_ep_np(struct dcesrv_context *dce_ctx, - struct loadparm_context *lp_ctx, - struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - NTSTATUS status; - - status = add_socket_rpc_pipe_iface(dce_ctx, e, event_ctx, model_ops); - NT_STATUS_NOT_OK_RETURN(status); - - return status; -} - -/* - add a socket address to the list of events, one event per dcerpc endpoint -*/ -static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops, - const char *address) -{ - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 0; - NTSTATUS status; - - if (e->ep_description->endpoint) { - port = atoi(e->ep_description->endpoint); - } - - dcesrv_sock = talloc(event_ctx, struct dcesrv_socket_context); - NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); - - /* remember the endpoint of this socket */ - dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); - - status = stream_setup_socket(event_ctx, dce_ctx->lp_ctx, - model_ops, &dcesrv_stream_ops, - "ipv4", address, &port, - lp_socket_options(dce_ctx->lp_ctx), - dcesrv_sock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", - address, port, nt_errstr(status))); - } - - if (e->ep_description->endpoint == NULL) { - e->ep_description->endpoint = talloc_asprintf(dce_ctx, "%d", port); - } - - return status; -} - -static NTSTATUS dcesrv_add_ep_tcp(struct dcesrv_context *dce_ctx, - struct loadparm_context *lp_ctx, - struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - NTSTATUS status; - - /* Add TCP/IP sockets */ - if (lp_interfaces(lp_ctx) && lp_bind_interfaces_only(lp_ctx)) { - int num_interfaces; - int i; - struct interface *ifaces; - - load_interfaces(dce_ctx, lp_interfaces(lp_ctx), &ifaces); - - num_interfaces = iface_count(ifaces); - for(i = 0; i < num_interfaces; i++) { - const char *address = iface_n_ip(ifaces, i); - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address); - NT_STATUS_NOT_OK_RETURN(status); - } - } else { - status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, - lp_socket_address(lp_ctx)); - NT_STATUS_NOT_OK_RETURN(status); - } - - return NT_STATUS_OK; -} - - -static NTSTATUS dcesrv_add_ep(struct dcesrv_context *dce_ctx, - struct loadparm_context *lp_ctx, - struct dcesrv_endpoint *e, - struct event_context *event_ctx, const struct model_ops *model_ops) -{ - switch (e->ep_description->transport) { - case NCACN_UNIX_STREAM: - return dcesrv_add_ep_unix(dce_ctx, lp_ctx, e, event_ctx, model_ops); - - case NCALRPC: - return dcesrv_add_ep_ncalrpc(dce_ctx, lp_ctx, e, event_ctx, model_ops); - - case NCACN_IP_TCP: - return dcesrv_add_ep_tcp(dce_ctx, lp_ctx, e, event_ctx, model_ops); - - case NCACN_NP: - return dcesrv_add_ep_np(dce_ctx, lp_ctx, e, event_ctx, model_ops); - - default: - return NT_STATUS_NOT_SUPPORTED; - } -} +NTSTATUS server_service_rpc_init(TALLOC_CTX *); /* open the dcerpc server sockets @@ -436,51 +49,109 @@ static void dcesrv_task_init(struct task_server *task) NTSTATUS status; struct dcesrv_context *dce_ctx; struct dcesrv_endpoint *e; - extern NTSTATUS dcerpc_server_wkssvc_init(void); - extern NTSTATUS dcerpc_server_drsuapi_init(void); - extern NTSTATUS dcerpc_server_winreg_init(void); - extern NTSTATUS dcerpc_server_spoolss_init(void); - extern NTSTATUS dcerpc_server_epmapper_init(void); - extern NTSTATUS dcerpc_server_srvsvc_init(void); - extern NTSTATUS dcerpc_server_netlogon_init(void); - extern NTSTATUS dcerpc_server_rpcecho_init(void); - extern NTSTATUS dcerpc_server_unixinfo_init(void); - extern NTSTATUS dcerpc_server_samr_init(void); - extern NTSTATUS dcerpc_server_remote_init(void); - extern NTSTATUS dcerpc_server_lsa_init(void); - init_module_fn static_init[] = { STATIC_DCESRV_MODULES }; - init_module_fn *shared_init = load_samba_modules(NULL, task->lp_ctx, "dcerpc_server"); - - run_init_functions(static_init); - run_init_functions(shared_init); + const struct model_ops *single_model_ops; - talloc_free(shared_init); + dcerpc_server_init(task->lp_ctx); task_server_set_title(task, "task[dcesrv]"); + /* + * run the rpc server as a single process to allow for shard + * handles, and sharing of ldb contexts. + * + * We make an exception for NETLOGON below, and this follows + * whatever the top level is. + */ + single_model_ops = process_model_startup("single"); + if (!single_model_ops) goto failed; + status = dcesrv_init_context(task->event_ctx, task->lp_ctx, - lp_dcerpc_endpoint_servers(task->lp_ctx), + lpcfg_dcerpc_endpoint_servers(task->lp_ctx), &dce_ctx); if (!NT_STATUS_IS_OK(status)) goto failed; /* Make sure the directory for NCALRPC exists */ - if (!directory_exist(lp_ncalrpc_dir(task->lp_ctx))) { - mkdir(lp_ncalrpc_dir(task->lp_ctx), 0755); + if (!directory_exist(lpcfg_ncalrpc_dir(task->lp_ctx))) { + mkdir(lpcfg_ncalrpc_dir(task->lp_ctx), 0755); } for (e=dce_ctx->endpoint_list;e;e=e->next) { - status = dcesrv_add_ep(dce_ctx, task->lp_ctx, e, task->event_ctx, task->model_ops); - if (!NT_STATUS_IS_OK(status)) goto failed; + const struct model_ops *this_model_ops = single_model_ops; + + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(e->ep_description); + const char *transport_str + = derpc_transport_string_by_transport(transport); + + struct dcesrv_if_list *iface_list; + + /* + * Ensure that -Msingle sets e->use_single_process for + * consistency + */ + + if (task->model_ops == single_model_ops) { + e->use_single_process = true; + } + + if (transport == NCACN_HTTP) { + /* + * We don't support ncacn_http yet + */ + continue; + + /* + * For the next two cases, what we are trying + * to do is put the NETLOGON server into the + * standard process model, not single, as it + * has no shared handles and takes a very high + * load. We only do this for ncacn_np and + * ncacn_ip_tcp as otherwise it is too hard as + * all servers share a socket for ncalrpc and + * unix. + */ + } else if (e->use_single_process == false) { + this_model_ops = task->model_ops; + } + + status = dcesrv_add_ep(dce_ctx, task->lp_ctx, e, task->event_ctx, + this_model_ops, task->process_context); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + DEBUG(5,("Added endpoint on %s " + "using process model %s for", + transport_str, + this_model_ops->name)); + + for (iface_list = e->interface_list; + iface_list != NULL; + iface_list = iface_list->next) { + DEBUGADD(5, (" %s", iface_list->iface.name)); + } + DEBUGADD(5, ("\n")); } + irpc_add_name(task->msg_ctx, "rpc_server"); return; failed: - task_server_terminate(task, "Failed to startup dcerpc server task"); -} - -NTSTATUS server_service_rpc_init(void) -{ - - return register_server_service("rpc", dcesrv_task_init); + task_server_terminate(task, "Failed to startup dcerpc server task", true); +} + +NTSTATUS server_service_rpc_init(TALLOC_CTX *ctx) +{ + static const struct service_details details = { + /* + * This is a SNOWFLAKE, but sadly one that we + * will have to keep for now. The RPC server + * code above overstamps the SINGLE process model + * most of the time, but we need to be in forking + * mode by defult to get a forking NETLOGON server + */ + .inhibit_fork_on_accept = false, + .inhibit_pre_fork = true + }; + return register_server_service(ctx, "rpc", dcesrv_task_init, &details); }