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"
28 #define FORMS_PREFIX "FORMS/"
29 #define DRIVERS_PREFIX "DRIVERS/"
30 #define PRINTERS_PREFIX "PRINTERS/"
31 #define SECDESC_PREFIX "SECDESC/"
33 static void dump_form(TALLOC_CTX
*mem_ctx
,
38 enum ndr_err_code ndr_err
;
41 struct ntprinting_form r
;
43 printf("found form: %s\n", key_name
);
45 blob
= data_blob_const(data
, length
);
49 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
50 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_form
);
51 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
52 d_fprintf(stderr
, _("form pull failed: %s\n"),
57 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, ntprinting_form
, &r
);
63 static void dump_driver(TALLOC_CTX
*mem_ctx
,
68 enum ndr_err_code ndr_err
;
71 struct ntprinting_driver r
;
73 printf("found driver: %s\n", key_name
);
75 blob
= data_blob_const(data
, length
);
79 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
80 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_driver
);
81 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
82 d_fprintf(stderr
, _("driver pull failed: %s\n"),
87 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, ntprinting_driver
, &r
);
93 static void dump_printer(TALLOC_CTX
*mem_ctx
,
98 enum ndr_err_code ndr_err
;
101 struct ntprinting_printer r
;
103 printf("found printer: %s\n", key_name
);
105 blob
= data_blob_const(data
, length
);
109 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
110 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_printer
);
111 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
112 d_fprintf(stderr
, _("printer pull failed: %s\n"),
113 ndr_errstr(ndr_err
));
117 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, ntprinting_printer
, &r
);
123 static void dump_sd(TALLOC_CTX
*mem_ctx
,
124 const char *key_name
,
128 enum ndr_err_code ndr_err
;
131 struct sec_desc_buf r
;
133 printf("found security descriptor: %s\n", key_name
);
135 blob
= data_blob_const(data
, length
);
139 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
140 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
142 d_fprintf(stderr
, _("security descriptor pull failed: %s\n"),
143 ndr_errstr(ndr_err
));
147 s
= NDR_PRINT_STRUCT_STRING(mem_ctx
, sec_desc_buf
, &r
);
154 static int net_printing_dump(struct net_context
*c
, int argc
,
158 TALLOC_CTX
*ctx
= talloc_stackframe();
160 TDB_DATA kbuf
, newkey
, dbuf
;
162 if (argc
< 1 || c
->display_usage
) {
163 d_fprintf(stderr
, "%s\nnet printing dump <file.tdb>\n",
168 tdb
= tdb_open_log(argv
[0], 0, TDB_DEFAULT
, O_RDONLY
, 0600);
170 d_fprintf(stderr
, _("failed to open tdb file: %s\n"), argv
[0]);
174 for (kbuf
= tdb_firstkey(tdb
);
176 newkey
= tdb_nextkey(tdb
, kbuf
), free(kbuf
.dptr
), kbuf
=newkey
)
178 dbuf
= tdb_fetch(tdb
, kbuf
);
183 if (strncmp((const char *)kbuf
.dptr
, FORMS_PREFIX
, strlen(FORMS_PREFIX
)) == 0) {
184 dump_form(ctx
, (const char *)kbuf
.dptr
+strlen(FORMS_PREFIX
), dbuf
.dptr
, dbuf
.dsize
);
185 SAFE_FREE(dbuf
.dptr
);
189 if (strncmp((const char *)kbuf
.dptr
, DRIVERS_PREFIX
, strlen(DRIVERS_PREFIX
)) == 0) {
190 dump_driver(ctx
, (const char *)kbuf
.dptr
+strlen(DRIVERS_PREFIX
), dbuf
.dptr
, dbuf
.dsize
);
191 SAFE_FREE(dbuf
.dptr
);
195 if (strncmp((const char *)kbuf
.dptr
, PRINTERS_PREFIX
, strlen(PRINTERS_PREFIX
)) == 0) {
196 dump_printer(ctx
, (const char *)kbuf
.dptr
+strlen(PRINTERS_PREFIX
), dbuf
.dptr
, dbuf
.dsize
);
197 SAFE_FREE(dbuf
.dptr
);
201 if (strncmp((const char *)kbuf
.dptr
, SECDESC_PREFIX
, strlen(SECDESC_PREFIX
)) == 0) {
202 dump_sd(ctx
, (const char *)kbuf
.dptr
+strlen(SECDESC_PREFIX
), dbuf
.dptr
, dbuf
.dsize
);
203 SAFE_FREE(dbuf
.dptr
);
216 static NTSTATUS
migrate_form(TALLOC_CTX
*mem_ctx
,
217 struct rpc_pipe_client
*pipe_hnd
,
218 const char *key_name
,
222 struct policy_handle hnd
;
223 enum ndr_err_code ndr_err
;
224 struct ntprinting_form r
;
225 union spoolss_AddFormInfo f
;
226 struct spoolss_AddFormInfo1 f1
;
231 blob
= data_blob_const(data
, length
);
235 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
236 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_form
);
237 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
238 d_fprintf(stderr
, _("form pull failed: %s\n"),
239 ndr_errstr(ndr_err
));
240 return NT_STATUS_NO_MEMORY
;
243 /* Don't migrate builtin forms */
244 if (r
.flag
== SPOOLSS_FORM_BUILTIN
) {
248 d_printf(_("Migrating Form: %s\n"), key_name
);
250 result
= rpccli_spoolss_openprinter_ex(pipe_hnd
,
252 pipe_hnd
->srv_name_slash
,
253 MAXIMUM_ALLOWED_ACCESS
,
255 if (!W_ERROR_IS_OK(result
)) {
256 d_fprintf(stderr
, _("OpenPrinter(%s) failed: %s\n"),
257 pipe_hnd
->srv_name_slash
, win_errstr(result
));
258 return werror_to_ntstatus(result
);
261 f1
.form_name
= key_name
;
264 f1
.size
.width
= r
.width
;
265 f1
.size
.height
= r
.length
;
268 f1
.area
.right
= r
.right
;
269 f1
.area
.bottom
= r
.bottom
;
270 f1
.area
.left
= r
.left
;
274 status
= rpccli_spoolss_AddForm(pipe_hnd
,
280 if (!NT_STATUS_IS_OK(status
)) {
281 d_printf(_("\tAddForm(%s) refused -- %s.\n"),
282 f
.info1
->form_name
, nt_errstr(status
));
285 rpccli_spoolss_ClosePrinter(pipe_hnd
, mem_ctx
, &hnd
, NULL
);
290 static NTSTATUS
migrate_driver(TALLOC_CTX
*mem_ctx
,
291 struct rpc_pipe_client
*pipe_hnd
,
292 const char *key_name
,
296 enum ndr_err_code ndr_err
;
297 struct ntprinting_driver r
;
298 struct spoolss_AddDriverInfoCtr d
;
299 struct spoolss_AddDriverInfo3 d3
;
300 struct spoolss_StringArray a
;
305 blob
= data_blob_const(data
, length
);
309 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
310 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_driver
);
311 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
312 d_fprintf(stderr
, _("driver pull failed: %s\n"),
313 ndr_errstr(ndr_err
));
314 return NT_STATUS_NO_MEMORY
;
317 d_printf(_("Migrating Printer Driver: %s\n"), key_name
);
322 a
.string
= r
.dependent_files
;
324 d3
.architecture
= r
.environment
;
325 d3
.config_file
= r
.configfile
;
326 d3
.data_file
= r
.datafile
;
327 d3
.default_datatype
= r
.defaultdatatype
;
328 d3
.dependent_files
= &a
;
329 d3
.driver_path
= r
.driverpath
;
330 d3
.help_file
= r
.helpfile
;
331 d3
.monitor_name
= r
.monitorname
;
332 d3
.driver_name
= r
.name
;
333 d3
.version
= r
.version
;
338 status
= rpccli_spoolss_AddPrinterDriver(pipe_hnd
,
343 if (!NT_STATUS_IS_OK(status
)) {
344 d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"),
345 d3
.driver_name
, nt_errstr(status
));
351 static NTSTATUS
migrate_printer(TALLOC_CTX
*mem_ctx
,
352 struct rpc_pipe_client
*pipe_hnd
,
353 const char *key_name
,
357 struct policy_handle hnd
;
358 enum ndr_err_code ndr_err
;
359 struct ntprinting_printer r
;
360 struct spoolss_SetPrinterInfo2 info2
;
361 struct spoolss_DeviceMode dm
;
362 struct spoolss_SetPrinterInfoCtr info_ctr
;
363 struct spoolss_DevmodeContainer devmode_ctr
;
364 struct sec_desc_buf secdesc_ctr
;
370 if (strequal(key_name
, "printers")) {
374 blob
= data_blob_const(data
, length
);
378 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
379 (ndr_pull_flags_fn_t
) ndr_pull_ntprinting_printer
);
380 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
381 d_fprintf(stderr
, _("printer pull failed: %s\n"),
382 ndr_errstr(ndr_err
));
383 return NT_STATUS_NO_MEMORY
;
386 d_printf(_("Migrating Printer: %s\n"), key_name
);
388 result
= rpccli_spoolss_openprinter_ex(pipe_hnd
,
391 MAXIMUM_ALLOWED_ACCESS
,
393 if (!W_ERROR_IS_OK(result
)) {
394 d_fprintf(stderr
, _("OpenPrinter(%s) failed: %s\n"),
395 key_name
, win_errstr(result
));
396 return werror_to_ntstatus(result
);
399 /* Create printer info level 2 */
401 ZERO_STRUCT(devmode_ctr
);
402 ZERO_STRUCT(secdesc_ctr
);
404 info2
.attributes
= r
.info
.attributes
;
405 info2
.averageppm
= r
.info
.averageppm
;
406 info2
.cjobs
= r
.info
.cjobs
;
407 info2
.comment
= r
.info
.comment
;
408 info2
.datatype
= r
.info
.datatype
;
409 info2
.defaultpriority
= r
.info
.default_priority
;
410 info2
.drivername
= r
.info
.drivername
;
411 info2
.location
= r
.info
.location
;
412 info2
.parameters
= r
.info
.parameters
;
413 info2
.portname
= r
.info
.portname
;
414 info2
.printername
= r
.info
.printername
;
415 info2
.printprocessor
= r
.info
.printprocessor
;
416 info2
.priority
= r
.info
.priority
;
417 info2
.sepfile
= r
.info
.sepfile
;
418 info2
.sharename
= r
.info
.sharename
;
419 info2
.starttime
= r
.info
.starttime
;
420 info2
.status
= r
.info
.status
;
421 info2
.untiltime
= r
.info
.untiltime
;
423 /* Create Device Mode */
424 if (r
.devmode
!= NULL
) {
427 dm
.bitsperpel
= r
.devmode
->bitsperpel
;
428 dm
.collate
= r
.devmode
->collate
;
429 dm
.color
= r
.devmode
->color
;
430 dm
.copies
= r
.devmode
->copies
;
431 dm
.defaultsource
= r
.devmode
->defaultsource
;
432 dm
.devicename
= r
.devmode
->devicename
;
433 dm
.displayflags
= r
.devmode
->displayflags
;
434 dm
.displayfrequency
= r
.devmode
->displayfrequency
;
435 dm
.dithertype
= r
.devmode
->dithertype
;
436 dm
.driverversion
= r
.devmode
->driverversion
;
437 dm
.duplex
= r
.devmode
->duplex
;
438 dm
.fields
= r
.devmode
->fields
;
439 dm
.formname
= r
.devmode
->formname
;
440 dm
.icmintent
= r
.devmode
->icmintent
;
441 dm
.icmmethod
= r
.devmode
->icmmethod
;
442 dm
.logpixels
= r
.devmode
->logpixels
;
443 dm
.mediatype
= r
.devmode
->mediatype
;
444 dm
.orientation
= r
.devmode
->orientation
;
445 dm
.panningheight
= r
.devmode
->pelsheight
;
446 dm
.panningwidth
= r
.devmode
->panningwidth
;
447 dm
.paperlength
= r
.devmode
->paperlength
;
448 dm
.papersize
= r
.devmode
->papersize
;
449 dm
.paperwidth
= r
.devmode
->paperwidth
;
450 dm
.pelsheight
= r
.devmode
->pelsheight
;
451 dm
.pelswidth
= r
.devmode
->pelswidth
;
452 dm
.printquality
= r
.devmode
->printquality
;
453 dm
.scale
= r
.devmode
->scale
;
454 dm
.specversion
= r
.devmode
->specversion
;
455 dm
.ttoption
= r
.devmode
->ttoption
;
456 dm
.yresolution
= r
.devmode
->yresolution
;
458 if (r
.devmode
->nt_dev_private
!= NULL
) {
459 dm
.driverextra_data
.data
= r
.devmode
->nt_dev_private
->data
;
460 dm
.driverextra_data
.length
= r
.devmode
->nt_dev_private
->length
;
461 dm
.__driverextra_length
= r
.devmode
->nt_dev_private
->length
;
464 devmode_ctr
.devmode
= &dm
;
466 info2
.devmode_ptr
= 1;
469 info_ctr
.info
.info2
= &info2
;
472 status
= rpccli_spoolss_SetPrinter(pipe_hnd
,
480 if (!NT_STATUS_IS_OK(status
)) {
481 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
482 key_name
, nt_errstr(status
));
486 /* migrate printerdata */
487 for (j
= 0; j
< r
.count
; j
++) {
491 if (r
.printer_data
[j
].type
== REG_NONE
) {
495 keyname
= CONST_DISCARD(char *, r
.printer_data
[j
].name
);
496 valuename
= strchr(keyname
, '\\');
497 if (valuename
== NULL
) {
504 printf(" data: %s\\%s\n", keyname
, valuename
);
506 status
= rpccli_spoolss_SetPrinterDataEx(pipe_hnd
,
511 r
.printer_data
[j
].type
,
512 r
.printer_data
[j
].data
.data
,
513 r
.printer_data
[j
].data
.length
,
515 if (!NT_STATUS_IS_OK(status
)) {
516 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
517 key_name
, keyname
, valuename
, nt_errstr(status
));
523 rpccli_spoolss_ClosePrinter(pipe_hnd
, mem_ctx
, &hnd
, NULL
);
528 static NTSTATUS
migrate_secdesc(TALLOC_CTX
*mem_ctx
,
529 struct rpc_pipe_client
*pipe_hnd
,
530 const char *key_name
,
534 struct policy_handle hnd
;
535 enum ndr_err_code ndr_err
;
536 struct sec_desc_buf secdesc_ctr
;
537 struct spoolss_SetPrinterInfo3 info3
;
538 struct spoolss_SetPrinterInfoCtr info_ctr
;
539 struct spoolss_DevmodeContainer devmode_ctr
;
544 if (strequal(key_name
, "printers")) {
548 blob
= data_blob_const(data
, length
);
550 ZERO_STRUCT(secdesc_ctr
);
552 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &secdesc_ctr
,
553 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
554 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
555 d_fprintf(stderr
, _("security descriptor pull failed: %s\n"),
556 ndr_errstr(ndr_err
));
557 return NT_STATUS_NO_MEMORY
;
560 d_printf(_("Migrating Security Descriptor: %s\n"), key_name
);
562 result
= rpccli_spoolss_openprinter_ex(pipe_hnd
,
565 MAXIMUM_ALLOWED_ACCESS
,
567 if (!W_ERROR_IS_OK(result
)) {
568 d_fprintf(stderr
, _("\tOpenPrinter(%s) failed: %s\n"),
569 key_name
, win_errstr(result
));
570 return werror_to_ntstatus(result
);
573 ZERO_STRUCT(devmode_ctr
);
575 info3
.sec_desc_ptr
= 1;
577 info_ctr
.info
.info3
= &info3
;
580 status
= rpccli_spoolss_SetPrinter(pipe_hnd
,
588 if (!NT_STATUS_IS_OK(status
)) {
589 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
590 key_name
, nt_errstr(status
));
593 rpccli_spoolss_ClosePrinter(pipe_hnd
, mem_ctx
, &hnd
, NULL
);
598 static NTSTATUS
printing_migrate_internal(struct net_context
*c
,
599 const struct dom_sid
*domain_sid
,
600 const char *domain_name
,
601 struct cli_state
*cli
,
602 struct rpc_pipe_client
*pipe_hnd
,
609 TDB_DATA kbuf
, newkey
, dbuf
;
612 tmp_ctx
= talloc_new(mem_ctx
);
613 if (tmp_ctx
== NULL
) {
614 return NT_STATUS_NO_MEMORY
;
617 tdb
= tdb_open_log(argv
[0], 0, TDB_DEFAULT
, O_RDONLY
, 0600);
619 d_fprintf(stderr
, _("failed to open tdb file: %s\n"), argv
[0]);
620 status
= NT_STATUS_NO_SUCH_FILE
;
624 for (kbuf
= tdb_firstkey(tdb
);
626 newkey
= tdb_nextkey(tdb
, kbuf
), free(kbuf
.dptr
), kbuf
= newkey
)
628 dbuf
= tdb_fetch(tdb
, kbuf
);
633 if (strncmp((const char *) kbuf
.dptr
, FORMS_PREFIX
, strlen(FORMS_PREFIX
)) == 0) {
634 migrate_form(tmp_ctx
,
636 (const char *) kbuf
.dptr
+ strlen(FORMS_PREFIX
),
639 SAFE_FREE(dbuf
.dptr
);
643 if (strncmp((const char *) kbuf
.dptr
, DRIVERS_PREFIX
, strlen(DRIVERS_PREFIX
)) == 0) {
644 migrate_driver(tmp_ctx
,
646 (const char *) kbuf
.dptr
+ strlen(DRIVERS_PREFIX
),
649 SAFE_FREE(dbuf
.dptr
);
653 if (strncmp((const char *) kbuf
.dptr
, PRINTERS_PREFIX
, strlen(PRINTERS_PREFIX
)) == 0) {
654 migrate_printer(tmp_ctx
,
656 (const char *) kbuf
.dptr
+ strlen(PRINTERS_PREFIX
),
659 SAFE_FREE(dbuf
.dptr
);
663 if (strncmp((const char *) kbuf
.dptr
, SECDESC_PREFIX
, strlen(SECDESC_PREFIX
)) == 0) {
664 migrate_secdesc(tmp_ctx
,
666 (const char *) kbuf
.dptr
+ strlen(SECDESC_PREFIX
),
669 SAFE_FREE(dbuf
.dptr
);
675 status
= NT_STATUS_OK
;
678 talloc_free(tmp_ctx
);
682 static int net_printing_migrate(struct net_context
*c
,
686 if (argc
< 1 || c
->display_usage
) {
688 "net printing migrate <file.tdb>\n"
691 _("Migrate tdb printing files to new storage"));
695 return run_rpc_command(c
,
697 &ndr_table_spoolss
.syntax_id
,
699 printing_migrate_internal
,
704 * 'net printing' entrypoint.
705 * @param argc Standard main() style argc.
706 * @param argv Standard main() style argv. Initial components are already
710 int net_printing(struct net_context
*c
, int argc
, const char **argv
)
714 struct functable func
[] = {
720 N_("net printing dump\n"
721 " Dump tdb printing file")
726 net_printing_migrate
,
727 NET_TRANSPORT_LOCAL
| NET_TRANSPORT_RPC
,
728 N_("Migrate printer databases"),
729 N_("net printing migrate\n"
730 " Migrate tdb printing files to new storage")
733 { NULL
, NULL
, 0, NULL
, NULL
}
736 ret
= net_run_function(c
, argc
, argv
, "net printing", func
);