s3-dcerpc: Pull packet in the caller, before validation
[Samba.git] / source3 / utils / net_printing.c
blob634b6766c9276af611448595e8ba78f06bf76a64
1 /*
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/>.
22 #include "includes.h"
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 "../librpc/gen_ndr/ndr_security.h"
29 #define FORMS_PREFIX "FORMS/"
30 #define DRIVERS_PREFIX "DRIVERS/"
31 #define PRINTERS_PREFIX "PRINTERS/"
32 #define SECDESC_PREFIX "SECDESC/"
34 static void dump_form(TALLOC_CTX *mem_ctx,
35 const char *key_name,
36 unsigned char *data,
37 size_t length)
39 enum ndr_err_code ndr_err;
40 DATA_BLOB blob;
41 char *s;
42 struct ntprinting_form r;
44 printf("found form: %s\n", key_name);
46 blob = data_blob_const(data, length);
48 ZERO_STRUCT(r);
50 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
51 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
52 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
53 d_fprintf(stderr, _("form pull failed: %s\n"),
54 ndr_errstr(ndr_err));
55 return;
58 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_form, &r);
59 if (s) {
60 printf("%s\n", s);
64 static void dump_driver(TALLOC_CTX *mem_ctx,
65 const char *key_name,
66 unsigned char *data,
67 size_t length)
69 enum ndr_err_code ndr_err;
70 DATA_BLOB blob;
71 char *s;
72 struct ntprinting_driver r;
74 printf("found driver: %s\n", key_name);
76 blob = data_blob_const(data, length);
78 ZERO_STRUCT(r);
80 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
81 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
82 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
83 d_fprintf(stderr, _("driver pull failed: %s\n"),
84 ndr_errstr(ndr_err));
85 return;
88 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
89 if (s) {
90 printf("%s\n", s);
94 static void dump_printer(TALLOC_CTX *mem_ctx,
95 const char *key_name,
96 unsigned char *data,
97 size_t length)
99 enum ndr_err_code ndr_err;
100 DATA_BLOB blob;
101 char *s;
102 struct ntprinting_printer r;
104 printf("found printer: %s\n", key_name);
106 blob = data_blob_const(data, length);
108 ZERO_STRUCT(r);
110 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
111 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
112 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
113 d_fprintf(stderr, _("printer pull failed: %s\n"),
114 ndr_errstr(ndr_err));
115 return;
118 s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
119 if (s) {
120 printf("%s\n", s);
124 static void dump_sd(TALLOC_CTX *mem_ctx,
125 const char *key_name,
126 unsigned char *data,
127 size_t length)
129 enum ndr_err_code ndr_err;
130 DATA_BLOB blob;
131 char *s;
132 struct sec_desc_buf r;
134 printf("found security descriptor: %s\n", key_name);
136 blob = data_blob_const(data, length);
138 ZERO_STRUCT(r);
140 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
141 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
143 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
144 ndr_errstr(ndr_err));
145 return;
148 s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
149 if (s) {
150 printf("%s\n", s);
155 static int net_printing_dump(struct net_context *c, int argc,
156 const char **argv)
158 int ret = -1;
159 TALLOC_CTX *ctx = talloc_stackframe();
160 TDB_CONTEXT *tdb;
161 TDB_DATA kbuf, newkey, dbuf;
163 if (argc < 1 || c->display_usage) {
164 d_fprintf(stderr, "%s\nnet printing dump <file.tdb>\n",
165 _("Usage:"));
166 goto done;
169 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
170 if (!tdb) {
171 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
172 goto done;
175 for (kbuf = tdb_firstkey(tdb);
176 kbuf.dptr;
177 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf=newkey)
179 dbuf = tdb_fetch(tdb, kbuf);
180 if (!dbuf.dptr) {
181 continue;
184 if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
185 dump_form(ctx, (const char *)kbuf.dptr+strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize);
186 SAFE_FREE(dbuf.dptr);
187 continue;
190 if (strncmp((const char *)kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
191 dump_driver(ctx, (const char *)kbuf.dptr+strlen(DRIVERS_PREFIX), dbuf.dptr, dbuf.dsize);
192 SAFE_FREE(dbuf.dptr);
193 continue;
196 if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
197 dump_printer(ctx, (const char *)kbuf.dptr+strlen(PRINTERS_PREFIX), dbuf.dptr, dbuf.dsize);
198 SAFE_FREE(dbuf.dptr);
199 continue;
202 if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
203 dump_sd(ctx, (const char *)kbuf.dptr+strlen(SECDESC_PREFIX), dbuf.dptr, dbuf.dsize);
204 SAFE_FREE(dbuf.dptr);
205 continue;
210 ret = 0;
212 done:
213 talloc_free(ctx);
214 return ret;
217 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
218 struct rpc_pipe_client *pipe_hnd,
219 const char *key_name,
220 unsigned char *data,
221 size_t length)
223 struct policy_handle hnd;
224 enum ndr_err_code ndr_err;
225 struct ntprinting_form r;
226 union spoolss_AddFormInfo f;
227 struct spoolss_AddFormInfo1 f1;
228 DATA_BLOB blob;
229 NTSTATUS status;
230 WERROR result;
232 blob = data_blob_const(data, length);
234 ZERO_STRUCT(r);
236 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
237 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
239 d_fprintf(stderr, _("form pull failed: %s\n"),
240 ndr_errstr(ndr_err));
241 return NT_STATUS_NO_MEMORY;
244 /* Don't migrate builtin forms */
245 if (r.flag == SPOOLSS_FORM_BUILTIN) {
246 return NT_STATUS_OK;
249 d_printf(_("Migrating Form: %s\n"), key_name);
251 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
252 mem_ctx,
253 pipe_hnd->srv_name_slash,
254 MAXIMUM_ALLOWED_ACCESS,
255 &hnd);
256 if (!W_ERROR_IS_OK(result)) {
257 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
258 pipe_hnd->srv_name_slash, win_errstr(result));
259 return werror_to_ntstatus(result);
262 f1.form_name = key_name;
263 f1.flags = r.flag;
265 f1.size.width = r.width;
266 f1.size.height = r.length;
268 f1.area.top = r.top;
269 f1.area.right = r.right;
270 f1.area.bottom = r.bottom;
271 f1.area.left = r.left;
273 f.info1 = &f1;
275 status = rpccli_spoolss_AddForm(pipe_hnd,
276 mem_ctx,
277 &hnd,
280 &result);
281 if (!NT_STATUS_IS_OK(status)) {
282 d_printf(_("\tAddForm(%s) refused -- %s.\n"),
283 f.info1->form_name, nt_errstr(status));
286 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
288 return status;
291 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
292 struct rpc_pipe_client *pipe_hnd,
293 const char *key_name,
294 unsigned char *data,
295 size_t length)
297 enum ndr_err_code ndr_err;
298 struct ntprinting_driver r;
299 struct spoolss_AddDriverInfoCtr d;
300 struct spoolss_AddDriverInfo3 d3;
301 struct spoolss_StringArray a;
302 DATA_BLOB blob;
303 NTSTATUS status;
304 WERROR result;
306 blob = data_blob_const(data, length);
308 ZERO_STRUCT(r);
310 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
311 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
312 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
313 d_fprintf(stderr, _("driver pull failed: %s\n"),
314 ndr_errstr(ndr_err));
315 return NT_STATUS_NO_MEMORY;
318 d_printf(_("Migrating Printer Driver: %s\n"), key_name);
320 ZERO_STRUCT(d3);
321 ZERO_STRUCT(a);
323 a.string = r.dependent_files;
325 d3.architecture = r.environment;
326 d3.config_file = r.configfile;
327 d3.data_file = r.datafile;
328 d3.default_datatype = r.defaultdatatype;
329 d3.dependent_files = &a;
330 d3.driver_path = r.driverpath;
331 d3.help_file = r.helpfile;
332 d3.monitor_name = r.monitorname;
333 d3.driver_name = r.name;
334 d3.version = r.version;
336 d.info.info3 = &d3;
337 d.level = 3;
339 status = rpccli_spoolss_AddPrinterDriver(pipe_hnd,
340 mem_ctx,
341 NULL,
343 &result);
344 if (!NT_STATUS_IS_OK(status)) {
345 d_printf(_("\tAddDriver driver: [%s] refused -- %s.\n"),
346 d3.driver_name, nt_errstr(status));
349 return status;
352 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
353 struct rpc_pipe_client *pipe_hnd,
354 const char *key_name,
355 unsigned char *data,
356 size_t length)
358 struct policy_handle hnd;
359 enum ndr_err_code ndr_err;
360 struct ntprinting_printer r;
361 struct spoolss_SetPrinterInfo2 info2;
362 struct spoolss_DeviceMode dm;
363 struct spoolss_SetPrinterInfoCtr info_ctr;
364 struct spoolss_DevmodeContainer devmode_ctr;
365 struct sec_desc_buf secdesc_ctr;
366 DATA_BLOB blob;
367 NTSTATUS status;
368 WERROR result;
369 int j;
371 if (strequal(key_name, "printers")) {
372 return NT_STATUS_OK;
375 blob = data_blob_const(data, length);
377 ZERO_STRUCT(r);
379 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
380 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382 d_fprintf(stderr, _("printer pull failed: %s\n"),
383 ndr_errstr(ndr_err));
384 return NT_STATUS_NO_MEMORY;
387 d_printf(_("Migrating Printer: %s\n"), key_name);
389 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
390 mem_ctx,
391 key_name,
392 MAXIMUM_ALLOWED_ACCESS,
393 &hnd);
394 if (!W_ERROR_IS_OK(result)) {
395 d_fprintf(stderr, _("OpenPrinter(%s) failed: %s\n"),
396 key_name, win_errstr(result));
397 return werror_to_ntstatus(result);
400 /* Create printer info level 2 */
401 ZERO_STRUCT(info2);
402 ZERO_STRUCT(devmode_ctr);
403 ZERO_STRUCT(secdesc_ctr);
405 info2.attributes = r.info.attributes;
406 info2.averageppm = r.info.averageppm;
407 info2.cjobs = r.info.cjobs;
408 info2.comment = r.info.comment;
409 info2.datatype = r.info.datatype;
410 info2.defaultpriority = r.info.default_priority;
411 info2.drivername = r.info.drivername;
412 info2.location = r.info.location;
413 info2.parameters = r.info.parameters;
414 info2.portname = r.info.portname;
415 info2.printername = r.info.printername;
416 info2.printprocessor = r.info.printprocessor;
417 info2.priority = r.info.priority;
418 info2.sepfile = r.info.sepfile;
419 info2.sharename = r.info.sharename;
420 info2.starttime = r.info.starttime;
421 info2.status = r.info.status;
422 info2.untiltime = r.info.untiltime;
424 /* Create Device Mode */
425 if (r.devmode != NULL) {
426 ZERO_STRUCT(dm);
428 dm.bitsperpel = r.devmode->bitsperpel;
429 dm.collate = r.devmode->collate;
430 dm.color = r.devmode->color;
431 dm.copies = r.devmode->copies;
432 dm.defaultsource = r.devmode->defaultsource;
433 dm.devicename = r.devmode->devicename;
434 dm.displayflags = r.devmode->displayflags;
435 dm.displayfrequency = r.devmode->displayfrequency;
436 dm.dithertype = r.devmode->dithertype;
437 dm.driverversion = r.devmode->driverversion;
438 dm.duplex = r.devmode->duplex;
439 dm.fields = r.devmode->fields;
440 dm.formname = r.devmode->formname;
441 dm.icmintent = r.devmode->icmintent;
442 dm.icmmethod = r.devmode->icmmethod;
443 dm.logpixels = r.devmode->logpixels;
444 dm.mediatype = r.devmode->mediatype;
445 dm.orientation = r.devmode->orientation;
446 dm.panningheight = r.devmode->pelsheight;
447 dm.panningwidth = r.devmode->panningwidth;
448 dm.paperlength = r.devmode->paperlength;
449 dm.papersize = r.devmode->papersize;
450 dm.paperwidth = r.devmode->paperwidth;
451 dm.pelsheight = r.devmode->pelsheight;
452 dm.pelswidth = r.devmode->pelswidth;
453 dm.printquality = r.devmode->printquality;
454 dm.scale = r.devmode->scale;
455 dm.specversion = r.devmode->specversion;
456 dm.ttoption = r.devmode->ttoption;
457 dm.yresolution = r.devmode->yresolution;
459 if (r.devmode->nt_dev_private != NULL) {
460 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
461 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
462 dm.__driverextra_length = r.devmode->nt_dev_private->length;
465 devmode_ctr.devmode = &dm;
467 info2.devmode_ptr = 1;
470 info_ctr.info.info2 = &info2;
471 info_ctr.level = 2;
473 status = rpccli_spoolss_SetPrinter(pipe_hnd,
474 mem_ctx,
475 &hnd,
476 &info_ctr,
477 &devmode_ctr,
478 &secdesc_ctr,
479 0, /* command */
480 &result);
481 if (!NT_STATUS_IS_OK(status)) {
482 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
483 key_name, nt_errstr(status));
484 goto done;
487 /* migrate printerdata */
488 for (j = 0; j < r.count; j++) {
489 char *valuename;
490 char *keyname;
492 if (r.printer_data[j].type == REG_NONE) {
493 continue;
496 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
497 valuename = strchr(keyname, '\\');
498 if (valuename == NULL) {
499 continue;
500 } else {
501 valuename[0] = '\0';
502 valuename++;
505 printf(" data: %s\\%s\n", keyname, valuename);
507 status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd,
508 mem_ctx,
509 &hnd,
510 keyname,
511 valuename,
512 r.printer_data[j].type,
513 r.printer_data[j].data.data,
514 r.printer_data[j].data.length,
515 &result);
516 if (!NT_STATUS_IS_OK(status)) {
517 d_printf(_("\tSetPrinterDataEx: printer [%s], keyname [%s], valuename [%s] refused -- %s.\n"),
518 key_name, keyname, valuename, nt_errstr(status));
519 break;
523 done:
524 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
526 return status;
529 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
530 struct rpc_pipe_client *pipe_hnd,
531 const char *key_name,
532 unsigned char *data,
533 size_t length)
535 struct policy_handle hnd;
536 enum ndr_err_code ndr_err;
537 struct sec_desc_buf secdesc_ctr;
538 struct spoolss_SetPrinterInfo3 info3;
539 struct spoolss_SetPrinterInfoCtr info_ctr;
540 struct spoolss_DevmodeContainer devmode_ctr;
541 DATA_BLOB blob;
542 NTSTATUS status;
543 WERROR result;
545 if (strequal(key_name, "printers")) {
546 return NT_STATUS_OK;
549 blob = data_blob_const(data, length);
551 ZERO_STRUCT(secdesc_ctr);
553 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
554 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
555 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
556 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
557 ndr_errstr(ndr_err));
558 return NT_STATUS_NO_MEMORY;
561 d_printf(_("Migrating Security Descriptor: %s\n"), key_name);
563 result = rpccli_spoolss_openprinter_ex(pipe_hnd,
564 mem_ctx,
565 key_name,
566 MAXIMUM_ALLOWED_ACCESS,
567 &hnd);
568 if (!W_ERROR_IS_OK(result)) {
569 d_fprintf(stderr, _("\tOpenPrinter(%s) failed: %s\n"),
570 key_name, win_errstr(result));
571 return werror_to_ntstatus(result);
574 ZERO_STRUCT(devmode_ctr);
576 info3.sec_desc_ptr = 1;
578 info_ctr.info.info3 = &info3;
579 info_ctr.level = 3;
581 status = rpccli_spoolss_SetPrinter(pipe_hnd,
582 mem_ctx,
583 &hnd,
584 &info_ctr,
585 &devmode_ctr,
586 &secdesc_ctr,
587 0, /* command */
588 &result);
589 if (!NT_STATUS_IS_OK(status)) {
590 d_printf(_("\tSetPrinter(%s) level 3 refused -- %s.\n"),
591 key_name, nt_errstr(status));
594 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
596 return status;
599 static NTSTATUS printing_migrate_internal(struct net_context *c,
600 const struct dom_sid *domain_sid,
601 const char *domain_name,
602 struct cli_state *cli,
603 struct rpc_pipe_client *pipe_hnd,
604 TALLOC_CTX *mem_ctx,
605 int argc,
606 const char **argv)
608 TALLOC_CTX *tmp_ctx;
609 TDB_CONTEXT *tdb;
610 TDB_DATA kbuf, newkey, dbuf;
611 NTSTATUS status;
613 tmp_ctx = talloc_new(mem_ctx);
614 if (tmp_ctx == NULL) {
615 return NT_STATUS_NO_MEMORY;
618 tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
619 if (tdb == NULL) {
620 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
621 status = NT_STATUS_NO_SUCH_FILE;
622 goto done;
625 for (kbuf = tdb_firstkey(tdb);
626 kbuf.dptr;
627 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
629 dbuf = tdb_fetch(tdb, kbuf);
630 if (!dbuf.dptr) {
631 continue;
634 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
635 migrate_form(tmp_ctx,
636 pipe_hnd,
637 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
638 dbuf.dptr,
639 dbuf.dsize);
640 SAFE_FREE(dbuf.dptr);
641 continue;
644 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
645 migrate_driver(tmp_ctx,
646 pipe_hnd,
647 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
648 dbuf.dptr,
649 dbuf.dsize);
650 SAFE_FREE(dbuf.dptr);
651 continue;
654 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
655 migrate_printer(tmp_ctx,
656 pipe_hnd,
657 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
658 dbuf.dptr,
659 dbuf.dsize);
660 SAFE_FREE(dbuf.dptr);
661 continue;
664 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
665 migrate_secdesc(tmp_ctx,
666 pipe_hnd,
667 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
668 dbuf.dptr,
669 dbuf.dsize);
670 SAFE_FREE(dbuf.dptr);
671 continue;
676 status = NT_STATUS_OK;
678 done:
679 talloc_free(tmp_ctx);
680 return status;
683 static int net_printing_migrate(struct net_context *c,
684 int argc,
685 const char **argv)
687 if (argc < 1 || c->display_usage) {
688 d_printf( "%s\n"
689 "net printing migrate <file.tdb>\n"
690 " %s\n",
691 _("Usage:"),
692 _("Migrate tdb printing files to new storage"));
693 return 0;
696 return run_rpc_command(c,
697 NULL,
698 &ndr_table_spoolss.syntax_id,
700 printing_migrate_internal,
701 argc,
702 argv);
705 * 'net printing' entrypoint.
706 * @param argc Standard main() style argc.
707 * @param argv Standard main() style argv. Initial components are already
708 * stripped.
711 int net_printing(struct net_context *c, int argc, const char **argv)
713 int ret = -1;
715 struct functable func[] = {
717 "dump",
718 net_printing_dump,
719 NET_TRANSPORT_LOCAL,
720 N_("Dump printer databases"),
721 N_("net printing dump\n"
722 " Dump tdb printing file")
726 "migrate",
727 net_printing_migrate,
728 NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC,
729 N_("Migrate printer databases"),
730 N_("net printing migrate\n"
731 " Migrate tdb printing files to new storage")
734 { NULL, NULL, 0, NULL, NULL }
737 ret = net_run_function(c, argc, argv, "net printing", func);
739 return ret;