mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
* 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 commit is contained in:
parent
4929c53bc8
commit
46e0a35819
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user