diff options
-rw-r--r-- | source4/librpc/idl/spoolss.idl | 19 | ||||
-rw-r--r-- | source4/rpc_server/spoolss/dcesrv_spoolss.c | 164 | ||||
-rw-r--r-- | source4/rpc_server/spoolss/dcesrv_spoolss.h | 4 | ||||
-rw-r--r-- | source4/torture/rpc/spoolss.c | 84 |
4 files changed, 250 insertions, 21 deletions
diff --git a/source4/librpc/idl/spoolss.idl b/source4/librpc/idl/spoolss.idl index 93efe7805f..0321ad16cb 100644 --- a/source4/librpc/idl/spoolss.idl +++ b/source4/librpc/idl/spoolss.idl @@ -573,7 +573,26 @@ /******************/ /* Function: 0x0c */ + typedef struct { + nstring directory_name; + } spoolss_DriverDirectoryInfo1; + + /* NOTE: it's seems that w2k3 completly ignores the level + in its server code + */ + typedef [nodiscriminant,relative_base,gensize,public] union { + [case(1)] spoolss_DriverDirectoryInfo1 info1; + [default] spoolss_DriverDirectoryInfo1 info1; + } spoolss_DriverDirectoryInfo; + WERROR spoolss_GetPrinterDriverDirectory( + [in] unistr *server, + [in] unistr *environment, + [in] uint32 level, + [in] DATA_BLOB *buffer, + [in] uint32 offered, + [out,subcontext(4),switch_is(level)] spoolss_DriverDirectoryInfo *info, + [out] uint32 needed ); /******************/ diff --git a/source4/rpc_server/spoolss/dcesrv_spoolss.c b/source4/rpc_server/spoolss/dcesrv_spoolss.c index b226816436..5c6506b7c2 100644 --- a/source4/rpc_server/spoolss/dcesrv_spoolss.c +++ b/source4/rpc_server/spoolss/dcesrv_spoolss.c @@ -356,7 +356,43 @@ static WERROR spoolss_GetPrinterDriver(struct dcesrv_call_state *dce_call, TALLO static WERROR spoolss_GetPrinterDriverDirectory(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_GetPrinterDriverDirectory *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + union spoolss_DriverDirectoryInfo *info; + const char *prefix; + const char *postfix; + + /* + * NOTE: normally r->in.level is 1, but both w2k3 and nt4 sp6a + * are ignoring the r->in.level completely, so we do :-) + */ + + /* + * TODO: check the server name is ours + * - if it's a invalid UNC then return WERR_INVALID_NAME + * - if it's the wrong host name return WERR_INVALID_PARAM + * - if it's "" then we need to return a local WINDOWS path + */ + if (strcmp("", r->in.server) == 0) { + prefix = "C:\\DRIVERS"; + } else { + prefix = talloc_asprintf(mem_ctx, "%s\\print$", r->in.server); + W_ERROR_HAVE_NO_MEMORY(prefix); + } + + if (strcmp(SPOOLSS_ARCHITECTURE_NT_X86, r->in.environment) == 0) { + postfix = "W32X86"; + } else { + return WERR_INVALID_ENVIRONMENT; + } + + info = talloc(mem_ctx, union spoolss_DriverDirectoryInfo); + W_ERROR_HAVE_NO_MEMORY(info); + + info->info1.directory_name = talloc_asprintf(mem_ctx, "%s\\%s", prefix, postfix); + W_ERROR_HAVE_NO_MEMORY(info->info1.directory_name); + + r->out.needed = ndr_size_spoolss_DriverDirectoryInfo(info, r->in.level, 0); + r->out.info = SPOOLSS_BUFFER_OK(info, NULL); + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); } @@ -666,16 +702,16 @@ static WERROR spoolss_EnumForms(struct dcesrv_call_state *dce_call, TALLOC_CTX * for (i=0; i < count; i++) { info[i].info1.flags = SPOOLSS_FORM_PRINTER; - info[i].info1.form_name = talloc_strdup(mem_ctx, "Samba Printer Form"); + info[i].info1.form_name = talloc_strdup(mem_ctx, "Letter"); W_ERROR_HAVE_NO_MEMORY(info[i].info1.form_name); - info[i].info1.size.width = 30; - info[i].info1.size.height = 40; + info[i].info1.size.width = 0x34b5c; + info[i].info1.size.height = 0x44368; info[i].info1.area.left = 0; info[i].info1.area.top = 0; - info[i].info1.area.right = 30; - info[i].info1.area.bottom = 40; + info[i].info1.area.right = 0x34b5c; + info[i].info1.area.bottom = 0x44368; } r->out.needed = SPOOLSS_BUFFER_SIZE(spoolss_EnumForms, r->in.level, count, info); r->out.info = SPOOLSS_BUFFER_OK(info, NULL); @@ -745,7 +781,46 @@ static WERROR spoolss_EnumPorts(struct dcesrv_call_state *dce_call, TALLOC_CTX * static WERROR spoolss_EnumMonitors(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_EnumMonitors *r) { - return WERR_OK; + union spoolss_MonitorInfo *info; + int count; + int i; + + count = 1; + + if (count == 0) return WERR_OK; + if (count < 0) return WERR_GENERAL_FAILURE; + + info = talloc_array(mem_ctx, union spoolss_MonitorInfo, count); + W_ERROR_HAVE_NO_MEMORY(info); + + switch (r->in.level) { + case 1: + for (i=0; i < count; i++) { + info[i].info1.monitor_name = talloc_strdup(mem_ctx, "Standard TCP/IP Port"); + W_ERROR_HAVE_NO_MEMORY(info[i].info1.monitor_name); + } + r->out.needed = SPOOLSS_BUFFER_SIZE(spoolss_EnumMonitors, r->in.level, count, info); + r->out.info = SPOOLSS_BUFFER_OK(info, NULL); + r->out.count = SPOOLSS_BUFFER_OK(count, 0); + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); + case 2: + for (i=0; i < count; i++) { + info[i].info2.monitor_name = talloc_strdup(mem_ctx, "Standard TCP/IP Port"); + W_ERROR_HAVE_NO_MEMORY(info[i].info2.monitor_name); + + info[i].info2.environment = talloc_strdup(mem_ctx, SPOOLSS_ARCHITECTURE_NT_X86); + W_ERROR_HAVE_NO_MEMORY(info[i].info2.environment); + + info[i].info2.dll_name = talloc_strdup(mem_ctx, "tcpmon.dll"); + W_ERROR_HAVE_NO_MEMORY(info[i].info2.dll_name); + } + r->out.needed = SPOOLSS_BUFFER_SIZE(spoolss_EnumMonitors, r->in.level, count, info); + r->out.info = SPOOLSS_BUFFER_OK(info, NULL); + r->out.count = SPOOLSS_BUFFER_OK(count, 0); + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); + } + + return WERR_UNKNOWN_LEVEL; } @@ -1108,6 +1183,41 @@ static WERROR spoolss_OpenPrinterEx_server(struct dcesrv_call_state *dce_call, return WERR_OK; } +static WERROR spoolss_OpenPrinterEx_port(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct spoolss_OpenPrinterEx *r, + const char *server_name, + const char *port_name) +{ + DEBUG(1, ("looking for port [%s] (server[%s])\n", port_name, server_name)); + + return WERR_INVALID_PRINTER_NAME; +} + +static WERROR spoolss_OpenPrinterEx_monitor(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct spoolss_OpenPrinterEx *r, + const char *server_name, + const char *monitor_name) +{ + if (strequal("Standard TCP/IP Port", monitor_name)) { + struct dcesrv_handle *handle; + + handle = dcesrv_handle_new(dce_call->context, SPOOLSS_HANDLE_MONITOR); + W_ERROR_HAVE_NO_MEMORY(handle); + + handle->data = NULL; + + *r->out.handle = handle->wire_handle; + + return WERR_OK; + } + + DEBUG(1, ("looking for monitor [%s] (server[%s])\n", monitor_name, server_name)); + + return WERR_INVALID_PRINTER_NAME; +} + static WERROR spoolss_OpenPrinterEx_printer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct spoolss_OpenPrinterEx *r, @@ -1127,7 +1237,7 @@ static WERROR spoolss_OpenPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_C { char *p; char *server = NULL; - const char *printer = r->in.printername; + const char *object = r->in.printername; ZERO_STRUCTP(r->out.handle); /* no printername is there it's like open server */ @@ -1160,25 +1270,49 @@ static WERROR spoolss_OpenPrinterEx(struct dcesrv_call_state *dce_call, TALLOC_C p[0] = '\0'; /* everything that follows is the printer name */ p++; - printer = p; + object = p; /* just "" as server is invalid */ if (strequal(server, "")) { - DEBUG(2,("ivalid server: [%s][%s][%s]\n", r->in.printername, server, printer)); + DEBUG(2,("OpenPrinterEx invalid print server: [%s][%s][%s]\n", r->in.printername, server, object)); return WERR_INVALID_PRINTER_NAME; } } /* just "" is invalid */ - if (strequal(printer, "")) { - DEBUG(2,("invalid printer: [%s][%s][%s]\n", r->in.printername, server, printer)); + if (strequal(object, "")) { + DEBUG(2,("OpenPrinterEx invalid object: [%s][%s][%s]\n", r->in.printername, server, object)); return WERR_INVALID_PRINTER_NAME; } - DEBUG(3,("printer: [%s][%s][%s]\n", r->in.printername, server, printer)); - return spoolss_OpenPrinterEx_printer(dce_call, mem_ctx, r, server, printer); -} + DEBUG(3,("OpenPrinterEx object: [%s][%s][%s]\n", r->in.printername, server, object)); + +#define XCV_PORT ",XcvPort " +#define XCV_MONITOR ",XcvMonitor " + if (strncmp(object, XCV_PORT, strlen(XCV_PORT)) == 0) { + object += strlen(XCV_PORT); + + /* just "" is invalid */ + if (strequal(object, "")) { + DEBUG(2,("OpenPrinterEx invalid port: [%s][%s][%s]\n", r->in.printername, server, object)); + return WERR_INVALID_PRINTER_NAME; + } + + return spoolss_OpenPrinterEx_port(dce_call, mem_ctx, r, server, object); + } else if (strncmp(object, XCV_MONITOR, strlen(XCV_MONITOR)) == 0) { + object += strlen(XCV_MONITOR); + /* just "" is invalid */ + if (strequal(object, "")) { + DEBUG(2,("OpenPrinterEx invalid monitor: [%s][%s][%s]\n", r->in.printername, server, object)); + return WERR_INVALID_PRINTER_NAME; + } + + return spoolss_OpenPrinterEx_monitor(dce_call, mem_ctx, r, server, object); + } + + return spoolss_OpenPrinterEx_printer(dce_call, mem_ctx, r, server, object); +} /* spoolss_AddPrinterEx diff --git a/source4/rpc_server/spoolss/dcesrv_spoolss.h b/source4/rpc_server/spoolss/dcesrv_spoolss.h index a72159a729..0b3f69ca2a 100644 --- a/source4/rpc_server/spoolss/dcesrv_spoolss.h +++ b/source4/rpc_server/spoolss/dcesrv_spoolss.h @@ -25,7 +25,9 @@ */ enum spoolss_handle_type { SPOOLSS_HANDLE_SERVER, - SPOOLSS_HANDLE_PRINTER + SPOOLSS_HANDLE_PRINTER, + SPOOLSS_HANDLE_PORT, + SPOOLSS_HANDLE_MONITOR }; /* diff --git a/source4/torture/rpc/spoolss.c b/source4/torture/rpc/spoolss.c index 7ae9291cf0..86a8c7155f 100644 --- a/source4/torture/rpc/spoolss.c +++ b/source4/torture/rpc/spoolss.c @@ -211,6 +211,78 @@ static BOOL test_EnumPorts(struct test_spoolss_context *ctx) return True; } +static BOOL test_GetPrinterDriverDirectory(struct test_spoolss_context *ctx) +{ + NTSTATUS status; + struct spoolss_GetPrinterDriverDirectory r; + struct { + uint16_t level; + const char *server; + } levels[] = {{ + .level = 1, + .server = "" + },{ + .level = 78, + .server = "" + },{ + .level = 1, + .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(ctx->p)) + },{ + .level = 1024, + .server = talloc_asprintf(ctx, "\\\\%s", dcerpc_server_name(ctx->p)) + } + }; + int i; + BOOL ret = True; + + for (i=0;i<ARRAY_SIZE(levels);i++) { + int level = levels[i].level; + DATA_BLOB blob; + + r.in.server = levels[i].server; + r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86; + r.in.level = level; + r.in.buffer = NULL; + r.in.offered = 0; + + printf("Testing GetPrinterDriverDirectory level %u\n", r.in.level); + + status = dcerpc_spoolss_GetPrinterDriverDirectory(ctx->p, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("dcerpc_spoolss_GetPrinterDriverDirectory failed - %s\n", nt_errstr(status)); + ret = False; + continue; + } + if (!W_ERROR_EQUAL(r.out.result, WERR_INSUFFICIENT_BUFFER)) { + printf("GetPrinterDriverDirectory unexspected return code %s, should be WERR_INSUFFICIENT_BUFFER\n", + win_errstr(r.out.result)); + ret = False; + continue; + } + + blob = data_blob_talloc(ctx, NULL, r.out.needed); + data_blob_clear(&blob); + r.in.buffer = &blob; + r.in.offered = r.out.needed; + + status = dcerpc_spoolss_GetPrinterDriverDirectory(ctx->p, ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("dcerpc_spoolss_GetPrinterDriverDirectory failed - %s\n", nt_errstr(status)); + ret = False; + continue; + } + + if (!W_ERROR_IS_OK(r.out.result)) { + printf("GetPrinterDriverDirectory failed - %s\n", + win_errstr(r.out.result)); + ret = False; + continue; + } + } + + return True; +} + static BOOL test_EnumPrinterDrivers(struct test_spoolss_context *ctx) { NTSTATUS status; @@ -223,11 +295,11 @@ static BOOL test_EnumPrinterDrivers(struct test_spoolss_context *ctx) int level = levels[i]; DATA_BLOB blob; - r.in.server = ""; - r.in.environment = "Windows NT x86"; - r.in.level = level; - r.in.buffer = NULL; - r.in.offered = 0; + r.in.server = ""; + r.in.environment = SPOOLSS_ARCHITECTURE_NT_X86; + r.in.level = level; + r.in.buffer = NULL; + r.in.offered = 0; printf("Testing EnumPrinterDrivers level %u\n", r.in.level); @@ -1994,6 +2066,8 @@ BOOL torture_rpc_spoolss(void) ret &= test_EnumPorts(ctx); + ret &= test_GetPrinterDriverDirectory(ctx); + ret &= test_EnumPrinterDrivers(ctx); ret &= test_EnumMonitors(ctx); |