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 "system/filesys.h"
24 #include "utils/net.h"
25 #include "rpc_client/rpc_client.h"
26 #include "librpc/gen_ndr/ndr_ntprinting.h"
27 #include "librpc/gen_ndr/ndr_spoolss_c.h"
28 #include "rpc_client/cli_spoolss.h"
29 #include "../libcli/security/security.h"
30 #include "../librpc/gen_ndr/ndr_security.h"
33 #define FORMS_PREFIX "FORMS/"
34 #define DRIVERS_PREFIX "DRIVERS/"
35 #define PRINTERS_PREFIX "PRINTERS/"
36 #define SECDESC_PREFIX "SECDESC/"
38 static void dump_form(TALLOC_CTX *mem_ctx,
43 enum ndr_err_code ndr_err;
46 struct ntprinting_form r;
48 printf("found form: %s\n", key_name);
50 blob = data_blob_const(data, length);
54 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
55 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
56 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
57 d_fprintf(stderr, _("form pull failed: %s\n"),
62 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_form, &r);
68 static void dump_driver(TALLOC_CTX *mem_ctx,
73 enum ndr_err_code ndr_err;
76 struct ntprinting_driver r;
78 printf("found driver: %s\n", key_name);
80 blob = data_blob_const(data, length);
84 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
85 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
86 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
87 d_fprintf(stderr, _("driver pull failed: %s\n"),
92 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
98 static void dump_printer(TALLOC_CTX *mem_ctx,
103 enum ndr_err_code ndr_err;
106 struct ntprinting_printer r;
108 printf("found printer: %s\n", key_name);
110 blob = data_blob_const(data, length);
114 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
115 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
116 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
117 d_fprintf(stderr, _("printer pull failed: %s\n"),
118 ndr_errstr(ndr_err));
122 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
128 static void dump_sd(TALLOC_CTX *mem_ctx,
129 const char *key_name,
133 enum ndr_err_code ndr_err;
136 struct sec_desc_buf r;
138 printf("found security descriptor: %s\n", key_name);
140 blob = data_blob_const(data, length);
144 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
145 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
146 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
147 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
148 ndr_errstr(ndr_err));
152 s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
159 static int net_printing_dump(struct net_context *c, int argc,
163 TALLOC_CTX *ctx = talloc_stackframe();
165 TDB_DATA kbuf, newkey, dbuf;
167 if (argc < 1 || c->display_usage) {
168 d_fprintf(stderr, "%s\nnet printing dump <file.tdb>\n",
173 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
175 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
179 for (kbuf = tdb_firstkey(tdb);
181 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf=newkey)
183 dbuf = tdb_fetch_compat(tdb, kbuf);
188 if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
189 dump_form(ctx, (const char *)kbuf.dptr+strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize);
190 SAFE_FREE(dbuf.dptr);
194 if (strncmp((const char *)kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
195 dump_driver(ctx, (const char *)kbuf.dptr+strlen(DRIVERS_PREFIX), dbuf.dptr, dbuf.dsize);
196 SAFE_FREE(dbuf.dptr);
200 if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
201 dump_printer(ctx, (const char *)kbuf.dptr+strlen(PRINTERS_PREFIX), dbuf.dptr, dbuf.dsize);
202 SAFE_FREE(dbuf.dptr);
206 if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
207 dump_sd(ctx, (const char *)kbuf.dptr+strlen(SECDESC_PREFIX), dbuf.dptr, dbuf.dsize);
208 SAFE_FREE(dbuf.dptr);
221 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
222 struct rpc_pipe_client *pipe_hnd,
223 const char *key_name,
227 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
228 struct policy_handle hnd;
229 enum ndr_err_code ndr_err;
230 struct ntprinting_form r;
231 union spoolss_AddFormInfo f;
232 struct spoolss_AddFormInfo1 f1;
237 blob = data_blob_const(data, length);
241 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
242 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
243 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
244 d_fprintf(stderr, _("form pull failed: %s\n"),
245 ndr_errstr(ndr_err));
246 return NT_STATUS_NO_MEMORY;
249 /* Don't migrate builtin forms */
250 if (r.flag == SPOOLSS_FORM_BUILTIN) {
254 d_printf(_("Migrating Form: %s\n"), key_name);
256 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
258 pipe_hnd->srv_name_slash,
259 MAXIMUM_ALLOWED_ACCESS,
261 if (!W_ERROR_IS_OK(result)) {
262 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
263 pipe_hnd->srv_name_slash, win_errstr(result));
264 return werror_to_ntstatus(result);
267 f1.form_name = key_name;
270 f1.size.width = r.width;
271 f1.size.height = r.length;
274 f1.area.right = r.right;
275 f1.area.bottom = r.bottom;
276 f1.area.left = r.left;
280 status = dcerpc_spoolss_AddForm(b,
286 if (!NT_STATUS_IS_OK(status)) {
287 d_printf(_("\tAddForm(%s) refused -- %s.\n"),
288 f.info1->form_name, nt_errstr(status));
289 } else if (!W_ERROR_IS_OK(result)) {
290 d_printf(_("\tAddForm(%s) refused -- %s.\n"),
291 f.info1->form_name, win_errstr(result));
292 status = werror_to_ntstatus(result);
295 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
300 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
301 struct rpc_pipe_client *pipe_hnd,
302 const char *key_name,
306 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
307 enum ndr_err_code ndr_err;
308 struct ntprinting_driver r;
309 struct spoolss_AddDriverInfoCtr d;
310 struct spoolss_AddDriverInfo3 d3;
311 struct spoolss_StringArray a;
316 blob = data_blob_const(data, length);
320 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
321 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
322 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
323 d_fprintf(stderr, _("driver pull failed: %s\n"),
324 ndr_errstr(ndr_err));
325 return NT_STATUS_NO_MEMORY;
328 d_printf(_("Migrating Printer Driver: %s\n"), key_name);
333 a.string = r.dependent_files;
335 d3.architecture = r.environment;
336 d3.config_file = r.configfile;
337 d3.data_file = r.datafile;
338 d3.default_datatype = r.defaultdatatype;
339 d3.dependent_files = &a;
340 d3.driver_path = r.driverpath;
341 d3.help_file = r.helpfile;
342 d3.monitor_name = r.monitorname;
343 d3.driver_name = r.name;
344 d3.version = r.version;
349 status = dcerpc_spoolss_AddPrinterDriver(b,
354 if (!NT_STATUS_IS_OK(status)) {
355 d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"),
356 d3.driver_name, nt_errstr(status));
357 } else if (!W_ERROR_IS_OK(result)) {
358 d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"),
359 d3.driver_name, win_errstr(result));
360 status = werror_to_ntstatus(result);
366 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
367 struct rpc_pipe_client *pipe_hnd,
368 const char *key_name,
372 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
373 struct policy_handle hnd;
374 enum ndr_err_code ndr_err;
375 struct ntprinting_printer r;
376 struct spoolss_SetPrinterInfo2 info2;
377 struct spoolss_DeviceMode dm;
378 struct spoolss_SetPrinterInfoCtr info_ctr;
379 struct spoolss_DevmodeContainer devmode_ctr;
380 struct sec_desc_buf secdesc_ctr;
386 if (strequal(key_name, "printers")) {
390 blob = data_blob_const(data, length);
394 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
395 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
397 d_fprintf(stderr, _("printer pull failed: %s\n"),
398 ndr_errstr(ndr_err));
399 return NT_STATUS_NO_MEMORY;
402 d_printf(_("Migrating Printer: %s\n"), key_name);
404 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
407 MAXIMUM_ALLOWED_ACCESS,
409 if (!W_ERROR_IS_OK(result)) {
410 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
411 key_name, win_errstr(result));
412 return werror_to_ntstatus(result);
415 /* Create printer info level 2 */
417 ZERO_STRUCT(devmode_ctr);
418 ZERO_STRUCT(secdesc_ctr);
420 info2.attributes = r.info.attributes;
421 info2.averageppm = r.info.averageppm;
422 info2.cjobs = r.info.cjobs;
423 info2.comment = r.info.comment;
424 info2.datatype = r.info.datatype;
425 info2.defaultpriority = r.info.default_priority;
426 info2.drivername = r.info.drivername;
427 info2.location = r.info.location;
428 info2.parameters = r.info.parameters;
429 info2.portname = r.info.portname;
430 info2.printername = r.info.printername;
431 info2.printprocessor = r.info.printprocessor;
432 info2.priority = r.info.priority;
433 info2.sepfile = r.info.sepfile;
434 info2.sharename = r.info.sharename;
435 info2.starttime = r.info.starttime;
436 info2.status = r.info.status;
437 info2.untiltime = r.info.untiltime;
439 /* Create Device Mode */
440 if (r.devmode != NULL) {
443 dm.bitsperpel = r.devmode->bitsperpel;
444 dm.collate = r.devmode->collate;
445 dm.color = r.devmode->color;
446 dm.copies = r.devmode->copies;
447 dm.defaultsource = r.devmode->defaultsource;
448 dm.devicename = r.devmode->devicename;
449 dm.displayflags = r.devmode->displayflags;
450 dm.displayfrequency = r.devmode->displayfrequency;
451 dm.dithertype = r.devmode->dithertype;
452 dm.driverversion = r.devmode->driverversion;
453 dm.duplex = r.devmode->duplex;
454 dm.fields = r.devmode->fields;
455 dm.formname = r.devmode->formname;
456 dm.icmintent = r.devmode->icmintent;
457 dm.icmmethod = r.devmode->icmmethod;
458 dm.logpixels = r.devmode->logpixels;
459 dm.mediatype = r.devmode->mediatype;
460 dm.orientation = r.devmode->orientation;
461 dm.panningheight = r.devmode->pelsheight;
462 dm.panningwidth = r.devmode->panningwidth;
463 dm.paperlength = r.devmode->paperlength;
464 dm.papersize = r.devmode->papersize;
465 dm.paperwidth = r.devmode->paperwidth;
466 dm.pelsheight = r.devmode->pelsheight;
467 dm.pelswidth = r.devmode->pelswidth;
468 dm.printquality = r.devmode->printquality;
469 dm.scale = r.devmode->scale;
470 dm.specversion = r.devmode->specversion;
471 dm.ttoption = r.devmode->ttoption;
472 dm.yresolution = r.devmode->yresolution;
474 if (r.devmode->nt_dev_private != NULL) {
475 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
476 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
477 dm.__driverextra_length = r.devmode->nt_dev_private->length;
480 devmode_ctr.devmode = &dm;
482 info2.devmode_ptr = 1;
485 info_ctr.info.info2 = &info2;
488 status = dcerpc_spoolss_SetPrinter(b,
496 if (!NT_STATUS_IS_OK(status)) {
497 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
498 key_name, nt_errstr(status));
500 } else if (!W_ERROR_IS_OK(result)) {
501 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
502 key_name, win_errstr(result));
503 status = werror_to_ntstatus(result);
507 /* migrate printerdata */
508 for (j = 0; j < r.count; j++) {
512 if (r.printer_data[j].type == REG_NONE) {
516 keyname = discard_const_p(char, r.printer_data[j].name);
517 valuename = strchr(keyname, '\\');
518 if (valuename == NULL) {
525 printf(" data: %s\\%s\n", keyname, valuename);
527 status = dcerpc_spoolss_SetPrinterDataEx(b,
532 r.printer_data[j].type,
533 r.printer_data[j].data.data,
534 r.printer_data[j].data.length,
536 if (!NT_STATUS_IS_OK(status)) {
537 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
538 key_name, keyname, valuename, nt_errstr(status));
540 } else if (!W_ERROR_IS_OK(result)) {
541 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
542 key_name, keyname, valuename, win_errstr(result));
543 status = werror_to_ntstatus(result);
549 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
554 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
555 struct rpc_pipe_client *pipe_hnd,
556 const char *key_name,
560 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
561 struct policy_handle hnd;
562 enum ndr_err_code ndr_err;
563 struct sec_desc_buf secdesc_ctr;
564 struct spoolss_SetPrinterInfo3 info3;
565 struct spoolss_SetPrinterInfoCtr info_ctr;
566 struct spoolss_DevmodeContainer devmode_ctr;
571 if (strequal(key_name, "printers")) {
575 blob = data_blob_const(data, length);
577 ZERO_STRUCT(secdesc_ctr);
579 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
580 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
581 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
582 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
583 ndr_errstr(ndr_err));
584 return NT_STATUS_NO_MEMORY;
587 d_printf(_("Migrating Security Descriptor: %s\n"), key_name);
589 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
592 MAXIMUM_ALLOWED_ACCESS,
594 if (!W_ERROR_IS_OK(result)) {
595 d_fprintf(stderr, _("\tOpenPrinter(%s) failed: %s\n"),
596 key_name, win_errstr(result));
597 return werror_to_ntstatus(result);
600 ZERO_STRUCT(devmode_ctr);
602 info3.sec_desc_ptr = 1;
604 info_ctr.info.info3 = &info3;
607 status = dcerpc_spoolss_SetPrinter(b,
615 if (!NT_STATUS_IS_OK(status)) {
616 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
617 key_name, nt_errstr(status));
618 } else if (!W_ERROR_IS_OK(result)) {
619 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
620 key_name, win_errstr(result));
621 status = werror_to_ntstatus(result);
624 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
629 static NTSTATUS printing_migrate_internal(struct net_context *c,
630 const struct dom_sid *domain_sid,
631 const char *domain_name,
632 struct cli_state *cli,
633 struct rpc_pipe_client *pipe_hnd,
640 TDB_DATA kbuf, newkey, dbuf;
643 tmp_ctx = talloc_new(mem_ctx);
644 if (tmp_ctx == NULL) {
645 return NT_STATUS_NO_MEMORY;
648 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
650 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
651 status = NT_STATUS_NO_SUCH_FILE;
655 for (kbuf = tdb_firstkey(tdb);
657 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
659 dbuf = tdb_fetch_compat(tdb, kbuf);
664 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
665 migrate_form(tmp_ctx,
667 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
670 SAFE_FREE(dbuf.dptr);
674 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
675 migrate_driver(tmp_ctx,
677 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
680 SAFE_FREE(dbuf.dptr);
684 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
685 migrate_printer(tmp_ctx,
687 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
690 SAFE_FREE(dbuf.dptr);
694 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
695 migrate_secdesc(tmp_ctx,
697 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
700 SAFE_FREE(dbuf.dptr);
706 status = NT_STATUS_OK;
709 talloc_free(tmp_ctx);
713 static int net_printing_migrate(struct net_context *c,
717 if (argc < 1 || c->display_usage) {
719 "net printing migrate <file.tdb>\n"
722 _("Migrate tdb printing files to new storage"));
726 return run_rpc_command(c,
728 &ndr_table_spoolss.syntax_id,
730 printing_migrate_internal,
735 * 'net printing' entrypoint.
736 * @param argc Standard main() style argc.
737 * @param argv Standard main() style argv. Initial components are already
741 int net_printing(struct net_context *c, int argc, const char **argv)
745 struct functable func[] = {
750 N_("Dump printer databases"),
751 N_("net printing dump\n"
752 " Dump tdb printing file")
757 net_printing_migrate,
758 NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC,
759 N_("Migrate printer databases"),
760 N_("net printing migrate\n"
761 " Migrate tdb printing files to new storage")
764 { NULL, NULL, 0, NULL, NULL }
767 ret = net_run_function(c, argc, argv, "net printing", func);