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 255 : 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 255 : struct gensec_security *gensec = NULL;
65 : NTSTATUS status;
66 :
67 255 : if (out == NULL) {
68 0 : return NT_STATUS_INVALID_PARAMETER;
69 : }
70 :
71 255 : status = auth_generic_prepare(mem_ctx,
72 255 : call->conn->remote_address,
73 255 : call->conn->local_address,
74 : "DCE/RPC",
75 : &gensec);
76 255 : 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 255 : *out = gensec;
82 :
83 255 : return NT_STATUS_OK;
84 : }
85 :
86 518 : void dcesrv_log_successful_authz(
87 : struct dcesrv_call_state *call,
88 : void *private_data)
89 : {
90 518 : TALLOC_CTX *frame = talloc_stackframe();
91 518 : struct auth4_context *auth4_context = NULL;
92 518 : struct dcesrv_auth *auth = call->auth_state;
93 518 : enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
94 518 : call->conn->endpoint->ep_description);
95 518 : const char *auth_type = derpc_transport_string_by_transport(transport);
96 518 : const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
97 : NTSTATUS status;
98 :
99 518 : if (frame == NULL) {
100 0 : DBG_ERR("No memory");
101 0 : return;
102 : }
103 :
104 518 : if (transport == NCACN_NP) {
105 282 : transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
106 : }
107 :
108 518 : become_root();
109 518 : status = make_auth4_context(frame, &auth4_context);
110 518 : unbecome_root();
111 518 : 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 518 : log_successful_authz_event(auth4_context->msg_ctx,
123 518 : auth4_context->lp_ctx,
124 518 : call->conn->remote_address,
125 518 : call->conn->local_address,
126 : "DCE/RPC",
127 : auth_type,
128 : transport_protection,
129 : auth->session_info);
130 :
131 518 : auth->auth_audited = true;
132 :
133 518 : TALLOC_FREE(frame);
134 : }
135 :
136 0 : static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
137 : {
138 : int ret;
139 0 : ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
140 0 : assoc_group->id);
141 0 : if (ret != 0) {
142 0 : DBG_ERR("Failed to remove assoc_group 0x%08x\n",
143 : assoc_group->id);
144 : }
145 0 : return 0;
146 : }
147 :
148 0 : static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
149 : {
150 0 : struct dcesrv_connection *conn = call->conn;
151 0 : struct dcesrv_context *dce_ctx = conn->dce_ctx;
152 0 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
153 : enum dcerpc_transport_t transport =
154 0 : dcerpc_binding_get_transport(endpoint->ep_description);
155 0 : struct dcesrv_assoc_group *assoc_group = NULL;
156 : int id;
157 :
158 0 : assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
159 0 : if (assoc_group == NULL) {
160 0 : return NT_STATUS_NO_MEMORY;
161 : }
162 :
163 0 : id = idr_get_new_random(dce_ctx->assoc_groups_idr,
164 : assoc_group,
165 : 1,
166 : UINT16_MAX);
167 0 : if (id == -1) {
168 0 : TALLOC_FREE(assoc_group);
169 0 : DBG_ERR("Out of association groups!\n");
170 0 : return NT_STATUS_RPC_OUT_OF_RESOURCES;
171 : }
172 :
173 0 : assoc_group->transport = transport;
174 0 : assoc_group->id = id;
175 0 : assoc_group->dce_ctx = dce_ctx;
176 :
177 0 : call->conn->assoc_group = assoc_group;
178 :
179 0 : talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
180 :
181 0 : return NT_STATUS_OK;
182 : }
183 :
184 0 : static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
185 : uint32_t assoc_group_id)
186 : {
187 0 : struct dcesrv_connection *conn = call->conn;
188 0 : const struct dcesrv_endpoint *endpoint = conn->endpoint;
189 : enum dcerpc_transport_t transport =
190 0 : dcerpc_binding_get_transport(endpoint->ep_description);
191 0 : struct dcesrv_assoc_group *assoc_group = NULL;
192 0 : void *id_ptr = NULL;
193 :
194 : /* find an association group given a assoc_group_id */
195 0 : id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
196 0 : if (id_ptr == NULL) {
197 : /*
198 : * FIXME If the association group is not found it has
199 : * been created in other process (preforking daemons).
200 : * Until this is properly fixed we just create a new
201 : * association group in this process
202 : */
203 0 : DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
204 : "server process, creating a new one\n",
205 : assoc_group_id);
206 0 : return dcesrv_assoc_group_new(call);
207 : }
208 0 : assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
209 :
210 0 : if (assoc_group->transport != transport) {
211 : const char *at =
212 0 : derpc_transport_string_by_transport(
213 : assoc_group->transport);
214 : const char *ct =
215 0 : derpc_transport_string_by_transport(
216 : transport);
217 :
218 0 : DBG_NOTICE("assoc_group 0x%08x (transport %s) "
219 : "is not available on transport %s",
220 : assoc_group_id, at, ct);
221 0 : return NT_STATUS_UNSUCCESSFUL;
222 : }
223 :
224 0 : conn->assoc_group = talloc_reference(conn, assoc_group);
225 0 : return NT_STATUS_OK;
226 : }
227 :
228 0 : NTSTATUS dcesrv_assoc_group_find(
229 : struct dcesrv_call_state *call,
230 : void *private_data)
231 : {
232 0 : uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
233 :
234 0 : if (assoc_group_id != 0) {
235 0 : return dcesrv_assoc_group_reference(call, assoc_group_id);
236 : }
237 :
238 : /* If not requested by client create a new association group */
239 0 : return dcesrv_assoc_group_new(call);
240 : }
241 :
242 699 : void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
243 : const char *reason)
244 : {
245 699 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
246 : dce_conn->transport.private_data,
247 : struct dcerpc_ncacn_conn);
248 :
249 699 : ncacn_terminate_connection(ncacn_conn, reason);
250 699 : }
251 :
252 699 : static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
253 : const char *reason)
254 : {
255 699 : if (reason == NULL) {
256 0 : reason = "Unknown reason";
257 : }
258 :
259 699 : DBG_NOTICE("Terminating connection - '%s'\n", reason);
260 :
261 699 : talloc_free(conn);
262 699 : }
263 :
264 0 : NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
265 : const char *pipe_name,
266 : struct dcesrv_endpoint **out)
267 : {
268 0 : struct dcesrv_endpoint *e = NULL;
269 :
270 0 : for (e = dce_ctx->endpoint_list; e; e = e->next) {
271 : enum dcerpc_transport_t transport =
272 0 : dcerpc_binding_get_transport(e->ep_description);
273 0 : const char *endpoint = NULL;
274 :
275 0 : if (transport != NCACN_NP) {
276 0 : continue;
277 : }
278 :
279 0 : endpoint = dcerpc_binding_get_string_option(e->ep_description,
280 : "endpoint");
281 0 : if (endpoint == NULL) {
282 0 : continue;
283 : }
284 :
285 0 : if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
286 0 : endpoint += 6;
287 : }
288 :
289 0 : if (strequal(endpoint, pipe_name)) {
290 0 : *out = e;
291 0 : return NT_STATUS_OK;
292 : }
293 : }
294 :
295 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
296 : }
297 :
298 9975 : struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
299 : {
300 9975 : struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
301 : conn->transport.private_data,
302 : struct dcerpc_ncacn_conn);
303 :
304 9975 : return &ncacn_conn->p;
305 : }
306 :
307 : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
|