diff options
-rw-r--r-- | source3/utils/net_printing.c | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/source3/utils/net_printing.c b/source3/utils/net_printing.c index 33de480a1b..eaea71e58f 100644 --- a/source3/utils/net_printing.c +++ b/source3/utils/net_printing.c @@ -22,6 +22,8 @@ #include "includes.h" #include "utils/net.h" #include "librpc/gen_ndr/ndr_ntprinting.h" +#include "librpc/gen_ndr/cli_spoolss.h" +#include "rpc_client/cli_spoolss.h" #define FORMS_PREFIX "FORMS/" #define DRIVERS_PREFIX "DRIVERS/" @@ -211,6 +213,493 @@ static int net_printing_dump(struct net_context *c, int argc, return ret; } +static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *pipe_hnd, + const char *key_name, + unsigned char *data, + size_t length) +{ + struct policy_handle hnd; + enum ndr_err_code ndr_err; + struct ntprinting_form r; + union spoolss_AddFormInfo f; + struct spoolss_AddFormInfo1 f1; + DATA_BLOB blob; + NTSTATUS status; + WERROR result; + + blob = data_blob_const(data, length); + + ZERO_STRUCT(r); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + d_fprintf(stderr, _("form pull failed: %s\n"), + ndr_errstr(ndr_err)); + return NT_STATUS_NO_MEMORY; + } + + /* Don't migrate builtin forms */ + if (r.flag == SPOOLSS_FORM_BUILTIN) { + return NT_STATUS_OK; + } + + d_printf(_("Migrating Form: %s\n"), key_name); + + result = rpccli_spoolss_openprinter_ex(pipe_hnd, + mem_ctx, + pipe_hnd->srv_name_slash, + MAXIMUM_ALLOWED_ACCESS, + &hnd); + if (!W_ERROR_IS_OK(result)) { + d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"), + pipe_hnd->srv_name_slash, win_errstr(result)); + return werror_to_ntstatus(result); + } + + f1.form_name = key_name; + f1.flags = r.flag; + + f1.size.width = r.width; + f1.size.height = r.length; + + f1.area.top = r.top; + f1.area.right = r.right; + f1.area.bottom = r.bottom; + f1.area.left = r.left; + + f.info1 = &f1; + + status = rpccli_spoolss_AddForm(pipe_hnd, + mem_ctx, + &hnd, + 1, + f, + &result); + if (!NT_STATUS_IS_OK(status)) { + d_printf(_("\tAddForm(%s) refused -- %s.\n"), + f.info1->form_name, nt_errstr(status)); + } + + rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL); + + return status; +} + +static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *pipe_hnd, + const char *key_name, + unsigned char *data, + size_t length) +{ + enum ndr_err_code ndr_err; + struct ntprinting_driver r; + struct spoolss_AddDriverInfoCtr d; + struct spoolss_AddDriverInfo3 d3; + struct spoolss_StringArray a; + DATA_BLOB blob; + NTSTATUS status; + WERROR result; + + blob = data_blob_const(data, length); + + ZERO_STRUCT(r); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + d_fprintf(stderr, _("driver pull failed: %s\n"), + ndr_errstr(ndr_err)); + return NT_STATUS_NO_MEMORY; + } + + d_printf(_("Migrating Printer Driver: %s\n"), key_name); + + ZERO_STRUCT(d3); + ZERO_STRUCT(a); + + a.string = r.dependent_files; + + d3.architecture = r.environment; + d3.config_file = r.configfile; + d3.data_file = r.datafile; + d3.default_datatype = r.defaultdatatype; + d3.dependent_files = &a; + d3.driver_path = r.driverpath; + d3.help_file = r.helpfile; + d3.monitor_name = r.monitorname; + d3.driver_name = r.name; + d3.version = r.version; + + d.info.info3 = &d3; + d.level = 3; + + status = rpccli_spoolss_AddPrinterDriver(pipe_hnd, + mem_ctx, + NULL, + &d, + &result); + if (!NT_STATUS_IS_OK(status)) { + d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"), + d3.driver_name, nt_errstr(status)); + } + + return status; +} + +static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *pipe_hnd, + const char *key_name, + unsigned char *data, + size_t length) +{ + struct policy_handle hnd; + enum ndr_err_code ndr_err; + struct ntprinting_printer r; + struct spoolss_SetPrinterInfo2 info2; + struct spoolss_DeviceMode dm; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_DevmodeContainer devmode_ctr; + struct sec_desc_buf secdesc_ctr; + DATA_BLOB blob; + NTSTATUS status; + WERROR result; + int j; + + if (strequal(key_name, "printers")) { + return NT_STATUS_OK; + } + + blob = data_blob_const(data, length); + + ZERO_STRUCT(r); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + d_fprintf(stderr, _("printer pull failed: %s\n"), + ndr_errstr(ndr_err)); + return NT_STATUS_NO_MEMORY; + } + + d_printf(_("Migrating Printer: %s\n"), key_name); + + result = rpccli_spoolss_openprinter_ex(pipe_hnd, + mem_ctx, + key_name, + MAXIMUM_ALLOWED_ACCESS, + &hnd); + if (!W_ERROR_IS_OK(result)) { + d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"), + key_name, win_errstr(result)); + return werror_to_ntstatus(result); + } + + /* Create printer info level 2 */ + ZERO_STRUCT(info2); + ZERO_STRUCT(devmode_ctr); + ZERO_STRUCT(secdesc_ctr); + + info2.attributes = r.info.attributes; + info2.averageppm = r.info.averageppm; + info2.cjobs = r.info.cjobs; + info2.comment = r.info.comment; + info2.datatype = r.info.datatype; + info2.defaultpriority = r.info.default_priority; + info2.drivername = r.info.drivername; + info2.location = r.info.location; + info2.parameters = r.info.parameters; + info2.portname = r.info.portname; + info2.printername = r.info.printername; + info2.printprocessor = r.info.printprocessor; + info2.priority = r.info.priority; + info2.sepfile = r.info.sepfile; + info2.sharename = r.info.sharename; + info2.starttime = r.info.starttime; + info2.status = r.info.status; + info2.untiltime = r.info.untiltime; + + /* Create Device Mode */ + if (r.devmode != NULL) { + ZERO_STRUCT(dm); + + dm.bitsperpel = r.devmode->bitsperpel; + dm.collate = r.devmode->collate; + dm.color = r.devmode->color; + dm.copies = r.devmode->copies; + dm.defaultsource = r.devmode->defaultsource; + dm.devicename = r.devmode->devicename; + dm.displayflags = r.devmode->displayflags; + dm.displayfrequency = r.devmode->displayfrequency; + dm.dithertype = r.devmode->dithertype; + dm.driverversion = r.devmode->driverversion; + dm.duplex = r.devmode->duplex; + dm.fields = r.devmode->fields; + dm.formname = r.devmode->formname; + dm.icmintent = r.devmode->icmintent; + dm.icmmethod = r.devmode->icmmethod; + dm.logpixels = r.devmode->logpixels; + dm.mediatype = r.devmode->mediatype; + dm.orientation = r.devmode->orientation; + dm.panningheight = r.devmode->pelsheight; + dm.panningwidth = r.devmode->panningwidth; + dm.paperlength = r.devmode->paperlength; + dm.papersize = r.devmode->papersize; + dm.paperwidth = r.devmode->paperwidth; + dm.pelsheight = r.devmode->pelsheight; + dm.pelswidth = r.devmode->pelswidth; + dm.printquality = r.devmode->printquality; + dm.scale = r.devmode->scale; + dm.specversion = r.devmode->specversion; + dm.ttoption = r.devmode->ttoption; + dm.yresolution = r.devmode->yresolution; + + if (r.devmode->nt_dev_private != NULL) { + dm.driverextra_data.data = r.devmode->nt_dev_private->data; + dm.driverextra_data.length = r.devmode->nt_dev_private->length; + dm.__driverextra_length = r.devmode->nt_dev_private->length; + } + + devmode_ctr.devmode = &dm; + + info2.devmode_ptr = 1; + } + + info_ctr.info.info2 = &info2; + info_ctr.level = 2; + + status = rpccli_spoolss_SetPrinter(pipe_hnd, + mem_ctx, + &hnd, + &info_ctr, + &devmode_ctr, + &secdesc_ctr, + 0, /* command */ + &result); + if (!NT_STATUS_IS_OK(status)) { + d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"), + key_name, nt_errstr(status)); + goto done; + } + + /* migrate printerdata */ + for (j = 0; j < r.count; j++) { + char *valuename; + char *keyname; + + if (r.printer_data[j].type == REG_NONE) { + continue; + } + + keyname = CONST_DISCARD(char *, r.printer_data[j].name); + valuename = strchr(keyname, '\\'); + if (valuename == NULL) { + continue; + } else { + valuename[0] = '\0'; + valuename++; + } + + printf(" data: %s\\%s\n", keyname, valuename); + + status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd, + mem_ctx, + &hnd, + keyname, + valuename, + r.printer_data[j].type, + r.printer_data[j].data.data, + r.printer_data[j].data.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"), + key_name, keyname, valuename, nt_errstr(status)); + break; + } + } + + done: + rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL); + + return status; +} + +static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx, + struct rpc_pipe_client *pipe_hnd, + const char *key_name, + unsigned char *data, + size_t length) +{ + struct policy_handle hnd; + enum ndr_err_code ndr_err; + struct sec_desc_buf secdesc_ctr; + struct spoolss_SetPrinterInfo3 info3; + struct spoolss_SetPrinterInfoCtr info_ctr; + struct spoolss_DevmodeContainer devmode_ctr; + DATA_BLOB blob; + NTSTATUS status; + WERROR result; + + if (strequal(key_name, "printers")) { + return NT_STATUS_OK; + } + + blob = data_blob_const(data, length); + + ZERO_STRUCT(secdesc_ctr); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr, + (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + d_fprintf(stderr, _("security descriptor pull failed: %s\n"), + ndr_errstr(ndr_err)); + return NT_STATUS_NO_MEMORY; + } + + d_printf(_("Migrating Security Descriptor: %s\n"), key_name); + + result = rpccli_spoolss_openprinter_ex(pipe_hnd, + mem_ctx, + key_name, + MAXIMUM_ALLOWED_ACCESS, + &hnd); + if (!W_ERROR_IS_OK(result)) { + d_fprintf(stderr, _("\tOpenPrinter(%s) failed: %s\n"), + key_name, win_errstr(result)); + return werror_to_ntstatus(result); + } + + ZERO_STRUCT(devmode_ctr); + + info3.sec_desc_ptr = 1; + + info_ctr.info.info3 = &info3; + info_ctr.level = 3; + + status = rpccli_spoolss_SetPrinter(pipe_hnd, + mem_ctx, + &hnd, + &info_ctr, + &devmode_ctr, + &secdesc_ctr, + 0, /* command */ + &result); + if (!NT_STATUS_IS_OK(status)) { + d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"), + key_name, nt_errstr(status)); + } + + rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL); + + return status; +} + +static NTSTATUS printing_migrate_internal(struct net_context *c, + const DOM_SID *domain_sid, + const char *domain_name, + struct cli_state *cli, + struct rpc_pipe_client *pipe_hnd, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + TALLOC_CTX *tmp_ctx; + TDB_CONTEXT *tdb; + TDB_DATA kbuf, newkey, dbuf; + NTSTATUS status; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600); + if (tdb == NULL) { + d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]); + status = NT_STATUS_NO_SUCH_FILE; + goto done; + } + + for (kbuf = tdb_firstkey(tdb); + kbuf.dptr; + newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey) + { + dbuf = tdb_fetch(tdb, kbuf); + if (!dbuf.dptr) { + continue; + } + + if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) { + migrate_form(tmp_ctx, + pipe_hnd, + (const char *) kbuf.dptr + strlen(FORMS_PREFIX), + dbuf.dptr, + dbuf.dsize); + SAFE_FREE(dbuf.dptr); + continue; + } + + if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) { + migrate_driver(tmp_ctx, + pipe_hnd, + (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX), + dbuf.dptr, + dbuf.dsize); + SAFE_FREE(dbuf.dptr); + continue; + } + + if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) { + migrate_printer(tmp_ctx, + pipe_hnd, + (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX), + dbuf.dptr, + dbuf.dsize); + SAFE_FREE(dbuf.dptr); + continue; + } + + if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) { + migrate_secdesc(tmp_ctx, + pipe_hnd, + (const char *) kbuf.dptr + strlen(SECDESC_PREFIX), + dbuf.dptr, + dbuf.dsize); + SAFE_FREE(dbuf.dptr); + continue; + } + + } + + status = NT_STATUS_OK; + + done: + talloc_free(tmp_ctx); + return status; +} + +static int net_printing_migrate(struct net_context *c, + int argc, + const char **argv) +{ + if (argc < 1 || c->display_usage) { + d_printf( "%s\n" + "net printing migrate <file.tdb>\n" + " %s\n", + _("Usage:"), + _("Migrate tdb printing files to new storage")); + return 0; + } + + return run_rpc_command(c, + NULL, + &ndr_table_spoolss.syntax_id, + 0, + printing_migrate_internal, + argc, + argv); +} /** * 'net printing' entrypoint. * @param argc Standard main() style argc. @@ -232,6 +721,15 @@ int net_printing(struct net_context *c, int argc, const char **argv) " Dump tdb printing file") }, + { + "migrate", + net_printing_migrate, + NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC, + N_("Migrate printer databases"), + N_("net printing migrate\n" + " Migrate tdb printing files to new storage") + }, + { NULL, NULL, 0, NULL, NULL } }; |