samba-tool/testparm: Fix traceback when checking client name/ip against hosts allowed.
[Samba/gebeck_regimport.git] / source3 / rpc_server / rpc_handles.c
blob87145ca848f5f84a9413f38af7babfdc564acc26
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.
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.
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/>.
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 "rpc_server/rpc_pipes.h"
27 #include "../libcli/security/security.h"
28 #include "lib/tsocket/tsocket.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
33 static struct pipes_struct *InternalPipes;
35 /* TODO
36 * the following prototypes are declared here to avoid
37 * code being moved about too much for a patch to be
38 * disrupted / less obvious.
40 * these functions, and associated functions that they
41 * call, should be moved behind a .so module-loading
42 * system _anyway_. so that's the next step...
45 int make_base_pipes_struct(TALLOC_CTX *mem_ctx,
46 struct messaging_context *msg_ctx,
47 const char *pipe_name,
48 enum dcerpc_transport_t transport,
49 bool endian, bool ncalrpc_as_system,
50 const struct tsocket_address *remote_address,
51 const struct tsocket_address *local_address,
52 struct pipes_struct **_p)
54 struct pipes_struct *p;
56 p = talloc_zero(mem_ctx, struct pipes_struct);
57 if (!p) {
58 return ENOMEM;
61 p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
62 if (!p->mem_ctx) {
63 talloc_free(p);
64 return ENOMEM;
67 p->msg_ctx = msg_ctx;
68 p->transport = transport;
69 p->endian = endian;
70 p->ncalrpc_as_system = ncalrpc_as_system;
72 p->remote_address = tsocket_address_copy(remote_address, p);
73 if (p->remote_address == NULL) {
74 talloc_free(p);
75 return ENOMEM;
78 if (local_address) {
79 p->local_address = tsocket_address_copy(local_address, p);
80 if (p->local_address == NULL) {
81 talloc_free(p);
82 return ENOMEM;
86 DLIST_ADD(InternalPipes, p);
87 talloc_set_destructor(p, close_internal_rpc_pipe_hnd);
89 *_p = p;
90 return 0;
94 bool check_open_pipes(void)
96 struct pipes_struct *p;
98 for (p = InternalPipes; p != NULL; p = p->next) {
99 if (num_pipe_handles(p) != 0) {
100 return true;
103 return false;
106 /****************************************************************************
107 Close an rpc pipe.
108 ****************************************************************************/
110 int close_internal_rpc_pipe_hnd(struct pipes_struct *p)
112 if (!p) {
113 DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n"));
114 return False;
117 /* Free the handles database. */
118 close_policy_by_pipe(p);
120 DLIST_REMOVE(InternalPipes, p);
122 return 0;
126 * Handle database - stored per pipe.
129 struct dcesrv_handle {
130 struct dcesrv_handle *prev, *next;
131 struct policy_handle wire_handle;
132 uint32_t access_granted;
133 void *data;
136 struct handle_list {
137 struct dcesrv_handle *handles; /* List of pipe handles. */
138 size_t count; /* Current number of handles. */
139 size_t pipe_ref_count; /* Number of pipe handles referring
140 * to this tree. */
143 /* This is the max handles across all instances of a pipe name. */
144 #ifndef MAX_OPEN_POLS
145 #define MAX_OPEN_POLS 2048
146 #endif
148 /****************************************************************************
149 Hack as handles need to be persisant over lsa pipe closes so long as a samr
150 pipe is open. JRA.
151 ****************************************************************************/
153 static bool is_samr_lsa_pipe(const struct ndr_syntax_id *syntax)
155 return (ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id)
156 || ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id));
159 size_t num_pipe_handles(struct pipes_struct *p)
161 if (p->pipe_handles == NULL) {
162 return 0;
164 return p->pipe_handles->count;
167 /****************************************************************************
168 Initialise a policy handle list on a pipe. Handle list is shared between all
169 pipes of the same name.
170 ****************************************************************************/
172 bool init_pipe_handles(struct pipes_struct *p, const struct ndr_syntax_id *syntax)
174 struct pipes_struct *plist;
175 struct handle_list *hl;
177 for (plist = InternalPipes; plist; plist = plist->next) {
178 struct pipe_rpc_fns *p_ctx;
179 bool stop = false;
181 for (p_ctx = plist->contexts;
182 p_ctx != NULL;
183 p_ctx = p_ctx->next) {
184 if (ndr_syntax_id_equal(syntax, &p_ctx->syntax)) {
185 stop = true;
186 break;
188 if (is_samr_lsa_pipe(&p_ctx->syntax)
189 && is_samr_lsa_pipe(syntax)) {
191 * samr and lsa share a handle space (same process
192 * under Windows?)
194 stop = true;
195 break;
199 if (stop) {
200 break;
204 if (plist != NULL) {
205 hl = plist->pipe_handles;
206 if (hl == NULL) {
207 return false;
209 } else {
211 * First open, we have to create the handle list
213 hl = talloc_zero(NULL, struct handle_list);
214 if (hl == NULL) {
215 return false;
218 DEBUG(10,("init_pipe_handle_list: created handle list for "
219 "pipe %s\n",
220 get_pipe_name_from_syntax(talloc_tos(), syntax)));
224 * One more pipe is using this list.
227 hl->pipe_ref_count++;
230 * Point this pipe at this list.
233 p->pipe_handles = hl;
235 DEBUG(10,("init_pipe_handle_list: pipe_handles ref count = %lu for "
236 "pipe %s\n", (unsigned long)p->pipe_handles->pipe_ref_count,
237 get_pipe_name_from_syntax(talloc_tos(), syntax)));
239 return True;
242 /****************************************************************************
243 find first available policy slot. creates a policy handle for you.
245 If "data_ptr" is given, this must be a talloc'ed object, create_policy_hnd
246 talloc_moves this into the handle. If the policy_hnd is closed,
247 data_ptr is TALLOC_FREE()'ed
248 ****************************************************************************/
250 static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p,
251 struct policy_handle *hnd, void *data_ptr)
253 struct dcesrv_handle *rpc_hnd;
254 static uint32 pol_hnd_low = 0;
255 static uint32 pol_hnd_high = 0;
256 time_t t = time(NULL);
258 if (p->pipe_handles->count > MAX_OPEN_POLS) {
259 DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
260 (int)p->pipe_handles->count));
261 return NULL;
264 rpc_hnd = talloc_zero(p->pipe_handles, struct dcesrv_handle);
265 if (!rpc_hnd) {
266 DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
267 return NULL;
270 if (data_ptr != NULL) {
271 rpc_hnd->data = talloc_move(rpc_hnd, &data_ptr);
274 pol_hnd_low++;
275 if (pol_hnd_low == 0) {
276 pol_hnd_high++;
279 /* first bit must be null */
280 SIVAL(&rpc_hnd->wire_handle.handle_type, 0 , 0);
282 /* second bit is incrementing */
283 SIVAL(&rpc_hnd->wire_handle.uuid.time_low, 0 , pol_hnd_low);
284 SSVAL(&rpc_hnd->wire_handle.uuid.time_mid, 0 , pol_hnd_high);
285 SSVAL(&rpc_hnd->wire_handle.uuid.time_hi_and_version, 0, (pol_hnd_high >> 16));
287 /* split the current time into two 16 bit values */
289 /* something random */
290 SSVAL(rpc_hnd->wire_handle.uuid.clock_seq, 0, (t >> 16));
291 /* something random */
292 SSVAL(rpc_hnd->wire_handle.uuid.node, 0, t);
293 /* something more random */
294 SIVAL(rpc_hnd->wire_handle.uuid.node, 2, sys_getpid());
296 DLIST_ADD(p->pipe_handles->handles, rpc_hnd);
297 p->pipe_handles->count++;
299 *hnd = rpc_hnd->wire_handle;
301 DEBUG(4, ("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
302 dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
304 return rpc_hnd;
307 bool create_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd,
308 void *data_ptr)
310 struct dcesrv_handle *rpc_hnd;
312 rpc_hnd = create_rpc_handle_internal(p, hnd, data_ptr);
313 if (rpc_hnd == NULL) {
314 return false;
316 return true;
319 /****************************************************************************
320 find policy by handle - internal version.
321 ****************************************************************************/
323 static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p,
324 const struct policy_handle *hnd, void **data_p)
326 struct dcesrv_handle *h;
327 unsigned int count;
329 if (data_p) {
330 *data_p = NULL;
333 count = 0;
334 for (h = p->pipe_handles->handles; h != NULL; h = h->next) {
335 if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) {
336 DEBUG(4,("Found policy hnd[%u] ", count));
337 dump_data(4, (const uint8 *)hnd, sizeof(*hnd));
338 if (data_p) {
339 *data_p = h->data;
341 return h;
343 count++;
346 DEBUG(4,("Policy not found: "));
347 dump_data(4, (const uint8_t *)hnd, sizeof(*hnd));
349 p->bad_handle_fault_state = true;
351 return NULL;
354 /****************************************************************************
355 find policy by handle
356 ****************************************************************************/
358 bool find_policy_by_hnd(struct pipes_struct *p, const struct policy_handle *hnd,
359 void **data_p)
361 struct dcesrv_handle *rpc_hnd;
363 rpc_hnd = find_policy_by_hnd_internal(p, hnd, data_p);
364 if (rpc_hnd == NULL) {
365 return false;
367 return true;
370 /****************************************************************************
371 Close a policy.
372 ****************************************************************************/
374 bool close_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd)
376 struct dcesrv_handle *rpc_hnd;
378 rpc_hnd = find_policy_by_hnd_internal(p, hnd, NULL);
380 if (rpc_hnd == NULL) {
381 DEBUG(3, ("Error closing policy (policy not found)\n"));
382 return false;
385 DEBUG(3,("Closed policy\n"));
387 p->pipe_handles->count--;
389 DLIST_REMOVE(p->pipe_handles->handles, rpc_hnd);
390 TALLOC_FREE(rpc_hnd);
392 return true;
395 /****************************************************************************
396 Close a pipe - free the handle set if it was the last pipe reference.
397 ****************************************************************************/
399 void close_policy_by_pipe(struct pipes_struct *p)
401 if (p->pipe_handles == NULL) {
402 return;
405 p->pipe_handles->pipe_ref_count--;
407 if (p->pipe_handles->pipe_ref_count == 0) {
409 * Last pipe open on this list - free the list.
411 TALLOC_FREE(p->pipe_handles);
413 DEBUG(10,("Deleted handle list for RPC connection %s\n",
414 get_pipe_name_from_syntax(talloc_tos(),
415 &p->contexts->syntax)));
419 /*******************************************************************
420 Shall we allow access to this rpc? Currently this function
421 implements the 'restrict anonymous' setting by denying access to
422 anonymous users if the restrict anonymous level is > 0. Further work
423 will be checking a security descriptor to determine whether a user
424 token has enough access to access the pipe.
425 ********************************************************************/
427 bool pipe_access_check(struct pipes_struct *p)
429 /* Don't let anonymous users access this RPC if restrict
430 anonymous > 0 */
432 if (lp_restrict_anonymous() > 0) {
434 /* schannel, so we must be ok */
435 if (p->pipe_bound &&
436 (p->auth.auth_type == DCERPC_AUTH_TYPE_SCHANNEL)) {
437 return True;
440 if (security_session_user_level(p->session_info, NULL) < SECURITY_USER) {
441 return False;
445 return True;
448 void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
449 uint32_t access_granted, size_t data_size,
450 const char *type, NTSTATUS *pstatus)
452 struct dcesrv_handle *rpc_hnd;
453 void *data;
455 if (p->pipe_handles->count > MAX_OPEN_POLS) {
456 DEBUG(0, ("ERROR: Too many handles (%d) for RPC connection %s\n",
457 (int) p->pipe_handles->count,
458 get_pipe_name_from_syntax(talloc_tos(),
459 &p->contexts->syntax)));
460 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
461 return NULL;
464 data = talloc_size(talloc_tos(), data_size);
465 if (data == NULL) {
466 *pstatus = NT_STATUS_NO_MEMORY;
467 return NULL;
469 talloc_set_name_const(data, type);
471 rpc_hnd = create_rpc_handle_internal(p, hnd, data);
472 if (rpc_hnd == NULL) {
473 TALLOC_FREE(data);
474 *pstatus = NT_STATUS_NO_MEMORY;
475 return NULL;
477 rpc_hnd->access_granted = access_granted;
478 *pstatus = NT_STATUS_OK;
479 return data;
482 void *_policy_handle_find(struct pipes_struct *p,
483 const struct policy_handle *hnd,
484 uint32_t access_required,
485 uint32_t *paccess_granted,
486 const char *name, const char *location,
487 NTSTATUS *pstatus)
489 struct dcesrv_handle *rpc_hnd;
490 void *data;
492 rpc_hnd = find_policy_by_hnd_internal(p, hnd, &data);
493 if (rpc_hnd == NULL) {
494 *pstatus = NT_STATUS_INVALID_HANDLE;
495 return NULL;
497 if (strcmp(name, talloc_get_name(data)) != 0) {
498 DEBUG(10, ("expected %s, got %s\n", name,
499 talloc_get_name(data)));
500 *pstatus = NT_STATUS_INVALID_HANDLE;
501 return NULL;
503 if ((access_required & rpc_hnd->access_granted) != access_required) {
504 if (geteuid() == sec_initial_uid()) {
505 DEBUG(4, ("%s: ACCESS should be DENIED (granted: "
506 "%#010x; required: %#010x)\n", location,
507 rpc_hnd->access_granted, access_required));
508 DEBUGADD(4,("but overwritten by euid == 0\n"));
509 goto okay;
511 DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: "
512 "%#010x)\n", location, rpc_hnd->access_granted,
513 access_required));
514 *pstatus = NT_STATUS_ACCESS_DENIED;
515 return NULL;
518 okay:
519 DEBUG(10, ("found handle of type %s\n", talloc_get_name(data)));
520 if (paccess_granted != NULL) {
521 *paccess_granted = rpc_hnd->access_granted;
523 *pstatus = NT_STATUS_OK;
524 return data;