diff options
-rw-r--r-- | source4/torture/rpc/rpc.c | 1 | ||||
-rw-r--r-- | source4/torture/rpc/samba3rpc.c | 331 |
2 files changed, 308 insertions, 24 deletions
diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c index 67ad1f1ae5..879fa7aa8e 100644 --- a/source4/torture/rpc/rpc.c +++ b/source4/torture/rpc/rpc.c @@ -135,6 +135,7 @@ NTSTATUS torture_rpc_init(void) register_torture_op("RPC-SAMBA3-GETUSERNAME", torture_samba3_rpc_getusername); register_torture_op("RPC-SAMBA3-LSA", torture_samba3_rpc_lsa); + register_torture_op("RPC-SAMBA3-SPOOLSS", torture_samba3_rpc_spoolss); register_torture_op("RPC-DRSUAPI", torture_rpc_drsuapi); register_torture_op("RPC-CRACKNAMES", torture_rpc_drsuapi_cracknames); register_torture_op("RPC-ROT", torture_rpc_rot); diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index cd7eb7c581..94613185dc 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -32,6 +32,8 @@ #include "librpc/gen_ndr/ndr_netlogon_c.h" #include "librpc/gen_ndr/ndr_srvsvc.h" #include "librpc/gen_ndr/ndr_srvsvc_c.h" +#include "librpc/gen_ndr/ndr_spoolss.h" +#include "librpc/gen_ndr/ndr_spoolss_c.h" #include "lib/cmdline/popt_common.h" #include "librpc/rpc/dcerpc.h" #include "torture/rpc/rpc.h" @@ -1355,17 +1357,18 @@ BOOL torture_samba3_sessionkey(struct torture_context *torture) * open pipe and bind, given an IPC$ context */ -static struct dcerpc_pipe *pipe_bind_smb(TALLOC_CTX *mem_ctx, - struct smbcli_tree *tree, - const char *pipe_name, - const struct dcerpc_interface_table *iface) +static NTSTATUS pipe_bind_smb(TALLOC_CTX *mem_ctx, + struct smbcli_tree *tree, + const char *pipe_name, + const struct dcerpc_interface_table *iface, + struct dcerpc_pipe **p) { struct dcerpc_pipe *result; NTSTATUS status; if (!(result = dcerpc_pipe_init( mem_ctx, tree->session->transport->socket->event.ctx))) { - return NULL; + return NT_STATUS_NO_MEMORY; } status = dcerpc_pipe_open_smb(result->conn, tree, pipe_name); @@ -1373,17 +1376,18 @@ static struct dcerpc_pipe *pipe_bind_smb(TALLOC_CTX *mem_ctx, d_printf("dcerpc_pipe_open_smb failed: %s\n", nt_errstr(status)); talloc_free(result); - return NULL; + return status; } status = dcerpc_bind_auth_none(result, iface); if (!NT_STATUS_IS_OK(status)) { d_printf("schannel bind failed: %s\n", nt_errstr(status)); talloc_free(result); - return NULL; + return status; } - return result; + *p = result; + return NT_STATUS_OK; } /* @@ -1486,9 +1490,11 @@ static struct dom_sid *whoami(TALLOC_CTX *mem_ctx, struct smbcli_tree *tree) struct lsa_StringPointer authority_name_p; struct dom_sid *result; - if (!(lsa = pipe_bind_smb(mem_ctx, tree, "\\pipe\\lsarpc", - &dcerpc_table_lsarpc))) { - d_printf("Could not bind to LSA\n"); + status = pipe_bind_smb(mem_ctx, tree, "\\pipe\\lsarpc", + &dcerpc_table_lsarpc, &lsa); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) Could not bind to LSA: %s\n", + __location__, nt_errstr(status)); return NULL; } @@ -1800,6 +1806,7 @@ BOOL torture_samba3_rpc_srvsvc(struct torture_context *torture) BOOL ret = True; const char *sharename = NULL; struct smbcli_state *cli; + NTSTATUS status; if (!(mem_ctx = talloc_new(torture))) { return False; @@ -1812,9 +1819,11 @@ BOOL torture_samba3_rpc_srvsvc(struct torture_context *torture) return False; } - if (!(p = pipe_bind_smb(mem_ctx, cli->tree, "\\pipe\\srvsvc", - &dcerpc_table_srvsvc))) { - d_printf("could not bind to srvsvc pipe\n"); + status = pipe_bind_smb(mem_ctx, cli->tree, "\\pipe\\srvsvc", + &dcerpc_table_srvsvc, &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) could not bind to srvsvc pipe: %s\n", + __location__, nt_errstr(status)); ret = False; goto done; } @@ -1853,9 +1862,11 @@ static struct security_descriptor *get_sharesec(TALLOC_CTX *mem_ctx, return NULL; } - if (!(p = pipe_bind_smb(mem_ctx, tree, "\\pipe\\srvsvc", - &dcerpc_table_srvsvc))) { - d_printf("could not bind to srvsvc pipe\n"); + status = pipe_bind_smb(mem_ctx, tree, "\\pipe\\srvsvc", + &dcerpc_table_srvsvc, &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) could not bind to srvsvc pipe: %s\n", + __location__, nt_errstr(status)); talloc_free(tmp_ctx); return NULL; } @@ -1906,9 +1917,11 @@ static NTSTATUS set_sharesec(TALLOC_CTX *mem_ctx, return NT_STATUS_UNSUCCESSFUL; } - if (!(p = pipe_bind_smb(mem_ctx, tree, "\\pipe\\srvsvc", - &dcerpc_table_srvsvc))) { - d_printf("could not bind to srvsvc pipe\n"); + status = pipe_bind_smb(mem_ctx, tree, "\\pipe\\srvsvc", + &dcerpc_table_srvsvc, &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) could not bind to srvsvc pipe: %s\n", + __location__, nt_errstr(status)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } @@ -2094,10 +2107,11 @@ BOOL torture_samba3_rpc_lsa(struct torture_context *torture) return False; } - p = pipe_bind_smb(mem_ctx, cli->tree, "\\lsarpc", - &dcerpc_table_lsarpc); - if (p == NULL) { - d_printf("(%s) pipe_bind_smb failed\n", __location__); + status = pipe_bind_smb(mem_ctx, cli->tree, "\\lsarpc", + &dcerpc_table_lsarpc, &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) pipe_bind_smb failed: %s\n", __location__, + nt_errstr(status)); talloc_free(mem_ctx); return False; } @@ -2148,3 +2162,272 @@ BOOL torture_samba3_rpc_lsa(struct torture_context *torture) return ret; } + +static NTSTATUS find_printers(TALLOC_CTX *ctx, struct smbcli_tree *tree, + const char ***printers, int *num_printers) +{ + TALLOC_CTX *mem_ctx; + NTSTATUS status; + struct dcerpc_pipe *p; + struct srvsvc_NetShareEnum r; + struct srvsvc_NetShareCtr1 c1_in; + struct srvsvc_NetShareCtr1 *c1; + int i; + + mem_ctx = talloc_new(ctx); + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = pipe_bind_smb(mem_ctx, tree, "\\srvsvc", &dcerpc_table_srvsvc, + &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("could not bind to srvsvc pipe\n"); + talloc_free(mem_ctx); + return status; + } + + r.in.server_unc = talloc_asprintf( + mem_ctx, "\\\\%s", dcerpc_server_name(p)); + r.in.level = 1; + ZERO_STRUCT(c1_in); + r.in.ctr.ctr1 = &c1_in; + r.in.max_buffer = (uint32_t)-1; + r.in.resume_handle = NULL; + + status = dcerpc_srvsvc_NetShareEnum(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("NetShareEnum level %u failed - %s\n", + r.in.level, nt_errstr(status)); + talloc_free(mem_ctx); + return status; + } + + *printers = NULL; + *num_printers = 0; + c1 = r.out.ctr.ctr1; + for (i=0; i<c1->count; i++) { + if (c1->array[i].type != STYPE_PRINTQ) { + continue; + } + if (!add_string_to_array(ctx, c1->array[i].name, + printers, num_printers)) { + talloc_free(ctx); + return NT_STATUS_NO_MEMORY; + } + } + + talloc_free(mem_ctx); + return NT_STATUS_OK; +} + +static NTSTATUS getprinterinfo(TALLOC_CTX *ctx, struct dcerpc_pipe *pipe, + struct policy_handle *handle, int level, + union spoolss_PrinterInfo **res) +{ + TALLOC_CTX *mem_ctx; + struct spoolss_GetPrinter r; + DATA_BLOB blob; + NTSTATUS status; + + mem_ctx = talloc_new(ctx); + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + r.in.handle = handle; + r.in.level = level; + r.in.buffer = NULL; + r.in.offered = 0; + + status = dcerpc_spoolss_GetPrinter(pipe, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) dcerpc_spoolss_GetPrinter failed: %s\n", + __location__, nt_errstr(status)); + talloc_free(mem_ctx); + return status; + } + + if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { + printf("GetPrinter unexpected return code %s, should " + "be WERR_INSUFFICIENT_BUFFER\n", + win_errstr(r.out.result)); + talloc_free(mem_ctx); + return NT_STATUS_UNSUCCESSFUL; + } + + r.in.handle = handle; + r.in.level = level; + blob = data_blob_talloc(mem_ctx, NULL, r.out.needed); + if (blob.data == NULL) { + talloc_free(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + memset(blob.data, 0, blob.length); + r.in.buffer = &blob; + r.in.offered = r.out.needed; + + status = dcerpc_spoolss_GetPrinter(pipe, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) { + d_printf("(%s) dcerpc_spoolss_GetPrinter failed: %s, " + "%s\n", __location__, nt_errstr(status), + win_errstr(r.out.result)); + talloc_free(mem_ctx); + return NT_STATUS_IS_OK(status) ? + NT_STATUS_UNSUCCESSFUL : status; + } + + if (res != NULL) { + *res = talloc_steal(ctx, r.out.info); + } + + talloc_free(mem_ctx); + return NT_STATUS_OK; +} + + +BOOL torture_samba3_rpc_spoolss(struct torture_context *torture) +{ + TALLOC_CTX *mem_ctx; + BOOL ret = True; + struct smbcli_state *cli; + struct dcerpc_pipe *p; + NTSTATUS status; + struct policy_handle server_handle, printer_handle; + const char **printers; + int num_printers; + struct spoolss_UserLevel1 userlevel1; + + if (!(mem_ctx = talloc_new(torture))) { + return False; + } + + if (!(torture_open_connection_share( + mem_ctx, &cli, lp_parm_string(-1, "torture", "host"), + "IPC$", NULL))) { + d_printf("IPC$ connection failed\n"); + talloc_free(mem_ctx); + return False; + } + + if (!NT_STATUS_IS_OK(find_printers(mem_ctx, cli->tree, + &printers, &num_printers))) { + talloc_free(mem_ctx); + return False; + } + + if (num_printers == 0) { + d_printf("Did not find printers\n"); + talloc_free(mem_ctx); + return True; + } + + status = pipe_bind_smb(mem_ctx, cli->tree, "\\spoolss", + &dcerpc_table_spoolss, &p); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) pipe_bind_smb failed: %s\n", __location__, + nt_errstr(status)); + talloc_free(mem_ctx); + return False; + } + + ZERO_STRUCT(userlevel1); + userlevel1.client = talloc_asprintf( + mem_ctx, "\\\\%s", lp_netbios_name()); + userlevel1.user = cli_credentials_get_username(cmdline_credentials); + userlevel1.build = 2600; + userlevel1.major = 3; + userlevel1.minor = 0; + userlevel1.processor = 0; + + { + struct spoolss_OpenPrinterEx r; + + ZERO_STRUCT(r); + r.in.printername = talloc_asprintf( + mem_ctx, "\\\\%s", dcerpc_server_name(p)); + r.in.datatype = NULL; + r.in.access_mask = 0; + r.in.level = 1; + r.in.userlevel.level1 = &userlevel1; + r.out.handle = &server_handle; + + status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) dcerpc_spoolss_OpenPrinterEx failed: " + "%s\n", __location__, nt_errstr(status)); + talloc_free(mem_ctx); + return False; + } + } + + { + struct spoolss_ClosePrinter r; + + r.in.handle = &server_handle; + r.out.handle = &server_handle; + + status = dcerpc_spoolss_ClosePrinter(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) dcerpc_spoolss_ClosePrinter failed: " + "%s\n", __location__, nt_errstr(status)); + talloc_free(mem_ctx); + return False; + } + } + + { + struct spoolss_OpenPrinterEx r; + + ZERO_STRUCT(r); + r.in.printername = talloc_asprintf( + mem_ctx, "\\\\%s\\%s", dcerpc_server_name(p), + printers[0]); + r.in.datatype = NULL; + r.in.access_mask = 0; + r.in.level = 1; + r.in.userlevel.level1 = &userlevel1; + r.out.handle = &printer_handle; + + status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) dcerpc_spoolss_OpenPrinterEx failed: " + "%s\n", __location__, nt_errstr(status)); + talloc_free(mem_ctx); + return False; + } + } + + { + int i; + + for (i=0; i<8; i++) { + status = getprinterinfo(mem_ctx, p, &printer_handle, + i, NULL); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) getprinterinfo %d failed: %s\n", + __location__, i, nt_errstr(status)); + ret = False; + } + } + } + + { + struct spoolss_ClosePrinter r; + + r.in.handle = &printer_handle; + r.out.handle = &printer_handle; + + status = dcerpc_spoolss_ClosePrinter(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + d_printf("(%s) dcerpc_spoolss_ClosePrinter failed: " + "%s\n", __location__, nt_errstr(status)); + talloc_free(mem_ctx); + return False; + } + } + + talloc_free(mem_ctx); + + return ret; +} |