diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-11-03 06:22:45 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-11-03 06:22:45 +0000 |
commit | c5cf47443985c34ad32c44c322901e0fc3a065d7 (patch) | |
tree | f7d6abd03304c4f2359a4753aae23e41982c0e17 /source4 | |
parent | 7fd381376f88ae99a4bf022d89f21ae497b48c1a (diff) | |
download | samba-c5cf47443985c34ad32c44c322901e0fc3a065d7.tar.gz samba-c5cf47443985c34ad32c44c322901e0fc3a065d7.tar.bz2 samba-c5cf47443985c34ad32c44c322901e0fc3a065d7.zip |
a major revamp of the low level dcerpc code in samba4, We can now do a
successful LSA OpenPolicy using smbtorture
(This used to be commit e925c315f55905060fcca1b188ae1f7e40baf514)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/Makefile.in | 12 | ||||
-rw-r--r-- | source4/include/dcerpc_interfaces.h | 93 | ||||
-rw-r--r-- | source4/include/includes.h | 5 | ||||
-rw-r--r-- | source4/include/smb.h | 1 | ||||
-rw-r--r-- | source4/include/smb_interfaces.h | 2 | ||||
-rw-r--r-- | source4/libcli/clidcerpc.c | 254 | ||||
-rw-r--r-- | source4/libcli/ndr/libndr.h (renamed from source4/libcli/rpc/librpc.h) | 18 | ||||
-rw-r--r-- | source4/libcli/ndr/ndr.c (renamed from source4/libcli/rpc/rpcparse.c) | 95 | ||||
-rw-r--r-- | source4/libcli/ndr/ndr_basic.c (renamed from source4/libcli/rpc/rpc_basic.c) | 67 | ||||
-rw-r--r-- | source4/libcli/ndr/ndr_sec.c | 201 | ||||
-rw-r--r-- | source4/libcli/ndr/ndr_sec.h (renamed from source4/libcli/rpc/rpc_sec.h) | 9 | ||||
-rw-r--r-- | source4/libcli/raw/clisession.c | 4 | ||||
-rw-r--r-- | source4/libcli/raw/rawacl.c | 52 | ||||
-rw-r--r-- | source4/libcli/raw/rawdcerpc.c | 215 | ||||
-rw-r--r-- | source4/libcli/raw/rawsearch.c | 8 | ||||
-rw-r--r-- | source4/libcli/rpc/dcerpc.c | 644 | ||||
-rw-r--r-- | source4/libcli/rpc/dcerpc.h | 124 | ||||
-rw-r--r-- | source4/libcli/rpc/rpc_sec.c | 179 | ||||
-rw-r--r-- | source4/torture/rpc/lsa.c | 79 | ||||
-rw-r--r-- | source4/torture/torture.c | 166 |
20 files changed, 1403 insertions, 825 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in index ef3267abd3..5c348733e2 100644 --- a/source4/Makefile.in +++ b/source4/Makefile.in @@ -193,7 +193,9 @@ LIBCLIUTIL_OBJ = libcli/util/asn1.o \ libcli/util/doserr.o libcli/util/errormap.o \ libcli/util/pwd_cache.o libcli/util/clierror.o libcli/util/cliutil.o -LIBRAW_RPC_OBJ = libcli/rpc/rpcparse.o libcli/rpc/rpc_basic.o libcli/rpc/rpc_sec.o +LIBRAW_NDR_OBJ = libcli/ndr/ndr.o libcli/ndr/ndr_basic.o libcli/ndr/ndr_sec.o + +LIBRAW_RPC_OBJ = libcli/rpc/dcerpc.o LIBRAW_OBJ = libcli/raw/rawfile.o libcli/raw/smb_signing.o \ libcli/raw/clisocket.o libcli/raw/clitransport.o \ @@ -205,13 +207,13 @@ LIBRAW_OBJ = libcli/raw/rawfile.o libcli/raw/smb_signing.o \ libcli/raw/rawnegotiate.o libcli/raw/rawfsinfo.o \ libcli/raw/rawfileinfo.o libcli/raw/rawnotify.o \ libcli/raw/rawioctl.o libcli/raw/rawacl.o libcli/raw/rawdcerpc.o \ - $(LIBRAW_RPC_OBJ) $(LIBSAMBA_OBJ) $(LIBCLIUTIL_OBJ) \ + $(LIBRAW_NDR_OBJ) $(LIBRAW_RPC_OBJ) $(LIBSAMBA_OBJ) $(LIBCLIUTIL_OBJ) \ $(RPC_PARSE_OBJ1) $(LIBNTLMSSP_OBJ) $(LIBNMB_OBJ) $(KRBCLIENT_OBJ) LIBSMB_OBJ = libcli/clireadwrite.o libcli/cliconnect.o \ libcli/clifile.o libcli/clilist.o libcli/clitrans2.o \ libcli/clisecdesc.o libcli/climessage.o \ - libcli/clideltree.o libcli/clidcerpc.o \ + libcli/clideltree.o \ $(LIBRAW_OBJ) # LIBDFS_OBJ = libcli/clidfs.o @@ -525,10 +527,12 @@ SMBTORTURE_RAW_OBJ = torture/raw/qfsinfo.o torture/raw/qfileinfo.o torture/raw/s torture/raw/chkpath.o torture/raw/unlink.o torture/raw/read.o torture/raw/context.o \ torture/raw/write.o torture/raw/lock.o torture/raw/rename.o torture/raw/seek.o +SMBTORTURE_RPC_OBJ = torture/rpc/lsa.o + SMBTORTURE_OBJ1 = torture/torture.o torture/torture_util.o torture/nbio.o torture/scanner.o \ torture/utable.o torture/denytest.o torture/mangle_test.o \ torture/aliases.o libcli/raw/clirewrite.o $(SMBTORTURE_RAW_OBJ) \ - rpc_parse/parse_lsa.o + $(SMBTORTURE_RPC_OBJ) rpc_parse/parse_lsa.o SMBTORTURE_OBJ = $(SMBTORTURE_OBJ1) \ $(LIBSMB_OBJ) $(LIBDFS_OBJ) $(PARAM_OBJ) $(LIB_OBJ) diff --git a/source4/include/dcerpc_interfaces.h b/source4/include/dcerpc_interfaces.h deleted file mode 100644 index 831e19c1e3..0000000000 --- a/source4/include/dcerpc_interfaces.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - Unix SMB/CIFS implementation. - DCERPC interface structures - Copyright (C) Tim Potter 2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -struct dcerpc_hdr { - uint8 rpc_vers; /* RPC version */ - uint8 rpc_vers_minor; /* Minor version */ - uint8 ptype; /* Packet type */ - uint8 pfc_flags; /* Fragmentation flags */ - uint8 drep[4]; /* NDR data representation */ - uint16 frag_len; /* Total length of fragment */ - uint32 call_id; /* Call identifier */ -}; - -struct dcerpc_uuid { - uint32 time_low; - uint16 time_mid; - uint16 time_hi_and_version; - uint8 remaining[8]; -}; - -struct syntax_id { - struct dcerpc_uuid if_uuid; - uint32 if_version; -}; - -struct p_ctx_list { - uint16 cont_id; /* Context id */ - uint8 num_ts; /* Number of transfer syntaxes */ - struct syntax_id *as; /* Abstract syntax */ - struct syntax_id *ts; /* Transfer syntaxes */ -}; - -struct dcerpc_bind { - struct { - struct dcerpc_hdr hdr; /* Header */ - uint16 max_xmit_frag; /* Max transmit frag size */ - uint16 max_recv_frag; /* Max receive frag size */ - uint32 assoc_group_id; /* Association group */ - uint8 num_contexts; /* Number of presentation contexts */ - struct p_ctx_list *ctx_list; /* Presentation context list */ - DATA_BLOB auth_verifier; - } in; - struct { - struct dcerpc_hdr hdr; /* Header */ - uint16 max_xmit_frag; /* Max transmit frag size */ - uint16 max_recv_frag; /* Max receive frag size */ - uint32 assoc_group_id; /* Association group */ - DATA_BLOB auth_verifier; - } out; -}; - -struct dcerpc_request { - struct { - struct dcerpc_hdr hdr; - uint32 alloc_hint; /* Allocation hint */ - uint16 cont_id; /* Context id */ - uint16 opnum; /* Operation number */ - DATA_BLOB stub_data; - DATA_BLOB auth_verifier; - } in; - struct { - struct dcerpc_hdr hdr; - uint32 alloc_hint; /* Allocation hint */ - uint8 cancel_count; /* Context id */ - DATA_BLOB stub_data; - DATA_BLOB auth_verifier; - } out; -}; - -struct cli_dcerpc_pipe { - TALLOC_CTX *mem_ctx; - uint16 fnum; - int reference_count; - uint32 call_id; - struct cli_tree *tree; -}; diff --git a/source4/include/includes.h b/source4/include/includes.h index 39b589a49d..68bd3b629f 100644 --- a/source4/include/includes.h +++ b/source4/include/includes.h @@ -776,8 +776,9 @@ extern int errno; #include "mutex.h" -#include "libcli/rpc/librpc.h" -#include "libcli/rpc/rpc_sec.h" +#include "libcli/ndr/libndr.h" +#include "libcli/ndr/ndr_sec.h" +#include "libcli/rpc/dcerpc.h" /* * Type for wide character dirent structure. diff --git a/source4/include/smb.h b/source4/include/smb.h index d0a8e43e81..b791182aa6 100644 --- a/source4/include/smb.h +++ b/source4/include/smb.h @@ -430,7 +430,6 @@ struct vuid_cache { #include "events.h" #include "context.h" #include "smb_interfaces.h" -#include "dcerpc_interfaces.h" #include "ntvfs.h" typedef struct smb_vfs_handle_struct diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 77b73ecd7c..fd393c9db3 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -1610,7 +1610,7 @@ struct smb_trans2 { uint32 timeout; uint8 setup_count; uint16 *setup; - char *trans_name; /* SMBtrans only */ + const char *trans_name; /* SMBtrans only */ DATA_BLOB params; DATA_BLOB data; } in; diff --git a/source4/libcli/clidcerpc.c b/source4/libcli/clidcerpc.c deleted file mode 100644 index fffd4e0941..0000000000 --- a/source4/libcli/clidcerpc.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - Unix SMB/CIFS implementation. - raw dcerpc operations - - Copyright (C) Tim Potter, 2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -struct cli_dcerpc_pipe *cli_dcerpc_pipe_init(struct cli_tree *tree) -{ - struct cli_dcerpc_pipe *p; - - TALLOC_CTX *mem_ctx = talloc_init("cli_dcerpc_tree"); - if (mem_ctx == NULL) - return NULL; - - p = talloc_zero(mem_ctx, sizeof(*p)); - if (!p) { - talloc_destroy(mem_ctx); - return NULL; - } - - p->mem_ctx = mem_ctx; - p->tree = tree; - p->tree->reference_count++; - - return p; -} - -void cli_dcerpc_pipe_close(struct cli_dcerpc_pipe *p) -{ - if (!p) return; - p->reference_count--; - if (p->reference_count <= 0) { - cli_tree_close(p->tree); - talloc_destroy(p->mem_ctx); - } -} - -static void init_dcerpc_hdr(struct dcerpc_hdr *hdr, uint8 ptype, - uint8 pfc_flags, uint32 call_id) -{ - hdr->rpc_vers = 5; - hdr->rpc_vers_minor = 0; - hdr->ptype = ptype; - hdr->pfc_flags = pfc_flags; - hdr->drep[0] = 0x10; /* Little endian */ - hdr->call_id = call_id; -} - -struct syntax_id trans_synt_v2 = -{ - { - 0x8a885d04, 0x1ceb, 0x11c9, - { 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60 } - }, 0x02 -}; - -struct syntax_id synt_netlogon_v2 = -{ - { - 0x8a885d04, 0x1ceb, 0x11c9, - { 0x9f, 0xe8, 0x08, 0x00, - 0x2b, 0x10, 0x48, 0x60 } - }, 0x02 -}; - -struct syntax_id synt_wkssvc_v1 = -{ - { - 0x6bffd098, 0xa112, 0x3610, - { 0x98, 0x33, 0x46, 0xc3, - 0xf8, 0x7e, 0x34, 0x5a } - }, 0x01 -}; - -struct syntax_id synt_srvsvc_v3 = -{ - { - 0x4b324fc8, 0x1670, 0x01d3, - { 0x12, 0x78, 0x5a, 0x47, - 0xbf, 0x6e, 0xe1, 0x88 } - }, 0x03 -}; - -struct syntax_id synt_lsarpc_v0 = -{ - { - 0x12345778, 0x1234, 0xabcd, - { 0xef, 0x00, 0x01, 0x23, - 0x45, 0x67, 0x89, 0xab } - }, 0x00 -}; - -struct syntax_id synt_lsarpc_v0_ds = -{ - { - 0x3919286a, 0xb10c, 0x11d0, - { 0x9b, 0xa8, 0x00, 0xc0, - 0x4f, 0xd9, 0x2e, 0xf5 } - }, 0x00 -}; - -struct syntax_id synt_samr_v1 = -{ - { - 0x12345778, 0x1234, 0xabcd, - { 0xef, 0x00, 0x01, 0x23, - 0x45, 0x67, 0x89, 0xac } - }, 0x01 -}; - -struct syntax_id synt_netlogon_v1 = -{ - { - 0x12345678, 0x1234, 0xabcd, - { 0xef, 0x00, 0x01, 0x23, - 0x45, 0x67, 0xcf, 0xfb } - }, 0x01 -}; - -struct syntax_id synt_winreg_v1 = -{ - { - 0x338cd001, 0x2244, 0x31f1, - { 0xaa, 0xaa, 0x90, 0x00, - 0x38, 0x00, 0x10, 0x03 } - }, 0x01 -}; - -struct syntax_id synt_spoolss_v1 = -{ - { - 0x12345678, 0x1234, 0xabcd, - { 0xef, 0x00, 0x01, 0x23, - 0x45, 0x67, 0x89, 0xab } - }, 0x01 -}; - -struct syntax_id synt_netdfs_v3 = -{ - { - 0x4fc742e0, 0x4a10, 0x11cf, - { 0x82, 0x73, 0x00, 0xaa, - 0x00, 0x4a, 0xe6, 0x73 } - }, 0x03 -}; - -struct known_pipes { - const char *client_pipe; - struct p_ctx_list ctx_list; -}; - -const struct known_pipes known_pipes[] = -{ - { PIPE_LSARPC , { 0, 1, &synt_lsarpc_v0, &trans_synt_v2 }}, - { PIPE_SAMR , { 0, 1, &synt_samr_v1, &trans_synt_v2 }}, - { PIPE_NETLOGON, { 0, 1, &synt_netlogon_v1, &trans_synt_v2 }}, - { PIPE_SRVSVC , { 0, 1, &synt_srvsvc_v3 , &trans_synt_v2 }}, - { PIPE_WKSSVC , { 0, 1, &synt_wkssvc_v1 , &trans_synt_v2 }}, - { PIPE_WINREG , { 0, 1, &synt_winreg_v1 , &trans_synt_v2 }}, - { PIPE_SPOOLSS , { 0, 1, &synt_spoolss_v1, &trans_synt_v2 }}, - { PIPE_NETDFS , { 0, 1, &synt_netdfs_v3 , &trans_synt_v2 }}, - { NULL , { 0, 0, NULL, NULL }} -}; - -/* Perform a bind using the given syntaxes */ - -NTSTATUS cli_dcerpc_bind(struct cli_dcerpc_pipe *p, int num_contexts, - struct p_ctx_list *ctx_list) -{ - TALLOC_CTX *mem_ctx; - struct dcerpc_bind parms; - NTSTATUS status; - - mem_ctx = talloc_init("cli_dcerpc_bind"); - - ZERO_STRUCT(parms); - - init_dcerpc_hdr(&parms.in.hdr, RPC_BIND, RPC_FLG_FIRST|RPC_FLG_LAST, - p->call_id++); - - parms.in.max_xmit_frag = 5680; - parms.in.max_recv_frag = 5680; - parms.in.num_contexts = num_contexts; - parms.in.ctx_list = ctx_list; - - status = dcerpc_raw_bind(p, &parms); - - talloc_destroy(mem_ctx); - - return status; -} - -/* Perform a bind using the given well-known pipe name */ - -NTSTATUS cli_dcerpc_bind_byname(struct cli_dcerpc_pipe *p, - const char *pipe_name) -{ - const struct known_pipes *pi; - - for (pi = known_pipes; pi->client_pipe; pi++) { - if (strequal(&pi->client_pipe[5], pipe_name)) - break; - } - - if (pi->client_pipe == NULL) - return NT_STATUS_UNSUCCESSFUL; - - - return cli_dcerpc_bind(p, 1, &pi->ctx_list); -} - -NTSTATUS cli_dcerpc_request(struct cli_dcerpc_pipe *p, uint16 opnum, - DATA_BLOB stub_data) -{ - TALLOC_CTX *mem_ctx; - struct dcerpc_request parms; - NTSTATUS status; - - mem_ctx = talloc_init("cli_dcerpc_request"); - - ZERO_STRUCT(parms); - - init_dcerpc_hdr(&parms.in.hdr, RPC_REQUEST, - RPC_FLG_FIRST|RPC_FLG_LAST, p->call_id++); - - parms.in.alloc_hint = 0; - parms.in.cont_id = 0; - parms.in.opnum = opnum; - parms.in.stub_data = stub_data; - - status = dcerpc_raw_request(p, &parms); - - talloc_destroy(mem_ctx); - - return status; -} diff --git a/source4/libcli/rpc/librpc.h b/source4/libcli/ndr/libndr.h index f4f7101c90..4369ebeb30 100644 --- a/source4/libcli/rpc/librpc.h +++ b/source4/libcli/ndr/libndr.h @@ -31,7 +31,7 @@ are being kept deliberately very simple, and are not tied to a particular transport */ -struct ndr_parse { +struct ndr_pull { uint32 flags; /* LIBNDR_FLAG_* */ char *data; uint32 data_size; @@ -39,11 +39,25 @@ struct ndr_parse { TALLOC_CTX *mem_ctx; }; -struct ndr_parse_save { +struct ndr_pull_save { uint32 data_size; uint32 offset; }; + +/* structure passed to functions that generate NDR formatted data */ +struct ndr_push { + uint32 flags; /* LIBNDR_FLAG_* */ + char *data; + uint32 alloc_size; + uint32 offset; + TALLOC_CTX *mem_ctx; +}; + +#define NDR_BASE_MARSHALL_SIZE 1024 + + + #define LIBNDR_FLAG_BIGENDIAN 1 diff --git a/source4/libcli/rpc/rpcparse.c b/source4/libcli/ndr/ndr.c index 41e6919b72..d9a5ff7735 100644 --- a/source4/libcli/rpc/rpcparse.c +++ b/source4/libcli/ndr/ndr.c @@ -1,6 +1,8 @@ /* Unix SMB/CIFS implementation. + libndr interface + Copyright (C) Andrew Tridgell 2003 This program is free software; you can redistribute it and/or modify @@ -19,7 +21,10 @@ */ /* - this provides the core routines for MSNDR parsing functions + this provides the core routines for NDR parsing functions + + see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details + of NDR encoding rules */ #include "includes.h" @@ -27,9 +32,9 @@ /* initialise a ndr parse structure from a data blob */ -struct ndr_parse *ndr_parse_init_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx) +struct ndr_pull *ndr_pull_init_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx) { - struct ndr_parse *ndr; + struct ndr_pull *ndr; ndr = talloc(mem_ctx, sizeof(*ndr)); if (!ndr) return NULL; @@ -52,7 +57,7 @@ struct ndr_parse *ndr_parse_init_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx) the 'ofs' parameter indicates how many bytes back from the current offset in the buffer the 'size' number of bytes starts */ -NTSTATUS ndr_parse_limit_size(struct ndr_parse *ndr, uint32 size, uint32 ofs) +NTSTATUS ndr_pull_limit_size(struct ndr_pull *ndr, uint32 size, uint32 ofs) { uint32 new_size; new_size = ndr->offset + size - ofs; @@ -69,7 +74,7 @@ NTSTATUS ndr_parse_limit_size(struct ndr_parse *ndr, uint32 size, uint32 ofs) /* advance by 'size' bytes */ -NTSTATUS ndr_parse_advance(struct ndr_parse *ndr, uint32 size) +NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32 size) { ndr->offset += size; if (ndr->offset > ndr->data_size) { @@ -81,7 +86,7 @@ NTSTATUS ndr_parse_advance(struct ndr_parse *ndr, uint32 size) /* set the parse offset to 'ofs' */ -NTSTATUS ndr_parse_set_offset(struct ndr_parse *ndr, uint32 ofs) +NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32 ofs) { ndr->offset = ofs; if (ndr->offset > ndr->data_size) { @@ -91,15 +96,89 @@ NTSTATUS ndr_parse_set_offset(struct ndr_parse *ndr, uint32 ofs) } /* save the offset/size of the current ndr state */ -void ndr_parse_save(struct ndr_parse *ndr, struct ndr_parse_save *save) +void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save) { save->offset = ndr->offset; save->data_size = ndr->data_size; } /* restore the size/offset of a ndr structure */ -void ndr_parse_restore(struct ndr_parse *ndr, struct ndr_parse_save *save) +void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save) { ndr->offset = save->offset; ndr->data_size = save->data_size; } + + + + +/* create a ndr_push structure, ready for some marshalling */ +struct ndr_push *ndr_push_init(void) +{ + struct ndr_push *ndr; + TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init"); + if (!mem_ctx) return NULL; + + ndr = talloc(mem_ctx, sizeof(*ndr)); + if (!ndr) { + talloc_destroy(mem_ctx); + return NULL; + } + + ndr->mem_ctx = mem_ctx; + ndr->flags = 0; + ndr->alloc_size = NDR_BASE_MARSHALL_SIZE; + ndr->data = talloc(ndr->mem_ctx, ndr->alloc_size); + if (!ndr->data) { + ndr_push_free(ndr); + return NULL; + } + ndr->offset = 0; + + return ndr; +} + +/* free a ndr_push structure */ +void ndr_push_free(struct ndr_push *ndr) +{ + talloc_destroy(ndr->mem_ctx); +} + + +/* return a DATA_BLOB structure for the current ndr_push marshalled data */ +DATA_BLOB ndr_push_blob(struct ndr_push *ndr) +{ + DATA_BLOB blob; + blob.data = ndr->data; + blob.length = ndr->offset; + return blob; +} + + +/* + expand the available space in the buffer to 'size' +*/ +NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32 size) +{ + if (ndr->alloc_size >= size) { + return NT_STATUS_OK; + } + + ndr->alloc_size = size; + ndr->data = realloc(ndr->data, ndr->alloc_size); + if (!ndr->data) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/* + set the push offset to 'ofs' +*/ +NTSTATUS ndr_push_set_offset(struct ndr_push *ndr, uint32 ofs) +{ + NDR_CHECK(ndr_push_expand(ndr, ofs)); + ndr->offset = ofs; + return NT_STATUS_OK; +} diff --git a/source4/libcli/rpc/rpc_basic.c b/source4/libcli/ndr/ndr_basic.c index 5ff17f9d99..736ad0b762 100644 --- a/source4/libcli/rpc/rpc_basic.c +++ b/source4/libcli/ndr/ndr_basic.c @@ -22,13 +22,13 @@ #include "includes.h" -#define NDR_NEED_BYTES(ndr, n) do { \ +#define NDR_PULL_NEED_BYTES(ndr, n) do { \ if ((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size) { \ return NT_STATUS_BUFFER_TOO_SMALL; \ } \ } while(0) -#define NDR_ALIGN(ndr, n) do { \ +#define NDR_PULL_ALIGN(ndr, n) do { \ ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ if (ndr->offset >= ndr->data_size) { \ return NT_STATUS_BUFFER_TOO_SMALL; \ @@ -38,10 +38,10 @@ /* parse a GUID */ -NTSTATUS ndr_parse_guid(struct ndr_parse *ndr, GUID *guid) +NTSTATUS ndr_pull_guid(struct ndr_pull *ndr, GUID *guid) { int i; - NDR_NEED_BYTES(ndr, GUID_SIZE); + NDR_PULL_NEED_BYTES(ndr, GUID_SIZE); for (i=0;i<GUID_SIZE;i++) { guid->info[i] = CVAL(ndr->data, ndr->offset + i); } @@ -53,9 +53,9 @@ NTSTATUS ndr_parse_guid(struct ndr_parse *ndr, GUID *guid) /* parse a u8 */ -NTSTATUS ndr_parse_u8(struct ndr_parse *ndr, uint8 *v) +NTSTATUS ndr_pull_u8(struct ndr_pull *ndr, uint8 *v) { - NDR_NEED_BYTES(ndr, 1); + NDR_PULL_NEED_BYTES(ndr, 1); *v = CVAL(ndr->data, ndr->offset); ndr->offset += 1; return NT_STATUS_OK; @@ -65,10 +65,10 @@ NTSTATUS ndr_parse_u8(struct ndr_parse *ndr, uint8 *v) /* parse a u16 */ -NTSTATUS ndr_parse_u16(struct ndr_parse *ndr, uint16 *v) +NTSTATUS ndr_pull_u16(struct ndr_pull *ndr, uint16 *v) { - NDR_ALIGN(ndr, 2); - NDR_NEED_BYTES(ndr, 2); + NDR_PULL_ALIGN(ndr, 2); + NDR_PULL_NEED_BYTES(ndr, 2); if (ndr->flags & LIBNDR_FLAG_BIGENDIAN) { *v = RSVAL(ndr->data, ndr->offset); } else { @@ -82,10 +82,10 @@ NTSTATUS ndr_parse_u16(struct ndr_parse *ndr, uint16 *v) /* parse a u32 */ -NTSTATUS ndr_parse_u32(struct ndr_parse *ndr, uint32 *v) +NTSTATUS ndr_pull_u32(struct ndr_pull *ndr, uint32 *v) { - NDR_ALIGN(ndr, 4); - NDR_NEED_BYTES(ndr, 4); + NDR_PULL_ALIGN(ndr, 4); + NDR_PULL_NEED_BYTES(ndr, 4); if (ndr->flags & LIBNDR_FLAG_BIGENDIAN) { *v = RIVAL(ndr->data, ndr->offset); } else { @@ -95,3 +95,46 @@ NTSTATUS ndr_parse_u32(struct ndr_parse *ndr, uint32 *v) return NT_STATUS_OK; } + + +#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, ndr->offset+(n))) + +#define NDR_PUSH_ALIGN(ndr, n) do { \ + ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ + NDR_CHECK(ndr_push_expand(ndr, ndr->offset)); \ +} while(0) + +/* + push a u8 +*/ +NTSTATUS ndr_push_u8(struct ndr_push *ndr, uint8 v) +{ + NDR_PUSH_NEED_BYTES(ndr, 1); + SCVAL(ndr->data, ndr->offset, v); + ndr->offset += 1; + return NT_STATUS_OK; +} + +/* + push a u16 +*/ +NTSTATUS ndr_push_u16(struct ndr_push *ndr, uint16 v) +{ + NDR_PUSH_ALIGN(ndr, 2); + NDR_PUSH_NEED_BYTES(ndr, 2); + SSVAL(ndr->data, ndr->offset, v); + ndr->offset += 2; + return NT_STATUS_OK; +} + +/* + push a u32 +*/ +NTSTATUS ndr_push_u32(struct ndr_push *ndr, uint32 v) +{ + NDR_PUSH_ALIGN(ndr, 4); + NDR_PUSH_NEED_BYTES(ndr, 4); + SIVAL(ndr->data, ndr->offset, v); + ndr->offset += 4; + return NT_STATUS_OK; +} diff --git a/source4/libcli/ndr/ndr_sec.c b/source4/libcli/ndr/ndr_sec.c new file mode 100644 index 0000000000..6b83a09d7a --- /dev/null +++ b/source4/libcli/ndr/ndr_sec.c @@ -0,0 +1,201 @@ +/* + Unix SMB/CIFS implementation. + + routines for marshalling/unmarshalling security descriptors + and related structures + + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include "includes.h" + +/* + parse a security_ace +*/ +NTSTATUS ndr_pull_security_ace(struct ndr_pull *ndr, struct security_ace *ace) +{ + uint16 size; + struct ndr_pull_save save; + + ndr_pull_save(ndr, &save); + + NDR_CHECK(ndr_pull_u8(ndr, &ace->type)); + NDR_CHECK(ndr_pull_u8(ndr, &ace->flags)); + NDR_CHECK(ndr_pull_u16(ndr, &size)); + NDR_CHECK(ndr_pull_limit_size(ndr, size, 4)); + + NDR_CHECK(ndr_pull_u32(ndr, &ace->access_mask)); + + if (sec_ace_object(ace->type)) { + NDR_ALLOC(ndr, ace->obj); + NDR_CHECK(ndr_pull_u32(ndr, &ace->obj->flags)); + if (ace->obj->flags & SEC_ACE_OBJECT_PRESENT) { + NDR_CHECK(ndr_pull_guid(ndr, &ace->obj->object_guid)); + } + if (ace->obj->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) { + NDR_CHECK(ndr_pull_guid(ndr, &ace->obj->inherit_guid)); + } + } + + + NDR_CHECK(ndr_pull_dom_sid(ndr, &ace->trustee)); + + ndr_pull_restore(ndr, &save); + NDR_CHECK(ndr_pull_advance(ndr, size)); + + return NT_STATUS_OK; +} + +/* + parse a security_acl +*/ +NTSTATUS ndr_pull_security_acl(struct ndr_pull *ndr, struct security_acl *acl) +{ + int i; + uint16 size; + struct ndr_pull_save save; + + ndr_pull_save(ndr, &save); + + NDR_CHECK(ndr_pull_u16(ndr, &acl->revision)); + NDR_CHECK(ndr_pull_u16(ndr, &size)); + NDR_CHECK(ndr_pull_limit_size(ndr, size, 4)); + NDR_CHECK(ndr_pull_u32(ndr, &acl->num_aces)); + + NDR_ALLOC_N(ndr, acl->aces, acl->num_aces); + + for (i=0;i<acl->num_aces;i++) { + NDR_CHECK(ndr_pull_security_ace(ndr, &acl->aces[i])); + } + + ndr_pull_restore(ndr, &save); + NDR_CHECK(ndr_pull_advance(ndr, size)); + + return NT_STATUS_OK; +} + +/* + parse a security_acl offset and structure +*/ +NTSTATUS ndr_pull_security_acl_ofs(struct ndr_pull *ndr, struct security_acl **acl) +{ + uint32 ofs; + struct ndr_pull_save save; + + NDR_CHECK(ndr_pull_u32(ndr, &ofs)); + if (ofs == 0) { + /* it is valid for an acl ptr to be NULL */ + *acl = NULL; + return NT_STATUS_OK; + } + + ndr_pull_save(ndr, &save); + NDR_CHECK(ndr_pull_set_offset(ndr, ofs)); + NDR_ALLOC(ndr, *acl); + NDR_CHECK(ndr_pull_security_acl(ndr, *acl)); + ndr_pull_restore(ndr, &save); + + return NT_STATUS_OK; +} + + +/* + parse a dom_sid +*/ +NTSTATUS ndr_pull_dom_sid(struct ndr_pull *ndr, struct dom_sid *sid) +{ + int i; + + NDR_CHECK(ndr_pull_u8(ndr, &sid->sid_rev_num)); + NDR_CHECK(ndr_pull_u8(ndr, &sid->num_auths)); + for (i=0;i<6;i++) { + NDR_CHECK(ndr_pull_u8(ndr, &sid->id_auth[i])); + } + + NDR_ALLOC_N(ndr, sid->sub_auths, sid->num_auths); + + for (i=0;i<sid->num_auths;i++) { + NDR_CHECK(ndr_pull_u32(ndr, &sid->sub_auths[i])); + } + + return NT_STATUS_OK; +} + +/* + parse a dom_sid offset and structure +*/ +NTSTATUS ndr_pull_dom_sid_ofs(struct ndr_pull *ndr, struct dom_sid **sid) +{ + uint32 ofs; + struct ndr_pull_save save; + + NDR_CHECK(ndr_pull_u32(ndr, &ofs)); + if (ofs == 0) { + /* it is valid for a dom_sid ptr to be NULL */ + *sid = NULL; + return NT_STATUS_OK; + } + + ndr_pull_save(ndr, &save); + NDR_CHECK(ndr_pull_set_offset(ndr, ofs)); + NDR_ALLOC(ndr, *sid); + NDR_CHECK(ndr_pull_dom_sid(ndr, *sid)); + ndr_pull_restore(ndr, &save); + + return NT_STATUS_OK; +} + +/* + parse a security descriptor +*/ +NTSTATUS ndr_pull_security_descriptor(struct ndr_pull *ndr, + struct security_descriptor **sd) +{ + NDR_ALLOC(ndr, *sd); + + NDR_CHECK(ndr_pull_u8(ndr, &(*sd)->revision)); + NDR_CHECK(ndr_pull_u16(ndr, &(*sd)->type)); + NDR_CHECK(ndr_pull_dom_sid_ofs(ndr, &(*sd)->owner_sid)); + NDR_CHECK(ndr_pull_dom_sid_ofs(ndr, &(*sd)->group_sid)); + NDR_CHECK(ndr_pull_security_acl_ofs(ndr, &(*sd)->sacl)); + NDR_CHECK(ndr_pull_security_acl_ofs(ndr, &(*sd)->dacl)); + + return NT_STATUS_OK; +} + +/* + generate a ndr security descriptor +*/ +NTSTATUS ndr_push_security_descriptor(struct ndr_push *ndr, + struct security_descriptor *sd) +{ + uint32 var_offset; + + var_offset = 20; + + NDR_CHECK(ndr_push_u8(ndr, sd->revision)); + NDR_CHECK(ndr_push_u16(ndr, sd->type)); +/* + NDR_CHECK(ndr_push_dom_sid_ofs(ndr, sd->owner_sid, &var_offset)); + NDR_CHECK(ndr_push_dom_sid_ofs(ndr, sd->group_sid, &var_offset)); + NDR_CHECK(ndr_push_security_acl_ofs(ndr, sd->sacl, &var_offset)); + NDR_CHECK(ndr_push_security_acl_ofs(ndr, sd->dacl, &var_offset)); +*/ + return NT_STATUS_OK; +} + diff --git a/source4/libcli/rpc/rpc_sec.h b/source4/libcli/ndr/ndr_sec.h index 3cda400eb2..0c9d542006 100644 --- a/source4/libcli/rpc/rpc_sec.h +++ b/source4/libcli/ndr/ndr_sec.h @@ -79,3 +79,12 @@ struct smb_query_secdesc { struct security_descriptor *sd; } out; }; + +/* set security descriptor */ +struct smb_set_secdesc { + struct { + uint16 fnum; + uint32 secinfo_flags; + struct security_descriptor *sd; + } in; +}; diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c index 406491e432..9d154e10cd 100644 --- a/source4/libcli/raw/clisession.c +++ b/source4/libcli/raw/clisession.c @@ -318,8 +318,8 @@ static NTSTATUS smb_raw_session_setup_generic_nt1(struct cli_session *session, s2.nt1.in.os = "Unix"; s2.nt1.in.lanman = "Samba"; - if (session->transport->negotiate.sec_mode & - NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) { + if (s2.nt1.in.user[0] && + (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) { s2.nt1.in.password1 = lanman_blob(parms->generic.in.password, session->transport->negotiate.secblob); s2.nt1.in.password2 = nt_blob(parms->generic.in.password, diff --git a/source4/libcli/raw/rawacl.c b/source4/libcli/raw/rawacl.c index 4cd3338ec5..c45152381d 100644 --- a/source4/libcli/raw/rawacl.c +++ b/source4/libcli/raw/rawacl.c @@ -58,7 +58,7 @@ NTSTATUS smb_raw_query_secdesc_recv(struct cli_request *req, { NTSTATUS status; struct smb_nttrans nt; - struct ndr_parse *rpc; + struct ndr_pull *ndr; status = smb_raw_nttrans_recv(req, mem_ctx, &nt); if (!NT_STATUS_IS_OK(status)) { @@ -73,12 +73,12 @@ NTSTATUS smb_raw_query_secdesc_recv(struct cli_request *req, nt.out.data.length = IVAL(nt.out.params.data, 0); - rpc = ndr_parse_init_blob(&nt.out.data, mem_ctx); - if (!rpc) { + ndr = ndr_pull_init_blob(&nt.out.data, mem_ctx); + if (!ndr) { return NT_STATUS_INVALID_PARAMETER; } - status = ndr_parse_security_descriptor(rpc, &query->out.sd); + status = ndr_pull_security_descriptor(ndr, &query->out.sd); return NT_STATUS_OK; } @@ -95,3 +95,47 @@ NTSTATUS smb_raw_query_secdesc(struct cli_tree *tree, return smb_raw_query_secdesc_recv(req, mem_ctx, query); } + + +/**************************************************************************** +set file ACL (async send) +****************************************************************************/ +struct cli_request *smb_raw_set_secdesc_send(struct cli_tree *tree, + struct smb_set_secdesc *set) +{ + struct smb_nttrans nt; + uint8 params[8]; + struct ndr_push *ndr; + struct cli_request *req; + NTSTATUS status; + + nt.in.max_setup = 0; + nt.in.max_param = 0; + nt.in.max_data = 0; + nt.in.setup_count = 0; + nt.in.function = NT_TRANSACT_SET_SECURITY_DESC; + nt.in.setup = NULL; + + SSVAL(params, 0, set->in.fnum); + SSVAL(params, 2, 0); /* padding */ + SIVAL(params, 4, set->in.secinfo_flags); + + nt.in.params.data = params; + nt.in.params.length = 8; + + ndr = ndr_push_init(); + if (!ndr) return NULL; + +// status = ndr_push_security_descriptor(ndr, set->in.sd); + if (!NT_STATUS_IS_OK(status)) { + ndr_push_free(ndr); + return NULL; + } + + nt.in.data = ndr_push_blob(ndr); + + req = smb_raw_nttrans_send(tree, &nt); + + ndr_push_free(ndr); + return req; +} diff --git a/source4/libcli/raw/rawdcerpc.c b/source4/libcli/raw/rawdcerpc.c index 1cc034de78..4a5159948d 100644 --- a/source4/libcli/raw/rawdcerpc.c +++ b/source4/libcli/raw/rawdcerpc.c @@ -2,7 +2,8 @@ Unix SMB/CIFS implementation. raw dcerpc operations - Copyright (C) Tim Potter, 2003 + Copyright (C) Tim Potter 2003 + Copyright (C) Andrew Tridgell 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,202 +22,62 @@ #include "includes.h" -static int put_uuid(char *data, int offset, struct dcerpc_uuid *uuid) -{ - int i; - - SIVAL(data, offset, uuid->time_low); offset += 4; - SSVAL(data, offset, uuid->time_mid); offset += 2; - SSVAL(data, offset, uuid->time_hi_and_version); offset += 2; - for (i = 0; i < 8; i++) - SCVAL(data, offset + i, uuid->remaining[i]); - offset += 8; - - return offset; -} - -DATA_BLOB dcerpc_raw_bind_setup(struct dcerpc_bind *parms) -{ - int i, offset, size; - char *data; - - /* Allocate storage for bind request */ - - size = 28; - for (i = 0; i < parms->in.num_contexts; i++) { - size += 24; /* as header + uuid */ - size += 20 * parms->in.ctx_list[i].num_ts; /* xfer syntaxes */ - } - size += parms->in.auth_verifier.length; - - data = smb_xmalloc(size); - memset(data, 0, size); - - parms->in.hdr.frag_len = size; - - /* Create bind request */ - - SCVAL(data, 0, parms->in.hdr.rpc_vers); - SCVAL(data, 1, parms->in.hdr.rpc_vers_minor); - SCVAL(data, 2, parms->in.hdr.ptype); - SCVAL(data, 3, parms->in.hdr.pfc_flags); - for (i = 0; i < 4; i++) - SCVAL(data, 4 + i, parms->in.hdr.drep[i]); - SSVAL(data, 8, parms->in.hdr.frag_len); - SSVAL(data, 10, parms->in.auth_verifier.length); - SIVAL(data, 12, parms->in.hdr.call_id); - - SSVAL(data, 16, parms->in.max_xmit_frag); - SSVAL(data, 18, parms->in.max_recv_frag); - SIVAL(data, 20, parms->in.assoc_group_id); - SIVAL(data, 24, parms->in.num_contexts); - - offset = 28; - for (i = 0; i < parms->in.num_contexts; i++) { - struct p_ctx_list *ctx = &parms->in.ctx_list[i]; - int j; - - SSVAL(data, offset, ctx->cont_id); offset += 2; - SSVAL(data, offset, ctx->num_ts); offset += 2; - offset = put_uuid(data, offset, &ctx->as->if_uuid); - SIVAL(data, offset, ctx->as->if_version); offset += 4; - for (j = 0; j < ctx->num_ts; j++) { - offset = put_uuid(data, offset, &ctx->ts[i].if_uuid); - SIVAL(data, offset, ctx->ts[i].if_version); - offset += 4; - } - } - - if (parms->in.auth_verifier.length) - memcpy(&data[offset], parms->in.auth_verifier.data, - parms->in.auth_verifier.length); - - return data_blob(data, size); -} - -NTSTATUS dcerpc_raw_bind_send(struct cli_dcerpc_pipe *p, - struct dcerpc_bind *parms) +struct cli_request *dcerpc_raw_send(struct dcerpc_pipe *p, DATA_BLOB *blob) { struct smb_trans2 trans; - DATA_BLOB blob; - NTSTATUS result; uint16 setup[2]; + struct cli_request *req; + TALLOC_CTX *mem_ctx; - blob = dcerpc_raw_bind_setup(parms); + mem_ctx = talloc_init("dcerpc_raw_send"); + if (!mem_ctx) return NULL; - ZERO_STRUCT(trans); + trans.in.data = *blob; + trans.in.params = data_blob(NULL, 0); + + setup[0] = TRANSACT_DCERPCCMD; + setup[1] = p->fnum; - trans.in.max_data = blob.length; + trans.in.max_param = 0; + trans.in.max_data = 0x8000; trans.in.setup_count = 2; trans.in.setup = setup; trans.in.trans_name = "\\PIPE\\"; - setup[0] = TRANSACT_DCERPCCMD; - setup[1] = p->fnum; - - trans.in.data = blob; - - result = smb_raw_trans(p->tree, p->mem_ctx, &trans); - - data_blob_free(&blob); + req = smb_raw_trans_send(p->tree, &trans); - return result; -} + talloc_destroy(mem_ctx); -NTSTATUS dcerpc_raw_bind_recv(struct cli_dcerpc_pipe *p, - struct dcerpc_bind *parms) -{ - return NT_STATUS_UNSUCCESSFUL; + return req; } -NTSTATUS dcerpc_raw_bind(struct cli_dcerpc_pipe *p, struct dcerpc_bind *parms) -{ - NTSTATUS result; - - result = dcerpc_raw_bind_send(p, parms); - if (NT_STATUS_IS_ERR(result)) - return result; - return dcerpc_raw_bind_recv(p, parms); -} - -DATA_BLOB dcerpc_raw_request_setup(struct dcerpc_request *parms) -{ - int size, i; - char *data; - - /* Allocate storage for request */ - - size = 24 + parms->in.stub_data.length; - - data = smb_xmalloc(size); - memset(data, 0, size); - - parms->in.hdr.frag_len = size; - parms->in.alloc_hint = parms->in.stub_data.length; - - SCVAL(data, 0, parms->in.hdr.rpc_vers); - SCVAL(data, 1, parms->in.hdr.rpc_vers_minor); - SCVAL(data, 2, parms->in.hdr.ptype); - SCVAL(data, 3, parms->in.hdr.pfc_flags); - for (i = 0; i < 4; i++) - SCVAL(data, 4 + i, parms->in.hdr.drep[i]); - SSVAL(data, 8, parms->in.hdr.frag_len); - SSVAL(data, 10, parms->in.auth_verifier.length); - SIVAL(data, 12, parms->in.hdr.call_id); - - SIVAL(data, 16, parms->in.alloc_hint); - SSVAL(data, 20, parms->in.cont_id); - SSVAL(data, 22, parms->in.opnum); - - if (parms->in.stub_data.length) - memcpy(&data[24], parms->in.stub_data.data, - parms->in.stub_data.length); - - return data_blob(data, size); -} - -NTSTATUS dcerpc_raw_request_send(struct cli_dcerpc_pipe *p, - struct dcerpc_request *parms) +NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p, + struct cli_request *req, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) { struct smb_trans2 trans; - DATA_BLOB blob; - NTSTATUS result; - uint16 setup[2]; - - blob = dcerpc_raw_request_setup(parms); - - ZERO_STRUCT(trans); + NTSTATUS status; - trans.in.max_data = blob.length; - trans.in.setup_count = 2; - trans.in.setup = setup; - trans.in.trans_name = "\\PIPE\\"; - - setup[0] = TRANSACT_DCERPCCMD; - setup[1] = p->fnum; - - trans.in.data = blob; - - result = smb_raw_trans(p->tree, p->mem_ctx, &trans); + status = smb_raw_trans_recv(req, mem_ctx, &trans); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - data_blob_free(&blob); + if (blob) { + *blob = trans.out.data; + } - return result; + return status; } -NTSTATUS dcerpc_raw_request_recv(struct cli_dcerpc_pipe *p, - struct dcerpc_request *parms) +NTSTATUS dcerpc_raw_packet(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *request_blob, + DATA_BLOB *reply_blob) { - return NT_STATUS_UNSUCCESSFUL; -} - -NTSTATUS dcerpc_raw_request(struct cli_dcerpc_pipe *p, - struct dcerpc_request *parms) -{ - NTSTATUS result; - - result = dcerpc_raw_request_send(p, parms); - if (NT_STATUS_IS_ERR(result)) - return result; - return dcerpc_raw_request_recv(p, parms); + struct cli_request *req; + req = dcerpc_raw_send(p, request_blob); + return dcerpc_raw_recv(p, req, mem_ctx, reply_blob); } + diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c index 430cf925a6..4c7da6ec4d 100644 --- a/source4/libcli/raw/rawsearch.c +++ b/source4/libcli/raw/rawsearch.c @@ -307,7 +307,7 @@ static int parse_trans2_search(struct cli_tree *tree, case RAW_SEARCH_FULL_DIRECTORY_INFO: if (blob->length < 69) return -1; - ofs = IVAL(blob->data, 0); + ofs = IVAL(blob->data, 0); data->full_directory_info.file_index = IVAL(blob->data, 4); data->full_directory_info.create_time = cli_pull_nttime(blob->data, 8); data->full_directory_info.access_time = cli_pull_nttime(blob->data, 16); @@ -364,7 +364,7 @@ static int parse_trans2_search(struct cli_tree *tree, case RAW_SEARCH_ID_FULL_DIRECTORY_INFO: if (blob->length < 81) return -1; - ofs = IVAL(blob->data, 0); + ofs = IVAL(blob->data, 0); data->id_full_directory_info.file_index = IVAL(blob->data, 4); data->id_full_directory_info.create_time = cli_pull_nttime(blob->data, 8); data->id_full_directory_info.access_time = cli_pull_nttime(blob->data, 16); @@ -385,7 +385,7 @@ static int parse_trans2_search(struct cli_tree *tree, case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO: if (blob->length < 105) return -1; - ofs = IVAL(blob->data, 0); + ofs = IVAL(blob->data, 0); data->id_both_directory_info.file_index = IVAL(blob->data, 4); data->id_both_directory_info.create_time = cli_pull_nttime(blob->data, 8); data->id_both_directory_info.access_time = cli_pull_nttime(blob->data, 16); @@ -481,7 +481,7 @@ NTSTATUS smb_raw_search_first(struct cli_tree *tree, return status; } - if (p_blob.length != 10) { + if (p_blob.length < 10) { DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n", p_blob.length)); return NT_STATUS_INVALID_PARAMETER; diff --git a/source4/libcli/rpc/dcerpc.c b/source4/libcli/rpc/dcerpc.c new file mode 100644 index 0000000000..56c6d95482 --- /dev/null +++ b/source4/libcli/rpc/dcerpc.c @@ -0,0 +1,644 @@ +/* + Unix SMB/CIFS implementation. + raw dcerpc operations + + Copyright (C) Tim Potter 2003 + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* initialise a dcerpc pipe. This currently assumes a SMB named pipe + transport */ +struct dcerpc_pipe *dcerpc_pipe_init(struct cli_tree *tree) +{ + struct dcerpc_pipe *p; + + TALLOC_CTX *mem_ctx = talloc_init("cli_dcerpc_tree"); + if (mem_ctx == NULL) + return NULL; + + p = talloc(mem_ctx, sizeof(*p)); + if (!p) { + talloc_destroy(mem_ctx); + return NULL; + } + + p->mem_ctx = mem_ctx; + p->tree = tree; + p->tree->reference_count++; + p->call_id = 1; + p->fnum = 0; + + return p; +} + +/* close down a dcerpc over SMB pipe */ +void dcerpc_pipe_close(struct dcerpc_pipe *p) +{ + if (!p) return; + p->reference_count--; + if (p->reference_count <= 0) { + cli_tree_close(p->tree); + talloc_destroy(p->mem_ctx); + } +} + +#define BLOB_CHECK_BOUNDS(blob, offset, len) do { \ + if ((offset) > blob->length || (blob->length - (offset) < (len))) { \ + return NT_STATUS_INVALID_PARAMETER; \ + } \ +} while (0) + +#define DCERPC_ALIGN(offset, n) do { \ + (offset) = ((offset) + ((n)-1)) & ~((n)-1); \ +} while (0) + +/* + pull a wire format uuid into a string. This will consume 16 bytes +*/ +static char *dcerpc_pull_uuid(char *data, TALLOC_CTX *mem_ctx) +{ + uint32 time_low; + uint16 time_mid, time_hi_and_version; + uint8 clock_seq_hi_and_reserved; + uint8 clock_seq_low; + uint8 node[6]; + int i; + + time_low = IVAL(data, 0); + time_mid = SVAL(data, 4); + time_hi_and_version = SVAL(data, 6); + clock_seq_hi_and_reserved = CVAL(data, 8); + clock_seq_low = CVAL(data, 9); + for (i=0;i<6;i++) { + node[i] = CVAL(data, 10 + i); + } + + return talloc_asprintf(mem_ctx, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + time_low, time_mid, time_hi_and_version, + clock_seq_hi_and_reserved, clock_seq_low, + node[0], node[1], node[2], node[3], node[4], node[5]); +} + +/* + push a uuid_str into wire format. It will consume 16 bytes +*/ +static NTSTATUS push_uuid_str(char *data, const char *uuid_str) +{ + uint32 time_low; + uint32 time_mid, time_hi_and_version; + uint32 clock_seq_hi_and_reserved; + uint32 clock_seq_low; + uint32 node[6]; + int i; + + if (11 != sscanf(uuid_str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &time_low, &time_mid, &time_hi_and_version, + &clock_seq_hi_and_reserved, &clock_seq_low, + &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) { + return NT_STATUS_INVALID_PARAMETER; + } + + SIVAL(data, 0, time_low); + SSVAL(data, 4, time_mid); + SSVAL(data, 6, time_hi_and_version); + SCVAL(data, 8, clock_seq_hi_and_reserved); + SCVAL(data, 9, clock_seq_low); + for (i=0;i<6;i++) { + SCVAL(data, 10 + i, node[i]); + } + + return NT_STATUS_OK; +} + +/* + pull a dcerpc syntax id from a blob +*/ +static NTSTATUS dcerpc_pull_syntax_id(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + uint32 *offset, + struct dcerpc_syntax_id *syntax) +{ + syntax->uuid_str = dcerpc_pull_uuid(blob->data + (*offset), mem_ctx); + if (!syntax->uuid_str) { + return NT_STATUS_NO_MEMORY; + } + (*offset) += 16; + syntax->if_version = IVAL(blob->data, *offset); + (*offset) += 4; + return NT_STATUS_OK; +} + +/* + push a syntax id onto the wire. It will consume 20 bytes +*/ +static NTSTATUS push_syntax_id(char *data, const struct dcerpc_syntax_id *syntax) +{ + NTSTATUS status; + + status = push_uuid_str(data, syntax->uuid_str); + SIVAL(data, 16, syntax->if_version); + + return status; +} + +/* + pull an auth verifier from a packet +*/ +static NTSTATUS dcerpc_pull_auth_verifier(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + uint32 *offset, + struct dcerpc_hdr *hdr, + DATA_BLOB *auth) +{ + if (hdr->auth_length == 0) { + return NT_STATUS_OK; + } + + BLOB_CHECK_BOUNDS(blob, *offset, hdr->auth_length); + *auth = data_blob_talloc(mem_ctx, blob->data + (*offset), hdr->auth_length); + if (!auth->data) { + return NT_STATUS_NO_MEMORY; + } + (*offset) += hdr->auth_length; + return NT_STATUS_OK; +} + +/* + parse a struct dcerpc_response +*/ +static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + uint32 *offset, + struct dcerpc_hdr *hdr, + struct dcerpc_response *pkt) +{ + uint32 alloc_hint, stub_len; + + BLOB_CHECK_BOUNDS(blob, *offset, 8); + + alloc_hint = IVAL(blob->data, (*offset) + 0); + pkt->context_id = SVAL(blob->data, (*offset) + 4); + pkt->cancel_count = CVAL(blob->data, (*offset) + 6); + + (*offset) += 8; + + stub_len = blob->length - ((*offset) + hdr->auth_length); + BLOB_CHECK_BOUNDS(blob, *offset, stub_len); + pkt->stub_data = data_blob_talloc(mem_ctx, blob->data + (*offset), stub_len); + if (!pkt->stub_data.data) { + return NT_STATUS_NO_MEMORY; + } + (*offset) += stub_len; + + return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier); +} + + +/* + parse a struct bind_ack +*/ +static NTSTATUS dcerpc_pull_bind_ack(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + uint32 *offset, + struct dcerpc_hdr *hdr, + struct dcerpc_bind_ack *pkt) +{ + uint16 len; + int i; + + BLOB_CHECK_BOUNDS(blob, *offset, 10); + pkt->max_xmit_frag = SVAL(blob->data, (*offset) + 0); + pkt->max_recv_frag = SVAL(blob->data, (*offset) + 2); + pkt->assoc_group_id = IVAL(blob->data, (*offset) + 4); + len = SVAL(blob->data, (*offset) + 8); + (*offset) += 10; + + if (len) { + BLOB_CHECK_BOUNDS(blob, *offset, len); + pkt->secondary_address = talloc_strndup(mem_ctx, blob->data + (*offset), len); + if (!pkt->secondary_address) { + return NT_STATUS_NO_MEMORY; + } + (*offset) += len; + } + + DCERPC_ALIGN(*offset, 4); + BLOB_CHECK_BOUNDS(blob, *offset, 4); + pkt->num_results = CVAL(blob->data, *offset); + (*offset) += 4; + + if (pkt->num_results > 0) { + pkt->ctx_list = talloc(mem_ctx, sizeof(pkt->ctx_list[0]) * pkt->num_results); + if (!pkt->ctx_list) { + return NT_STATUS_NO_MEMORY; + } + } + + for (i=0;i<pkt->num_results;i++) { + NTSTATUS status; + + BLOB_CHECK_BOUNDS(blob, *offset, 24); + pkt->ctx_list[i].result = IVAL(blob->data, *offset); + (*offset) += 4; + status = dcerpc_pull_syntax_id(blob, mem_ctx, offset, &pkt->ctx_list[i].syntax); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier); +} + + +/* + parse a dcerpc header +*/ +static NTSTATUS dcerpc_pull_hdr(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr) +{ + BLOB_CHECK_BOUNDS(blob, *offset, 16); + + hdr->rpc_vers = CVAL(blob->data, (*offset) + 0); + hdr->rpc_vers_minor = CVAL(blob->data, (*offset) + 1); + hdr->ptype = CVAL(blob->data, (*offset) + 2); + hdr->pfc_flags = CVAL(blob->data, (*offset) + 3); + memcpy(hdr->drep, blob->data + (*offset) + 4, 4); + hdr->frag_length = SVAL(blob->data, (*offset) + 8); + hdr->auth_length = SVAL(blob->data, (*offset) + 10); + hdr->call_id = IVAL(blob->data, (*offset) + 12); + + (*offset) += 16; + + return NT_STATUS_OK; +} + +/* + parse a dcerpc header. It consumes 16 bytes +*/ +static void dcerpc_push_hdr(char *data, struct dcerpc_hdr *hdr) +{ + SCVAL(data, 0, hdr->rpc_vers); + SCVAL(data, 1, hdr->rpc_vers_minor); + SCVAL(data, 2, hdr->ptype); + SCVAL(data, 3, hdr->pfc_flags); + memcpy(data + 4, hdr->drep, 4); + SSVAL(data, 8, hdr->frag_length); + SSVAL(data, 12, hdr->call_id); +} + + + +/* + parse a data blob into a dcerpc_packet structure. This handles both + input and output packets +*/ +NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt) +{ + NTSTATUS status; + uint32 offset = 0; + + status = dcerpc_pull_hdr(blob, &offset, &pkt->hdr); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (pkt->hdr.ptype) { + case DCERPC_PKT_BIND_ACK: + status = dcerpc_pull_bind_ack(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.bind_ack); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + + case DCERPC_PKT_RESPONSE: + status = dcerpc_pull_response(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.response); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + + default: + return NT_STATUS_INVALID_LEVEL; + } + + return status; +} + + +/* + push a dcerpc_bind into a blob +*/ +static NTSTATUS dcerpc_push_bind(DATA_BLOB *blob, uint32 *offset, + struct dcerpc_hdr *hdr, + struct dcerpc_bind *pkt) +{ + int i, j; + + SSVAL(blob->data, (*offset) + 0, pkt->max_xmit_frag); + SSVAL(blob->data, (*offset) + 2, pkt->max_recv_frag); + SIVAL(blob->data, (*offset) + 4, pkt->assoc_group_id); + SCVAL(blob->data, (*offset) + 8, pkt->num_contexts); + (*offset) += 12; + + for (i=0;i<pkt->num_contexts;i++) { + NTSTATUS status; + + SSVAL(blob->data, (*offset) + 0, pkt->ctx_list[i].context_id); + SCVAL(blob->data, (*offset) + 2, pkt->ctx_list[i].num_transfer_syntaxes); + status = push_syntax_id(blob->data + (*offset) + 4, &pkt->ctx_list[i].abstract_syntax); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + (*offset) += 24; + for (j=0;j<pkt->ctx_list[i].num_transfer_syntaxes;j++) { + status = push_syntax_id(blob->data + (*offset), + &pkt->ctx_list[i].transfer_syntaxes[j]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + (*offset) += 20; + } + } + + return NT_STATUS_OK; +} + +/* + push a dcerpc_request into a blob +*/ +static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset, + struct dcerpc_hdr *hdr, + struct dcerpc_request *pkt) +{ + uint32 alloc_hint = 8 + pkt->stub_data.length + pkt->auth_verifier.length; + + SIVAL(blob->data, (*offset) + 0, alloc_hint); + SSVAL(blob->data, (*offset) + 4, pkt->context_id); + SSVAL(blob->data, (*offset) + 6, pkt->opnum); + + (*offset) += 8; + + memcpy(blob->data + (*offset), pkt->stub_data.data, pkt->stub_data.length); + (*offset) += pkt->stub_data.length; + + memcpy(blob->data + (*offset), pkt->auth_verifier.data, pkt->auth_verifier.length); + (*offset) += pkt->auth_verifier.length; + + return NT_STATUS_OK; +} + + +/* + work out the wire size of a dcerpc packet +*/ +static uint32 dcerpc_wire_size(struct dcerpc_packet *pkt) +{ + int i; + uint32 size = 0; + + size += 16; /* header */ + + switch (pkt->hdr.ptype) { + case DCERPC_PKT_REQUEST: + size += 8; + size += pkt->in.request.stub_data.length; + size += pkt->in.request.auth_verifier.length; + break; + + case DCERPC_PKT_RESPONSE: + size += 8; + size += pkt->out.response.stub_data.length; + size += pkt->hdr.auth_length; + break; + + case DCERPC_PKT_BIND: + size += 12; + for (i=0;i<pkt->in.bind.num_contexts;i++) { + size += 24; + size += pkt->in.bind.ctx_list[i].num_transfer_syntaxes * 20; + } + size += pkt->hdr.auth_length; + break; + + case DCERPC_PKT_BIND_ACK: + size += 10; + if (pkt->out.bind_ack.secondary_address) { + size += strlen(pkt->out.bind_ack.secondary_address) + 1; + } + size += 4; + size += pkt->out.bind_ack.num_results * 24; + size += pkt->hdr.auth_length; + break; + } + + return size; +} + +/* + push a dcerpc_packet into a blob. This handles both input and + output packets +*/ +NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt) +{ + uint32 offset = 0; + uint32 wire_size; + NTSTATUS status; + + /* work out how big the packet will be on the wire */ + wire_size = dcerpc_wire_size(pkt); + + (*blob) = data_blob_talloc(mem_ctx, NULL, wire_size); + if (!blob->data) { + return NT_STATUS_NO_MEMORY; + } + + pkt->hdr.frag_length = wire_size; + + dcerpc_push_hdr(blob->data + offset, &pkt->hdr); + offset += 16; + + switch (pkt->hdr.ptype) { + case DCERPC_PKT_BIND: + status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind); + break; + + case DCERPC_PKT_REQUEST: + status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request); + break; + + default: + status = NT_STATUS_INVALID_LEVEL; + } + + return status; +} + + + + +/* + fill in the fixed values in a dcerpc header +*/ +static void init_dcerpc_hdr(struct dcerpc_hdr *hdr) +{ + hdr->rpc_vers = 5; + hdr->rpc_vers_minor = 0; + hdr->drep[0] = 0x10; /* Little endian */ + hdr->drep[1] = 0; + hdr->drep[2] = 0; + hdr->drep[3] = 0; +} + + +/* + perform a bind using the given syntax +*/ +NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, + const struct dcerpc_syntax_id *syntax, + const struct dcerpc_syntax_id *transfer_syntax) +{ + TALLOC_CTX *mem_ctx; + struct dcerpc_packet pkt; + NTSTATUS status; + DATA_BLOB blob; + DATA_BLOB blob_out; + + mem_ctx = talloc_init("cli_dcerpc_bind"); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + init_dcerpc_hdr(&pkt.hdr); + + pkt.hdr.ptype = DCERPC_PKT_BIND; + pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.hdr.call_id = p->call_id++; + pkt.hdr.auth_length = 0; + + pkt.in.bind.max_xmit_frag = 5680; + pkt.in.bind.max_recv_frag = 5680; + pkt.in.bind.assoc_group_id = 0; + pkt.in.bind.num_contexts = 1; + pkt.in.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.in.bind.ctx_list[0])); + if (!pkt.in.bind.ctx_list) { + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + pkt.in.bind.ctx_list[0].context_id = 0; + pkt.in.bind.ctx_list[0].num_transfer_syntaxes = 1; + pkt.in.bind.ctx_list[0].abstract_syntax = *syntax; + pkt.in.bind.ctx_list[0].transfer_syntaxes = transfer_syntax; + + pkt.in.bind.auth_verifier = data_blob(NULL, 0); + + status = dcerpc_push(&blob, mem_ctx, &pkt); + if (!NT_STATUS_IS_OK(status)) { + talloc_destroy(mem_ctx); + return status; + } + + status = dcerpc_raw_packet(p, mem_ctx, &blob, &blob_out); + if (!NT_STATUS_IS_OK(status)) { + talloc_destroy(mem_ctx); + return status; + } + + status = dcerpc_pull(&blob_out, mem_ctx, &pkt); + if (!NT_STATUS_IS_OK(status)) { + talloc_destroy(mem_ctx); + return status; + } + + if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK) { + status = NT_STATUS_UNSUCCESSFUL; + } + + + p->srv_max_xmit_frag = pkt.out.bind_ack.max_xmit_frag; + p->srv_max_recv_frag = pkt.out.bind_ack.max_recv_frag; + + talloc_destroy(mem_ctx); + + return status; +} + +#define TRANSFER_SYNTAX_V2 {"8a885d04-1ceb-11c9-9fe8-08002b104860", 2} + +static const struct { + const char *name; + struct dcerpc_syntax_id syntax; + struct dcerpc_syntax_id transfer_syntax; +} known_pipes[] = { + { "lsarpc" , { "12345778-1234-abcd-ef00-0123456789ab", 0 }, TRANSFER_SYNTAX_V2 }, + { "samr" , { "12345778-1234-abcd-ef00-0123456789ac", 1 }, TRANSFER_SYNTAX_V2 }, + { "netlogon", { "12345778-1234-abcd-ef00-01234567cffb", 1 }, TRANSFER_SYNTAX_V2 }, + { "srvsvc" , { "4b324fc8-1670-01d3-1278-5a47bf6ee188", 3 }, TRANSFER_SYNTAX_V2 }, + { "wkssvc" , { "6bffd098-a112-3610-9833-46c3f87e345a", 1 }, TRANSFER_SYNTAX_V2 }, + { "winreg" , { "338cd001-2244-31f1-aaaa-900038001003", 1 }, TRANSFER_SYNTAX_V2 }, + { "spoolss" , { "12345678-1234-abcd-ef00-0123456789ab", 1 }, TRANSFER_SYNTAX_V2 }, + { "netdfs" , { "4fc742e0-4a10-11cf-8273-00aa004ae673", 3 }, TRANSFER_SYNTAX_V2 }, + { NULL , } +}; + + +/* Perform a bind using the given well-known pipe name */ +NTSTATUS cli_dcerpc_bind_byname(struct dcerpc_pipe *p, const char *pipe_name) +{ + int i; + + for (i=0; known_pipes[i].name; i++) { + if (strcasecmp(known_pipes[i].name, pipe_name) == 0) + break; + } + + if (known_pipes[i].name == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + return dcerpc_bind(p, &known_pipes[i].syntax, &known_pipes[i].transfer_syntax); +} + +NTSTATUS cli_dcerpc_request(struct dcerpc_pipe *p, + uint16 opnum, + TALLOC_CTX *mem_ctx, + DATA_BLOB *stub_data_in, + DATA_BLOB *stub_data_out) +{ + + struct dcerpc_packet pkt; + NTSTATUS status; + DATA_BLOB blob; + + init_dcerpc_hdr(&pkt.hdr); + + pkt.hdr.ptype = DCERPC_PKT_REQUEST; + pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.hdr.call_id = p->call_id++; + pkt.hdr.auth_length = 0; + + pkt.in.request.context_id = 0; + pkt.in.request.opnum = opnum; + pkt.in.request.stub_data = *stub_data_in; + pkt.in.request.auth_verifier = data_blob(NULL, 0); + + status = dcerpc_push(&blob, mem_ctx, &pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_raw_packet(p, mem_ctx, &blob, stub_data_out); + + return status; +} diff --git a/source4/libcli/rpc/dcerpc.h b/source4/libcli/rpc/dcerpc.h new file mode 100644 index 0000000000..cd1bc728e2 --- /dev/null +++ b/source4/libcli/rpc/dcerpc.h @@ -0,0 +1,124 @@ +/* + Unix SMB/CIFS implementation. + DCERPC interface structures + + Copyright (C) Tim Potter 2003 + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for details + of these structures + + note that the structure definitions here don't include some of the + fields that are wire-artifacts. Those are put on the wire by the + marshalling/unmarshalling routines in decrpc.c +*/ + +struct dcerpc_pipe { + TALLOC_CTX *mem_ctx; + uint16 fnum; + int reference_count; + uint32 call_id; + uint32 srv_max_xmit_frag; + uint32 srv_max_recv_frag; + struct cli_tree *tree; +}; + +/* dcerpc packet types */ +#define DCERPC_PKT_REQUEST 0 +#define DCERPC_PKT_RESPONSE 2 +#define DCERPC_PKT_BIND 11 +#define DCERPC_PKT_BIND_ACK 12 +#define DCERPC_PKT_BIND_NAK 13 + +/* hdr.pfc_flags */ +#define DCERPC_PFC_FLAG_FIRST 0x01 +#define DCERPC_PFC_FLAG_LAST 0x02 +#define DCERPC_PFC_FLAG_NOCALL 0x20 + +/* + all dcerpc packets use this structure. +*/ +struct dcerpc_packet { + /* all requests and responses contain a dcerpc header */ + struct dcerpc_hdr { + uint8 rpc_vers; /* RPC version */ + uint8 rpc_vers_minor; /* Minor version */ + uint8 ptype; /* Packet type */ + uint8 pfc_flags; /* Fragmentation flags */ + uint8 drep[4]; /* NDR data representation */ + uint16 frag_length; /* Total length of fragment */ + uint16 auth_length; /* authenticator length */ + uint32 call_id; /* Call identifier */ + } hdr; + + union { + struct dcerpc_bind { + uint16 max_xmit_frag; + uint16 max_recv_frag; + uint32 assoc_group_id; + uint8 num_contexts; + struct { + uint16 context_id; + uint8 num_transfer_syntaxes; + struct dcerpc_syntax_id { + const char *uuid_str; + uint32 if_version; + } abstract_syntax; + const struct dcerpc_syntax_id *transfer_syntaxes; + } *ctx_list; + DATA_BLOB auth_verifier; + } bind; + + struct dcerpc_request { + uint16 context_id; + uint16 opnum; + DATA_BLOB stub_data; + DATA_BLOB auth_verifier; + } request; + } in; + + union { + struct dcerpc_bind_ack { + uint16 max_xmit_frag; + uint16 max_recv_frag; + uint32 assoc_group_id; + const char *secondary_address; + uint8 num_results; + struct { + uint32 result; + struct dcerpc_syntax_id syntax; + } *ctx_list; + DATA_BLOB auth_verifier; + } bind_ack; + + struct dcerpc_bind_nak { + uint16 reject_reason; + uint32 num_versions; + uint32 *versions; + } bind_nak; + + struct dcerpc_response { + uint16 context_id; + uint8 cancel_count; + DATA_BLOB stub_data; + DATA_BLOB auth_verifier; + } response; + } out; +}; + diff --git a/source4/libcli/rpc/rpc_sec.c b/source4/libcli/rpc/rpc_sec.c deleted file mode 100644 index 49b50c758c..0000000000 --- a/source4/libcli/rpc/rpc_sec.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - routines for marshalling/unmarshalling security descriptors - and related structures - - Copyright (C) Andrew Tridgell 2003 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include "includes.h" - -/* - parse a security_ace -*/ -NTSTATUS ndr_parse_security_ace(struct ndr_parse *ndr, struct security_ace *ace) -{ - uint16 size; - struct ndr_parse_save save; - - ndr_parse_save(ndr, &save); - - NDR_CHECK(ndr_parse_u8(ndr, &ace->type)); - NDR_CHECK(ndr_parse_u8(ndr, &ace->flags)); - NDR_CHECK(ndr_parse_u16(ndr, &size)); - NDR_CHECK(ndr_parse_limit_size(ndr, size, 4)); - - NDR_CHECK(ndr_parse_u32(ndr, &ace->access_mask)); - - if (sec_ace_object(ace->type)) { - NDR_ALLOC(ndr, ace->obj); - NDR_CHECK(ndr_parse_u32(ndr, &ace->obj->flags)); - if (ace->obj->flags & SEC_ACE_OBJECT_PRESENT) { - NDR_CHECK(ndr_parse_guid(ndr, &ace->obj->object_guid)); - } - if (ace->obj->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) { - NDR_CHECK(ndr_parse_guid(ndr, &ace->obj->inherit_guid)); - } - } - - - NDR_CHECK(ndr_parse_dom_sid(ndr, &ace->trustee)); - - ndr_parse_restore(ndr, &save); - NDR_CHECK(ndr_parse_advance(ndr, size)); - - return NT_STATUS_OK; -} - -/* - parse a security_acl -*/ -NTSTATUS ndr_parse_security_acl(struct ndr_parse *ndr, struct security_acl *acl) -{ - int i; - uint16 size; - struct ndr_parse_save save; - - ndr_parse_save(ndr, &save); - - NDR_CHECK(ndr_parse_u16(ndr, &acl->revision)); - NDR_CHECK(ndr_parse_u16(ndr, &size)); - NDR_CHECK(ndr_parse_limit_size(ndr, size, 4)); - NDR_CHECK(ndr_parse_u32(ndr, &acl->num_aces)); - - NDR_ALLOC_N(ndr, acl->aces, acl->num_aces); - - for (i=0;i<acl->num_aces;i++) { - NDR_CHECK(ndr_parse_security_ace(ndr, &acl->aces[i])); - } - - ndr_parse_restore(ndr, &save); - NDR_CHECK(ndr_parse_advance(ndr, size)); - - return NT_STATUS_OK; -} - -/* - parse a security_acl offset and structure -*/ -NTSTATUS ndr_parse_security_acl_ofs(struct ndr_parse *ndr, struct security_acl **acl) -{ - uint32 ofs; - struct ndr_parse_save save; - - NDR_CHECK(ndr_parse_u32(ndr, &ofs)); - if (ofs == 0) { - /* it is valid for an acl ptr to be NULL */ - *acl = NULL; - return NT_STATUS_OK; - } - - ndr_parse_save(ndr, &save); - NDR_CHECK(ndr_parse_set_offset(ndr, ofs)); - NDR_ALLOC(ndr, *acl); - NDR_CHECK(ndr_parse_security_acl(ndr, *acl)); - ndr_parse_restore(ndr, &save); - - return NT_STATUS_OK; -} - - -/* - parse a dom_sid -*/ -NTSTATUS ndr_parse_dom_sid(struct ndr_parse *ndr, struct dom_sid *sid) -{ - int i; - - NDR_CHECK(ndr_parse_u8(ndr, &sid->sid_rev_num)); - NDR_CHECK(ndr_parse_u8(ndr, &sid->num_auths)); - for (i=0;i<6;i++) { - NDR_CHECK(ndr_parse_u8(ndr, &sid->id_auth[i])); - } - - NDR_ALLOC_N(ndr, sid->sub_auths, sid->num_auths); - - for (i=0;i<sid->num_auths;i++) { - NDR_CHECK(ndr_parse_u32(ndr, &sid->sub_auths[i])); - } - - return NT_STATUS_OK; -} - -/* - parse a dom_sid offset and structure -*/ -NTSTATUS ndr_parse_dom_sid_ofs(struct ndr_parse *ndr, struct dom_sid **sid) -{ - uint32 ofs; - struct ndr_parse_save save; - - NDR_CHECK(ndr_parse_u32(ndr, &ofs)); - if (ofs == 0) { - /* it is valid for a dom_sid ptr to be NULL */ - *sid = NULL; - return NT_STATUS_OK; - } - - ndr_parse_save(ndr, &save); - NDR_CHECK(ndr_parse_set_offset(ndr, ofs)); - NDR_ALLOC(ndr, *sid); - NDR_CHECK(ndr_parse_dom_sid(ndr, *sid)); - ndr_parse_restore(ndr, &save); - - return NT_STATUS_OK; -} - -/* - parse a security descriptor -*/ -NTSTATUS ndr_parse_security_descriptor(struct ndr_parse *ndr, - struct security_descriptor **sd) -{ - NDR_ALLOC(ndr, *sd); - - NDR_CHECK(ndr_parse_u8(ndr, &(*sd)->revision)); - NDR_CHECK(ndr_parse_u16(ndr, &(*sd)->type)); - NDR_CHECK(ndr_parse_dom_sid_ofs(ndr, &(*sd)->owner_sid)); - NDR_CHECK(ndr_parse_dom_sid_ofs(ndr, &(*sd)->group_sid)); - NDR_CHECK(ndr_parse_security_acl_ofs(ndr, &(*sd)->sacl)); - NDR_CHECK(ndr_parse_security_acl_ofs(ndr, &(*sd)->dacl)); - - return NT_STATUS_OK; -} diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c new file mode 100644 index 0000000000..dcf97cbfe2 --- /dev/null +++ b/source4/torture/rpc/lsa.c @@ -0,0 +1,79 @@ +/* + Unix SMB/CIFS implementation. + test suite for lsa rpc operations + Copyright (C) Tim Potter 2003 + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* Helper function for RPC-OPEN test */ +static DATA_BLOB blob_lsa_open_policy_req(TALLOC_CTX *mem_ctx, BOOL sec_qos, + uint32 des_access) +{ + prs_struct qbuf; + LSA_Q_OPEN_POL q; + LSA_SEC_QOS qos; + + ZERO_STRUCT(q); + + /* Initialise parse structures */ + + prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); + + /* Initialise input parameters */ + + if (sec_qos) { + init_lsa_sec_qos(&qos, 2, 1, 0); + init_q_open_pol(&q, '\\', 0, des_access, &qos); + } else { + init_q_open_pol(&q, '\\', 0, des_access, NULL); + } + + if (lsa_io_q_open_pol("", &q, &qbuf, 0)) + return data_blob_talloc( + mem_ctx, prs_data_p(&qbuf), prs_offset(&qbuf)); + + return data_blob(NULL, 0); +} + +BOOL torture_rpc_lsa(int dummy) +{ + NTSTATUS status; + struct dcerpc_pipe *p; + DATA_BLOB request; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("torture_rpc_lsa"); + + status = torture_rpc_connection(&p, "lsarpc"); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + request = blob_lsa_open_policy_req(mem_ctx, True, + SEC_RIGHTS_MAXIMUM_ALLOWED); + + status = cli_dcerpc_request(p, LSA_OPENPOLICY, mem_ctx, &request, NULL); + if (!NT_STATUS_IS_OK(status)) { + d_printf("Failed to LSA_OPENPOLICY - %s\n", nt_errstr(status)); + } + + torture_rpc_close(p); + + return NT_STATUS_IS_OK(status); +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index eccc6e5d11..c3f7514e9b 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -98,11 +98,11 @@ BOOL torture_open_connection(struct cli_state **c) if (use_kerberos) flags |= CLI_FULL_CONNECTION_USE_KERBEROS; - + status = cli_full_connection(c, lp_netbios_name(), host, NULL, share, "?????", - username, lp_workgroup(), + username, username[0]?lp_workgroup():"", password, flags, &retry); if (!NT_STATUS_IS_OK(status)) { printf("Failed to open connection - %s\n", nt_errstr(status)); @@ -131,6 +131,87 @@ BOOL torture_close_connection(struct cli_state *c) return ret; } +/* open a rpc connection to a named pipe */ +NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p, const char *pipe_name) +{ + struct cli_state *cli; + int fnum; + NTSTATUS status; + char *name = NULL; + union smb_open open_parms; + TALLOC_CTX *mem_ctx; + + if (!torture_open_connection(&cli)) { + return NT_STATUS_UNSUCCESSFUL; + } + + asprintf(&name, "\\%s", pipe_name); + if (!name) { + return NT_STATUS_NO_MEMORY; + } + + open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX; + open_parms.ntcreatex.in.flags = 0; + open_parms.ntcreatex.in.root_fid = 0; + open_parms.ntcreatex.in.access_mask = + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_WRITE_ATTRIBUTES | + SA_RIGHT_FILE_WRITE_EA | + GENERIC_RIGHTS_FILE_READ; + open_parms.ntcreatex.in.file_attr = 0; + open_parms.ntcreatex.in.alloc_size = 0; + open_parms.ntcreatex.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + open_parms.ntcreatex.in.create_options = 0; + open_parms.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION; + open_parms.ntcreatex.in.security_flags = 0; + open_parms.ntcreatex.in.fname = name; + + mem_ctx = talloc_init("torture_rpc_connection"); + status = smb_raw_open(cli->tree, mem_ctx, &open_parms); + free(name); + talloc_destroy(mem_ctx); + + if (!NT_STATUS_IS_OK(status)) { + printf("Open of pipe %s failed with error (%s)\n", + pipe_name, nt_errstr(status)); + return status; + } + + if (!(*p = dcerpc_pipe_init(cli->tree))) { + return NT_STATUS_NO_MEMORY; + } + + (*p)->fnum = open_parms.ntcreatex.out.fnum; + + status = cli_dcerpc_bind_byname(*p, pipe_name); + + if (!NT_STATUS_IS_OK(status)) { + cli_close(cli, fnum); + dcerpc_pipe_close(*p); + } + + return status; +} + +/* close a rpc connection to a named pipe */ +NTSTATUS torture_rpc_close(struct dcerpc_pipe *p) +{ + union smb_close io; + NTSTATUS status; + + io.close.level = RAW_CLOSE_CLOSE; + io.close.in.fnum = p->fnum; + io.close.in.write_time = 0; + status = smb_raw_close(p->tree, &io); + + dcerpc_pipe_close(p); + + return status; +} + /* check if the server produced the expected error code */ static BOOL check_error(int line, struct cli_state *c, @@ -3755,85 +3836,6 @@ static BOOL run_deny3test(int dummy) return True; } -/* Helper function for RPC-OPEN test */ - -static DATA_BLOB blob_lsa_open_policy_req(TALLOC_CTX *mem_ctx, BOOL sec_qos, - uint32 des_access) -{ - prs_struct qbuf; - LSA_Q_OPEN_POL q; - LSA_SEC_QOS qos; - - ZERO_STRUCT(q); - - /* Initialise parse structures */ - - prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - - /* Initialise input parameters */ - - if (sec_qos) { - init_lsa_sec_qos(&qos, 2, 1, 0); - init_q_open_pol(&q, '\\', 0, des_access, &qos); - } else { - init_q_open_pol(&q, '\\', 0, des_access, NULL); - } - - if (lsa_io_q_open_pol("", &q, &qbuf, 0)) - return data_blob_talloc( - mem_ctx, prs_data_p(&qbuf), prs_offset(&qbuf)); - - return data_blob(NULL, 0); -} - -static BOOL torture_rpc_open(int dummy) -{ - struct cli_state *cli; - const char *pipe_name = "\\lsarpc"; - int fnum; - TALLOC_CTX *mem_ctx; - NTSTATUS status; - struct cli_dcerpc_pipe *p; - DATA_BLOB request; - - mem_ctx = talloc_init("rpc_open"); - - printf("starting rpc test\n"); - - if (!torture_open_connection(&cli)) - return False; - - fnum = cli_nt_create_full(cli, pipe_name, 0, SA_RIGHT_FILE_READ_DATA, - FILE_ATTRIBUTE_NORMAL, - NTCREATEX_SHARE_ACCESS_READ| - NTCREATEX_SHARE_ACCESS_WRITE, - NTCREATEX_DISP_OPEN_IF, 0, 0); - - if (fnum == -1) { - printf("Open of pipe %s failed with error (%s)\n", - pipe_name, cli_errstr(cli)); - return False; - } - - if (!(p = cli_dcerpc_pipe_init(cli->tree))) - return False; - - p->fnum = fnum; - - status = cli_dcerpc_bind_byname(p, pipe_name); - - request = blob_lsa_open_policy_req(mem_ctx, True, - SEC_RIGHTS_MAXIMUM_ALLOWED); - - status = cli_dcerpc_request(p, LSA_OPENPOLICY, request); - - talloc_destroy(mem_ctx); - - torture_close_connection(cli); - - return True; -} - static void sigcont(void) { } @@ -4023,7 +4025,7 @@ static struct { {"SCAN-NTTRANS", torture_nttrans_scan, 0}, {"SCAN-ALIASES", torture_trans2_aliases, 0}, {"SCAN-SMB", torture_smb_scan, 0}, - {"RPC-OPEN", torture_rpc_open, 0}, + {"RPC-LSA", torture_rpc_lsa, 0}, {NULL, NULL, 0}}; |