* the RPC-ECHO pipe now works in smbd, as long as the data sizes
authorAndrew Tridgell <tridge@samba.org>
Fri, 12 Dec 2003 03:59:09 +0000 (03:59 +0000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 12 Dec 2003 03:59:09 +0000 (03:59 +0000)
   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)

21 files changed:
source4/auth/auth.c
source4/auth/pampass.c
source4/build/pidl/parser.pm
source4/include/client.h
source4/include/context.h
source4/include/dlinklist.h
source4/include/includes.h
source4/include/ntvfs.h
source4/include/smb.h
source4/lib/data_blob.c
source4/lib/tdb/tdbutil.c
source4/librpc/idl/dcerpc.idl
source4/librpc/ndr/ndr.c
source4/ntvfs/ipc/vfs_ipc.c
source4/passdb/pdb_interface.c
source4/printing/notify.c
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/rpc_echo.c
source4/smbd/trans2.c
source4/tdb/tdbutil.c

index 514a6bde6a40f5e111014db1c66cfb4f8894b875..2dc14248f96efc89ae18539765e35f113cbb8285 100644 (file)
@@ -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));
index 045ceb7c7297a74d5417d7e2af67985cba366377..a5c9a5de16ae4b4f3bd3bce8e94b63622d9b4222 100644 (file)
@@ -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;
index ee24e9d5ef939b70bb3f5afb6633ae10dd7e3433..88ba34848640210bb5c1de726bfa397b9c880b52 100644 (file)
@@ -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";
index 015c8fb18a667ffd576e1aa08d3c9746cff70b6f..8b0aedd48cc60d45ddfb0f1784d64d38f7c396ef 100644 (file)
@@ -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 */
index 959793ab5e3f766e194c05461a40ec668ad835c0..f9a9bdc5547412c10381b92b195087b4289a241f 100644 (file)
@@ -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;
 };
 
+
index f1ceb8acf3e36321691c0b59ec19249ebc8a9889..6191299384270a4c90a24bda5892fa874a52ab02 100644 (file)
@@ -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)
 
index 9683d032cc5a2c798723a3a98383faed218681d0..305875cae03bf46264bdaa7a1db35ee44ba78e12 100644 (file)
@@ -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 {
index 88122166eefeb7c34f3027428a85fd2b1b646062..b03ab218c6ee7884469dc4192d9ea04cda5a6dbf 100644 (file)
 
 
 
-/* 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 {
index a0a190190b89f4884929f9066119d9cc107f198e..9b8bc28614439a395540cd4b4ed3a941641ec410 100644 (file)
@@ -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;
index 933617e9eea2fd126181ab700988c99a57e550d9..457ad382a28aa196021005cb6835ba04e2e5b403 100644 (file)
@@ -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;
        }
index ce5188300cc5baf8dc0e1e43129712cbf9b247a4..3c22333b4de362c59caf2327297896f43469c4a0 100644 (file)
@@ -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 {
index 32850b90cf84e6435815d90d5f1f963ced0ecebd..7646f7d223e0c8ef79a6b02a970ddd24e00d3889 100644 (file)
@@ -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;
index 3f6d968cd2abc9ebebe87e5ba42521d4168219a7..a1e5fe538f55585f873696a5032e8ebf222333c2 100644 (file)
@@ -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;
 
index 5ab608c46b31f7b02925b0e0e4b6525c0efa784c..b57e72f14afbff2f8c70d7f4bf741e46abe4031e 100644 (file)
@@ -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
index 6b25a1fdaddc42f616855fe8abf0fb09eaf3d76a..5b2c08127527c80fda105912efe120b7b499f031 100644 (file)
@@ -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++;
        }
 
index 9e92e5daa6b6c3d2a2f371fb39c7f507692ab2cb..a745e9e3083441e325ea94f7d04a4136a6920fac 100644 (file)
@@ -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,
index e1d6da2292ec33a7d9f8041793a94b7f316a07b9..f5e7ff858e647a95ad876755c0d4b5dff993ed5f 100644 (file)
@@ -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;
 }
 
 
index b28f40768a9ec9b82371f07e45b0dcdce8d4d05a..9895254cada67c19c8190648b9fb91dfec02f4ec 100644 (file)
@@ -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 *);
index 51914f7946d1e8cabea06efcf72383e33633a5d6..37b72f764b8f537988f6af79f572379826511580 100644 (file)
 #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
 };
index 3115a330e5a7271c28a0c28fff3f7d8bce00bf5d..19f313a8604b0b517a0f66332cbf0488339824b4 100644 (file)
@@ -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);
 }
 
 
index ce5188300cc5baf8dc0e1e43129712cbf9b247a4..3c22333b4de362c59caf2327297896f43469c4a0 100644 (file)
@@ -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 {