2 Samba Unix/Linux SMB client library
3 Distributed SMB/CIFS Server Management Utility
4 Local printing tdb migration interface
6 Copyright (C) Guenther Deschner 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "utils/net.h"
24 #include "librpc/gen_ndr/ndr_ntprinting.h"
25 #include "librpc/gen_ndr/cli_spoolss.h"
26 #include "rpc_client/cli_spoolss.h"
27 #include "../libcli/security/security.h"
28 #include "../librpc/gen_ndr/ndr_security.h"
30 #define FORMS_PREFIX "FORMS/"
31 #define DRIVERS_PREFIX "DRIVERS/"
32 #define PRINTERS_PREFIX "PRINTERS/"
33 #define SECDESC_PREFIX "SECDESC/"
35 static void dump_form(TALLOC_CTX *mem_ctx,
40 enum ndr_err_code ndr_err;
43 struct ntprinting_form r;
45 printf("found form: %s\n", key_name);
47 blob = data_blob_const(data, length);
51 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
52 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
53 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
54 d_fprintf(stderr, _("form pull failed: %s\n"),
59 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_form, &r);
65 static void dump_driver(TALLOC_CTX *mem_ctx,
70 enum ndr_err_code ndr_err;
73 struct ntprinting_driver r;
75 printf("found driver: %s\n", key_name);
77 blob = data_blob_const(data, length);
81 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
82 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 d_fprintf(stderr, _("driver pull failed: %s\n"),
89 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
95 static void dump_printer(TALLOC_CTX *mem_ctx,
100 enum ndr_err_code ndr_err;
103 struct ntprinting_printer r;
105 printf("found printer: %s\n", key_name);
107 blob = data_blob_const(data, length);
111 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
112 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
113 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
114 d_fprintf(stderr, _("printer pull failed: %s\n"),
115 ndr_errstr(ndr_err));
119 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
125 static void dump_sd(TALLOC_CTX *mem_ctx,
126 const char *key_name,
130 enum ndr_err_code ndr_err;
133 struct sec_desc_buf r;
135 printf("found security descriptor: %s\n", key_name);
137 blob = data_blob_const(data, length);
141 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
142 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
143 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
144 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
145 ndr_errstr(ndr_err));
149 s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
156 static int net_printing_dump(struct net_context *c, int argc,
160 TALLOC_CTX *ctx = talloc_stackframe();
162 TDB_DATA kbuf, newkey, dbuf;
164 if (argc < 1 || c->display_usage) {
165 d_fprintf(stderr, "%s\nnet printing dump <file.tdb>\n",
170 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
172 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
176 for (kbuf = tdb_firstkey(tdb);
178 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf=newkey)
180 dbuf = tdb_fetch(tdb, kbuf);
185 if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
186 dump_form(ctx, (const char *)kbuf.dptr+strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize);
187 SAFE_FREE(dbuf.dptr);
191 if (strncmp((const char *)kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
192 dump_driver(ctx, (const char *)kbuf.dptr+strlen(DRIVERS_PREFIX), dbuf.dptr, dbuf.dsize);
193 SAFE_FREE(dbuf.dptr);
197 if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
198 dump_printer(ctx, (const char *)kbuf.dptr+strlen(PRINTERS_PREFIX), dbuf.dptr, dbuf.dsize);
199 SAFE_FREE(dbuf.dptr);
203 if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
204 dump_sd(ctx, (const char *)kbuf.dptr+strlen(SECDESC_PREFIX), dbuf.dptr, dbuf.dsize);
205 SAFE_FREE(dbuf.dptr);
218 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
219 struct rpc_pipe_client *pipe_hnd,
220 const char *key_name,
224 struct policy_handle hnd;
225 enum ndr_err_code ndr_err;
226 struct ntprinting_form r;
227 union spoolss_AddFormInfo f;
228 struct spoolss_AddFormInfo1 f1;
233 blob = data_blob_const(data, length);
237 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
238 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
239 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
240 d_fprintf(stderr, _("form pull failed: %s\n"),
241 ndr_errstr(ndr_err));
242 return NT_STATUS_NO_MEMORY;
245 /* Don't migrate builtin forms */
246 if (r.flag == SPOOLSS_FORM_BUILTIN) {
250 d_printf(_("Migrating Form: %s\n"), key_name);
252 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
254 pipe_hnd->srv_name_slash,
255 MAXIMUM_ALLOWED_ACCESS,
257 if (!W_ERROR_IS_OK(result)) {
258 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
259 pipe_hnd->srv_name_slash, win_errstr(result));
260 return werror_to_ntstatus(result);
263 f1.form_name = key_name;
266 f1.size.width = r.width;
267 f1.size.height = r.length;
270 f1.area.right = r.right;
271 f1.area.bottom = r.bottom;
272 f1.area.left = r.left;
276 status = rpccli_spoolss_AddForm(pipe_hnd,
282 if (!NT_STATUS_IS_OK(status)) {
283 d_printf(_("\tAddForm(%s) refused -- %s.\n"),
284 f.info1->form_name, nt_errstr(status));
287 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
292 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
293 struct rpc_pipe_client *pipe_hnd,
294 const char *key_name,
298 enum ndr_err_code ndr_err;
299 struct ntprinting_driver r;
300 struct spoolss_AddDriverInfoCtr d;
301 struct spoolss_AddDriverInfo3 d3;
302 struct spoolss_StringArray a;
307 blob = data_blob_const(data, length);
311 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
312 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
313 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
314 d_fprintf(stderr, _("driver pull failed: %s\n"),
315 ndr_errstr(ndr_err));
316 return NT_STATUS_NO_MEMORY;
319 d_printf(_("Migrating Printer Driver: %s\n"), key_name);
324 a.string = r.dependent_files;
326 d3.architecture = r.environment;
327 d3.config_file = r.configfile;
328 d3.data_file = r.datafile;
329 d3.default_datatype = r.defaultdatatype;
330 d3.dependent_files = &a;
331 d3.driver_path = r.driverpath;
332 d3.help_file = r.helpfile;
333 d3.monitor_name = r.monitorname;
334 d3.driver_name = r.name;
335 d3.version = r.version;
340 status = rpccli_spoolss_AddPrinterDriver(pipe_hnd,
345 if (!NT_STATUS_IS_OK(status)) {
346 d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"),
347 d3.driver_name, nt_errstr(status));
353 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
354 struct rpc_pipe_client *pipe_hnd,
355 const char *key_name,
359 struct policy_handle hnd;
360 enum ndr_err_code ndr_err;
361 struct ntprinting_printer r;
362 struct spoolss_SetPrinterInfo2 info2;
363 struct spoolss_DeviceMode dm;
364 struct spoolss_SetPrinterInfoCtr info_ctr;
365 struct spoolss_DevmodeContainer devmode_ctr;
366 struct sec_desc_buf secdesc_ctr;
372 if (strequal(key_name, "printers")) {
376 blob = data_blob_const(data, length);
380 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
381 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
382 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
383 d_fprintf(stderr, _("printer pull failed: %s\n"),
384 ndr_errstr(ndr_err));
385 return NT_STATUS_NO_MEMORY;
388 d_printf(_("Migrating Printer: %s\n"), key_name);
390 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
393 MAXIMUM_ALLOWED_ACCESS,
395 if (!W_ERROR_IS_OK(result)) {
396 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
397 key_name, win_errstr(result));
398 return werror_to_ntstatus(result);
401 /* Create printer info level 2 */
403 ZERO_STRUCT(devmode_ctr);
404 ZERO_STRUCT(secdesc_ctr);
406 info2.attributes = r.info.attributes;
407 info2.averageppm = r.info.averageppm;
408 info2.cjobs = r.info.cjobs;
409 info2.comment = r.info.comment;
410 info2.datatype = r.info.datatype;
411 info2.defaultpriority = r.info.default_priority;
412 info2.drivername = r.info.drivername;
413 info2.location = r.info.location;
414 info2.parameters = r.info.parameters;
415 info2.portname = r.info.portname;
416 info2.printername = r.info.printername;
417 info2.printprocessor = r.info.printprocessor;
418 info2.priority = r.info.priority;
419 info2.sepfile = r.info.sepfile;
420 info2.sharename = r.info.sharename;
421 info2.starttime = r.info.starttime;
422 info2.status = r.info.status;
423 info2.untiltime = r.info.untiltime;
425 /* Create Device Mode */
426 if (r.devmode != NULL) {
429 dm.bitsperpel = r.devmode->bitsperpel;
430 dm.collate = r.devmode->collate;
431 dm.color = r.devmode->color;
432 dm.copies = r.devmode->copies;
433 dm.defaultsource = r.devmode->defaultsource;
434 dm.devicename = r.devmode->devicename;
435 dm.displayflags = r.devmode->displayflags;
436 dm.displayfrequency = r.devmode->displayfrequency;
437 dm.dithertype = r.devmode->dithertype;
438 dm.driverversion = r.devmode->driverversion;
439 dm.duplex = r.devmode->duplex;
440 dm.fields = r.devmode->fields;
441 dm.formname = r.devmode->formname;
442 dm.icmintent = r.devmode->icmintent;
443 dm.icmmethod = r.devmode->icmmethod;
444 dm.logpixels = r.devmode->logpixels;
445 dm.mediatype = r.devmode->mediatype;
446 dm.orientation = r.devmode->orientation;
447 dm.panningheight = r.devmode->pelsheight;
448 dm.panningwidth = r.devmode->panningwidth;
449 dm.paperlength = r.devmode->paperlength;
450 dm.papersize = r.devmode->papersize;
451 dm.paperwidth = r.devmode->paperwidth;
452 dm.pelsheight = r.devmode->pelsheight;
453 dm.pelswidth = r.devmode->pelswidth;
454 dm.printquality = r.devmode->printquality;
455 dm.scale = r.devmode->scale;
456 dm.specversion = r.devmode->specversion;
457 dm.ttoption = r.devmode->ttoption;
458 dm.yresolution = r.devmode->yresolution;
460 if (r.devmode->nt_dev_private != NULL) {
461 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
462 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
463 dm.__driverextra_length = r.devmode->nt_dev_private->length;
466 devmode_ctr.devmode = &dm;
468 info2.devmode_ptr = 1;
471 info_ctr.info.info2 = &info2;
474 status = rpccli_spoolss_SetPrinter(pipe_hnd,
482 if (!NT_STATUS_IS_OK(status)) {
483 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
484 key_name, nt_errstr(status));
488 /* migrate printerdata */
489 for (j = 0; j < r.count; j++) {
493 if (r.printer_data[j].type == REG_NONE) {
497 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
498 valuename = strchr(keyname, '\\');
499 if (valuename == NULL) {
506 printf(" data: %s\\%s\n", keyname, valuename);
508 status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd,
513 r.printer_data[j].type,
514 r.printer_data[j].data.data,
515 r.printer_data[j].data.length,
517 if (!NT_STATUS_IS_OK(status)) {
518 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
519 key_name, keyname, valuename, nt_errstr(status));
525 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
530 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
531 struct rpc_pipe_client *pipe_hnd,
532 const char *key_name,
536 struct policy_handle hnd;
537 enum ndr_err_code ndr_err;
538 struct sec_desc_buf secdesc_ctr;
539 struct spoolss_SetPrinterInfo3 info3;
540 struct spoolss_SetPrinterInfoCtr info_ctr;
541 struct spoolss_DevmodeContainer devmode_ctr;
546 if (strequal(key_name, "printers")) {
550 blob = data_blob_const(data, length);
552 ZERO_STRUCT(secdesc_ctr);
554 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
555 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
556 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
557 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
558 ndr_errstr(ndr_err));
559 return NT_STATUS_NO_MEMORY;
562 d_printf(_("Migrating Security Descriptor: %s\n"), key_name);
564 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
567 MAXIMUM_ALLOWED_ACCESS,
569 if (!W_ERROR_IS_OK(result)) {
570 d_fprintf(stderr, _("\tOpenPrinter(%s) failed: %s\n"),
571 key_name, win_errstr(result));
572 return werror_to_ntstatus(result);
575 ZERO_STRUCT(devmode_ctr);
577 info3.sec_desc_ptr = 1;
579 info_ctr.info.info3 = &info3;
582 status = rpccli_spoolss_SetPrinter(pipe_hnd,
590 if (!NT_STATUS_IS_OK(status)) {
591 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
592 key_name, nt_errstr(status));
595 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
600 static NTSTATUS printing_migrate_internal(struct net_context *c,
601 const struct dom_sid *domain_sid,
602 const char *domain_name,
603 struct cli_state *cli,
604 struct rpc_pipe_client *pipe_hnd,
611 TDB_DATA kbuf, newkey, dbuf;
614 tmp_ctx = talloc_new(mem_ctx);
615 if (tmp_ctx == NULL) {
616 return NT_STATUS_NO_MEMORY;
619 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
621 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
622 status = NT_STATUS_NO_SUCH_FILE;
626 for (kbuf = tdb_firstkey(tdb);
628 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
630 dbuf = tdb_fetch(tdb, kbuf);
635 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
636 migrate_form(tmp_ctx,
638 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
641 SAFE_FREE(dbuf.dptr);
645 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
646 migrate_driver(tmp_ctx,
648 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
651 SAFE_FREE(dbuf.dptr);
655 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
656 migrate_printer(tmp_ctx,
658 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
661 SAFE_FREE(dbuf.dptr);
665 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
666 migrate_secdesc(tmp_ctx,
668 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
671 SAFE_FREE(dbuf.dptr);
677 status = NT_STATUS_OK;
680 talloc_free(tmp_ctx);
684 static int net_printing_migrate(struct net_context *c,
688 if (argc < 1 || c->display_usage) {
690 "net printing migrate <file.tdb>\n"
693 _("Migrate tdb printing files to new storage"));
697 return run_rpc_command(c,
699 &ndr_table_spoolss.syntax_id,
701 printing_migrate_internal,
706 * 'net printing' entrypoint.
707 * @param argc Standard main() style argc.
708 * @param argv Standard main() style argv. Initial components are already
712 int net_printing(struct net_context *c, int argc, const char **argv)
716 struct functable func[] = {
721 N_("Dump printer databases"),
722 N_("net printing dump\n"
723 " Dump tdb printing file")
728 net_printing_migrate,
729 NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC,
730 N_("Migrate printer databases"),
731 N_("net printing migrate\n"
732 " Migrate tdb printing files to new storage")
735 { NULL, NULL, 0, NULL, NULL }
738 ret = net_run_function(c, argc, argv, "net printing", func);