*/
#include "includes.h"
+#include "system/passwd.h" /* uid_wrapper */
#include "../librpc/gen_ndr/ndr_lsa.h"
#include "../librpc/gen_ndr/ndr_samr.h"
#include "auth.h"
+#include "rpc_server/rpc_pipes.h"
+#include "../libcli/security/security.h"
+#include "lib/tsocket/tsocket.h"
+#include "librpc/ndr/ndr_table.h"
+#include "librpc/rpc/dcesrv_core.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-/*
- * Handle database - stored per pipe.
- */
-
-struct dcesrv_handle {
- struct dcesrv_handle *prev, *next;
- struct policy_handle wire_handle;
- uint32_t access_granted;
- void *data;
-};
-
-struct handle_list {
- struct dcesrv_handle *handles; /* List of pipe handles. */
- size_t count; /* Current number of handles. */
- size_t pipe_ref_count; /* Number of pipe handles referring
- * to this tree. */
-};
-
-/* This is the max handles across all instances of a pipe name. */
-#ifndef MAX_OPEN_POLS
-#define MAX_OPEN_POLS 2048
-#endif
+static size_t num_handles = 0;
-/****************************************************************************
- Hack as handles need to be persisant over lsa pipe closes so long as a samr
- pipe is open. JRA.
-****************************************************************************/
+/* TODO
+ * the following prototypes are declared here to avoid
+ * code being moved about too much for a patch to be
+ * disrupted / less obvious.
+ *
+ * these functions, and associated functions that they
+ * call, should be moved behind a .so module-loading
+ * system _anyway_. so that's the next step...
+ */
-static bool is_samr_lsa_pipe(const struct ndr_syntax_id *syntax)
+int make_base_pipes_struct(TALLOC_CTX *mem_ctx,
+ struct messaging_context *msg_ctx,
+ const char *pipe_name,
+ enum dcerpc_transport_t transport,
+ const struct tsocket_address *remote_address,
+ const struct tsocket_address *local_address,
+ struct pipes_struct **_p)
{
- return (ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id)
- || ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id));
-}
+ struct pipes_struct *p;
-size_t num_pipe_handles(struct pipes_struct *p)
-{
- if (p->pipe_handles == NULL) {
- return 0;
+ p = talloc_zero(mem_ctx, struct pipes_struct);
+ if (!p) {
+ return ENOMEM;
}
- return p->pipe_handles->count;
-}
-
-/****************************************************************************
- Initialise a policy handle list on a pipe. Handle list is shared between all
- pipes of the same name.
-****************************************************************************/
-bool init_pipe_handles(struct pipes_struct *p, const struct ndr_syntax_id *syntax)
-{
- struct pipes_struct *plist;
- struct handle_list *hl;
-
- for (plist = get_first_internal_pipe();
- plist;
- plist = get_next_internal_pipe(plist)) {
- if (ndr_syntax_id_equal(syntax, &plist->syntax)) {
- break;
- }
- if (is_samr_lsa_pipe(&plist->syntax)
- && is_samr_lsa_pipe(syntax)) {
- /*
- * samr and lsa share a handle space (same process
- * under Windows?)
- */
- break;
- }
+ p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
+ if (!p->mem_ctx) {
+ talloc_free(p);
+ return ENOMEM;
}
- if (plist != NULL) {
- hl = plist->pipe_handles;
- if (hl == NULL) {
- return false;
- }
- } else {
- /*
- * First open, we have to create the handle list
- */
- hl = talloc_zero(NULL, struct handle_list);
- if (hl == NULL) {
- return false;
- }
+ p->msg_ctx = msg_ctx;
+ p->transport = transport;
- DEBUG(10,("init_pipe_handle_list: created handle list for "
- "pipe %s\n",
- get_pipe_name_from_syntax(talloc_tos(), syntax)));
+ p->remote_address = tsocket_address_copy(remote_address, p);
+ if (p->remote_address == NULL) {
+ talloc_free(p);
+ return ENOMEM;
}
- /*
- * One more pipe is using this list.
- */
-
- hl->pipe_ref_count++;
+ if (local_address) {
+ p->local_address = tsocket_address_copy(local_address, p);
+ if (p->local_address == NULL) {
+ talloc_free(p);
+ return ENOMEM;
+ }
+ }
- /*
- * Point this pipe at this list.
- */
+ *_p = p;
+ return 0;
+}
- p->pipe_handles = hl;
+bool check_open_pipes(void)
+{
+ if (num_handles > 0) {
+ return true;
+ }
- DEBUG(10,("init_pipe_handle_list: pipe_handles ref count = %lu for "
- "pipe %s\n", (unsigned long)p->pipe_handles->pipe_ref_count,
- get_pipe_name_from_syntax(talloc_tos(), syntax)));
+ return false;
+}
- return True;
+size_t num_pipe_handles(void)
+{
+ return num_handles;
}
/****************************************************************************
data_ptr is TALLOC_FREE()'ed
****************************************************************************/
-static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p,
- struct policy_handle *hnd, void *data_ptr)
+bool create_policy_hnd(struct pipes_struct *p,
+ struct policy_handle *hnd,
+ uint8_t handle_type,
+ void *data_ptr)
{
- struct dcesrv_handle *rpc_hnd;
- static uint32 pol_hnd_low = 0;
- static uint32 pol_hnd_high = 0;
- time_t t = time(NULL);
-
- if (p->pipe_handles->count > MAX_OPEN_POLS) {
- DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
- (int)p->pipe_handles->count));
- return NULL;
- }
+ struct dcesrv_handle *rpc_hnd = NULL;
- rpc_hnd = talloc_zero(p->pipe_handles, struct dcesrv_handle);
- if (!rpc_hnd) {
- DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
- return NULL;
+ rpc_hnd = dcesrv_handle_create(p->dce_call, handle_type);
+ if (rpc_hnd == NULL) {
+ return false;
}
if (data_ptr != NULL) {
rpc_hnd->data = talloc_move(rpc_hnd, &data_ptr);
}
- pol_hnd_low++;
- if (pol_hnd_low == 0) {
- pol_hnd_high++;
- }
-
- /* first bit must be null */
- SIVAL(&rpc_hnd->wire_handle.handle_type, 0 , 0);
-
- /* second bit is incrementing */
- SIVAL(&rpc_hnd->wire_handle.uuid.time_low, 0 , pol_hnd_low);
- SSVAL(&rpc_hnd->wire_handle.uuid.time_mid, 0 , pol_hnd_high);
- SSVAL(&rpc_hnd->wire_handle.uuid.time_hi_and_version, 0, (pol_hnd_high >> 16));
-
- /* split the current time into two 16 bit values */
-
- /* something random */
- SSVAL(rpc_hnd->wire_handle.uuid.clock_seq, 0, (t >> 16));
- /* something random */
- SSVAL(rpc_hnd->wire_handle.uuid.node, 0, t);
- /* something more random */
- SIVAL(rpc_hnd->wire_handle.uuid.node, 2, sys_getpid());
-
- DLIST_ADD(p->pipe_handles->handles, rpc_hnd);
- p->pipe_handles->count++;
-
*hnd = rpc_hnd->wire_handle;
- DEBUG(4, ("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
- dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
+ num_handles++;
- return rpc_hnd;
-}
-
-bool create_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd,
- void *data_ptr)
-{
- struct dcesrv_handle *rpc_hnd;
-
- rpc_hnd = create_rpc_handle_internal(p, hnd, data_ptr);
- if (rpc_hnd == NULL) {
- return false;
- }
return true;
}
find policy by handle - internal version.
****************************************************************************/
-static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p,
- const struct policy_handle *hnd, void **data_p)
+static struct dcesrv_handle *find_policy_by_hnd_internal(
+ struct pipes_struct *p,
+ const struct policy_handle *hnd,
+ uint8_t handle_type,
+ void **data_p)
{
- struct dcesrv_handle *h;
- unsigned int count;
+ struct dcesrv_handle *h = NULL;
if (data_p) {
*data_p = NULL;
}
- count = 0;
- for (h = p->pipe_handles->handles; h != NULL; h = h->next) {
- if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) {
- DEBUG(4,("Found policy hnd[%u] ", count));
- dump_data(4, (uint8 *)hnd, sizeof(*hnd));
- if (data_p) {
- *data_p = h->data;
- }
- return h;
+ /*
+ * Do not pass handle_type to avoid setting the fault_state in the
+ * pipes_struct if the handle type does not match
+ */
+ h = dcesrv_handle_lookup(p->dce_call, hnd, DCESRV_HANDLE_ANY);
+ if (h != NULL) {
+ if (handle_type != DCESRV_HANDLE_ANY &&
+ h->wire_handle.handle_type != handle_type) {
+ /* Just return NULL, do not set a fault
+ * state in pipes_struct */
+ return NULL;
}
- count++;
+ if (data_p) {
+ *data_p = h->data;
+ }
+ return h;
}
- DEBUG(4,("Policy not found: "));
- dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
-
- p->bad_handle_fault_state = true;
+ p->fault_state = DCERPC_FAULT_CONTEXT_MISMATCH;
return NULL;
}
find policy by handle
****************************************************************************/
-bool find_policy_by_hnd(struct pipes_struct *p, const struct policy_handle *hnd,
- void **data_p)
+void *_find_policy_by_hnd(struct pipes_struct *p,
+ const struct policy_handle *hnd,
+ uint8_t handle_type,
+ NTSTATUS *pstatus)
{
- struct dcesrv_handle *rpc_hnd;
+ struct dcesrv_handle *rpc_hnd = NULL;
+ void *data = NULL;
- rpc_hnd = find_policy_by_hnd_internal(p, hnd, data_p);
+ rpc_hnd = find_policy_by_hnd_internal(p, hnd, handle_type, &data);
if (rpc_hnd == NULL) {
- return false;
+ *pstatus = NT_STATUS_INVALID_HANDLE;
+ return NULL;
}
- return true;
+
+ *pstatus = NT_STATUS_OK;
+ return data;
}
/****************************************************************************
Close a policy.
****************************************************************************/
-bool close_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd)
+bool close_policy_hnd(struct pipes_struct *p,
+ struct policy_handle *hnd)
{
- struct dcesrv_handle *rpc_hnd;
-
- rpc_hnd = find_policy_by_hnd_internal(p, hnd, NULL);
+ struct dcesrv_handle *rpc_hnd = NULL;
+ rpc_hnd = find_policy_by_hnd_internal(p, hnd, DCESRV_HANDLE_ANY, NULL);
if (rpc_hnd == NULL) {
DEBUG(3, ("Error closing policy (policy not found)\n"));
return false;
}
- DEBUG(3,("Closed policy\n"));
-
- p->pipe_handles->count--;
-
- DLIST_REMOVE(p->pipe_handles->handles, rpc_hnd);
TALLOC_FREE(rpc_hnd);
- return true;
-}
-
-/****************************************************************************
- Close a pipe - free the handle set if it was the last pipe reference.
-****************************************************************************/
-
-void close_policy_by_pipe(struct pipes_struct *p)
-{
- p->pipe_handles->pipe_ref_count--;
+ num_handles--;
- if (p->pipe_handles->pipe_ref_count == 0) {
- /*
- * Last pipe open on this list - free the list.
- */
- TALLOC_FREE(p->pipe_handles);
-
- DEBUG(10,("close_policy_by_pipe: deleted handle list for "
- "pipe %s\n",
- get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
- }
+ return true;
}
/*******************************************************************
return True;
}
- if (p->session_info->guest) {
+ if (security_session_user_level(p->session_info, NULL) < SECURITY_USER) {
return False;
}
}
return True;
}
-
-void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
- uint32_t access_granted, size_t data_size,
- const char *type, NTSTATUS *pstatus)
-{
- struct dcesrv_handle *rpc_hnd;
- void *data;
-
- if (p->pipe_handles->count > MAX_OPEN_POLS) {
- DEBUG(0, ("policy_handle_create: ERROR: too many handles (%d) "
- "on pipe %s.\n", (int)p->pipe_handles->count,
- get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
- *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
- return NULL;
- }
-
- data = talloc_size(talloc_tos(), data_size);
- if (data == NULL) {
- *pstatus = NT_STATUS_NO_MEMORY;
- return NULL;
- }
- talloc_set_name_const(data, type);
-
- rpc_hnd = create_rpc_handle_internal(p, hnd, data);
- if (rpc_hnd == NULL) {
- TALLOC_FREE(data);
- *pstatus = NT_STATUS_NO_MEMORY;
- return NULL;
- }
- rpc_hnd->access_granted = access_granted;
- *pstatus = NT_STATUS_OK;
- return data;
-}
-
-void *_policy_handle_find(struct pipes_struct *p,
- const struct policy_handle *hnd,
- uint32_t access_required,
- uint32_t *paccess_granted,
- const char *name, const char *location,
- NTSTATUS *pstatus)
-{
- struct dcesrv_handle *rpc_hnd;
- void *data;
-
- rpc_hnd = find_policy_by_hnd_internal(p, hnd, &data);
- if (rpc_hnd == NULL) {
- *pstatus = NT_STATUS_INVALID_HANDLE;
- return NULL;
- }
- if (strcmp(name, talloc_get_name(data)) != 0) {
- DEBUG(10, ("expected %s, got %s\n", name,
- talloc_get_name(data)));
- *pstatus = NT_STATUS_INVALID_HANDLE;
- return NULL;
- }
- if ((access_required & rpc_hnd->access_granted) != access_required) {
- if (geteuid() == sec_initial_uid()) {
- DEBUG(4, ("%s: ACCESS should be DENIED (granted: "
- "%#010x; required: %#010x)\n", location,
- rpc_hnd->access_granted, access_required));
- DEBUGADD(4,("but overwritten by euid == 0\n"));
- goto okay;
- }
- DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: "
- "%#010x)\n", location, rpc_hnd->access_granted,
- access_required));
- *pstatus = NT_STATUS_ACCESS_DENIED;
- return NULL;
- }
-
- okay:
- DEBUG(10, ("found handle of type %s\n", talloc_get_name(data)));
- if (paccess_granted != NULL) {
- *paccess_granted = rpc_hnd->access_granted;
- }
- *pstatus = NT_STATUS_OK;
- return data;
-}