/* Unix SMB/CIFS implementation. test suite for spoolss rpc 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" #include "librpc/gen_ndr/ndr_spoolss.h" static BOOL test_GetPrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { NTSTATUS status; struct spoolss_GetPrinter r; uint16_t levels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; int i; BOOL ret = True; for (i=0;ilast_fault_code == DCERPC_FAULT_OP_RNG_ERROR) { printf("GetPrinterDataEx not supported by server\n"); return True; } printf("GetPrinterDataEx failed - %s\n", nt_errstr(status)); return False; } if (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA)) { status = dcerpc_spoolss_GetPrinterDataEx(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("GetPrinterDataEx failed - %s\n", nt_errstr(status)); return False; } if (!W_ERROR_IS_OK(r.out.result)) { printf("GetPrinterDataEx failed - %s\n", win_errstr(r.out.result)); return False; } } return True; } static BOOL test_EnumPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { NTSTATUS status; struct spoolss_EnumPrinterData r; r.in.handle = handle; r.in.enum_index = 0; do { uint32_t data_size; r.in.value_offered = 0; data_size = 0; r.in.data_size = &data_size; r.out.data_size = &data_size; printf("Testing EnumPrinterData\n"); status = dcerpc_spoolss_EnumPrinterData(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("EnumPrinterData failed - %s\n", nt_errstr(status)); return False; } r.in.value_offered = r.out.value_needed; status = dcerpc_spoolss_EnumPrinterData(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("EnumPrinterData failed - %s\n", nt_errstr(status)); return False; } test_GetPrinterData(p, mem_ctx, handle, r.out.value_name); test_GetPrinterDataEx( p, mem_ctx, handle, "PrinterDriverData", r.out.value_name); r.in.enum_index++; } while (W_ERROR_IS_OK(r.out.result)); return True; } static BOOL test_EnumPrinterDataEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { NTSTATUS status; struct spoolss_EnumPrinterDataEx r; r.in.handle = handle; r.in.key_name = "PrinterDriverData"; r.in.buf_size = 0; printf("Testing EnumPrinterDataEx\n"); status = dcerpc_spoolss_EnumPrinterDataEx(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("EnumPrinterDataEx failed - %s\n", nt_errstr(status)); return False; } r.in.buf_size = r.out.buf_size; status = dcerpc_spoolss_EnumPrinterDataEx(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("EnumPrinterDataEx failed - %s\n", nt_errstr(status)); return False; } return True; } static BOOL test_DeletePrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle, const char *value_name) { NTSTATUS status; struct spoolss_DeletePrinterData r; r.in.handle = handle; r.in.value_name = value_name; printf("Testing DeletePrinterData\n"); status = dcerpc_spoolss_DeletePrinterData(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("DeletePrinterData failed - %s\n", nt_errstr(status)); return False; } return True; } static BOOL test_SetPrinterData(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { NTSTATUS status; struct spoolss_SetPrinterData r; const char *value_name = "spottyfoot"; r.in.handle = handle; r.in.value_name = value_name; r.in.type = 0; r.in.buffer = data_blob_talloc(mem_ctx, "dog", 4); r.in.real_len = 4; printf("Testing SetPrinterData\n"); status = dcerpc_spoolss_SetPrinterData(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("SetPrinterData failed - %s\n", nt_errstr(status)); return False; } if (!test_DeletePrinterData(p, mem_ctx, handle, value_name)) { return False; } return True; } static BOOL test_SecondaryClosePrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct policy_handle *handle) { NTSTATUS status; struct dcerpc_binding *b; struct dcerpc_pipe *p2; BOOL ret = True; /* only makes sense on SMB */ if (p->conn->transport.transport != NCACN_NP) { return True; } printf("testing close on secondary pipe\n"); status = dcerpc_parse_binding(mem_ctx, p->conn->binding_string, &b); if (!NT_STATUS_IS_OK(status)) { printf("Failed to parse dcerpc binding '%s'\n", p->conn->binding_string); return False; } status = dcerpc_secondary_connection(p, &p2, b); if (!NT_STATUS_IS_OK(status)) { printf("Failed to create secondary connection\n"); return False; } status = dcerpc_bind_auth_none(p2, DCERPC_SPOOLSS_UUID, DCERPC_SPOOLSS_VERSION); if (!NT_STATUS_IS_OK(status)) { printf("Failed to create bind on secondary connection\n"); talloc_free(p2); return False; } if (test_ClosePrinter(p2, mem_ctx, handle)) { printf("ERROR: Allowed close on secondary connection!\n"); ret = False; } if (p2->last_fault_code != DCERPC_FAULT_CONTEXT_MISMATCH) { printf("Unexpected fault code 0x%x - expected 0x%x\n", p2->last_fault_code, DCERPC_FAULT_CONTEXT_MISMATCH); ret = False; } talloc_free(p2); return ret; } static BOOL test_OpenPrinter_badname(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *name) { NTSTATUS status; struct spoolss_OpenPrinter op; struct spoolss_OpenPrinterEx opEx; struct policy_handle handle; BOOL ret = True; op.in.printername = name; op.in.datatype = NULL; op.in.devmode_ctr.size = 0; op.in.devmode_ctr.devmode= NULL; op.in.access_mask = 0; op.out.handle = &handle; printf("\nTesting OpenPrinter(%s) with bad name\n", op.in.printername); status = dcerpc_spoolss_OpenPrinter(p, mem_ctx, &op); if (!NT_STATUS_IS_OK(status)) { printf("OpenPrinter failed - %s\n", nt_errstr(status)); ret = False; } if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,op.out.result)) { printf("OpenPrinter(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", name, win_errstr(op.out.result)); } if (W_ERROR_IS_OK(op.out.result)) { ret &=test_ClosePrinter(p, mem_ctx, &handle); } opEx.in.printername = name; opEx.in.datatype = NULL; opEx.in.devmode_ctr.size = 0; opEx.in.devmode_ctr.devmode = NULL; opEx.in.access_mask = 0; opEx.in.level = 1; opEx.in.userlevel.level1 = NULL; opEx.out.handle = &handle; printf("\nTesting OpenPrinterEx(%s) with bad name\n", opEx.in.printername); status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &opEx); if (!NT_STATUS_IS_OK(status)) { printf("OpenPrinter failed - %s\n", nt_errstr(status)); ret = False; } if (!W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME,opEx.out.result)) { printf("OpenPrinterEx(%s) unexpected result[%s] should be WERR_INVALID_PRINTER_NAME\n", name, win_errstr(opEx.out.result)); } if (W_ERROR_IS_OK(opEx.out.result)) { ret &=test_ClosePrinter(p, mem_ctx, &handle); } return ret; } static BOOL test_OpenPrinter_badnames(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) { BOOL ret = True; char *name; ret &= test_OpenPrinter_badname(p, mem_ctx, "__INVALID_PRINTER__"); ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\__INVALID_HOST__"); ret &= test_OpenPrinter_badname(p, mem_ctx, ""); ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\\\"); ret &= test_OpenPrinter_badname(p, mem_ctx, "\\\\\\__INVALID_PRINTER__"); name = talloc_asprintf(mem_ctx, "\\\\%s\\", dcerpc_server_name(p)); ret &= test_OpenPrinter_badname(p, mem_ctx, name); talloc_free(name); name = talloc_asprintf(mem_ctx, "\\\\%s\\__INVALID_PRINTER__", dcerpc_server_name(p)); ret &= test_OpenPrinter_badname(p, mem_ctx, name); talloc_free(name); return ret; } static BOOL test_OpenPrinter(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *name) { NTSTATUS status; struct spoolss_OpenPrinter r; struct policy_handle handle; BOOL ret = True; r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", dcerpc_server_name(p), name); r.in.datatype = NULL; r.in.devmode_ctr.size = 0; r.in.devmode_ctr.devmode= NULL; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.out.handle = &handle; printf("\nTesting OpenPrinter(%s)\n", r.in.printername); status = dcerpc_spoolss_OpenPrinter(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("OpenPrinter failed - %s\n", nt_errstr(status)); return False; } if (!W_ERROR_IS_OK(r.out.result)) { printf("OpenPrinter failed - %s\n", win_errstr(r.out.result)); return False; } if (!test_GetPrinter(p, mem_ctx, &handle)) { ret = False; } if (!test_SecondaryClosePrinter(p, mem_ctx, &handle)) { ret = False; } if (!test_ClosePrinter(p, mem_ctx, &handle)) { ret = False; } return ret; } static BOOL call_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *name, struct policy_handle *handle) { struct spoolss_OpenPrinterEx r; struct spoolss_UserLevel1 userlevel1; NTSTATUS status; if (name && name[0]) { r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", dcerpc_server_name(p), name); } else { r.in.printername = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); } r.in.datatype = NULL; r.in.devmode_ctr.size = 0; r.in.devmode_ctr.devmode= NULL; r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; r.in.level = 1; r.in.userlevel.level1 = &userlevel1; r.out.handle = handle; userlevel1.size = 1234; userlevel1.client = "hello"; userlevel1.user = "spottyfoot!"; userlevel1.build = 1; userlevel1.major = 2; userlevel1.minor = 3; userlevel1.processor = 4; printf("Testing OpenPrinterEx(%s)\n", r.in.printername); status = dcerpc_spoolss_OpenPrinterEx(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("OpenPrinterEx failed - %s\n", nt_errstr(status)); return False; } if (!W_ERROR_IS_OK(r.out.result)) { printf("OpenPrinterEx failed - %s\n", win_errstr(r.out.result)); return False; } return True; } static BOOL test_OpenPrinterEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *name) { struct policy_handle handle; BOOL ret = True; if (!call_OpenPrinterEx(p, mem_ctx, name, &handle)) { return False; } if (!test_GetPrinter(p, mem_ctx, &handle)) { ret = False; } if (!test_EnumForms(p, mem_ctx, &handle)) { ret = False; } if (!test_AddForm(p, mem_ctx, &handle)) { ret = False; } if (!test_EnumPrinterData(p, mem_ctx, &handle)) { ret = False; } if (!test_EnumPrinterDataEx(p, mem_ctx, &handle)) { ret = False; } if (!test_EnumJobs(p, mem_ctx, &handle)) { ret = False; } if (!test_SetPrinterData(p, mem_ctx, &handle)) { ret = False; } if (!test_SecondaryClosePrinter(p, mem_ctx, &handle)) { ret = False; } if (!test_ClosePrinter(p, mem_ctx, &handle)) { ret = False; } return ret; } static BOOL test_EnumPrinters(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) { struct spoolss_EnumPrinters r; NTSTATUS status; uint16_t levels[] = {1, 2, 4, 5}; int i; BOOL ret = True; for (i=0;i