/* Unix SMB/CIFS implementation. RPC pipe client Copyright (C) Gerald Carter 2001-2005 Copyright (C) Tim Potter 2000 Copyright (C) Andrew Tridgell 1992-1999 Copyright (C) Luke Kenneth Casson Leighton 1996-1999 Copyright (C) Guenther Deschner 2009 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 3 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, see . */ #include "includes.h" #include "rpcclient.h" #include "../librpc/gen_ndr/ndr_spoolss_c.h" #include "../librpc/gen_ndr/ndr_spoolss.h" #include "rpc_client/cli_spoolss.h" #include "rpc_client/init_spoolss.h" #include "nt_printing.h" #include "../libcli/security/display_sec.h" #include "../libcli/security/security_descriptor.h" #include "../libcli/registry/util_reg.h" #include "libsmb/libsmb.h" #include "lib/util/smb_strtox.h" #include "lib/util/string_wrappers.h" #include "lib/cmdline/cmdline.h" #define RPCCLIENT_PRINTERNAME(_printername, _cli, _arg) \ { \ _printername = talloc_asprintf_strupper_m(mem_ctx, "%s\\%s", \ _cli->srv_name_slash, _arg); \ W_ERROR_HAVE_NO_MEMORY(_printername); \ } /** * @file * * rpcclient module for SPOOLSS rpc pipe. * * This generally just parses and checks command lines, and then calls * a cli_spoolss function. **/ /**************************************************************************** function to do the mapping between the long architecture name and the short one. ****************************************************************************/ static const char *cmd_spoolss_get_short_archi(const char *long_archi) { int i=-1; DEBUG(107,("Getting architecture dependent directory\n")); do { i++; } while ( (archi_table[i].long_archi!=NULL ) && strcasecmp_m(long_archi, archi_table[i].long_archi) ); if (archi_table[i].long_archi==NULL) { DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi)); return NULL; } /* this might be client code - but shouldn't this be an fstrcpy etc? */ DEBUGADD(108,("index: [%d]\n", i)); DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi)); DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi)); return archi_table[i].short_archi; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_open_printer_ex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror; struct policy_handle hnd; uint32_t access_mask = PRINTER_ALL_ACCESS; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc < 2) { printf("Usage: %s [access_mask]\n", argv[0]); return WERR_OK; } if (argc >= 3) { sscanf(argv[2], "%x", &access_mask); } /* Open the printer handle */ werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, argv[1], access_mask, &hnd); if (W_ERROR_IS_OK(werror)) { printf("Printer %s opened successfully\n", argv[1]); dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror); if (!W_ERROR_IS_OK(werror)) { printf("Error closing printer handle! (%s)\n", get_dos_error_msg(werror)); } } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_open_printer(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror; struct policy_handle hnd; uint32_t access_mask = PRINTER_ALL_ACCESS; NTSTATUS status; struct spoolss_DevmodeContainer devmode_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; ZERO_STRUCT(devmode_ctr); if (argc < 2) { printf("Usage: %s [access_mask]\n", argv[0]); return WERR_OK; } if (argc >= 3) { sscanf(argv[2], "%x", &access_mask); } /* Open the printer handle */ status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, argv[1], NULL, devmode_ctr, access_mask, &hnd, &werror); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_IS_OK(werror)) { printf("Printer %s opened successfully\n", argv[1]); dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &werror); if (!W_ERROR_IS_OK(werror)) { printf("Error closing printer handle! (%s)\n", get_dos_error_msg(werror)); } } return werror; } /**************************************************************************** ****************************************************************************/ static void display_print_info0(struct spoolss_PrinterInfo0 *r) { if (!r) return; printf("\tprintername:[%s]\n", r->printername); printf("\tservername:[%s]\n", r->servername); printf("\tcjobs:[0x%x]\n", r->cjobs); printf("\ttotal_jobs:[0x%x]\n", r->total_jobs); printf("\ttotal_bytes:[0x%x]\n", r->total_bytes); printf("\t:date: [%d]-[%d]-[%d] (%d)\n", r->time.year, r->time.month, r->time.day, r->time.day_of_week); printf("\t:time: [%d]-[%d]-[%d]-[%d]\n", r->time.hour, r->time.minute, r->time.second, r->time.millisecond); printf("\tglobal_counter:[0x%x]\n", r->global_counter); printf("\ttotal_pages:[0x%x]\n", r->total_pages); printf("\tversion:[0x%x]\n", r->version); printf("\tfree_build:[0x%x]\n", r->free_build); printf("\tspooling:[0x%x]\n", r->spooling); printf("\tmax_spooling:[0x%x]\n", r->max_spooling); printf("\tsession_counter:[0x%x]\n", r->session_counter); printf("\tnum_error_out_of_paper:[0x%x]\n", r->num_error_out_of_paper); printf("\tnum_error_not_ready:[0x%x]\n", r->num_error_not_ready); printf("\tjob_error:[0x%x]\n", r->job_error); printf("\tnumber_of_processors:[0x%x]\n", r->number_of_processors); printf("\tprocessor_type:[0x%x]\n", r->processor_type); printf("\thigh_part_total_bytes:[0x%x]\n", r->high_part_total_bytes); printf("\tchange_id:[0x%x]\n", r->change_id); printf("\tlast_error: %s\n", win_errstr(r->last_error)); printf("\tstatus:[0x%x]\n", r->status); printf("\tenumerate_network_printers:[0x%x]\n", r->enumerate_network_printers); printf("\tc_setprinter:[0x%x]\n", r->c_setprinter); printf("\tprocessor_architecture:[0x%x]\n", r->processor_architecture); printf("\tprocessor_level:[0x%x]\n", r->processor_level); printf("\tref_ic:[0x%x]\n", r->ref_ic); printf("\treserved2:[0x%x]\n", r->reserved2); printf("\treserved3:[0x%x]\n", r->reserved3); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info1(struct spoolss_PrinterInfo1 *r) { printf("\tflags:[0x%x]\n", r->flags); printf("\tname:[%s]\n", r->name); printf("\tdescription:[%s]\n", r->description); printf("\tcomment:[%s]\n", r->comment); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info2(struct spoolss_PrinterInfo2 *r) { printf("\tservername:[%s]\n", r->servername); printf("\tprintername:[%s]\n", r->printername); printf("\tsharename:[%s]\n", r->sharename); printf("\tportname:[%s]\n", r->portname); printf("\tdrivername:[%s]\n", r->drivername); printf("\tcomment:[%s]\n", r->comment); printf("\tlocation:[%s]\n", r->location); printf("\tsepfile:[%s]\n", r->sepfile); printf("\tprintprocessor:[%s]\n", r->printprocessor); printf("\tdatatype:[%s]\n", r->datatype); printf("\tparameters:[%s]\n", r->parameters); printf("\tattributes:[0x%x]\n", r->attributes); printf("\tpriority:[0x%x]\n", r->priority); printf("\tdefaultpriority:[0x%x]\n", r->defaultpriority); printf("\tstarttime:[0x%x]\n", r->starttime); printf("\tuntiltime:[0x%x]\n", r->untiltime); printf("\tstatus:[0x%x]\n", r->status); printf("\tcjobs:[0x%x]\n", r->cjobs); printf("\taverageppm:[0x%x]\n", r->averageppm); if (r->secdesc) display_sec_desc(r->secdesc); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info3(struct spoolss_PrinterInfo3 *r) { display_sec_desc(r->secdesc); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info4(struct spoolss_PrinterInfo4 *r) { printf("\tservername:[%s]\n", r->servername); printf("\tprintername:[%s]\n", r->printername); printf("\tattributes:[0x%x]\n", r->attributes); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info5(struct spoolss_PrinterInfo5 *r) { printf("\tprintername:[%s]\n", r->printername); printf("\tportname:[%s]\n", r->portname); printf("\tattributes:[0x%x]\n", r->attributes); printf("\tdevice_not_selected_timeout:[0x%x]\n", r->device_not_selected_timeout); printf("\ttransmission_retry_timeout:[0x%x]\n", r->transmission_retry_timeout); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info6(struct spoolss_PrinterInfo6 *r) { printf("\tstatus:[0x%x]\n", r->status); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_info7(struct spoolss_PrinterInfo7 *r) { printf("\tguid:[%s]\n", r->guid); printf("\taction:[0x%x]\n", r->action); printf("\n"); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_printers(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; uint32_t level = 1; union spoolss_PrinterInfo *info; uint32_t i, count; const char *name; uint32_t flags = PRINTER_ENUM_LOCAL; if (argc > 4) { printf("Usage: %s [level] [name] [flags]\n", argv[0]); return WERR_OK; } if (argc >= 2) { level = atoi(argv[1]); } if (argc >= 3) { name = argv[2]; } else { name = cli->srv_name_slash; } if (argc == 4) { flags = atoi(argv[3]); } result = rpccli_spoolss_enumprinters(cli, mem_ctx, flags, name, level, 0, &count, &info); if (W_ERROR_IS_OK(result)) { if (!count) { printf ("No printers returned.\n"); goto done; } for (i = 0; i < count; i++) { switch (level) { case 0: display_print_info0(&info[i].info0); break; case 1: display_print_info1(&info[i].info1); break; case 2: display_print_info2(&info[i].info2); break; case 3: display_print_info3(&info[i].info3); break; case 4: display_print_info4(&info[i].info4); break; case 5: display_print_info5(&info[i].info5); break; case 6: display_print_info6(&info[i].info6); break; default: printf("unknown info level %d\n", level); goto done; } } } done: return result; } /**************************************************************************** ****************************************************************************/ static void display_port_info_1(struct spoolss_PortInfo1 *r) { printf("\tPort Name:\t[%s]\n", r->port_name); } /**************************************************************************** ****************************************************************************/ static void display_port_info_2(struct spoolss_PortInfo2 *r) { printf("\tPort Name:\t[%s]\n", r->port_name); printf("\tMonitor Name:\t[%s]\n", r->monitor_name); printf("\tDescription:\t[%s]\n", r->description); printf("\tPort Type:\t" ); if (r->port_type) { int comma = 0; /* hack */ printf( "[" ); if (r->port_type & SPOOLSS_PORT_TYPE_READ) { printf( "Read" ); comma = 1; } if (r->port_type & SPOOLSS_PORT_TYPE_WRITE) { printf( "%sWrite", comma ? ", " : "" ); comma = 1; } /* These two have slightly different interpretations on 95/98/ME but I'm disregarding that for now */ if (r->port_type & SPOOLSS_PORT_TYPE_REDIRECTED) { printf( "%sRedirected", comma ? ", " : "" ); comma = 1; } if (r->port_type & SPOOLSS_PORT_TYPE_NET_ATTACHED) { printf( "%sNet-Attached", comma ? ", " : "" ); } printf( "]\n" ); } else { printf( "[Unset]\n" ); } printf("\tReserved:\t[%d]\n", r->reserved); printf("\n"); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_ports(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; uint32_t level = 1; uint32_t count; union spoolss_PortInfo *info; if (argc > 2) { printf("Usage: %s [level]\n", argv[0]); return WERR_OK; } if (argc == 2) { level = atoi(argv[1]); } /* Enumerate ports */ result = rpccli_spoolss_enumports(cli, mem_ctx, cli->srv_name_slash, level, 0, &count, &info); if (W_ERROR_IS_OK(result)) { int i; for (i = 0; i < count; i++) { switch (level) { case 1: display_port_info_1(&info[i].info1); break; case 2: display_port_info_2(&info[i].info2); break; default: printf("unknown info level %d\n", level); break; } } } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_setprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR result; NTSTATUS status; uint32_t info_level = 2; union spoolss_PrinterInfo info; struct spoolss_SetPrinterInfoCtr info_ctr; struct spoolss_SetPrinterInfo2 info2; const char *printername, *comment = NULL; struct spoolss_DevmodeContainer devmode_ctr; struct sec_desc_buf secdesc_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc == 1 || argc > 3) { printf("Usage: %s printername comment\n", argv[0]); return WERR_OK; } /* Open a printer handle */ if (argc == 3) { comment = argv[2]; } ZERO_STRUCT(devmode_ctr); ZERO_STRUCT(secdesc_ctr); RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, PRINTER_ALL_ACCESS, &pol); if (!W_ERROR_IS_OK(result)) goto done; /* Get printer info */ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, 0, &info); if (!W_ERROR_IS_OK(result)) goto done; /* Modify the comment. */ spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); info2.comment = comment; info_ctr.level = 2; info_ctr.info.info2 = &info2; status = dcerpc_spoolss_SetPrinter(b, mem_ctx, &pol, &info_ctr, &devmode_ctr, &secdesc_ctr, 0, /* command */ &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (W_ERROR_IS_OK(result)) printf("Success in setting comment.\n"); done: if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_setprintername(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR result; NTSTATUS status; uint32_t info_level = 2; union spoolss_PrinterInfo info; const char *printername, *new_printername = NULL; struct spoolss_SetPrinterInfoCtr info_ctr; struct spoolss_SetPrinterInfo2 info2; struct spoolss_DevmodeContainer devmode_ctr; struct sec_desc_buf secdesc_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; ZERO_STRUCT(devmode_ctr); ZERO_STRUCT(secdesc_ctr); if (argc == 1 || argc > 3) { printf("Usage: %s printername new_printername\n", argv[0]); return WERR_OK; } /* Open a printer handle */ if (argc == 3) { new_printername = argv[2]; } RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, PRINTER_ALL_ACCESS, &pol); if (!W_ERROR_IS_OK(result)) goto done; /* Get printer info */ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, info_level, 0, &info); if (!W_ERROR_IS_OK(result)) goto done; /* Modify the printername. */ spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); info2.printername = new_printername; info_ctr.level = 2; info_ctr.info.info2 = &info2; status = dcerpc_spoolss_SetPrinter(b, mem_ctx, &pol, &info_ctr, &devmode_ctr, &secdesc_ctr, 0, /* command */ &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (W_ERROR_IS_OK(result)) printf("Success in setting printername.\n"); done: if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getprinter(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR result; uint32_t level = 1; const char *printername; union spoolss_PrinterInfo info; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc == 1 || argc > 3) { printf("Usage: %s [level]\n", argv[0]); return WERR_OK; } /* Open a printer handle */ if (argc == 3) { level = atoi(argv[2]); } RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!W_ERROR_IS_OK(result)) { goto done; } /* Get printer info */ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, 0, &info); if (!W_ERROR_IS_OK(result)) { goto done; } /* Display printer info */ switch (level) { case 0: display_print_info0(&info.info0); break; case 1: display_print_info1(&info.info1); break; case 2: display_print_info2(&info.info2); break; case 3: display_print_info3(&info.info3); break; case 4: display_print_info4(&info.info4); break; case 5: display_print_info5(&info.info5); break; case 6: display_print_info6(&info.info6); break; case 7: display_print_info7(&info.info7); break; default: printf("unknown info level %d\n", level); break; } done: if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static void display_reg_value(const char *name, enum winreg_Type type, DATA_BLOB blob) { const char *text = NULL; switch(type) { case REG_DWORD: if (blob.length >= sizeof(uint32_t)) { printf("%s: REG_DWORD: 0x%08x\n", name, IVAL(blob.data,0)); } else { printf("%s: REG_DWORD: \n", name); } break; case REG_SZ: pull_reg_sz(talloc_tos(), &blob, &text); printf("%s: REG_SZ: %s\n", name, text ? text : ""); break; case REG_BINARY: { char *hex = hex_encode_talloc(NULL, blob.data, blob.length); size_t i, len; printf("%s: REG_BINARY:", name); len = strlen(hex); for (i=0; ibinding_handle; if (argc != 3) { printf("Usage: %s \n", argv[0]); printf(" of . queries print server\n"); return WERR_OK; } valuename = argv[2]; /* Open a printer handle */ if (strncmp(argv[1], ".", sizeof(".")) == 0) fstrcpy(printername, cli->srv_name_slash); else slprintf(printername, sizeof(printername)-1, "%s\\%s", cli->srv_name_slash, argv[1]); /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!W_ERROR_IS_OK(result)) goto done; /* Get printer info */ result = rpccli_spoolss_getprinterdata(cli, mem_ctx, &pol, valuename, 0, &type, &needed, &data); if (!W_ERROR_IS_OK(result)) goto done; /* Display printer data */ display_printer_data(valuename, type, data, needed); done: if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getprinterdataex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR result; NTSTATUS status; fstring printername; const char *valuename, *keyname; enum winreg_Type type; uint8_t *data = NULL; uint32_t offered = 0; uint32_t needed; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc != 4) { printf("Usage: %s \n", argv[0]); printf(" of . queries print server\n"); return WERR_OK; } valuename = argv[3]; keyname = argv[2]; /* Open a printer handle */ if (strncmp(argv[1], ".", sizeof(".")) == 0) fstrcpy(printername, cli->srv_name_slash); else slprintf(printername, sizeof(printername)-1, "%s\\%s", cli->srv_name_slash, argv[1]); /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!W_ERROR_IS_OK(result)) goto done; /* Get printer info */ data = talloc_zero_array(mem_ctx, uint8_t, offered); if (!data) { goto done; } status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx, &pol, keyname, valuename, &type, data, offered, &needed, &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) { offered = needed; data = talloc_zero_array(mem_ctx, uint8_t, offered); if (!data) { goto done; } status = dcerpc_spoolss_GetPrinterDataEx(b, mem_ctx, &pol, keyname, valuename, &type, data, offered, &needed, &result); } if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) goto done; /* Display printer data */ display_printer_data(valuename, type, data, needed); done: if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static void display_print_driver1(struct spoolss_DriverInfo1 *r) { if (!r) { return; } printf("Printer Driver Info 1:\n"); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver2(struct spoolss_DriverInfo2 *r) { if (!r) { return; } printf("Printer Driver Info 2:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver3(struct spoolss_DriverInfo3 *r) { int i; if (!r) { return; } printf("Printer Driver Info 3:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\tHelpfile: [%s]\n", r->help_file); for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); } printf("\tMonitorname: [%s]\n", r->monitor_name); printf("\tDefaultdatatype: [%s]\n", r->default_datatype); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver4(struct spoolss_DriverInfo4 *r) { int i; if (!r) { return; } printf("Printer Driver Info 4:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\tHelpfile: [%s]\n", r->help_file); for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); } printf("\tMonitorname: [%s]\n", r->monitor_name); printf("\tDefaultdatatype: [%s]\n", r->default_datatype); for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { printf("\tPrevious Names: [%s]\n", r->previous_names[i]); } printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver5(struct spoolss_DriverInfo5 *r) { if (!r) { return; } printf("Printer Driver Info 5:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\tDriver Attributes: [0x%x]\n", r->driver_attributes); printf("\tConfig Version: [0x%x]\n", r->config_version); printf("\tDriver Version: [0x%x]\n", r->driver_version); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver6(struct spoolss_DriverInfo6 *r) { int i; if (!r) { return; } printf("Printer Driver Info 6:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\tHelpfile: [%s]\n", r->help_file); for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); } printf("\tMonitorname: [%s]\n", r->monitor_name); printf("\tDefaultdatatype: [%s]\n", r->default_datatype); for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { printf("\tPrevious Names: [%s]\n", r->previous_names[i]); } printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date)); printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version); printf("\tManufacturer Name: [%s]\n", r->manufacturer_name); printf("\tManufacturer Url: [%s]\n", r->manufacturer_url); printf("\tHardware ID: [%s]\n", r->hardware_id); printf("\tProvider: [%s]\n", r->provider); printf("\n"); } /**************************************************************************** ****************************************************************************/ static void display_print_driver8(struct spoolss_DriverInfo8 *r) { int i; if (!r) { return; } printf("Printer Driver Info 8:\n"); printf("\tVersion: [%x]\n", r->version); printf("\tDriver Name: [%s]\n", r->driver_name); printf("\tArchitecture: [%s]\n", r->architecture); printf("\tDriver Path: [%s]\n", r->driver_path); printf("\tDatafile: [%s]\n", r->data_file); printf("\tConfigfile: [%s]\n", r->config_file); printf("\tHelpfile: [%s]\n", r->help_file); printf("\tMonitorname: [%s]\n", r->monitor_name); printf("\tDefaultdatatype: [%s]\n", r->default_datatype); for (i=0; r->dependent_files && r->dependent_files[i] != NULL; i++) { printf("\tDependentfiles: [%s]\n", r->dependent_files[i]); } for (i=0; r->previous_names && r->previous_names[i] != NULL; i++) { printf("\tPrevious Names: [%s]\n", r->previous_names[i]); } printf("\tDriver Date: [%s]\n", nt_time_string(talloc_tos(), r->driver_date)); printf("\tDriver Version: [0x%016llx]\n", (long long unsigned int)r->driver_version); printf("\tManufacturer Name: [%s]\n", r->manufacturer_name); printf("\tManufacturer Url: [%s]\n", r->manufacturer_url); printf("\tHardware ID: [%s]\n", r->hardware_id); printf("\tProvider: [%s]\n", r->provider); printf("\tPrint Processor: [%s]\n", r->print_processor); printf("\tVendor Setup: [%s]\n", r->vendor_setup); for (i=0; r->color_profiles && r->color_profiles[i] != NULL; i++) { printf("\tColor Profiles: [%s]\n", r->color_profiles[i]); } printf("\tInf Path: [%s]\n", r->inf_path); printf("\tPrinter Driver Attributes: [0x%x]\n", r->printer_driver_attributes); for (i=0; r->core_driver_dependencies && r->core_driver_dependencies[i] != NULL; i++) { printf("\tCore Driver Dependencies: [%s]\n", r->core_driver_dependencies[i]); } printf("\tMin Driver Inbox Driver Version Date: [%s]\n", nt_time_string(talloc_tos(), r->min_inbox_driver_ver_date)); printf("\tMin Driver Inbox Driver Version Version: [0x%016llx]\n", (long long unsigned int)r->min_inbox_driver_ver_version); printf("\n"); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getdriver(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR werror; uint32_t level = 3; const char *printername; uint32_t i; bool success = false; union spoolss_DriverInfo info; uint32_t server_major_version; uint32_t server_minor_version; struct dcerpc_binding_handle *b = cli->binding_handle; if ((argc == 1) || (argc > 3)) { printf("Usage: %s [level]\n", argv[0]); return WERR_OK; } /* get the arguments need to open the printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); if (argc == 3) { level = atoi(argv[2]); } /* Open a printer handle */ werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, PRINTER_ACCESS_USE, &pol); if (!W_ERROR_IS_OK(werror)) { printf("Error opening printer handle for %s!\n", printername); return werror; } /* loop through and print driver info level for each architecture */ for (i=0; archi_table[i].long_archi!=NULL; i++) { werror = rpccli_spoolss_getprinterdriver2(cli, mem_ctx, &pol, archi_table[i].long_archi, level, 0, /* offered */ archi_table[i].version, 2, &info, &server_major_version, &server_minor_version); if (!W_ERROR_IS_OK(werror)) { continue; } /* need at least one success */ success = true; printf("\n[%s]\n", archi_table[i].long_archi); switch (level) { case 1: display_print_driver1(&info.info1); break; case 2: display_print_driver2(&info.info2); break; case 3: display_print_driver3(&info.info3); break; case 4: display_print_driver4(&info.info4); break; case 5: display_print_driver5(&info.info5); break; case 6: display_print_driver6(&info.info6); break; case 8: display_print_driver8(&info.info8); break; default: printf("unknown info level %d\n", level); break; } } /* Cleanup */ if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } if (success) { werror = WERR_OK; } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR enum_driver_by_architecture(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *architecture, uint32_t level) { WERROR werror; uint32_t count = 0; union spoolss_DriverInfo *info = NULL; uint32_t j; werror = rpccli_spoolss_enumprinterdrivers(cli, mem_ctx, cli->srv_name_slash, architecture, level, 0, &count, &info); if (W_ERROR_EQUAL(werror, WERR_INVALID_ENVIRONMENT)) { printf("Server does not support environment [%s]\n", architecture); return WERR_OK; } if (count == 0) { return WERR_OK; } if (!W_ERROR_IS_OK(werror)) { printf("Error getting driver for environment [%s] - %s\n", architecture, win_errstr(werror)); return werror; } printf("\n[%s]\n", architecture); switch (level) { case 1: for (j=0; j < count; j++) { display_print_driver1(&info[j].info1); } break; case 2: for (j=0; j < count; j++) { display_print_driver2(&info[j].info2); } break; case 3: for (j=0; j < count; j++) { display_print_driver3(&info[j].info3); } break; case 4: for (j=0; j < count; j++) { display_print_driver4(&info[j].info4); } break; case 5: for (j=0; j < count; j++) { display_print_driver5(&info[j].info5); } break; case 6: for (j=0; j < count; j++) { display_print_driver6(&info[j].info6); } break; case 8: for (j=0; j < count; j++) { display_print_driver8(&info[j].info8); } break; default: printf("unknown info level %d\n", level); return WERR_INVALID_LEVEL; } return werror; } static WERROR cmd_spoolss_enum_drivers(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror = WERR_OK; uint32_t level = 1; uint32_t i; const char *architecture = NULL; if (argc > 3) { printf("Usage: enumdrivers [level] [architecture]\n"); return WERR_OK; } if (argc >= 2) { level = atoi(argv[1]); } if (argc == 3) { architecture = argv[2]; } if (architecture) { return enum_driver_by_architecture(cli, mem_ctx, architecture, level); } /* loop through and print driver info level for each architecture */ for (i=0; archi_table[i].long_archi!=NULL; i++) { /* check to see if we already asked for this architecture string */ if (i>0 && strequal(archi_table[i].long_archi, archi_table[i-1].long_archi)) { continue; } werror = enum_driver_by_architecture(cli, mem_ctx, archi_table[i].long_archi, level); if (!W_ERROR_IS_OK(werror)) { break; } } return werror; } /**************************************************************************** ****************************************************************************/ static void display_printdriverdir_1(struct spoolss_DriverDirectoryInfo1 *r) { printf("\tDirectory Name:[%s]\n", r->directory_name); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getdriverdir(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; const char *env = SPOOLSS_ARCHITECTURE_NT_X86; DATA_BLOB buffer; uint32_t offered; union spoolss_DriverDirectoryInfo info; uint32_t needed; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc > 2) { printf("Usage: %s [environment]\n", argv[0]); return WERR_OK; } /* Get the arguments need to open the printer handle */ if (argc == 2) { env = argv[1]; } /* Get the directory. Only use Info level 1 */ status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx, cli->srv_name_slash, env, 1, NULL, /* buffer */ 0, /* offered */ NULL, /* info */ &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { offered = needed; buffer = data_blob_talloc_zero(mem_ctx, needed); status = dcerpc_spoolss_GetPrinterDriverDirectory(b, mem_ctx, cli->srv_name_slash, env, 1, &buffer, offered, &info, &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } } if (W_ERROR_IS_OK(result)) { display_printdriverdir_1(&info.info1); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getdriverpackagepath(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { HRESULT hresult; NTSTATUS status; const char *env = SPOOLSS_ARCHITECTURE_NT_X86; uint32_t offered; uint32_t needed; struct dcerpc_binding_handle *b = cli->binding_handle; const char *package_id = ""; const char *cab = NULL; if (argc > 4) { printf("Usage: %s [environment] [package_id]\n", argv[0]); return WERR_OK; } /* Get the arguments need to open the printer handle */ if (argc >= 2) { env = argv[1]; } if (argc == 3) { package_id = argv[2]; } offered = 1; cab = talloc_zero_array(mem_ctx, char, offered); if (cab == NULL) { return WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_spoolss_GetPrinterDriverPackagePath(b, mem_ctx, cli->srv_name_slash, env, NULL, package_id, cab, offered, &needed, &hresult); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_EQUAL(W_ERROR(WIN32_FROM_HRESULT(hresult)), WERR_INSUFFICIENT_BUFFER)) { offered = needed; cab = talloc_zero_array(mem_ctx, char, offered); if (cab == NULL) { return WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_spoolss_GetPrinterDriverPackagePath(b, mem_ctx, cli->srv_name_slash, env, NULL, package_id, cab, offered, &needed, &hresult); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } } return W_ERROR(WIN32_FROM_HRESULT(hresult)); } /**************************************************************************** ****************************************************************************/ static void set_drv_info_3_env(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *info, const char *arch) { int i; for (i=0; archi_table[i].long_archi != NULL; i++) { if (strcmp(arch, archi_table[i].short_archi) == 0) { info->version = archi_table[i].version; info->architecture = talloc_strdup(mem_ctx, archi_table[i].long_archi); break; } } if (archi_table[i].long_archi == NULL) { DEBUG(0, ("set_drv_info_3_env: Unknown arch [%s]\n", arch)); } return; } /************************************************************************** wrapper for strtok to get the next parameter from a delimited list. Needed to handle the empty parameter string denoted by "NULL" *************************************************************************/ static char *get_driver_3_param(TALLOC_CTX *mem_ctx, char *str, const char *delim, const char **dest, char **saveptr) { char *ptr; /* get the next token */ ptr = strtok_r(str, delim, saveptr); /* a string of 'NULL' is used to represent an empty parameter because two consecutive delimiters will not return an empty string. See man strtok(3) for details */ if (ptr && (strcasecmp_m(ptr, "NULL") == 0)) { ptr = NULL; } if (dest != NULL) { *dest = talloc_strdup(mem_ctx, ptr); } return ptr; } /******************************************************************************** fill in the members of a spoolss_AddDriverInfo3 struct using a character string in the form of :::\ :::\ : *******************************************************************************/ static bool init_drv_info_3_members(TALLOC_CTX *mem_ctx, struct spoolss_AddDriverInfo3 *r, char *args) { char *str, *str2; size_t count = 0; char *saveptr = NULL; struct spoolss_StringArray *deps; const char **file_array = NULL; int i; /* fill in the UNISTR fields */ str = get_driver_3_param(mem_ctx, args, ":", &r->driver_name, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->driver_path, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->data_file, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->config_file, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->help_file, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->monitor_name, &saveptr); str = get_driver_3_param(mem_ctx, NULL, ":", &r->default_datatype, &saveptr); /* */ /* save the beginning of the string */ str2 = get_driver_3_param(mem_ctx, NULL, ":", NULL, &saveptr); str = str2; /* begin to strip out each filename */ str = strtok_r(str, ",", &saveptr); /* no dependent files, we are done */ if (!str) { return true; } deps = talloc_zero(mem_ctx, struct spoolss_StringArray); if (!deps) { return false; } while (str != NULL) { bool ok; ok = add_string_to_array(deps, str, &file_array, &count); if (!ok) { return false; } str = strtok_r(NULL, ",", &saveptr); } deps->string = talloc_zero_array(deps, const char *, count + 1); if (!deps->string) { return false; } for (i=0; i < count; i++) { deps->string[i] = file_array[i]; } r->dependent_files = deps; return true; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_addprinterdriver(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; uint32_t level = 3; struct spoolss_AddDriverInfoCtr info_ctr; struct spoolss_AddDriverInfo3 info3; const char *arch; char *driver_args; struct dcerpc_binding_handle *b = cli->binding_handle; /* parse the command arguments */ if (argc != 3 && argc != 4) { printf ("Usage: %s \\\n", argv[0]); printf ("\t:::\\\n"); printf ("\t:::\\\n"); printf ("\t: \\\n"); printf ("\t[version]\n"); return WERR_OK; } /* Fill in the spoolss_AddDriverInfo3 struct */ ZERO_STRUCT(info3); arch = cmd_spoolss_get_short_archi(argv[1]); if (!arch) { printf ("Error Unknown architecture [%s]\n", argv[1]); return WERR_INVALID_PARAMETER; } set_drv_info_3_env(mem_ctx, &info3, arch); driver_args = talloc_strdup( mem_ctx, argv[2] ); if (!init_drv_info_3_members(mem_ctx, &info3, driver_args )) { printf ("Error Invalid parameter list - %s.\n", argv[2]); return WERR_INVALID_PARAMETER; } /* if printer driver version specified, override the default version * used by the architecture. This allows installation of Windows * 2000 (version 3) printer drivers. */ if (argc == 4) { info3.version = atoi(argv[3]); } info_ctr.level = level; info_ctr.info.info3 = &info3; status = dcerpc_spoolss_AddPrinterDriver(b, mem_ctx, cli->srv_name_slash, &info_ctr, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_IS_OK(result)) { printf ("Printer Driver %s successfully installed.\n", info3.driver_name); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_addprinterex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; struct spoolss_SetPrinterInfoCtr info_ctr; struct spoolss_SetPrinterInfo2 info2; /* parse the command arguments */ if (argc != 5) { printf ("Usage: %s \n", argv[0]); return WERR_OK; } /* Fill in the DRIVER_INFO_2 struct */ ZERO_STRUCT(info2); info2.printername = argv[1]; info2.drivername = argv[3]; info2.sharename = argv[2]; info2.portname = argv[4]; info2.comment = "Created by rpcclient"; info2.printprocessor = "winprint"; info2.datatype = "RAW"; info2.devmode_ptr = 0; info2.secdesc_ptr = 0; info2.attributes = PRINTER_ATTRIBUTE_SHARED; info2.priority = 0; info2.defaultpriority = 0; info2.starttime = 0; info2.untiltime = 0; /* These three fields must not be used by AddPrinter() as defined in the MS Platform SDK documentation.. --jerry info2.status = 0; info2.cjobs = 0; info2.averageppm = 0; */ info_ctr.level = 2; info_ctr.info.info2 = &info2; result = rpccli_spoolss_addprinterex(cli, mem_ctx, &info_ctr); if (W_ERROR_IS_OK(result)) printf ("Printer %s successfully installed.\n", argv[1]); return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_setdriver(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle pol; WERROR result; NTSTATUS status; uint32_t level = 2; const char *printername; union spoolss_PrinterInfo info; struct spoolss_SetPrinterInfoCtr info_ctr; struct spoolss_SetPrinterInfo2 info2; struct spoolss_DevmodeContainer devmode_ctr; struct sec_desc_buf secdesc_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; ZERO_STRUCT(devmode_ctr); ZERO_STRUCT(secdesc_ctr); /* parse the command arguments */ if (argc != 3) { printf ("Usage: %s \n", argv[0]); return WERR_OK; } RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); /* Get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, PRINTER_ALL_ACCESS, &pol); if (!W_ERROR_IS_OK(result)) goto done; /* Get printer info */ result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, level, 0, &info); if (!W_ERROR_IS_OK(result)) { printf ("Unable to retrieve printer information!\n"); goto done; } /* Set the printer driver */ spoolss_printerinfo2_to_setprinterinfo2(&info.info2, &info2); info2.drivername = argv[2]; info_ctr.level = 2; info_ctr.info.info2 = &info2; status = dcerpc_spoolss_SetPrinter(b, mem_ctx, &pol, &info_ctr, &devmode_ctr, &secdesc_ctr, 0, /* command */ &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { printf("SetPrinter call failed!\n"); goto done; } printf("Successfully set %s to driver %s.\n", argv[1], argv[2]); done: /* Cleanup */ if (is_valid_policy_hnd(&pol)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_deletedriverex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result, ret = WERR_UNKNOWN_PRINTER_DRIVER; NTSTATUS status; struct dcerpc_binding_handle *b = cli->binding_handle; int i; int vers = -1; const char *arch = NULL; uint32_t delete_flags = 0; /* parse the command arguments */ if (argc < 2 || argc > 5) { printf("Usage: %s [arch] [version] [flags]\n", argv[0]); return WERR_OK; } if (argc >= 3) arch = argv[2]; if (argc >= 4) { vers = atoi(argv[3]); delete_flags |= DPD_DELETE_SPECIFIC_VERSION; } if (argc == 5) delete_flags = atoi(argv[4]); /* delete the driver for all architectures */ for (i=0; archi_table[i].long_archi; i++) { if (arch && !strequal(archi_table[i].long_archi, arch)) continue; if (vers >= 0 && archi_table[i].version != vers) continue; /* make the call to remove the driver */ status = dcerpc_spoolss_DeletePrinterDriverEx(b, mem_ctx, cli->srv_name_slash, archi_table[i].long_archi, argv[1], delete_flags, archi_table[i].version, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if ( !W_ERROR_IS_OK(result) ) { if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) { printf ("Failed to remove driver %s for arch [%s] (version: %d): %s\n", argv[1], archi_table[i].long_archi, archi_table[i].version, win_errstr(result)); } } else { printf ("Driver %s and files removed for arch [%s] (version: %d).\n", argv[1], archi_table[i].long_archi, archi_table[i].version); ret = WERR_OK; } } return ret; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_deletedriver(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result = WERR_OK; NTSTATUS status; int i; struct dcerpc_binding_handle *b = cli->binding_handle; /* parse the command arguments */ if (argc != 2) { printf ("Usage: %s \n", argv[0]); return WERR_OK; } /* delete the driver for all architectures */ for (i=0; archi_table[i].long_archi; i++) { result = WERR_OK; /* make the call to remove the driver */ status = dcerpc_spoolss_DeletePrinterDriver(b, mem_ctx, cli->srv_name_slash, archi_table[i].long_archi, argv[1], &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); continue; } if ( !W_ERROR_IS_OK(result) ) { if ( !W_ERROR_EQUAL(result, WERR_UNKNOWN_PRINTER_DRIVER) ) { printf ("Failed to remove driver %s for arch [%s] - error %s!\n", argv[1], archi_table[i].long_archi, win_errstr(result)); } } else { printf ("Driver %s removed for arch [%s].\n", argv[1], archi_table[i].long_archi); } } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getprintprocdir(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; const char *environment = SPOOLSS_ARCHITECTURE_NT_X86; DATA_BLOB buffer; uint32_t offered; union spoolss_PrintProcessorDirectoryInfo info = {}; uint32_t needed; struct dcerpc_binding_handle *b = cli->binding_handle; /* parse the command arguments */ if (argc > 2) { printf ("Usage: %s [environment]\n", argv[0]); return WERR_OK; } if (argc == 2) { environment = argv[1]; } status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx, cli->srv_name_slash, environment, 1, NULL, /* buffer */ 0, /* offered */ NULL, /* info */ &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { offered = needed; buffer = data_blob_talloc_zero(mem_ctx, needed); status = dcerpc_spoolss_GetPrintProcessorDirectory(b, mem_ctx, cli->srv_name_slash, environment, 1, &buffer, offered, &info, &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } } if (W_ERROR_IS_OK(result) && info.info1.directory_name != NULL) { printf("%s\n", info.info1.directory_name); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_addform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle handle; WERROR werror; NTSTATUS status; const char *printername; struct spoolss_AddFormInfoCtr info_ctr; struct spoolss_AddFormInfo1 info1; struct spoolss_AddFormInfo2 info2; uint32_t level = 1; struct dcerpc_binding_handle *b = cli->binding_handle; /* Parse the command arguments */ if (argc < 3 || argc > 5) { printf ("Usage: %s [level]\n", argv[0]); return WERR_OK; } /* Get a printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, PRINTER_ALL_ACCESS, &handle); if (!W_ERROR_IS_OK(werror)) goto done; /* Dummy up some values for the form data */ if (argc == 4) { level = atoi(argv[3]); } switch (level) { case 1: info1.flags = SPOOLSS_FORM_USER; info1.form_name = argv[2]; info1.size.width = 100; info1.size.height = 100; info1.area.left = 0; info1.area.top = 10; info1.area.right = 20; info1.area.bottom = 30; info_ctr.level = 1; info_ctr.info.info1 = &info1; break; case 2: info2.flags = SPOOLSS_FORM_USER; info2.form_name = argv[2]; info2.size.width = 100; info2.size.height = 100; info2.area.left = 0; info2.area.top = 10; info2.area.right = 20; info2.area.bottom = 30; info2.keyword = argv[2]; info2.string_type = SPOOLSS_FORM_STRING_TYPE_NONE; info2.mui_dll = NULL; info2.ressource_id = 0; info2.display_name = argv[2]; info2.lang_id = 0; info_ctr.level = 2; info_ctr.info.info2 = &info2; break; default: werror = WERR_INVALID_PARAMETER; goto done; } /* Add the form */ status = dcerpc_spoolss_AddForm(b, mem_ctx, &handle, &info_ctr, &werror); if (!NT_STATUS_IS_OK(status)) { werror = ntstatus_to_werror(status); goto done; } done: if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_setform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle handle; WERROR werror; NTSTATUS status; const char *printername; struct spoolss_AddFormInfoCtr info_ctr; struct spoolss_AddFormInfo1 info1; struct dcerpc_binding_handle *b = cli->binding_handle; /* Parse the command arguments */ if (argc != 3) { printf ("Usage: %s \n", argv[0]); return WERR_OK; } /* Get a printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(werror)) goto done; /* Dummy up some values for the form data */ info1.flags = SPOOLSS_FORM_PRINTER; info1.size.width = 100; info1.size.height = 100; info1.area.left = 0; info1.area.top = 1000; info1.area.right = 2000; info1.area.bottom = 3000; info1.form_name = argv[2]; info_ctr.info.info1 = &info1; info_ctr.level = 1; /* Set the form */ status = dcerpc_spoolss_SetForm(b, mem_ctx, &handle, argv[2], &info_ctr, &werror); if (!NT_STATUS_IS_OK(status)) { werror = ntstatus_to_werror(status); goto done; } done: if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return werror; } /**************************************************************************** ****************************************************************************/ static const char *get_form_flag(int form_flag) { switch (form_flag) { case SPOOLSS_FORM_USER: return "FORM_USER"; case SPOOLSS_FORM_BUILTIN: return "FORM_BUILTIN"; case SPOOLSS_FORM_PRINTER: return "FORM_PRINTER"; default: return "unknown"; } } /**************************************************************************** ****************************************************************************/ static void display_form_info1(struct spoolss_FormInfo1 *r) { printf("%s\n" \ "\tflag: %s (%d)\n" \ "\twidth: %d, length: %d\n" \ "\tleft: %d, right: %d, top: %d, bottom: %d\n\n", r->form_name, get_form_flag(r->flags), r->flags, r->size.width, r->size.height, r->area.left, r->area.right, r->area.top, r->area.bottom); } /**************************************************************************** ****************************************************************************/ static void display_form_info2(struct spoolss_FormInfo2 *r) { printf("%s\n" \ "\tflag: %s (%d)\n" \ "\twidth: %d, length: %d\n" \ "\tleft: %d, right: %d, top: %d, bottom: %d\n", r->form_name, get_form_flag(r->flags), r->flags, r->size.width, r->size.height, r->area.left, r->area.right, r->area.top, r->area.bottom); printf("\tkeyword: %s\n", r->keyword); printf("\tstring_type: 0x%08x\n", r->string_type); printf("\tmui_dll: %s\n", r->mui_dll); printf("\tressource_id: 0x%08x\n", r->ressource_id); printf("\tdisplay_name: %s\n", r->display_name); printf("\tlang_id: %d\n", r->lang_id); printf("\n"); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_getform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle handle; WERROR werror; NTSTATUS status; const char *printername; DATA_BLOB buffer; uint32_t offered = 0; union spoolss_FormInfo info; uint32_t needed; uint32_t level = 1; struct dcerpc_binding_handle *b = cli->binding_handle; /* Parse the command arguments */ if (argc < 3 || argc > 5) { printf ("Usage: %s [level]\n", argv[0]); return WERR_OK; } /* Get a printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(werror)) goto done; if (argc == 4) { level = atoi(argv[3]); } /* Get the form */ status = dcerpc_spoolss_GetForm(b, mem_ctx, &handle, argv[2], level, NULL, offered, &info, &needed, &werror); if (!NT_STATUS_IS_OK(status)) { werror = ntstatus_to_werror(status); goto done; } if (W_ERROR_EQUAL(werror, WERR_INSUFFICIENT_BUFFER)) { buffer = data_blob_talloc_zero(mem_ctx, needed); offered = needed; status = dcerpc_spoolss_GetForm(b, mem_ctx, &handle, argv[2], level, &buffer, offered, &info, &needed, &werror); if (!NT_STATUS_IS_OK(status)) { werror = ntstatus_to_werror(status); goto done; } } if (!W_ERROR_IS_OK(werror)) { goto done; } switch (level) { case 1: display_form_info1(&info.info1); break; case 2: display_form_info2(&info.info2); break; } done: if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_deleteform(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle handle; WERROR werror; NTSTATUS status; const char *printername; struct dcerpc_binding_handle *b = cli->binding_handle; /* Parse the command arguments */ if (argc != 3) { printf ("Usage: %s \n", argv[0]); return WERR_OK; } /* Get a printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(werror)) goto done; /* Delete the form */ status = dcerpc_spoolss_DeleteForm(b, mem_ctx, &handle, argv[2], &werror); if (!NT_STATUS_IS_OK(status)) { werror = ntstatus_to_werror(status); goto done; } done: if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_forms(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct policy_handle handle; WERROR werror; const char *printername; uint32_t num_forms, level = 1, i; union spoolss_FormInfo *forms; struct dcerpc_binding_handle *b = cli->binding_handle; /* Parse the command arguments */ if (argc < 2 || argc > 4) { printf ("Usage: %s [level]\n", argv[0]); return WERR_OK; } /* Get a printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(werror)) goto done; if (argc == 3) { level = atoi(argv[2]); } /* Enumerate forms */ werror = rpccli_spoolss_enumforms(cli, mem_ctx, &handle, level, 0, &num_forms, &forms); if (!W_ERROR_IS_OK(werror)) goto done; /* Display output */ for (i = 0; i < num_forms; i++) { switch (level) { case 1: display_form_info1(&forms[i].info1); break; case 2: display_form_info2(&forms[i].info2); break; } } done: if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return werror; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_setprinterdata(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; const char *printername; struct policy_handle pol = { 0, }; union spoolss_PrinterInfo info; enum winreg_Type type; union spoolss_PrinterData data; DATA_BLOB blob; struct dcerpc_binding_handle *b = cli->binding_handle; int error = 0; /* parse the command arguments */ if (argc < 5) { printf ("Usage: %s " " \n", argv[0]); return WERR_OK; } RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); type = REG_NONE; if (strequal(argv[2], "string")) { type = REG_SZ; } if (strequal(argv[2], "binary")) { type = REG_BINARY; } if (strequal(argv[2], "dword")) { type = REG_DWORD; } if (strequal(argv[2], "multistring")) { type = REG_MULTI_SZ; } if (type == REG_NONE) { printf("Unknown data type: %s\n", argv[2]); result = WERR_INVALID_PARAMETER; goto done; } /* get a printer handle */ result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!W_ERROR_IS_OK(result)) { goto done; } result = rpccli_spoolss_getprinter(cli, mem_ctx, &pol, 0, 0, &info); if (!W_ERROR_IS_OK(result)) { goto done; } printf("%s\n", current_timestring(mem_ctx, true)); printf("\tchange_id (before set)\t:[0x%x]\n", info.info0.change_id); /* Set the printer data */ switch (type) { case REG_SZ: data.string = talloc_strdup(mem_ctx, argv[4]); W_ERROR_HAVE_NO_MEMORY(data.string); break; case REG_DWORD: data.value = smb_strtoul(argv[4], NULL, 10, &error, SMB_STR_STANDARD); if (error != 0) { result = WERR_INVALID_PARAMETER; goto done; } break; case REG_BINARY: data.binary = strhex_to_data_blob(mem_ctx, argv[4]); break; case REG_MULTI_SZ: { int i; size_t num_strings; const char **strings = NULL; num_strings = 0; for (i=4; iposition, r->job_id, r->user_name, r->document_name, r->text_status, r->pages_printed, r->total_pages); } /**************************************************************************** ****************************************************************************/ static void display_job_info2(struct spoolss_JobInfo2 *r) { printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d bytes\n", r->position, r->job_id, r->user_name, r->document_name, r->text_status, r->pages_printed, r->total_pages, r->size); } /**************************************************************************** ****************************************************************************/ static void display_job_info3(struct spoolss_JobInfo3 *r) { printf("jobid[%d], next_jobid[%d]\n", r->job_id, r->next_job_id); } /**************************************************************************** ****************************************************************************/ static void display_job_info4(struct spoolss_JobInfo4 *r) { printf("%d: jobid[%d]: %s %s %s %d/%d pages, %d/%d bytes\n", r->position, r->job_id, r->user_name, r->document_name, r->text_status, r->pages_printed, r->total_pages, r->size, r->size_high); } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_jobs(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; uint32_t level = 1, count, i; const char *printername; struct policy_handle hnd; union spoolss_JobInfo *info; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc < 2 || argc > 3) { printf("Usage: %s printername [level]\n", argv[0]); return WERR_OK; } if (argc == 3) { level = atoi(argv[2]); } /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) goto done; /* Enumerate ports */ result = rpccli_spoolss_enumjobs(cli, mem_ctx, &hnd, 0, /* firstjob */ 1000, /* numjobs */ level, 0, &count, &info); if (!W_ERROR_IS_OK(result)) { goto done; } for (i = 0; i < count; i++) { switch (level) { case 1: display_job_info1(&info[i].info1); break; case 2: display_job_info2(&info[i].info2); break; default: d_printf("unknown info level %d\n", level); break; } } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_get_job(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; const char *printername; struct policy_handle hnd; uint32_t job_id; uint32_t level = 1; union spoolss_JobInfo info; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc < 3 || argc > 4) { printf("Usage: %s printername job_id [level]\n", argv[0]); return WERR_OK; } job_id = atoi(argv[2]); if (argc == 4) { level = atoi(argv[3]); } /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { goto done; } /* Enumerate ports */ result = rpccli_spoolss_getjob(cli, mem_ctx, &hnd, job_id, level, 0, &info); if (!W_ERROR_IS_OK(result)) { goto done; } switch (level) { case 1: display_job_info1(&info.info1); break; case 2: display_job_info2(&info.info2); break; case 3: display_job_info3(&info.info3); break; case 4: display_job_info4(&info.info4); break; default: d_printf("unknown info level %d\n", level); break; } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static struct { const char *name; enum spoolss_JobControl val; } cmdvals[] = { {"PAUSE", SPOOLSS_JOB_CONTROL_PAUSE}, {"RESUME", SPOOLSS_JOB_CONTROL_RESUME}, {"CANCEL", SPOOLSS_JOB_CONTROL_CANCEL}, {"RESTART", SPOOLSS_JOB_CONTROL_RESTART}, {"DELETE", SPOOLSS_JOB_CONTROL_DELETE}, {"SEND_TO_PRINTER", SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER}, {"EJECTED", SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED}, {"RETAIN", SPOOLSS_JOB_CONTROL_RETAIN}, {"RELEASE", SPOOLSS_JOB_CONTROL_RELEASE} }; static enum spoolss_JobControl parse_setjob_command(const char *cmd) { int i; for (i = 0; i < sizeof(cmdvals)/sizeof(cmdvals[0]); i++) { if (strequal(cmdvals[i].name, cmd)) { return cmdvals[i].val; } } return (enum spoolss_JobControl)atoi(cmd); } static WERROR cmd_spoolss_set_job(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; const char *printername; struct policy_handle hnd; uint32_t job_id; enum spoolss_JobControl command; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc != 4) { printf("Usage: %s printername job_id command\n", argv[0]); printf("command = [PAUSE|RESUME|CANCEL|RESTART|DELETE|" "SEND_TO_PRINTER|EJECTED|RETAIN|RELEASE]\n"); return WERR_OK; } job_id = atoi(argv[2]); command = parse_setjob_command(argv[3]); /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { goto done; } /* Set Job */ status = dcerpc_spoolss_SetJob(b, mem_ctx, &hnd, job_id, NULL, command, &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { goto done; } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; const char *printername; struct policy_handle hnd; uint32_t value_needed; enum winreg_Type type; uint32_t data_needed; struct dcerpc_binding_handle *b = cli->binding_handle; struct spoolss_EnumPrinterData r; if (argc != 2) { printf("Usage: %s printername\n", argv[0]); return WERR_OK; } /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { goto done; } /* Enumerate data */ r.in.handle = &hnd; r.in.enum_index = 0; r.in.value_offered = 0; r.in.data_offered = 0; r.out.value_name = NULL; r.out.value_needed = &value_needed; r.out.type = &type; r.out.data = NULL; r.out.data_needed = &data_needed; status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(r.out.result)) { result = r.out.result; goto done; } r.in.data_offered = *r.out.data_needed; r.in.value_offered = *r.out.value_needed; r.out.data = talloc_zero_array(mem_ctx, uint8_t, r.in.data_offered); r.out.value_name = talloc_zero_array(mem_ctx, char, r.in.value_offered); do { status = dcerpc_spoolss_EnumPrinterData_r(b, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (W_ERROR_EQUAL(r.out.result, WERR_NO_MORE_ITEMS)) { result = WERR_OK; break; } r.in.enum_index++; display_reg_value(r.out.value_name, *r.out.type, data_blob_const(r.out.data, r.in.data_offered)); } while (W_ERROR_IS_OK(r.out.result)); done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_data_ex( struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; uint32_t i; const char *printername; struct policy_handle hnd; uint32_t count; struct spoolss_PrinterEnumValues *info; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc != 3) { printf("Usage: %s printername \n", argv[0]); return WERR_OK; } /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { goto done; } /* Enumerate subkeys */ result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &hnd, argv[2], 0, &count, &info); if (!W_ERROR_IS_OK(result)) { goto done; } for (i=0; i < count; i++) { display_printer_data(info[i].value_name, info[i].type, info[i].data->data, info[i].data->length); } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_enum_printerkey(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; const char *printername; const char *keyname = NULL; struct policy_handle hnd; const char **key_buffer = NULL; int i; uint32_t offered = 0; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc < 2 || argc > 4) { printf("Usage: %s printername [keyname] [offered]\n", argv[0]); return WERR_OK; } if (argc >= 3) { keyname = argv[2]; } else { keyname = ""; } if (argc == 4) { offered = atoi(argv[3]); } /* Open printer handle */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { goto done; } /* Enumerate subkeys */ result = rpccli_spoolss_enumprinterkey(cli, mem_ctx, &hnd, keyname, &key_buffer, offered); if (!W_ERROR_IS_OK(result)) { goto done; } for (i=0; key_buffer && key_buffer[i]; i++) { printf("%s\n", key_buffer[i]); } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_rffpcnex(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { const char *printername; const char *clientname; struct policy_handle hnd = { 0, }; WERROR result; NTSTATUS status; struct spoolss_NotifyOption option; struct dcerpc_binding_handle *b = cli->binding_handle; if (argc != 2) { printf("Usage: %s printername\n", argv[0]); result = WERR_OK; goto done; } /* Open printer */ RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &hnd); if (!W_ERROR_IS_OK(result)) { printf("Error opening %s\n", argv[1]); goto done; } /* Create spool options */ option.version = 2; option.count = 2; option.types = talloc_array(mem_ctx, struct spoolss_NotifyOptionType, 2); if (option.types == NULL) { result = WERR_NOT_ENOUGH_MEMORY; goto done; } option.types[0].type = PRINTER_NOTIFY_TYPE; option.types[0].count = 1; option.types[0].fields = talloc_array(mem_ctx, union spoolss_Field, 1); if (option.types[0].fields == NULL) { result = WERR_NOT_ENOUGH_MEMORY; goto done; } option.types[0].fields[0].field = PRINTER_NOTIFY_FIELD_SERVER_NAME; option.types[1].type = JOB_NOTIFY_TYPE; option.types[1].count = 1; option.types[1].fields = talloc_array(mem_ctx, union spoolss_Field, 1); if (option.types[1].fields == NULL) { result = WERR_NOT_ENOUGH_MEMORY; goto done; } option.types[1].fields[0].field = JOB_NOTIFY_FIELD_PRINTER_NAME; clientname = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name()); if (!clientname) { result = WERR_NOT_ENOUGH_MEMORY; goto done; } /* Send rffpcnex */ status = dcerpc_spoolss_RemoteFindFirstPrinterChangeNotifyEx(b, mem_ctx, &hnd, 0, 0, clientname, 123, &option, &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { printf("Error rffpcnex %s\n", argv[1]); goto done; } done: if (is_valid_policy_hnd(&hnd)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &_result); } return result; } /**************************************************************************** ****************************************************************************/ static bool compare_printer( struct rpc_pipe_client *cli1, struct policy_handle *hnd1, struct rpc_pipe_client *cli2, struct policy_handle *hnd2 ) { union spoolss_PrinterInfo info1, info2; WERROR werror; TALLOC_CTX *mem_ctx = talloc_init("compare_printer"); printf("Retrieving printer propertiesfor %s...", cli1->desthost); werror = rpccli_spoolss_getprinter(cli1, mem_ctx, hnd1, 2, 0, &info1); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); talloc_destroy(mem_ctx); return false; } printf("ok\n"); printf("Retrieving printer properties for %s...", cli2->desthost); werror = rpccli_spoolss_getprinter(cli2, mem_ctx, hnd2, 2, 0, &info2); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); talloc_destroy(mem_ctx); return false; } printf("ok\n"); talloc_destroy(mem_ctx); return true; } /**************************************************************************** ****************************************************************************/ static bool compare_printer_secdesc( struct rpc_pipe_client *cli1, struct policy_handle *hnd1, struct rpc_pipe_client *cli2, struct policy_handle *hnd2 ) { union spoolss_PrinterInfo info1, info2; WERROR werror; TALLOC_CTX *mem_ctx = talloc_init("compare_printer_secdesc"); struct security_descriptor *sd1, *sd2; bool result = true; printf("Retrieving printer security for %s...", cli1->desthost); werror = rpccli_spoolss_getprinter(cli1, mem_ctx, hnd1, 3, 0, &info1); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); result = false; goto done; } printf("ok\n"); printf("Retrieving printer security for %s...", cli2->desthost); werror = rpccli_spoolss_getprinter(cli2, mem_ctx, hnd2, 3, 0, &info2); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); result = false; goto done; } printf("ok\n"); printf("++ "); sd1 = info1.info3.secdesc; sd2 = info2.info3.secdesc; if ( (sd1 != sd2) && ( !sd1 || !sd2 ) ) { printf("NULL secdesc!\n"); result = false; goto done; } if (!security_descriptor_equal( sd1, sd2 ) ) { printf("Security Descriptors *not* equal!\n"); result = false; goto done; } printf("Security descriptors match\n"); done: talloc_destroy(mem_ctx); return result; } /**************************************************************************** ****************************************************************************/ static WERROR cmd_spoolss_printercmp(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { const char *printername; char *printername_path = NULL; struct cli_state *cli_server2 = NULL; struct rpc_pipe_client *cli2 = NULL; struct policy_handle hPrinter1, hPrinter2; NTSTATUS nt_status; WERROR werror; struct cli_credentials *creds = samba_cmdline_get_creds(); if ( argc != 3 ) { printf("Usage: %s \n", argv[0]); return WERR_OK; } printername = argv[1]; /* first get the connection to the remote server */ nt_status = cli_full_connection_creds(&cli_server2, lp_netbios_name(), argv[2], NULL, 0, "IPC$", "IPC", creds, CLI_FULL_CONNECTION_IPC); if ( !NT_STATUS_IS_OK(nt_status) ) return WERR_GEN_FAILURE; nt_status = cli_rpc_pipe_open_noauth(cli_server2, &ndr_table_spoolss, &cli2); if (!NT_STATUS_IS_OK(nt_status)) { printf("failed to open spoolss pipe on server %s (%s)\n", argv[2], nt_errstr(nt_status)); return WERR_GEN_FAILURE; } /* now open up both printers */ RPCCLIENT_PRINTERNAME(printername_path, cli, printername); printf("Opening %s...", printername_path); werror = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername_path, PRINTER_ALL_ACCESS, &hPrinter1); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); goto done; } printf("ok\n"); RPCCLIENT_PRINTERNAME(printername_path, cli2, printername); printf("Opening %s...", printername_path); werror = rpccli_spoolss_openprinter_ex(cli2, mem_ctx, printername_path, PRINTER_ALL_ACCESS, &hPrinter2); if ( !W_ERROR_IS_OK(werror) ) { printf("failed (%s)\n", win_errstr(werror)); goto done; } printf("ok\n"); compare_printer( cli, &hPrinter1, cli2, &hPrinter2 ); compare_printer_secdesc( cli, &hPrinter1, cli2, &hPrinter2 ); #if 0 compare_printerdata( cli_server1, &hPrinter1, cli_server2, &hPrinter2 ); #endif done: /* cleanup */ printf("Closing printers..."); { WERROR _result; dcerpc_spoolss_ClosePrinter(cli->binding_handle, mem_ctx, &hPrinter1, &_result); dcerpc_spoolss_ClosePrinter(cli2->binding_handle, mem_ctx, &hPrinter2, &_result); } printf("ok\n"); /* close the second remote connection */ cli_shutdown( cli_server2 ); return WERR_OK; } static void display_proc_info1(struct spoolss_PrintProcessorInfo1 *r) { printf("print_processor_name: %s\n", r->print_processor_name); } static WERROR cmd_spoolss_enum_procs(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror; const char *environment = SPOOLSS_ARCHITECTURE_NT_X86; uint32_t num_procs, level = 1, i; union spoolss_PrintProcessorInfo *procs; /* Parse the command arguments */ if (argc < 1 || argc > 4) { printf ("Usage: %s [environment] [level]\n", argv[0]); return WERR_OK; } if (argc >= 2) { environment = argv[1]; } if (argc == 3) { level = atoi(argv[2]); } /* Enumerate Print Processors */ werror = rpccli_spoolss_enumprintprocessors(cli, mem_ctx, cli->srv_name_slash, environment, level, 0, &num_procs, &procs); if (!W_ERROR_IS_OK(werror)) goto done; /* Display output */ for (i = 0; i < num_procs; i++) { switch (level) { case 1: display_proc_info1(&procs[i].info1); break; } } done: return werror; } static void display_proc_data_types_info1(struct spoolss_PrintProcDataTypesInfo1 *r) { printf("name_array: %s\n", r->name_array); } static WERROR cmd_spoolss_enum_proc_data_types(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror; const char *print_processor_name = "winprint"; uint32_t num_procs, level = 1, i; union spoolss_PrintProcDataTypesInfo *procs; /* Parse the command arguments */ if (argc < 1 || argc > 4) { printf ("Usage: %s [environment] [level]\n", argv[0]); return WERR_OK; } if (argc >= 2) { print_processor_name = argv[1]; } if (argc == 3) { level = atoi(argv[2]); } /* Enumerate Print Processor Data Types */ werror = rpccli_spoolss_enumprintprocessordatatypes(cli, mem_ctx, cli->srv_name_slash, print_processor_name, level, 0, &num_procs, &procs); if (!W_ERROR_IS_OK(werror)) goto done; /* Display output */ for (i = 0; i < num_procs; i++) { switch (level) { case 1: display_proc_data_types_info1(&procs[i].info1); break; } } done: return werror; } static void display_monitor1(const struct spoolss_MonitorInfo1 *r) { printf("monitor_name: %s\n", r->monitor_name); } static void display_monitor2(const struct spoolss_MonitorInfo2 *r) { printf("monitor_name: %s\n", r->monitor_name); printf("environment: %s\n", r->environment); printf("dll_name: %s\n", r->dll_name); } static WERROR cmd_spoolss_enum_monitors(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR werror; uint32_t count, level = 1, i; union spoolss_MonitorInfo *info; /* Parse the command arguments */ if (argc > 2) { printf("Usage: %s [level]\n", argv[0]); return WERR_OK; } if (argc == 2) { level = atoi(argv[1]); } /* Enumerate Print Monitors */ werror = rpccli_spoolss_enummonitors(cli, mem_ctx, cli->srv_name_slash, level, 0, &count, &info); if (!W_ERROR_IS_OK(werror)) { goto done; } /* Display output */ for (i = 0; i < count; i++) { switch (level) { case 1: display_monitor1(&info[i].info1); break; case 2: display_monitor2(&info[i].info2); break; } } done: return werror; } static WERROR cmd_spoolss_create_printer_ic(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; struct policy_handle handle, gdi_handle; const char *printername; struct spoolss_DevmodeContainer devmode_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(result)) { return result; } ZERO_STRUCT(devmode_ctr); status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx, &handle, &gdi_handle, &devmode_ctr, &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { goto done; } done: if (is_valid_policy_hnd(&gdi_handle)) { WERROR _result; dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result); } if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return result; } static WERROR cmd_spoolss_play_gdi_script_on_printer_ic(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { WERROR result; NTSTATUS status; struct policy_handle handle, gdi_handle; const char *printername; struct spoolss_DevmodeContainer devmode_ctr; struct dcerpc_binding_handle *b = cli->binding_handle; DATA_BLOB in,out; uint32_t count = 0; RPCCLIENT_PRINTERNAME(printername, cli, argv[1]); result = rpccli_spoolss_openprinter_ex(cli, mem_ctx, printername, SEC_FLAG_MAXIMUM_ALLOWED, &handle); if (!W_ERROR_IS_OK(result)) { return result; } ZERO_STRUCT(devmode_ctr); status = dcerpc_spoolss_CreatePrinterIC(b, mem_ctx, &handle, &gdi_handle, &devmode_ctr, &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { goto done; } in = data_blob_string_const(""); out = data_blob_talloc_zero(mem_ctx, 4); status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, &gdi_handle, in.data, in.length, out.data, out.length, 0, /* ul */ &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { goto done; } count = IVAL(out.data, 0); out = data_blob_talloc_zero(mem_ctx, count * sizeof(struct UNIVERSAL_FONT_ID) + 4); status = dcerpc_spoolss_PlayGDIScriptOnPrinterIC(b, mem_ctx, &gdi_handle, in.data, in.length, out.data, out.length, 0, /* ul */ &result); if (!NT_STATUS_IS_OK(status)) { result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { goto done; } { enum ndr_err_code ndr_err; struct UNIVERSAL_FONT_ID_ctr r; ndr_err = ndr_pull_struct_blob(&out, mem_ctx, &r, (ndr_pull_flags_fn_t)ndr_pull_UNIVERSAL_FONT_ID_ctr); if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { NDR_PRINT_DEBUG(UNIVERSAL_FONT_ID_ctr, &r); } } done: if (is_valid_policy_hnd(&gdi_handle)) { WERROR _result; dcerpc_spoolss_DeletePrinterIC(b, mem_ctx, &gdi_handle, &_result); } if (is_valid_policy_hnd(&handle)) { WERROR _result; dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &_result); } return result; } static WERROR cmd_spoolss_get_core_printer_drivers(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status; HRESULT result; struct dcerpc_binding_handle *b = cli->binding_handle; const char *architecture = SPOOLSS_ARCHITECTURE_x64; struct spoolss_CorePrinterDriver core_printer_drivers; DATA_BLOB blob; bool ok; int i; uint32_t count; const char **array; if (argc == 1) { count = 1; array = talloc_zero_array(mem_ctx, const char *, count + 1); if (array == NULL) { return WERR_NOT_ENOUGH_MEMORY; } array[0] = talloc_strdup(array, SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV); if (array[0] == NULL) { return WERR_NOT_ENOUGH_MEMORY; } } else { count = argc -1; array = talloc_zero_array(mem_ctx, const char *, count + 1); if (array == NULL) { return WERR_NOT_ENOUGH_MEMORY; } for (i = 0; i < argc - 1; i++) { array[i] = talloc_strdup(array, argv[i + 1]); if (array[i] == NULL) { return WERR_NOT_ENOUGH_MEMORY; } } } ok = push_reg_multi_sz(mem_ctx, &blob, array); if (!ok) { return WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_spoolss_GetCorePrinterDrivers(b, mem_ctx, cli->srv_name_slash, architecture, blob.length/2, (uint16_t *)blob.data, count, &core_printer_drivers, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (!HRES_IS_OK(result)) { return W_ERROR(WIN32_FROM_HRESULT(result)); } return WERR_OK; } static WERROR cmd_spoolss_enum_permachineconnections(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status; WERROR result; struct dcerpc_binding_handle *b = cli->binding_handle; const char *servername = cli->srv_name_slash; DATA_BLOB in = data_blob_null; struct spoolss_PrinterInfo4 *info; uint32_t needed, count; if (argc > 2) { printf("usage: %s [servername]\n", argv[0]); return WERR_OK; } if (argc > 1) { servername = argv[1]; } status = dcerpc_spoolss_EnumPerMachineConnections(b, mem_ctx, servername, &in, in.length, &count, &info, &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } if (W_ERROR_EQUAL(result, WERR_INSUFFICIENT_BUFFER)) { in = data_blob_talloc_zero(mem_ctx, needed); status = dcerpc_spoolss_EnumPerMachineConnections(b, mem_ctx, servername, &in, in.length, &count, &info, &needed, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } } return result; } static WERROR cmd_spoolss_add_permachineconnection(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status; WERROR result; struct dcerpc_binding_handle *b = cli->binding_handle; const char *servername = cli->srv_name_slash; const char *printername = "Microsoft Print to PDF"; const char *printserver = "samba.org"; const char *provider = ""; /* refers to Win32spl.dll then */ const char *composed_printername; if (argc > 5) { printf("usage: %s [servername] [printername] [printserver] [provider]\n", argv[0]); return WERR_OK; } if (argc > 1) { servername = argv[1]; } if (argc > 2) { printername = argv[2]; } if (argc > 3) { printserver = argv[3]; } if (argc > 4) { provider = argv[4]; } composed_printername = talloc_asprintf(mem_ctx, "%s\\%s", servername, printername); if (composed_printername == NULL) { return WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_spoolss_AddPerMachineConnection(b, mem_ctx, servername, composed_printername, printserver, provider, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } return result; } static WERROR cmd_spoolss_del_permachineconnection(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status; WERROR result; struct dcerpc_binding_handle *b = cli->binding_handle; const char *servername = cli->srv_name_slash; const char *printername = "Microsoft Print to PDF"; const char *composed_printername; if (argc > 3) { printf("usage: %s [servername] [printername]\n", argv[0]); return WERR_OK; } if (argc > 1) { servername = argv[1]; } if (argc > 2) { printername = argv[2]; } composed_printername = talloc_asprintf(mem_ctx, "%s\\%s", servername, printername); if (composed_printername == NULL) { return WERR_NOT_ENOUGH_MEMORY; } status = dcerpc_spoolss_DeletePerMachineConnection(b, mem_ctx, servername, composed_printername, &result); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } return result; } /* List of commands exported by this module */ struct cmd_set spoolss_commands[] = { { .name = "SPOOLSS", }, { .name = "adddriver", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_addprinterdriver, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Add a print driver", .usage = "", .use_netlogon_creds = false, }, { .name = "addprinter", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_addprinterex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Add a printer", .usage = "", }, { .name = "deldriver", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_deletedriver, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Delete a printer driver", .usage = "", }, { .name = "deldriverex", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_deletedriverex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Delete a printer driver with files", .usage = "", }, { .name = "enumdata", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_data, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate printer data", .usage = "", }, { .name = "enumdataex", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_data_ex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate printer data for a key", .usage = "", }, { .name = "enumkey", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_printerkey, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate printer keys", .usage = "", }, { .name = "enumjobs", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_jobs, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate print jobs", .usage = "", }, { .name = "getjob", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_get_job, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print job", .usage = "", }, { .name = "setjob", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_set_job, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set print job", .usage = "", }, { .name = "enumports", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_ports, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate printer ports", .usage = "", }, { .name = "enumdrivers", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_drivers, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate installed printer drivers", .usage = "", }, { .name = "enumprinters", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_printers, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate printers", .usage = "", }, { .name = "getdata", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getprinterdata, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print driver data", .usage = "", }, { .name = "getdataex", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getprinterdataex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get printer driver data with keyname", .usage = "", }, { .name = "getdriver", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getdriver, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print driver information", .usage = "", }, { .name = "getdriverdir", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getdriverdir, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print driver upload directory", .usage = "", }, { .name = "getdriverpackagepath", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getdriverpackagepath, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print driver package download directory", .usage = "", }, { .name = "getprinter", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getprinter, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get printer info", .usage = "", }, { .name = "openprinter", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_open_printer, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Open printer handle", .usage = "", }, { .name = "openprinter_ex", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_open_printer_ex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Open printer handle", .usage = "", }, { .name = "setdriver", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_setdriver, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set printer driver", .usage = "", }, { .name = "getprintprocdir", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getprintprocdir, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get print processor directory", .usage = "", }, { .name = "addform", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_addform, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Add form", .usage = "", }, { .name = "setform", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_setform, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set form", .usage = "", }, { .name = "getform", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_getform, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get form", .usage = "", }, { .name = "deleteform", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_deleteform, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Delete form", .usage = "", }, { .name = "enumforms", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_forms, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate forms", .usage = "", }, { .name = "setprinter", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_setprinter, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set printer comment", .usage = "", }, { .name = "setprintername", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_setprintername, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set printername", .usage = "", }, { .name = "setprinterdata", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_setprinterdata, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Set REG_SZ printer data", .usage = "", }, { .name = "rffpcnex", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_rffpcnex, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Rffpcnex test", .usage = "", }, { .name = "printercmp", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_printercmp, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Printer comparison test", .usage = "", }, { .name = "enumprocs", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_procs, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate Print Processors", .usage = "", }, { .name = "enumprocdatatypes", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_proc_data_types, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate Print Processor Data Types", .usage = "", }, { .name = "enummonitors", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_monitors, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate Print Monitors", .usage = "", }, { .name = "createprinteric", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_create_printer_ic, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Create Printer IC", .usage = "", }, { .name = "playgdiscriptonprinteric", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_play_gdi_script_on_printer_ic, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Create Printer IC", .usage = "", }, { .name = "getcoreprinterdrivers", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_get_core_printer_drivers, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Get CorePrinterDriver", .usage = "", }, { .name = "enumpermachineconnections", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_enum_permachineconnections, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Enumerate Per Machine Connections", .usage = "", }, { .name = "addpermachineconnection", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_add_permachineconnection, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Add Per Machine Connection", .usage = "", }, { .name = "delpermachineconnection", .returntype = RPC_RTYPE_WERROR, .ntfn = NULL, .wfn = cmd_spoolss_del_permachineconnection, .table = &ndr_table_spoolss, .rpc_pipe = NULL, .description = "Delete Per Machine Connection", .usage = "", }, { .name = NULL, }, };