Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : smbd-specific dcerpc server code
5 :
6 : Copyright (C) Andrew Tridgell 2003-2005
7 : Copyright (C) Stefan (metze) Metzmacher 2004-2005
8 : Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2004,2007
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "librpc/gen_ndr/ndr_dcerpc.h"
26 : #include "auth/auth.h"
27 : #include "../lib/util/dlinklist.h"
28 : #include "rpc_server/dcerpc_server.h"
29 : #include "rpc_server/dcerpc_server_proto.h"
30 : #include "librpc/rpc/dcerpc.h"
31 : #include "system/filesys.h"
32 : #include "lib/messaging/irpc.h"
33 : #include "system/network.h"
34 : #include "lib/socket/netif.h"
35 : #include "param/param.h"
36 : #include "../lib/tsocket/tsocket.h"
37 : #include "librpc/rpc/dcerpc_proto.h"
38 : #include "../lib/util/tevent_ntstatus.h"
39 : #include "libcli/raw/smb.h"
40 : #include "samba/process_model.h"
41 :
42 45086 : static void skip_become_root(void)
43 : {
44 45086 : }
45 :
46 45086 : static void skip_unbecome_root(void)
47 : {
48 45086 : }
49 :
50 : static struct dcesrv_context_callbacks srv_callbacks = {
51 : .log.successful_authz = log_successful_dcesrv_authz_event,
52 : .auth.gensec_prepare = dcesrv_gensec_prepare,
53 : .auth.become_root = skip_become_root,
54 : .auth.unbecome_root = skip_unbecome_root,
55 : .assoc_group.find = dcesrv_assoc_group_find_s4,
56 : };
57 :
58 : /*
59 : * Need to run the majority of the RPC endpoints in a single process to allow
60 : * for shared handles, and the sharing of ldb contexts.
61 : *
62 : * However other endpoints are capable of being run in multiple processes
63 : * e.g. NETLOGON.
64 : *
65 : * To support this the process model is manipulated to force those end points
66 : * not supporting multiple processes into the single process model. The code
67 : * responsible for this is in dcesrv_init_endpoints
68 : *
69 : */
70 : NTSTATUS server_service_rpc_init(TALLOC_CTX *);
71 :
72 : /*
73 : * Initialise the rpc endpoints.
74 : */
75 134 : static NTSTATUS dcesrv_init_endpoints(struct task_server *task,
76 : struct dcesrv_context *dce_ctx,
77 : bool use_single_process)
78 : {
79 :
80 4 : struct dcesrv_endpoint *e;
81 134 : const struct model_ops *model_ops = NULL;
82 :
83 : /*
84 : * For those RPC services that run with shared context we need to
85 : * ensure that they don't fork a new process on accept (standard_model).
86 : * And as there is only one process handling these requests we need
87 : * to handle accept errors in a similar manner to the single process
88 : * model.
89 : *
90 : * To do this we override the process model operations with the single
91 : * process operations. This is not the most elegant solution, but it is
92 : * the least ugly, and is confined to the next block of code.
93 : */
94 134 : if (use_single_process) {
95 68 : model_ops = process_model_startup("single");
96 68 : if (model_ops == NULL) {
97 0 : DBG_ERR("Unable to load single process model\n");
98 0 : return NT_STATUS_INTERNAL_ERROR;
99 : }
100 : } else {
101 66 : model_ops = task->model_ops;
102 : }
103 :
104 2516 : for (e = dce_ctx->endpoint_list; e; e = e->next) {
105 :
106 68 : enum dcerpc_transport_t transport =
107 2382 : dcerpc_binding_get_transport(e->ep_description);
108 :
109 2382 : if (transport == NCACN_HTTP) {
110 : /*
111 : * We don't support ncacn_http yet
112 : */
113 134 : continue;
114 : }
115 2248 : if (e->use_single_process == use_single_process) {
116 32 : NTSTATUS status;
117 1136 : status = dcesrv_add_ep(dce_ctx,
118 : task->lp_ctx,
119 : e,
120 : task->event_ctx,
121 : model_ops,
122 : task->process_context);
123 1136 : if (!NT_STATUS_IS_OK(status)) {
124 0 : return status;
125 : }
126 : }
127 : }
128 134 : return NT_STATUS_OK;
129 : }
130 :
131 : /*
132 : * Initialise the RPC service.
133 : * And those end points that can be serviced by multiple processes.
134 : * The endpoints that need to be run in a single process are setup in the
135 : * post_fork hook.
136 : */
137 66 : static NTSTATUS dcesrv_task_init(struct task_server *task)
138 : {
139 66 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
140 2 : struct dcesrv_context *dce_ctx;
141 66 : const char **ep_servers = NULL;
142 :
143 66 : dcerpc_server_init(task->lp_ctx);
144 :
145 66 : task_server_set_title(task, "task[dcesrv]");
146 :
147 66 : status = dcesrv_init_context(task->event_ctx,
148 : task->lp_ctx,
149 : &srv_callbacks,
150 : &dce_ctx);
151 66 : if (!NT_STATUS_IS_OK(status)) {
152 0 : return status;
153 : }
154 :
155 66 : ep_servers = lpcfg_dcerpc_endpoint_servers(task->lp_ctx);
156 66 : status = dcesrv_init_ep_servers(dce_ctx, ep_servers);
157 66 : if (!NT_STATUS_IS_OK(status)) {
158 0 : return status;
159 : }
160 :
161 : /* Make sure the directory for NCALRPC exists */
162 66 : if (!directory_exist(lpcfg_ncalrpc_dir(task->lp_ctx))) {
163 2 : int ret;
164 :
165 65 : ret = mkdir(lpcfg_ncalrpc_dir(task->lp_ctx), 0755);
166 65 : if (ret == -1 && errno != EEXIST) {
167 0 : return map_nt_error_from_unix_common(errno);
168 : }
169 : }
170 66 : status = dcesrv_init_endpoints(task, dce_ctx, false);
171 66 : if (!NT_STATUS_IS_OK(status)) {
172 0 : return status;
173 : }
174 :
175 66 : task->private_data = dce_ctx;
176 66 : return NT_STATUS_OK;
177 : }
178 :
179 : /*
180 : * Initialise the endpoints that need to run in a single process fork.
181 : * The endpoint registration is only done for the first process instance.
182 : *
183 : */
184 146 : static void dcesrv_post_fork(struct task_server *task,
185 : struct process_details *pd)
186 : {
187 :
188 146 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
189 8 : struct dcesrv_context *dce_ctx;
190 :
191 146 : if (task->private_data == NULL) {
192 0 : task_server_terminate(task, "dcerpc: No dcesrv_context", true);
193 0 : return;
194 : }
195 8 : dce_ctx =
196 146 : talloc_get_type_abort(task->private_data, struct dcesrv_context);
197 :
198 : /*
199 : * Ensure the single process endpoints are only available to the
200 : * first instance.
201 : */
202 146 : if (pd->instances == 0) {
203 68 : status = dcesrv_init_endpoints(task, dce_ctx, true);
204 68 : if (!NT_STATUS_IS_OK(status)) {
205 0 : task_server_terminate(
206 : task,
207 : "dcerpc: Failed to initialise end points",
208 : true);
209 0 : return;
210 : }
211 : }
212 :
213 146 : irpc_add_name(task->msg_ctx, "rpc_server");
214 : }
215 :
216 66 : NTSTATUS server_service_rpc_init(TALLOC_CTX *ctx)
217 : {
218 3 : static const struct service_details details = {
219 : .inhibit_fork_on_accept = false,
220 : .inhibit_pre_fork = false,
221 : .task_init = dcesrv_task_init,
222 : .post_fork = dcesrv_post_fork};
223 66 : return register_server_service(ctx, "rpc", &details);
224 : }
|