1 | /*
|
---|
2 | * Unix SMB/CIFS implementation.
|
---|
3 | * RPC Pipe client / server routines
|
---|
4 | * Copyright (C) Andrew Tridgell 1992-1997,
|
---|
5 | * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
|
---|
6 | * Copyright (C) Jeremy Allison 2001.
|
---|
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/gen_ndr/ndr_lsa.h"
|
---|
24 | #include "../librpc/gen_ndr/ndr_samr.h"
|
---|
25 | #include "auth.h"
|
---|
26 | #include "ntdomain.h"
|
---|
27 | #include "rpc_server/rpc_ncacn_np.h"
|
---|
28 |
|
---|
29 | #undef DBGC_CLASS
|
---|
30 | #define DBGC_CLASS DBGC_RPC_SRV
|
---|
31 |
|
---|
32 | /*
|
---|
33 | * Handle database - stored per pipe.
|
---|
34 | */
|
---|
35 |
|
---|
36 | struct dcesrv_handle {
|
---|
37 | struct dcesrv_handle *prev, *next;
|
---|
38 | struct policy_handle wire_handle;
|
---|
39 | uint32_t access_granted;
|
---|
40 | void *data;
|
---|
41 | };
|
---|
42 |
|
---|
43 | struct handle_list {
|
---|
44 | struct dcesrv_handle *handles; /* List of pipe handles. */
|
---|
45 | size_t count; /* Current number of handles. */
|
---|
46 | size_t pipe_ref_count; /* Number of pipe handles referring
|
---|
47 | * to this tree. */
|
---|
48 | };
|
---|
49 |
|
---|
50 | /* This is the max handles across all instances of a pipe name. */
|
---|
51 | #ifndef MAX_OPEN_POLS
|
---|
52 | #define MAX_OPEN_POLS 2048
|
---|
53 | #endif
|
---|
54 |
|
---|
55 | /****************************************************************************
|
---|
56 | Hack as handles need to be persisant over lsa pipe closes so long as a samr
|
---|
57 | pipe is open. JRA.
|
---|
58 | ****************************************************************************/
|
---|
59 |
|
---|
60 | static bool is_samr_lsa_pipe(const struct ndr_syntax_id *syntax)
|
---|
61 | {
|
---|
62 | return (ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id)
|
---|
63 | || ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id));
|
---|
64 | }
|
---|
65 |
|
---|
66 | size_t num_pipe_handles(struct pipes_struct *p)
|
---|
67 | {
|
---|
68 | if (p->pipe_handles == NULL) {
|
---|
69 | return 0;
|
---|
70 | }
|
---|
71 | return p->pipe_handles->count;
|
---|
72 | }
|
---|
73 |
|
---|
74 | /****************************************************************************
|
---|
75 | Initialise a policy handle list on a pipe. Handle list is shared between all
|
---|
76 | pipes of the same name.
|
---|
77 | ****************************************************************************/
|
---|
78 |
|
---|
79 | bool init_pipe_handles(struct pipes_struct *p, const struct ndr_syntax_id *syntax)
|
---|
80 | {
|
---|
81 | struct pipes_struct *plist;
|
---|
82 | struct handle_list *hl;
|
---|
83 |
|
---|
84 | for (plist = get_first_internal_pipe();
|
---|
85 | plist;
|
---|
86 | plist = get_next_internal_pipe(plist)) {
|
---|
87 | if (ndr_syntax_id_equal(syntax, &plist->syntax)) {
|
---|
88 | break;
|
---|
89 | }
|
---|
90 | if (is_samr_lsa_pipe(&plist->syntax)
|
---|
91 | && is_samr_lsa_pipe(syntax)) {
|
---|
92 | /*
|
---|
93 | * samr and lsa share a handle space (same process
|
---|
94 | * under Windows?)
|
---|
95 | */
|
---|
96 | break;
|
---|
97 | }
|
---|
98 | }
|
---|
99 |
|
---|
100 | if (plist != NULL) {
|
---|
101 | hl = plist->pipe_handles;
|
---|
102 | if (hl == NULL) {
|
---|
103 | return false;
|
---|
104 | }
|
---|
105 | } else {
|
---|
106 | /*
|
---|
107 | * First open, we have to create the handle list
|
---|
108 | */
|
---|
109 | hl = talloc_zero(NULL, struct handle_list);
|
---|
110 | if (hl == NULL) {
|
---|
111 | return false;
|
---|
112 | }
|
---|
113 |
|
---|
114 | DEBUG(10,("init_pipe_handle_list: created handle list for "
|
---|
115 | "pipe %s\n",
|
---|
116 | get_pipe_name_from_syntax(talloc_tos(), syntax)));
|
---|
117 | }
|
---|
118 |
|
---|
119 | /*
|
---|
120 | * One more pipe is using this list.
|
---|
121 | */
|
---|
122 |
|
---|
123 | hl->pipe_ref_count++;
|
---|
124 |
|
---|
125 | /*
|
---|
126 | * Point this pipe at this list.
|
---|
127 | */
|
---|
128 |
|
---|
129 | p->pipe_handles = hl;
|
---|
130 |
|
---|
131 | DEBUG(10,("init_pipe_handle_list: pipe_handles ref count = %lu for "
|
---|
132 | "pipe %s\n", (unsigned long)p->pipe_handles->pipe_ref_count,
|
---|
133 | get_pipe_name_from_syntax(talloc_tos(), syntax)));
|
---|
134 |
|
---|
135 | return True;
|
---|
136 | }
|
---|
137 |
|
---|
138 | /****************************************************************************
|
---|
139 | find first available policy slot. creates a policy handle for you.
|
---|
140 |
|
---|
141 | If "data_ptr" is given, this must be a talloc'ed object, create_policy_hnd
|
---|
142 | talloc_moves this into the handle. If the policy_hnd is closed,
|
---|
143 | data_ptr is TALLOC_FREE()'ed
|
---|
144 | ****************************************************************************/
|
---|
145 |
|
---|
146 | static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p,
|
---|
147 | struct policy_handle *hnd, void *data_ptr)
|
---|
148 | {
|
---|
149 | struct dcesrv_handle *rpc_hnd;
|
---|
150 | static uint32 pol_hnd_low = 0;
|
---|
151 | static uint32 pol_hnd_high = 0;
|
---|
152 | time_t t = time(NULL);
|
---|
153 |
|
---|
154 | if (p->pipe_handles->count > MAX_OPEN_POLS) {
|
---|
155 | DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
|
---|
156 | (int)p->pipe_handles->count));
|
---|
157 | return NULL;
|
---|
158 | }
|
---|
159 |
|
---|
160 | rpc_hnd = talloc_zero(p->pipe_handles, struct dcesrv_handle);
|
---|
161 | if (!rpc_hnd) {
|
---|
162 | DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
|
---|
163 | return NULL;
|
---|
164 | }
|
---|
165 |
|
---|
166 | if (data_ptr != NULL) {
|
---|
167 | rpc_hnd->data = talloc_move(rpc_hnd, &data_ptr);
|
---|
168 | }
|
---|
169 |
|
---|
170 | pol_hnd_low++;
|
---|
171 | if (pol_hnd_low == 0) {
|
---|
172 | pol_hnd_high++;
|
---|
173 | }
|
---|
174 |
|
---|
175 | /* first bit must be null */
|
---|
176 | SIVAL(&rpc_hnd->wire_handle.handle_type, 0 , 0);
|
---|
177 |
|
---|
178 | /* second bit is incrementing */
|
---|
179 | SIVAL(&rpc_hnd->wire_handle.uuid.time_low, 0 , pol_hnd_low);
|
---|
180 | SSVAL(&rpc_hnd->wire_handle.uuid.time_mid, 0 , pol_hnd_high);
|
---|
181 | SSVAL(&rpc_hnd->wire_handle.uuid.time_hi_and_version, 0, (pol_hnd_high >> 16));
|
---|
182 |
|
---|
183 | /* split the current time into two 16 bit values */
|
---|
184 |
|
---|
185 | /* something random */
|
---|
186 | SSVAL(rpc_hnd->wire_handle.uuid.clock_seq, 0, (t >> 16));
|
---|
187 | /* something random */
|
---|
188 | SSVAL(rpc_hnd->wire_handle.uuid.node, 0, t);
|
---|
189 | /* something more random */
|
---|
190 | SIVAL(rpc_hnd->wire_handle.uuid.node, 2, sys_getpid());
|
---|
191 |
|
---|
192 | DLIST_ADD(p->pipe_handles->handles, rpc_hnd);
|
---|
193 | p->pipe_handles->count++;
|
---|
194 |
|
---|
195 | *hnd = rpc_hnd->wire_handle;
|
---|
196 |
|
---|
197 | DEBUG(4, ("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
|
---|
198 | dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
|
---|
199 |
|
---|
200 | return rpc_hnd;
|
---|
201 | }
|
---|
202 |
|
---|
203 | bool create_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd,
|
---|
204 | void *data_ptr)
|
---|
205 | {
|
---|
206 | struct dcesrv_handle *rpc_hnd;
|
---|
207 |
|
---|
208 | rpc_hnd = create_rpc_handle_internal(p, hnd, data_ptr);
|
---|
209 | if (rpc_hnd == NULL) {
|
---|
210 | return false;
|
---|
211 | }
|
---|
212 | return true;
|
---|
213 | }
|
---|
214 |
|
---|
215 | /****************************************************************************
|
---|
216 | find policy by handle - internal version.
|
---|
217 | ****************************************************************************/
|
---|
218 |
|
---|
219 | static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p,
|
---|
220 | const struct policy_handle *hnd, void **data_p)
|
---|
221 | {
|
---|
222 | struct dcesrv_handle *h;
|
---|
223 | unsigned int count;
|
---|
224 |
|
---|
225 | if (data_p) {
|
---|
226 | *data_p = NULL;
|
---|
227 | }
|
---|
228 |
|
---|
229 | count = 0;
|
---|
230 | for (h = p->pipe_handles->handles; h != NULL; h = h->next) {
|
---|
231 | if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) {
|
---|
232 | DEBUG(4,("Found policy hnd[%u] ", count));
|
---|
233 | dump_data(4, (uint8 *)hnd, sizeof(*hnd));
|
---|
234 | if (data_p) {
|
---|
235 | *data_p = h->data;
|
---|
236 | }
|
---|
237 | return h;
|
---|
238 | }
|
---|
239 | count++;
|
---|
240 | }
|
---|
241 |
|
---|
242 | DEBUG(4,("Policy not found: "));
|
---|
243 | dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
|
---|
244 |
|
---|
245 | p->fault_state = DCERPC_FAULT_CONTEXT_MISMATCH;
|
---|
246 |
|
---|
247 | return NULL;
|
---|
248 | }
|
---|
249 |
|
---|
250 | /****************************************************************************
|
---|
251 | find policy by handle
|
---|
252 | ****************************************************************************/
|
---|
253 |
|
---|
254 | bool find_policy_by_hnd(struct pipes_struct *p, const struct policy_handle *hnd,
|
---|
255 | void **data_p)
|
---|
256 | {
|
---|
257 | struct dcesrv_handle *rpc_hnd;
|
---|
258 |
|
---|
259 | rpc_hnd = find_policy_by_hnd_internal(p, hnd, data_p);
|
---|
260 | if (rpc_hnd == NULL) {
|
---|
261 | return false;
|
---|
262 | }
|
---|
263 | return true;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /****************************************************************************
|
---|
267 | Close a policy.
|
---|
268 | ****************************************************************************/
|
---|
269 |
|
---|
270 | bool close_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd)
|
---|
271 | {
|
---|
272 | struct dcesrv_handle *rpc_hnd;
|
---|
273 |
|
---|
274 | rpc_hnd = find_policy_by_hnd_internal(p, hnd, NULL);
|
---|
275 |
|
---|
276 | if (rpc_hnd == NULL) {
|
---|
277 | DEBUG(3, ("Error closing policy (policy not found)\n"));
|
---|
278 | return false;
|
---|
279 | }
|
---|
280 |
|
---|
281 | DEBUG(3,("Closed policy\n"));
|
---|
282 |
|
---|
283 | p->pipe_handles->count--;
|
---|
284 |
|
---|
285 | DLIST_REMOVE(p->pipe_handles->handles, rpc_hnd);
|
---|
286 | TALLOC_FREE(rpc_hnd);
|
---|
287 |
|
---|
288 | return true;
|
---|
289 | }
|
---|
290 |
|
---|
291 | /****************************************************************************
|
---|
292 | Close a pipe - free the handle set if it was the last pipe reference.
|
---|
293 | ****************************************************************************/
|
---|
294 |
|
---|
295 | void close_policy_by_pipe(struct pipes_struct *p)
|
---|
296 | {
|
---|
297 | p->pipe_handles->pipe_ref_count--;
|
---|
298 |
|
---|
299 | if (p->pipe_handles->pipe_ref_count == 0) {
|
---|
300 | /*
|
---|
301 | * Last pipe open on this list - free the list.
|
---|
302 | */
|
---|
303 | TALLOC_FREE(p->pipe_handles);
|
---|
304 |
|
---|
305 | DEBUG(10,("close_policy_by_pipe: deleted handle list for "
|
---|
306 | "pipe %s\n",
|
---|
307 | get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
|
---|
308 | }
|
---|
309 | }
|
---|
310 |
|
---|
311 | /*******************************************************************
|
---|
312 | Shall we allow access to this rpc? Currently this function
|
---|
313 | implements the 'restrict anonymous' setting by denying access to
|
---|
314 | anonymous users if the restrict anonymous level is > 0. Further work
|
---|
315 | will be checking a security descriptor to determine whether a user
|
---|
316 | token has enough access to access the pipe.
|
---|
317 | ********************************************************************/
|
---|
318 |
|
---|
319 | bool pipe_access_check(struct pipes_struct *p)
|
---|
320 | {
|
---|
321 | /* Don't let anonymous users access this RPC if restrict
|
---|
322 | anonymous > 0 */
|
---|
323 |
|
---|
324 | if (lp_restrict_anonymous() > 0) {
|
---|
325 |
|
---|
326 | /* schannel, so we must be ok */
|
---|
327 | if (p->pipe_bound &&
|
---|
328 | (p->auth.auth_type == DCERPC_AUTH_TYPE_SCHANNEL)) {
|
---|
329 | return True;
|
---|
330 | }
|
---|
331 |
|
---|
332 | if (p->session_info->guest) {
|
---|
333 | return False;
|
---|
334 | }
|
---|
335 | }
|
---|
336 |
|
---|
337 | return True;
|
---|
338 | }
|
---|
339 |
|
---|
340 | void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
|
---|
341 | uint32_t access_granted, size_t data_size,
|
---|
342 | const char *type, NTSTATUS *pstatus)
|
---|
343 | {
|
---|
344 | struct dcesrv_handle *rpc_hnd;
|
---|
345 | void *data;
|
---|
346 |
|
---|
347 | if (p->pipe_handles->count > MAX_OPEN_POLS) {
|
---|
348 | DEBUG(0, ("policy_handle_create: ERROR: too many handles (%d) "
|
---|
349 | "on pipe %s.\n", (int)p->pipe_handles->count,
|
---|
350 | get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
|
---|
351 | *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
|
---|
352 | return NULL;
|
---|
353 | }
|
---|
354 |
|
---|
355 | data = talloc_size(talloc_tos(), data_size);
|
---|
356 | if (data == NULL) {
|
---|
357 | *pstatus = NT_STATUS_NO_MEMORY;
|
---|
358 | return NULL;
|
---|
359 | }
|
---|
360 | talloc_set_name_const(data, type);
|
---|
361 |
|
---|
362 | rpc_hnd = create_rpc_handle_internal(p, hnd, data);
|
---|
363 | if (rpc_hnd == NULL) {
|
---|
364 | TALLOC_FREE(data);
|
---|
365 | *pstatus = NT_STATUS_NO_MEMORY;
|
---|
366 | return NULL;
|
---|
367 | }
|
---|
368 | rpc_hnd->access_granted = access_granted;
|
---|
369 | *pstatus = NT_STATUS_OK;
|
---|
370 | return data;
|
---|
371 | }
|
---|
372 |
|
---|
373 | void *_policy_handle_find(struct pipes_struct *p,
|
---|
374 | const struct policy_handle *hnd,
|
---|
375 | uint32_t access_required,
|
---|
376 | uint32_t *paccess_granted,
|
---|
377 | const char *name, const char *location,
|
---|
378 | NTSTATUS *pstatus)
|
---|
379 | {
|
---|
380 | struct dcesrv_handle *rpc_hnd;
|
---|
381 | void *data;
|
---|
382 |
|
---|
383 | rpc_hnd = find_policy_by_hnd_internal(p, hnd, &data);
|
---|
384 | if (rpc_hnd == NULL) {
|
---|
385 | *pstatus = NT_STATUS_INVALID_HANDLE;
|
---|
386 | return NULL;
|
---|
387 | }
|
---|
388 | if (strcmp(name, talloc_get_name(data)) != 0) {
|
---|
389 | DEBUG(10, ("expected %s, got %s\n", name,
|
---|
390 | talloc_get_name(data)));
|
---|
391 | *pstatus = NT_STATUS_INVALID_HANDLE;
|
---|
392 | return NULL;
|
---|
393 | }
|
---|
394 | if ((access_required & rpc_hnd->access_granted) != access_required) {
|
---|
395 | if (geteuid() == sec_initial_uid()) {
|
---|
396 | DEBUG(4, ("%s: ACCESS should be DENIED (granted: "
|
---|
397 | "%#010x; required: %#010x)\n", location,
|
---|
398 | rpc_hnd->access_granted, access_required));
|
---|
399 | DEBUGADD(4,("but overwritten by euid == 0\n"));
|
---|
400 | goto okay;
|
---|
401 | }
|
---|
402 | DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: "
|
---|
403 | "%#010x)\n", location, rpc_hnd->access_granted,
|
---|
404 | access_required));
|
---|
405 | *pstatus = NT_STATUS_ACCESS_DENIED;
|
---|
406 | return NULL;
|
---|
407 | }
|
---|
408 |
|
---|
409 | okay:
|
---|
410 | DEBUG(10, ("found handle of type %s\n", talloc_get_name(data)));
|
---|
411 | if (paccess_granted != NULL) {
|
---|
412 | *paccess_granted = rpc_hnd->access_granted;
|
---|
413 | }
|
---|
414 | *pstatus = NT_STATUS_OK;
|
---|
415 | return data;
|
---|
416 | }
|
---|