Line data Source code
1 : /*
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
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
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"
27 : #include "rpc_dce.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"
33 : #include "auth.h"
34 : #include "rpc_server/rpc_ncacn_np.h"
35 : #include "rpc_server/srv_pipe_hnd.h"
36 : #include "lib/util/idtree_random.h"
37 :
38 : #undef DBGC_CLASS
39 : #define DBGC_CLASS DBGC_RPC_SRV
40 :
41 : /* Start listening on the appropriate unix socket and setup all is needed to
42 : * dispatch requests to the pipes rpc implementation */
43 :
44 : struct dcerpc_ncacn_listen_state {
45 : int fd;
46 :
47 : struct tevent_context *ev_ctx;
48 : struct messaging_context *msg_ctx;
49 : struct dcesrv_context *dce_ctx;
50 : struct dcesrv_endpoint *endpoint;
51 : dcerpc_ncacn_termination_fn termination_fn;
52 : void *termination_data;
53 : };
54 :
55 : static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
56 : const char *reason);
57 :
58 779 : NTSTATUS dcesrv_auth_gensec_prepare(
59 : TALLOC_CTX *mem_ctx,
60 : struct dcesrv_call_state *call,
61 : struct gensec_security **out,
62 : void *private_data)
63 : {
64 779 : struct gensec_security *gensec = NULL;
65 0 : NTSTATUS status;
66 :
67 779 : if (out == NULL) {
68 0 : return NT_STATUS_INVALID_PARAMETER;
69 : }
70 :
71 779 : status = auth_generic_prepare(mem_ctx,
72 779 : call->conn->remote_address,
73 779 : call->conn->local_address,
74 : "DCE/RPC",
75 : &gensec);
76 779 : if (!NT_STATUS_IS_OK(status)) {
77 0 : DBG_ERR("Failed to prepare gensec: %s\n", nt_errstr(status));
78 0 : return status;
79 : }
80 :
81 779 : *out = gensec;
82 :
83 779 : return NT_STATUS_OK;
84 : }
85 :
86 34045 : void dcesrv_log_successful_authz(
87 : struct dcesrv_call_state *call,
88 : void *private_data)
89 : {
90 34045 : TALLOC_CTX *frame = talloc_stackframe();
91 34045 : struct auth4_context *auth4_context = NULL;
92 34045 : struct dcesrv_auth *auth = call->auth_state;
93 34045 : enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
94 34045 : call->conn->endpoint->ep_description);
95 34045 : const char *auth_type = derpc_transport_string_by_transport(transport);
96 34045 : const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
97 0 : NTSTATUS status;
98 :
99 34045 : if (frame == NULL) {
100 0 : DBG_ERR("No memory\n");
101 0 : return;
102 : }
103 :
104 34045 : if (transport == NCACN_NP) {
105 33651 : transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
106 : }
107 :
108 34045 : become_root();
109 34045 : status = make_auth4_context(frame, &auth4_context);
110 34045 : unbecome_root();
111 34045 : if (!NT_STATUS_IS_OK(status)) {
112 0 : DBG_ERR("Unable to make auth context for authz log.\n");
113 0 : TALLOC_FREE(frame);
114 0 : return;
115 : }
116 :
117 : /*
118 : * Log the authorization to this RPC interface. This
119 : * covered ncacn_np pass-through auth, and anonymous
120 : * DCE/RPC (eg epmapper, netlogon etc)
121 : */
122 34045 : log_successful_authz_event(auth4_context->msg_ctx,
123 34045 : auth4_context->lp_ctx,
124 34045 : call->conn->remote_address,
125 34045 : call->conn->local_address,
126 : "DCE/RPC",
127 : auth_type,
128 : transport_protection,
129 : auth->session_info,
130 : NULL /* client_audit_info */,
131 : NULL /* server_audit_info */);
132 :
133 34045 : auth->auth_audited = true;
134 :
135 34045 : TALLOC_FREE(frame);
136 : }
137 :
138 0 : static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
139 : {
140 0 : int ret;
141 0 : ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
142 0 : assoc_group->id);
143 0 : if (ret != 0) {
144 0 : DBG_ERR("Failed to remove assoc_group 0x%08x\n",
145 : assoc_group->id);
146 : }
147 0 : return 0;
148 : }
149 :
150 0 : static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
151 : {
152 0 : struct dcesrv_connection *conn = call->conn;
153 0 : struct dcesrv_context *dce_ctx = conn->dce_ctx;
154 0 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
155 0 : enum dcerpc_transport_t transport =
156 0 : dcerpc_binding_get_transport(endpoint->ep_description);
157 0 : struct dcesrv_assoc_group *assoc_group = NULL;
158 0 : int id;
159 :
160 0 : assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
161 0 : if (assoc_group == NULL) {
162 0 : return NT_STATUS_NO_MEMORY;
163 : }
164 :
165 0 : id = idr_get_new_random(dce_ctx->assoc_groups_idr,
166 : assoc_group,
167 : 1,
168 : UINT16_MAX);
169 0 : if (id == -1) {
170 0 : TALLOC_FREE(assoc_group);
171 0 : DBG_ERR("Out of association groups!\n");
172 0 : return NT_STATUS_RPC_OUT_OF_RESOURCES;
173 : }
174 :
175 0 : assoc_group->transport = transport;
176 0 : assoc_group->id = id;
177 0 : assoc_group->dce_ctx = dce_ctx;
178 :
179 0 : call->conn->assoc_group = assoc_group;
180 :
181 0 : talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
182 :
183 0 : return NT_STATUS_OK;
184 : }
185 :
186 0 : static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
187 : uint32_t assoc_group_id)
188 : {
189 0 : struct dcesrv_connection *conn = call->conn;
190 0 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
191 0 : enum dcerpc_transport_t transport =
192 0 : dcerpc_binding_get_transport(endpoint->ep_description);
193 0 : struct dcesrv_assoc_group *assoc_group = NULL;
194 0 : void *id_ptr = NULL;
195 :
196 : /* find an association group given a assoc_group_id */
197 0 : id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
198 0 : if (id_ptr == NULL) {
199 : /*
200 : * FIXME If the association group is not found it has
201 : * been created in other process (preforking daemons).
202 : * Until this is properly fixed we just create a new
203 : * association group in this process
204 : */
205 0 : DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
206 : "server process, creating a new one\n",
207 : assoc_group_id);
208 0 : return dcesrv_assoc_group_new(call);
209 : }
210 0 : assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
211 :
212 0 : if (assoc_group->transport != transport) {
213 0 : const char *at =
214 0 : derpc_transport_string_by_transport(
215 : assoc_group->transport);
216 0 : const char *ct =
217 0 : derpc_transport_string_by_transport(
218 : transport);
219 :
220 0 : DBG_NOTICE("assoc_group 0x%08x (transport %s) "
221 : "is not available on transport %s\n",
222 : assoc_group_id, at, ct);
223 0 : return NT_STATUS_UNSUCCESSFUL;
224 : }
225 :
226 0 : conn->assoc_group = talloc_reference(conn, assoc_group);
227 0 : return NT_STATUS_OK;
228 : }
229 :
230 0 : NTSTATUS dcesrv_assoc_group_find(
231 : struct dcesrv_call_state *call,
232 : void *private_data)
233 : {
234 0 : uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
235 :
236 0 : if (assoc_group_id != 0) {
237 0 : return dcesrv_assoc_group_reference(call, assoc_group_id);
238 : }
239 :
240 : /* If not requested by client create a new association group */
241 0 : return dcesrv_assoc_group_new(call);
242 : }
243 :
244 34750 : void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
245 : const char *reason)
246 : {
247 34750 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
248 : dce_conn->transport.private_data,
249 : struct dcerpc_ncacn_conn);
250 :
251 34750 : ncacn_terminate_connection(ncacn_conn, reason);
252 34750 : }
253 :
254 34750 : static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
255 : const char *reason)
256 : {
257 34750 : if (reason == NULL) {
258 0 : reason = "Unknown reason";
259 : }
260 :
261 34750 : DBG_NOTICE("Terminating connection - '%s'\n", reason);
262 :
263 34750 : talloc_free(conn);
264 34750 : }
265 :
266 0 : NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
267 : const char *pipe_name,
268 : struct dcesrv_endpoint **out)
269 : {
270 0 : struct dcesrv_endpoint *e = NULL;
271 :
272 0 : for (e = dce_ctx->endpoint_list; e; e = e->next) {
273 0 : enum dcerpc_transport_t transport =
274 0 : dcerpc_binding_get_transport(e->ep_description);
275 0 : const char *endpoint = NULL;
276 :
277 0 : if (transport != NCACN_NP) {
278 0 : continue;
279 : }
280 :
281 0 : endpoint = dcerpc_binding_get_string_option(e->ep_description,
282 : "endpoint");
283 0 : if (endpoint == NULL) {
284 0 : continue;
285 : }
286 :
287 0 : if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
288 0 : endpoint += 6;
289 : }
290 :
291 0 : if (strequal(endpoint, pipe_name)) {
292 0 : *out = e;
293 0 : return NT_STATUS_OK;
294 : }
295 : }
296 :
297 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
298 : }
299 :
300 604898 : struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
301 : {
302 604898 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
303 : conn->transport.private_data,
304 : struct dcerpc_ncacn_conn);
305 :
306 604898 : return &ncacn_conn->p;
307 : }
308 :
309 : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
|