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();
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_compat(tdb
);
181 kbuf
= tdb_nextkey_compat(tdb
, kbuf
))
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
.size
= r
.devmode
->size
;
470 dm
.scale
= r
.devmode
->scale
;
471 dm
.specversion
= r
.devmode
->specversion
;
472 dm
.ttoption
= r
.devmode
->ttoption
;
473 dm
.yresolution
= r
.devmode
->yresolution
;
475 if (r
.devmode
->nt_dev_private
!= NULL
) {
476 dm
.driverextra_data
.data
= r
.devmode
->nt_dev_private
->data
;
477 dm
.driverextra_data
.length
= r
.devmode
->nt_dev_private
->length
;
478 dm
.__driverextra_length
= r
.devmode
->nt_dev_private
->length
;
481 devmode_ctr
.devmode
= &dm
;
483 info2
.devmode_ptr
= 1;
486 info_ctr
.info
.info2
= &info2
;
489 status
= dcerpc_spoolss_SetPrinter(b
,
497 if (!NT_STATUS_IS_OK(status
)) {
498 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
499 key_name
, nt_errstr(status
));
501 } else if (!W_ERROR_IS_OK(result
)) {
502 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
503 key_name
, win_errstr(result
));
504 status
= werror_to_ntstatus(result
);
508 /* migrate printerdata */
509 for (j
= 0; j
< r
.count
; j
++) {
513 if (r
.printer_data
[j
].type
== REG_NONE
) {
517 keyname
= discard_const_p(char, r
.printer_data
[j
].name
);
518 valuename
= strchr(keyname
, '\\');
519 if (valuename
== NULL
) {
526 printf(" data: %s\\%s\n", keyname
, valuename
);
528 status
= dcerpc_spoolss_SetPrinterDataEx(b
,
533 r
.printer_data
[j
].type
,
534 r
.printer_data
[j
].data
.data
,
535 r
.printer_data
[j
].data
.length
,
537 if (!NT_STATUS_IS_OK(status
)) {
538 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
539 key_name
, keyname
, valuename
, nt_errstr(status
));
541 } else if (!W_ERROR_IS_OK(result
)) {
542 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
543 key_name
, keyname
, valuename
, win_errstr(result
));
544 status
= werror_to_ntstatus(result
);
550 dcerpc_spoolss_ClosePrinter(b
, mem_ctx
, &hnd
, &result
);
555 static NTSTATUS
migrate_secdesc(TALLOC_CTX
*mem_ctx
,
556 struct rpc_pipe_client
*pipe_hnd
,
557 const char *key_name
,
561 struct dcerpc_binding_handle
*b
= pipe_hnd
->binding_handle
;
562 struct policy_handle hnd
;
563 enum ndr_err_code ndr_err
;
564 struct sec_desc_buf secdesc_ctr
;
565 struct spoolss_SetPrinterInfo3 info3
;
566 struct spoolss_SetPrinterInfoCtr info_ctr
;
567 struct spoolss_DevmodeContainer devmode_ctr
;
572 if (strequal(key_name
, "printers")) {
576 blob
= data_blob_const(data
, length
);
578 ZERO_STRUCT(secdesc_ctr
);
580 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &secdesc_ctr
,
581 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
582 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
583 d_fprintf(stderr
, _("security descriptor pull failed: %s\n"),
584 ndr_errstr(ndr_err
));
585 return NT_STATUS_NO_MEMORY
;
588 d_printf(_("Migrating Security Descriptor: %s\n"), key_name
);
590 result
= rpccli_spoolss_openprinter_ex(pipe_hnd
,
593 MAXIMUM_ALLOWED_ACCESS
,
595 if (!W_ERROR_IS_OK(result
)) {
596 d_fprintf(stderr
, _("\tOpenPrinter(%s) failed: %s\n"),
597 key_name
, win_errstr(result
));
598 return werror_to_ntstatus(result
);
601 ZERO_STRUCT(devmode_ctr
);
603 info3
.sec_desc_ptr
= 1;
605 info_ctr
.info
.info3
= &info3
;
608 status
= dcerpc_spoolss_SetPrinter(b
,
616 if (!NT_STATUS_IS_OK(status
)) {
617 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
618 key_name
, nt_errstr(status
));
619 } else if (!W_ERROR_IS_OK(result
)) {
620 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
621 key_name
, win_errstr(result
));
622 status
= werror_to_ntstatus(result
);
625 dcerpc_spoolss_ClosePrinter(b
, mem_ctx
, &hnd
, &result
);
630 static NTSTATUS
printing_migrate_internal(struct net_context
*c
,
631 const struct dom_sid
*domain_sid
,
632 const char *domain_name
,
633 struct cli_state
*cli
,
634 struct rpc_pipe_client
*pipe_hnd
,
644 tmp_ctx
= talloc_new(mem_ctx
);
645 if (tmp_ctx
== NULL
) {
646 return NT_STATUS_NO_MEMORY
;
649 tdb
= tdb_open_log(argv
[0], 0, TDB_DEFAULT
, O_RDONLY
, 0600);
651 d_fprintf(stderr
, _("failed to open tdb file: %s\n"), argv
[0]);
652 status
= NT_STATUS_NO_SUCH_FILE
;
656 for (kbuf
= tdb_firstkey_compat(tdb
);
658 kbuf
= tdb_nextkey_compat(tdb
, kbuf
))
660 dbuf
= tdb_fetch_compat(tdb
, kbuf
);
665 if (strncmp((const char *) kbuf
.dptr
, FORMS_PREFIX
, strlen(FORMS_PREFIX
)) == 0) {
666 migrate_form(tmp_ctx
,
668 (const char *) kbuf
.dptr
+ strlen(FORMS_PREFIX
),
671 SAFE_FREE(dbuf
.dptr
);
675 if (strncmp((const char *) kbuf
.dptr
, DRIVERS_PREFIX
, strlen(DRIVERS_PREFIX
)) == 0) {
676 migrate_driver(tmp_ctx
,
678 (const char *) kbuf
.dptr
+ strlen(DRIVERS_PREFIX
),
681 SAFE_FREE(dbuf
.dptr
);
685 if (strncmp((const char *) kbuf
.dptr
, PRINTERS_PREFIX
, strlen(PRINTERS_PREFIX
)) == 0) {
686 migrate_printer(tmp_ctx
,
688 (const char *) kbuf
.dptr
+ strlen(PRINTERS_PREFIX
),
691 SAFE_FREE(dbuf
.dptr
);
695 if (strncmp((const char *) kbuf
.dptr
, SECDESC_PREFIX
, strlen(SECDESC_PREFIX
)) == 0) {
696 migrate_secdesc(tmp_ctx
,
698 (const char *) kbuf
.dptr
+ strlen(SECDESC_PREFIX
),
701 SAFE_FREE(dbuf
.dptr
);
707 status
= NT_STATUS_OK
;
710 talloc_free(tmp_ctx
);
714 static int net_printing_migrate(struct net_context
*c
,
718 if (argc
< 1 || c
->display_usage
) {
720 "net printing migrate <file.tdb>\n"
723 _("Migrate tdb printing files to new storage"));
727 return run_rpc_command(c
,
729 &ndr_table_spoolss
.syntax_id
,
731 printing_migrate_internal
,
736 * 'net printing' entrypoint.
737 * @param argc Standard main() style argc.
738 * @param argv Standard main() style argv. Initial components are already
742 int net_printing(struct net_context
*c
, int argc
, const char **argv
)
746 struct functable func
[] = {
751 N_("Dump printer databases"),
752 N_("net printing dump\n"
753 " Dump tdb printing file")
758 net_printing_migrate
,
759 NET_TRANSPORT_LOCAL
| NET_TRANSPORT_RPC
,
760 N_("Migrate printer databases"),
761 N_("net printing migrate\n"
762 " Migrate tdb printing files to new storage")
765 { NULL
, NULL
, 0, NULL
, NULL
}
768 ret
= net_run_function(c
, argc
, argv
, "net printing", func
);