mirror of
https://github.com/samba-team/samba.git
synced 2025-03-29 02:50:28 +03:00
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)
This commit is contained in:
parent
7fd381376f
commit
c5cf474439
@ -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)
|
||||
|
@ -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;
|
||||
};
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
201
source4/libcli/ndr/ndr_sec.c
Normal file
201
source4/libcli/ndr/ndr_sec.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
req = smb_raw_trans_send(p->tree, &trans);
|
||||
|
||||
trans.in.data = blob;
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
result = smb_raw_trans(p->tree, p->mem_ctx, &trans);
|
||||
|
||||
data_blob_free(&blob);
|
||||
|
||||
return result;
|
||||
return req;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_raw_bind_recv(struct cli_dcerpc_pipe *p,
|
||||
struct dcerpc_bind *parms)
|
||||
NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p,
|
||||
struct cli_request *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
DATA_BLOB *blob)
|
||||
{
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
struct smb_trans2 trans;
|
||||
NTSTATUS status;
|
||||
|
||||
status = smb_raw_trans_recv(req, mem_ctx, &trans);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (blob) {
|
||||
*blob = trans.out.data;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_raw_bind(struct cli_dcerpc_pipe *p, struct dcerpc_bind *parms)
|
||||
NTSTATUS dcerpc_raw_packet(struct dcerpc_pipe *p,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
DATA_BLOB *request_blob,
|
||||
DATA_BLOB *reply_blob)
|
||||
{
|
||||
NTSTATUS result;
|
||||
|
||||
result = dcerpc_raw_bind_send(p, parms);
|
||||
if (NT_STATUS_IS_ERR(result))
|
||||
return result;
|
||||
return dcerpc_raw_bind_recv(p, parms);
|
||||
struct cli_request *req;
|
||||
req = dcerpc_raw_send(p, request_blob);
|
||||
return dcerpc_raw_recv(p, req, mem_ctx, reply_blob);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct smb_trans2 trans;
|
||||
DATA_BLOB blob;
|
||||
NTSTATUS result;
|
||||
uint16 setup[2];
|
||||
|
||||
blob = dcerpc_raw_request_setup(parms);
|
||||
|
||||
ZERO_STRUCT(trans);
|
||||
|
||||
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);
|
||||
|
||||
data_blob_free(&blob);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NTSTATUS dcerpc_raw_request_recv(struct cli_dcerpc_pipe *p,
|
||||
struct dcerpc_request *parms)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
644
source4/libcli/rpc/dcerpc.c
Normal file
644
source4/libcli/rpc/dcerpc.c
Normal file
@ -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;
|
||||
}
|
124
source4/libcli/rpc/dcerpc.h
Normal file
124
source4/libcli/rpc/dcerpc.h
Normal file
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
79
source4/torture/rpc/lsa.c
Normal file
79
source4/torture/rpc/lsa.c
Normal file
@ -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);
|
||||
}
|
@ -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}};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user