diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-12-12 03:59:09 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-12-12 03:59:09 +0000 |
commit | 16309de71d6c8de96e869aeaab0b879185991d87 (patch) | |
tree | d122fe6bd25cd87df5422b0af661c9e93db31ef8 | |
parent | fcc4efd1ea637c810eed8444080b87d7f92c837a (diff) | |
download | samba-16309de71d6c8de96e869aeaab0b879185991d87.tar.gz samba-16309de71d6c8de96e869aeaab0b879185991d87.tar.bz2 samba-16309de71d6c8de96e869aeaab0b879185991d87.zip |
* the RPC-ECHO pipe now works in smbd, as long as the data sizes
don't cause fragmented pdus (I'll add fragments shortly)
* change data_blob_talloc() to not zero memory when the 2nd argument
is NULL. The zeroing just masks bugs, and can't even allow a DOS
attack
* modified pidl to ensure that [ref] arguments to the out side of
functions are allocated when parsing the in side. This allows rpc
backends to assume that [ref] variables are all setup. Doesn't work
correctly for [ref] arrays yet
* changed DLIST_ADD_END() to take the type instead of a tmp
variable. This means you don't need to declare a silly tmp variable in
the caller
(This used to be commit 46e0a358198eeb9af1907ee2a29025d3ab23b6d1)
-rw-r--r-- | source4/auth/auth.c | 3 | ||||
-rw-r--r-- | source4/auth/pampass.c | 3 | ||||
-rw-r--r-- | source4/build/pidl/parser.pm | 5 | ||||
-rw-r--r-- | source4/include/client.h | 1 | ||||
-rw-r--r-- | source4/include/context.h | 39 | ||||
-rw-r--r-- | source4/include/dlinklist.h | 9 | ||||
-rw-r--r-- | source4/include/includes.h | 5 | ||||
-rw-r--r-- | source4/include/ntvfs.h | 6 | ||||
-rw-r--r-- | source4/include/smb.h | 31 | ||||
-rw-r--r-- | source4/lib/data_blob.c | 2 | ||||
-rw-r--r-- | source4/lib/tdb/tdbutil.c | 3 | ||||
-rw-r--r-- | source4/librpc/idl/dcerpc.idl | 4 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/ipc/vfs_ipc.c | 5 | ||||
-rw-r--r-- | source4/passdb/pdb_interface.c | 4 | ||||
-rw-r--r-- | source4/printing/notify.c | 4 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 308 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.h | 31 | ||||
-rw-r--r-- | source4/rpc_server/rpc_echo.c | 79 | ||||
-rw-r--r-- | source4/smbd/trans2.c | 6 | ||||
-rw-r--r-- | source4/tdb/tdbutil.c | 3 |
21 files changed, 485 insertions, 68 deletions
diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 514a6bde6a..2dc14248f9 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -324,7 +324,6 @@ static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, { auth_methods *list = NULL; auth_methods *t = NULL; - auth_methods *tmp; int i; NTSTATUS nt_status; @@ -358,7 +357,7 @@ static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, if (NT_STATUS_IS_OK(builtin_auth_init_functions[i].init(*auth_context, module_params, &t))) { DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n", *text_list)); - DLIST_ADD_END(list, t, tmp); + DLIST_ADD_END(list, t, auth_methods *); } else { DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n", *text_list)); diff --git a/source4/auth/pampass.c b/source4/auth/pampass.c index 045ceb7c72..a5c9a5de16 100644 --- a/source4/auth/pampass.c +++ b/source4/auth/pampass.c @@ -208,7 +208,6 @@ static struct chat_struct *make_pw_chat(char *p) fstring reply; struct chat_struct *list = NULL; struct chat_struct *t; - struct chat_struct *tmp; while (1) { t = (struct chat_struct *)malloc(sizeof(*t)); @@ -219,7 +218,7 @@ static struct chat_struct *make_pw_chat(char *p) ZERO_STRUCTP(t); - DLIST_ADD_END(list, t, tmp); + DLIST_ADD_END(list, t, struct chat_struct *); if (!next_token(&p, prompt, NULL, sizeof(fstring))) break; diff --git a/source4/build/pidl/parser.pm b/source4/build/pidl/parser.pm index ee24e9d5ef..88ba348486 100644 --- a/source4/build/pidl/parser.pm +++ b/source4/build/pidl/parser.pm @@ -1256,6 +1256,11 @@ sub ParseFunctionPull($) if (util::has_property($e, "in")) { ParseFunctionElementPull($e, "in"); } + # we need to allocate any reference output variables, so that + # a dcerpc backend can be sure they are non-null + if (util::has_property($e, "out") && util::has_property($e, "ref")) { + pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n"; + } } pidl "\nndr_out:\n"; diff --git a/source4/include/client.h b/source4/include/client.h index 015c8fb18a..8b0aedd48c 100644 --- a/source4/include/client.h +++ b/source4/include/client.h @@ -114,5 +114,4 @@ struct cli_client #define CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK 0x0004 #define CLI_FULL_CONNECTION_USE_DFS 0x0008 -#include "cli_context.h" #endif /* _CLIENT_H */ diff --git a/source4/include/context.h b/source4/include/context.h index 959793ab5e..f9a9bdc554 100644 --- a/source4/include/context.h +++ b/source4/include/context.h @@ -42,6 +42,44 @@ struct user_context { struct user_struct *vuser; }; + +/* each backend has to be one one of the following 3 basic types. In + * earlier versions of Samba backends needed to handle all types, now + * we implement them separately. */ +enum ntvfs_type {NTVFS_DISK, NTVFS_PRINT, NTVFS_IPC}; + +/* we need a forward declaration of the ntvfs_ops strucutre to prevent + include recursion */ +struct ntvfs_ops; + +struct tcon_context { + struct tcon_context *next, *prev; + + /* the server context that this was created on */ + struct server_context *smb; + + /* a talloc context for all data in this structure */ + TALLOC_CTX *mem_ctx; + + /* a private structure used by the active NTVFS backend */ + void *ntvfs_private; + + uint16 cnum; /* an index passed over the wire (the TID) */ + int service; + enum ntvfs_type type; + BOOL read_only; + BOOL admin_user; + + /* the NTVFS operations - see source/ntvfs/ and include/ntvfs.h for details */ + struct ntvfs_ops *ntvfs_ops; + + /* the reported filesystem type */ + char *fs_type; + + /* the reported device type */ + char *dev_type; +}; + /* the context for a single SMB request. This is passed to any request-context functions */ struct request_context { @@ -343,3 +381,4 @@ struct server_context { struct model_ops *model_ops; }; + diff --git a/source4/include/dlinklist.h b/source4/include/dlinklist.h index f1ceb8acf3..6191299384 100644 --- a/source4/include/dlinklist.h +++ b/source4/include/dlinklist.h @@ -57,16 +57,17 @@ do { \ } while (0) /* hook into the end of the list - needs a tmp pointer */ -#define DLIST_ADD_END(list, p, tmp) \ +#define DLIST_ADD_END(list, p, type) \ do { \ if (!(list)) { \ (list) = (p); \ (p)->next = (p)->prev = NULL; \ } else { \ - for ((tmp) = (list); (tmp)->next; (tmp) = (tmp)->next) ; \ - (tmp)->next = (p); \ + type tmp; \ + for (tmp = (list); tmp->next; tmp = tmp->next) ; \ + tmp->next = (p); \ (p)->next = NULL; \ - (p)->prev = (tmp); \ + (p)->prev = tmp; \ } \ } while (0) diff --git a/source4/include/includes.h b/source4/include/includes.h index 9683d032cc..305875cae0 100644 --- a/source4/include/includes.h +++ b/source4/include/includes.h @@ -773,6 +773,11 @@ extern int errno; #include "librpc/ndr/libndr.h" #include "librpc/rpc/dcerpc.h" +#include "rpc_server/dcerpc_server.h" +#include "context.h" +#include "ntvfs.h" +#include "cli_context.h" + /* used in net.c */ struct functable { diff --git a/source4/include/ntvfs.h b/source4/include/ntvfs.h index 88122166ee..b03ab218c6 100644 --- a/source4/include/ntvfs.h +++ b/source4/include/ntvfs.h @@ -23,12 +23,6 @@ -/* each backend has to be one one of the following 3 basic types. In - * earlier versions of Samba backends needed to handle all types, now - * we implement them separately. */ -enum ntvfs_type {NTVFS_DISK, NTVFS_PRINT, NTVFS_IPC}; - - /* the ntvfs operations structure - contains function pointers to the backend implementations of each operation */ struct ntvfs_ops { diff --git a/source4/include/smb.h b/source4/include/smb.h index a0a190190b..9b8bc28614 100644 --- a/source4/include/smb.h +++ b/source4/include/smb.h @@ -421,10 +421,7 @@ struct vuid_cache { #include "smb_acls.h" #include "enums.h" #include "events.h" -#include "rpc_server/dcerpc_server.h" -#include "context.h" #include "smb_interfaces.h" -#include "ntvfs.h" typedef struct smb_vfs_handle_struct { @@ -435,34 +432,6 @@ typedef struct smb_vfs_handle_struct } smb_vfs_handle_struct; -struct tcon_context { - struct tcon_context *next, *prev; - - /* the server context that this was created on */ - struct server_context *smb; - - /* a talloc context for all data in this structure */ - TALLOC_CTX *mem_ctx; - - /* a private structure used by the active NTVFS backend */ - void *ntvfs_private; - - uint16 cnum; /* an index passed over the wire (the TID) */ - int service; - enum ntvfs_type type; - BOOL read_only; - BOOL admin_user; - - /* the NTVFS operations - see source/ntvfs/ and include/ntvfs.h for details */ - struct ntvfs_ops *ntvfs_ops; - - /* the reported filesystem type */ - char *fs_type; - - /* the reported device type */ - char *dev_type; -}; - struct current_user { struct tcon_context *conn; diff --git a/source4/lib/data_blob.c b/source4/lib/data_blob.c index 933617e9ee..457ad382a2 100644 --- a/source4/lib/data_blob.c +++ b/source4/lib/data_blob.c @@ -67,12 +67,12 @@ DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length) } if (p == NULL) { + /* note that we do NOT zero memory in this case */ ret.data = talloc(mem_ctx, length); if (ret.data == NULL) { smb_panic("data_blob_talloc: talloc_memdup failed.\n"); } ret.length = length; - memset(ret.data, 0, ret.length); ret.free = NULL; return ret; } diff --git a/source4/lib/tdb/tdbutil.c b/source4/lib/tdb/tdbutil.c index ce5188300c..3c22333b4d 100644 --- a/source4/lib/tdb/tdbutil.c +++ b/source4/lib/tdb/tdbutil.c @@ -710,7 +710,6 @@ TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern) TDB_DATA key, next; TDB_LIST_NODE *list = NULL; TDB_LIST_NODE *rec = NULL; - TDB_LIST_NODE *tmp = NULL; for (key = tdb_firstkey(tdb); key.dptr; key = next) { /* duplicate key string to ensure null-termination */ @@ -731,7 +730,7 @@ TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern) rec->node_key = key; - DLIST_ADD_END(list, rec, tmp); + DLIST_ADD_END(list, rec, TDB_LIST_NODE *); DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern)); } else { diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl index 32850b90cf..7646f7d223 100644 --- a/source4/librpc/idl/dcerpc.idl +++ b/source4/librpc/idl/dcerpc.idl @@ -81,6 +81,10 @@ interface dcerpc const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002; + /* we return this fault when we haven't yet run the test + to see what fault w2k3 returns in this case */ + const int DCERPC_FAULT_TODO = 0x00000042; + typedef struct { uint32 alloc_hint; uint16 context_id; diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index 3f6d968cd2..a1e5fe538f 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -43,7 +43,7 @@ size_t ndr_align_size(uint32 offset, size_t n) /* initialise a ndr parse structure from a data blob */ -struct ndr_pull *ndr_pull_init_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx) +struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx) { struct ndr_pull *ndr; diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index 5ab608c46b..b57e72f14a 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -526,6 +526,11 @@ static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans) return NT_STATUS_INVALID_HANDLE; } + trans->out.data = data_blob_talloc(req->mem_ctx, NULL, trans->in.max_data); + if (!trans->out.data.data) { + return NT_STATUS_NO_MEMORY; + } + /* pass the data to the dcerpc server. Note that we don't expect this to fail, and things like NDR faults are not reported at this stage. Those sorts of errors happen in the diff --git a/source4/passdb/pdb_interface.c b/source4/passdb/pdb_interface.c index 6b25a1fdad..5b2c081275 100644 --- a/source4/passdb/pdb_interface.c +++ b/source4/passdb/pdb_interface.c @@ -385,7 +385,7 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) NTSTATUS make_pdb_context_list(struct pdb_context **context, const char **selected) { int i = 0; - struct pdb_methods *curmethods, *tmpmethods; + struct pdb_methods *curmethods; NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; if (!NT_STATUS_IS_OK(nt_status = make_pdb_context(context))) { @@ -401,7 +401,7 @@ NTSTATUS make_pdb_context_list(struct pdb_context **context, const char **select return nt_status; } curmethods->parent = *context; - DLIST_ADD_END((*context)->pdb_methods, curmethods, tmpmethods); + DLIST_ADD_END((*context)->pdb_methods, curmethods, struct pdb_methods *); i++; } diff --git a/source4/printing/notify.c b/source4/printing/notify.c index 9e92e5daa6..a745e9e308 100644 --- a/source4/printing/notify.c +++ b/source4/printing/notify.c @@ -212,7 +212,7 @@ static BOOL copy_notify2_msg( SPOOLSS_NOTIFY_MSG *to, SPOOLSS_NOTIFY_MSG *from ) static void send_spoolss_notify2_msg(SPOOLSS_NOTIFY_MSG *msg) { - struct notify_queue *pnqueue, *tmp_ptr; + struct notify_queue *pnqueue; /* * Ensure we only have one message unique to each name/type/field/id/flags @@ -262,7 +262,7 @@ to notify_queue_head\n", msg->type, msg->field, msg->printer)); * the messages are sent in the order they were received. JRA. */ - DLIST_ADD_END(notify_queue_head, pnqueue, tmp_ptr); + DLIST_ADD_END(notify_queue_head, pnqueue, struct notify_queue *); } static void send_notify_field_values(const char *printer_name, uint32 type, diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index e1d6da2292..f5e7ff858e 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -30,7 +30,7 @@ static const struct dcesrv_endpoint_ops *find_endpoint(struct server_context *sm { struct dce_endpoint *ep; for (ep=smb->dcesrv.endpoint_list; ep; ep=ep->next) { - if (ep->endpoint_ops->query(endpoint)) { + if (ep->endpoint_ops->query_endpoint(endpoint)) { return ep->endpoint_ops; } } @@ -86,6 +86,7 @@ NTSTATUS dcesrv_endpoint_connect(struct server_context *smb, (*p)->endpoint = *endpoint; (*p)->ops = ops; (*p)->private = NULL; + (*p)->call_list = NULL; /* make sure the endpoint server likes the connection */ status = ops->connect(*p); @@ -107,23 +108,318 @@ void dcesrv_endpoint_disconnect(struct dcesrv_state *p) talloc_destroy(p->mem_ctx); } +/* + return a dcerpc fault +*/ +static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32 fault_code) +{ + struct ndr_push *push; + struct dcerpc_packet pkt; + NTSTATUS status; + + /* setup a bind_ack */ + pkt.rpc_vers = 5; + pkt.rpc_vers_minor = 0; + pkt.drep[0] = 0x10; /* Little endian */ + pkt.drep[1] = 0; + pkt.drep[2] = 0; + pkt.drep[3] = 0; + pkt.auth_length = 0; + pkt.call_id = call->pkt.call_id; + pkt.ptype = DCERPC_PKT_FAULT; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.u.fault.alloc_hint = 0; + pkt.u.fault.context_id = 0; + pkt.u.fault.cancel_count = 0; + pkt.u.fault.status = fault_code; + + /* now form the NDR for the bind_ack */ + push = ndr_push_init_ctx(call->mem_ctx); + if (!push) { + return NT_STATUS_NO_MEMORY; + } + + status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + call->data = ndr_push_blob(push); + SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length); + + return NT_STATUS_OK; +} + + +/* + handle a bind request +*/ +static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) +{ + const char *uuid, *transfer_syntax; + uint32 if_version, transfer_syntax_version; + struct dcerpc_packet pkt; + struct ndr_push *push; + NTSTATUS status; + + if (call->pkt.u.bind.num_contexts != 1 || + call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) { + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.major_version; + uuid = GUID_string(call->mem_ctx, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid); + if (!uuid) { + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].major_version; + transfer_syntax = GUID_string(call->mem_ctx, + &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid); + if (!transfer_syntax || + strcasecmp(NDR_GUID, transfer_syntax) != 0 || + NDR_GUID_VERSION != transfer_syntax_version) { + /* we only do NDR encoded dcerpc */ + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + if (!call->dce->ops->set_interface(call->dce, uuid, if_version)) { + DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version)); + /* we don't know about that interface */ + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + /* setup a bind_ack */ + pkt.rpc_vers = 5; + pkt.rpc_vers_minor = 0; + pkt.drep[0] = 0x10; /* Little endian */ + pkt.drep[1] = 0; + pkt.drep[2] = 0; + pkt.drep[3] = 0; + pkt.auth_length = 0; + pkt.call_id = call->pkt.call_id; + pkt.ptype = DCERPC_PKT_BIND_ACK; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.u.bind_ack.max_xmit_frag = 0x2000; + pkt.u.bind_ack.max_recv_frag = 0x2000; + pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id; + pkt.u.bind_ack.secondary_address = talloc_asprintf(call->mem_ctx, "\\PIPE\\%s", + call->dce->ndr->name); + pkt.u.bind_ack.num_results = 1; + pkt.u.bind_ack.ctx_list = talloc(call->mem_ctx, sizeof(struct dcerpc_ack_ctx)); + if (!pkt.u.bind_ack.ctx_list) { + return NT_STATUS_NO_MEMORY; + } + pkt.u.bind_ack.ctx_list[0].result = 0; + pkt.u.bind_ack.ctx_list[0].reason = 0; + GUID_from_string(uuid, &pkt.u.bind_ack.ctx_list[0].syntax.uuid); + pkt.u.bind_ack.ctx_list[0].syntax.major_version = if_version; + pkt.u.bind_ack.ctx_list[0].syntax.minor_version = 0; + pkt.u.bind_ack.auth_info = data_blob(NULL, 0); + + /* now form the NDR for the bind_ack */ + push = ndr_push_init_ctx(call->mem_ctx); + if (!push) { + return NT_STATUS_NO_MEMORY; + } + + status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + call->data = ndr_push_blob(push); + SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length); + + return NT_STATUS_OK; +} + + +/* + handle a dcerpc request packet +*/ +static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) +{ + struct ndr_pull *pull; + struct ndr_push *push; + uint16 opnum; + void *r; + NTSTATUS status; + DATA_BLOB stub; + struct dcerpc_packet pkt; + + if (call->pkt.pfc_flags != (DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST)) { + /* we don't do fragments in the server yet */ + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + opnum = call->pkt.u.request.opnum; + + if (opnum >= call->dce->ndr->num_calls) { + return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR); + } + + pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call->mem_ctx); + if (!pull) { + return NT_STATUS_NO_MEMORY; + } + + r = talloc(call->mem_ctx, call->dce->ndr->calls[opnum].struct_size); + if (!r) { + return NT_STATUS_NO_MEMORY; + } + + /* unravel the NDR for the packet */ + status = call->dce->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + /* call the dispatch function */ + status = call->dce->dispatch[opnum](call->dce, call->mem_ctx, r); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + /* form the reply NDR */ + push = ndr_push_init_ctx(call->mem_ctx); + if (!push) { + return NT_STATUS_NO_MEMORY; + } + + status = call->dce->ndr->calls[opnum].ndr_push(push, NDR_OUT, r); + if (!NT_STATUS_IS_OK(status)) { + return dcesrv_fault(call, DCERPC_FAULT_TODO); + } + + stub = ndr_push_blob(push); + + /* form the dcerpc response packet */ + pkt.rpc_vers = 5; + pkt.rpc_vers_minor = 0; + pkt.drep[0] = 0x10; /* Little endian */ + pkt.drep[1] = 0; + pkt.drep[2] = 0; + pkt.drep[3] = 0; + pkt.auth_length = 0; + pkt.call_id = call->pkt.call_id; + pkt.ptype = DCERPC_PKT_RESPONSE; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.u.response.alloc_hint = stub.length; + pkt.u.response.context_id = call->pkt.u.request.context_id; + pkt.u.response.cancel_count = 0; + pkt.u.response.stub_and_verifier = stub; + + push = ndr_push_init_ctx(call->mem_ctx); + if (!push) { + return NT_STATUS_NO_MEMORY; + } + + status = ndr_push_dcerpc_packet(push, NDR_SCALARS|NDR_BUFFERS, &pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + call->data = ndr_push_blob(push); + SSVAL(call->data.data, DCERPC_FRAG_LEN_OFFSET, call->data.length); + + return NT_STATUS_OK; +} + /* provide some input to a dcerpc endpoint server. This passes data from a dcerpc client into the server */ -NTSTATUS dcesrv_input(struct dcesrv_state *p, const DATA_BLOB *data) +NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data) { - return NT_STATUS_NOT_IMPLEMENTED; + struct ndr_pull *ndr; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + struct dcesrv_call_state *call; + + mem_ctx = talloc_init("dcesrv_input"); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + call = talloc(mem_ctx, sizeof(*call)); + if (!call) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + call->mem_ctx = mem_ctx; + call->dce = dce; + + ndr = ndr_pull_init_blob(data, mem_ctx); + if (!ndr) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt); + if (!NT_STATUS_IS_OK(status)) { + talloc_destroy(mem_ctx); + return status; + } + + /* TODO: at this point we should see if the packet is a + continuation of an existing call, but I'm too lazy for that + right now ... maybe tomorrow */ + + + switch (call->pkt.ptype) { + case DCERPC_PKT_BIND: + status = dcesrv_bind(call); + break; + case DCERPC_PKT_REQUEST: + status = dcesrv_request(call); + break; + default: + status = NT_STATUS_INVALID_PARAMETER; + break; + } + + /* if we are going to be sending a reply then add + it to the list of pending calls. We add it to the end to keep the call + list in the order we will answer */ + if (NT_STATUS_IS_OK(status)) { + DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *); + } else { + talloc_destroy(mem_ctx); + } + + return status; } /* retrieve some output from a dcerpc server. The amount of data that - is wanted is in data->length + is wanted is in data->length and data->data is already allocated + to hold that much data. */ -NTSTATUS dcesrv_output(struct dcesrv_state *p, DATA_BLOB *data) +NTSTATUS dcesrv_output(struct dcesrv_state *dce, DATA_BLOB *data) { - return NT_STATUS_NOT_IMPLEMENTED; + struct dcesrv_call_state *call; + + call = dce->call_list; + if (!call) { + return NT_STATUS_FOOBAR; + } + + if (data->length >= call->data.length) { + data->length = call->data.length; + } + + memcpy(data->data, call->data.data, data->length); + call->data.length -= data->length; + call->data.data += data->length; + + if (call->data.length == 0) { + /* we're done with this call */ + DLIST_REMOVE(dce->call_list, call); + talloc_destroy(call->mem_ctx); + } + + return NT_STATUS_OK; } diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index b28f40768a..9895254cad 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -32,6 +32,19 @@ struct dcesrv_endpoint { } info; }; +struct dcesrv_state; + +/* the dispatch functions for an interface take this form */ +typedef NTSTATUS (*dcesrv_dispatch_fn_t)(struct dcesrv_state *, TALLOC_CTX *, void *); + +/* the state of an ongoing dcerpc call */ +struct dcesrv_call_state { + struct dcesrv_call_state *next, *prev; + struct dcesrv_state *dce; + TALLOC_CTX *mem_ctx; + struct dcerpc_packet pkt; + DATA_BLOB data; +}; /* the state associated with a dcerpc server connection */ struct dcesrv_state { @@ -43,15 +56,29 @@ struct dcesrv_state { /* endpoint operations provided by the endpoint server */ const struct dcesrv_endpoint_ops *ops; + /* the ndr function table for the chosen interface */ + const struct dcerpc_interface_table *ndr; + + /* the dispatch table for the chosen interface. Must contain + enough entries for all entries in the ndr table */ + const dcesrv_dispatch_fn_t *dispatch; + + /* the state of the current calls */ + struct dcesrv_call_state *call_list; + /* private data for the endpoint server */ void *private; }; struct dcesrv_endpoint_ops { - /* the query function is used to ask an endpoint server if it + /* this function is used to ask an endpoint server if it handles a particular endpoint */ - BOOL (*query)(const struct dcesrv_endpoint *); + BOOL (*query_endpoint)(const struct dcesrv_endpoint *); + + /* this function sets up the dispatch table for this + connection */ + BOOL (*set_interface)(struct dcesrv_state *, const char *, uint32); /* connect() is called when a connection is made to an endpoint */ NTSTATUS (*connect)(struct dcesrv_state *); diff --git a/source4/rpc_server/rpc_echo.c b/source4/rpc_server/rpc_echo.c index 51914f7946..37b72f764b 100644 --- a/source4/rpc_server/rpc_echo.c +++ b/source4/rpc_server/rpc_echo.c @@ -23,20 +23,94 @@ #include "includes.h" +static NTSTATUS echo_AddOne(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_AddOne *r) +{ + *r->out.v = *r->in.v + 1; + return NT_STATUS_OK; +} + +static NTSTATUS echo_EchoData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_EchoData *r) +{ + r->out.out_data = talloc(mem_ctx, r->in.len); + if (!r->out.out_data) { + return NT_STATUS_NO_MEMORY; + } + memcpy(r->out.out_data, r->in.in_data, r->in.len); + + return NT_STATUS_OK; +} + +static NTSTATUS echo_SinkData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_SinkData *r) +{ + return NT_STATUS_OK; +} + +static NTSTATUS echo_SourceData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_SourceData *r) +{ + int i; + r->out.data = talloc(mem_ctx, r->in.len); + if (!r->out.data) { + return NT_STATUS_NO_MEMORY; + } + for (i=0;i<r->in.len;i++) { + r->out.data[i] = i; + } + + return NT_STATUS_OK; +} + +static NTSTATUS echo_TestCall(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct TestCall *r) +{ + return NT_STATUS_BAD_NETWORK_NAME; +} + +static NTSTATUS echo_TestCall2(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct TestCall2 *r) +{ + return NT_STATUS_BAD_NETWORK_NAME; +} + + + /************************************************************************** all the code below this point is boilerplate that will be auto-generated ***************************************************************************/ +static const dcesrv_dispatch_fn_t dispatch_table[] = { + (dcesrv_dispatch_fn_t)echo_AddOne, + (dcesrv_dispatch_fn_t)echo_EchoData, + (dcesrv_dispatch_fn_t)echo_SinkData, + (dcesrv_dispatch_fn_t)echo_SourceData, + (dcesrv_dispatch_fn_t)echo_TestCall, + (dcesrv_dispatch_fn_t)echo_TestCall2 +}; + /* return True if we want to handle the given endpoint */ -static BOOL op_query(const struct dcesrv_endpoint *ep) +static BOOL op_query_endpoint(const struct dcesrv_endpoint *ep) { return dcesrv_table_query(&dcerpc_table_rpcecho, ep); } +/* + setup for a particular rpc interface +*/ +static BOOL op_set_interface(struct dcesrv_state *dce, const char *uuid, uint32 if_version) +{ + if (strcasecmp(uuid, dcerpc_table_rpcecho.uuid) != 0 || + if_version != dcerpc_table_rpcecho.if_version) { + DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version)); + return False; + } + + dce->ndr = &dcerpc_table_rpcecho; + dce->dispatch = dispatch_table; + + return True; +} + /* op_connect is called when a connection is made to an endpoint */ static NTSTATUS op_connect(struct dcesrv_state *dce) @@ -51,7 +125,8 @@ static void op_disconnect(struct dcesrv_state *dce) static const struct dcesrv_endpoint_ops rpc_echo_ops = { - op_query, + op_query_endpoint, + op_set_interface, op_connect, op_disconnect }; diff --git a/source4/smbd/trans2.c b/source4/smbd/trans2.c index 3115a330e5..19f313a860 100644 --- a/source4/smbd/trans2.c +++ b/source4/smbd/trans2.c @@ -1219,8 +1219,10 @@ static NTSTATUS trans2_backend(struct request_context *req, struct smb_trans2 *t */ static NTSTATUS trans_backend(struct request_context *req, struct smb_trans2 *trans) { - - return NT_STATUS_NOT_IMPLEMENTED; + if (!req->conn->ntvfs_ops->trans) { + return NT_STATUS_NOT_IMPLEMENTED; + } + return req->conn->ntvfs_ops->trans(req, trans); } diff --git a/source4/tdb/tdbutil.c b/source4/tdb/tdbutil.c index ce5188300c..3c22333b4d 100644 --- a/source4/tdb/tdbutil.c +++ b/source4/tdb/tdbutil.c @@ -710,7 +710,6 @@ TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern) TDB_DATA key, next; TDB_LIST_NODE *list = NULL; TDB_LIST_NODE *rec = NULL; - TDB_LIST_NODE *tmp = NULL; for (key = tdb_firstkey(tdb); key.dptr; key = next) { /* duplicate key string to ensure null-termination */ @@ -731,7 +730,7 @@ TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern) rec->node_key = key; - DLIST_ADD_END(list, rec, tmp); + DLIST_ADD_END(list, rec, TDB_LIST_NODE *); DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern)); } else { |