2f8caad8fda75de3c9de9a44b6d49783d3dc6207
[ddiss/samba.git] / source3 / utils / net_printing.c
1 /*
2    Samba Unix/Linux SMB client library
3    Distributed SMB/CIFS Server Management Utility
4    Local printing tdb migration interface
5
6    Copyright (C) Guenther Deschner 2010
7
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.
12
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.
17
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/>.
20  */
21
22 #include "includes.h"
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"
31 #include "util_tdb.h"
32
33 #define FORMS_PREFIX "FORMS/"
34 #define DRIVERS_PREFIX "DRIVERS/"
35 #define PRINTERS_PREFIX "PRINTERS/"
36 #define SECDESC_PREFIX "SECDESC/"
37
38 static void dump_form(TALLOC_CTX *mem_ctx,
39                       const char *key_name,
40                       unsigned char *data,
41                       size_t length)
42 {
43         enum ndr_err_code ndr_err;
44         DATA_BLOB blob;
45         char *s;
46         struct ntprinting_form r;
47
48         printf("found form: %s\n", key_name);
49
50         blob = data_blob_const(data, length);
51
52         ZERO_STRUCT(r);
53
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"),
58                           ndr_errstr(ndr_err));
59                 return;
60         }
61
62         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_form, &r);
63         if (s) {
64                 printf("%s\n", s);
65         }
66 }
67
68 static void dump_driver(TALLOC_CTX *mem_ctx,
69                         const char *key_name,
70                         unsigned char *data,
71                         size_t length)
72 {
73         enum ndr_err_code ndr_err;
74         DATA_BLOB blob;
75         char *s;
76         struct ntprinting_driver r;
77
78         printf("found driver: %s\n", key_name);
79
80         blob = data_blob_const(data, length);
81
82         ZERO_STRUCT(r);
83
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"),
88                           ndr_errstr(ndr_err));
89                 return;
90         }
91
92         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
93         if (s) {
94                 printf("%s\n", s);
95         }
96 }
97
98 static void dump_printer(TALLOC_CTX *mem_ctx,
99                          const char *key_name,
100                          unsigned char *data,
101                          size_t length)
102 {
103         enum ndr_err_code ndr_err;
104         DATA_BLOB blob;
105         char *s;
106         struct ntprinting_printer r;
107
108         printf("found printer: %s\n", key_name);
109
110         blob = data_blob_const(data, length);
111
112         ZERO_STRUCT(r);
113
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));
119                 return;
120         }
121
122         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
123         if (s) {
124                 printf("%s\n", s);
125         }
126 }
127
128 static void dump_sd(TALLOC_CTX *mem_ctx,
129                     const char *key_name,
130                     unsigned char *data,
131                     size_t length)
132 {
133         enum ndr_err_code ndr_err;
134         DATA_BLOB blob;
135         char *s;
136         struct sec_desc_buf r;
137
138         printf("found security descriptor: %s\n", key_name);
139
140         blob = data_blob_const(data, length);
141
142         ZERO_STRUCT(r);
143
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));
149                 return;
150         }
151
152         s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
153         if (s) {
154                 printf("%s\n", s);
155         }
156 }
157
158
159 static int net_printing_dump(struct net_context *c, int argc,
160                              const char **argv)
161 {
162         int ret = -1;
163         TALLOC_CTX *ctx = talloc_stackframe();
164         TDB_CONTEXT *tdb;
165         TDB_DATA kbuf, dbuf;
166
167         if (argc < 1 || c->display_usage) {
168                 d_fprintf(stderr, "%s\nnet printing dump <file.tdb>\n",
169                           _("Usage:"));
170                 goto done;
171         }
172
173         tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
174         if (!tdb) {
175                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
176                 goto done;
177         }
178
179         for (kbuf = tdb_firstkey_compat(tdb);
180              kbuf.dptr;
181              kbuf = tdb_nextkey_compat(tdb, kbuf))
182         {
183                 dbuf = tdb_fetch_compat(tdb, kbuf);
184                 if (!dbuf.dptr) {
185                         continue;
186                 }
187
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);
191                         continue;
192                 }
193
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);
197                         continue;
198                 }
199
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);
203                         continue;
204                 }
205
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);
209                         continue;
210                 }
211
212         }
213
214         ret = 0;
215
216  done:
217         talloc_free(ctx);
218         return ret;
219 }
220
221 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
222                          struct rpc_pipe_client *pipe_hnd,
223                          const char *key_name,
224                          unsigned char *data,
225                          size_t length)
226 {
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;
233         DATA_BLOB blob;
234         NTSTATUS status;
235         WERROR result;
236
237         blob = data_blob_const(data, length);
238
239         ZERO_STRUCT(r);
240
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;
247         }
248
249         /* Don't migrate builtin forms */
250         if (r.flag == SPOOLSS_FORM_BUILTIN) {
251                 return NT_STATUS_OK;
252         }
253
254         d_printf(_("Migrating Form: %s\n"), key_name);
255
256         result = rpccli_spoolss_openprinter_ex(pipe_hnd,
257                                                mem_ctx,
258                                                pipe_hnd->srv_name_slash,
259                                                MAXIMUM_ALLOWED_ACCESS,
260                                                &hnd);
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);
265         }
266
267         f1.form_name = key_name;
268         f1.flags = r.flag;
269
270         f1.size.width = r.width;
271         f1.size.height = r.length;
272
273         f1.area.top = r.top;
274         f1.area.right = r.right;
275         f1.area.bottom = r.bottom;
276         f1.area.left = r.left;
277
278         f.info1 = &f1;
279
280         status = dcerpc_spoolss_AddForm(b,
281                                         mem_ctx,
282                                         &hnd,
283                                         1,
284                                         f,
285                                         &result);
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);
293         }
294
295         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
296
297         return status;
298 }
299
300 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
301                                struct rpc_pipe_client *pipe_hnd,
302                                const char *key_name,
303                                unsigned char *data,
304                                size_t length)
305 {
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;
312         DATA_BLOB blob;
313         NTSTATUS status;
314         WERROR result;
315
316         blob = data_blob_const(data, length);
317
318         ZERO_STRUCT(r);
319
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;
326         }
327
328         d_printf(_("Migrating Printer Driver: %s\n"), key_name);
329
330         ZERO_STRUCT(d3);
331         ZERO_STRUCT(a);
332
333         a.string = r.dependent_files;
334
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;
345
346         d.info.info3 = &d3;
347         d.level = 3;
348
349         status = dcerpc_spoolss_AddPrinterDriver(b,
350                                                  mem_ctx,
351                                                  NULL,
352                                                  &d,
353                                                  &result);
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);
361         }
362
363         return status;
364 }
365
366 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
367                                 struct rpc_pipe_client *pipe_hnd,
368                                 const char *key_name,
369                                 unsigned char *data,
370                                 size_t length)
371 {
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;
381         DATA_BLOB blob;
382         NTSTATUS status;
383         WERROR result;
384         int j;
385
386         if (strequal(key_name, "printers")) {
387                 return NT_STATUS_OK;
388         }
389
390         blob = data_blob_const(data, length);
391
392         ZERO_STRUCT(r);
393
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;
400         }
401
402         d_printf(_("Migrating Printer: %s\n"), key_name);
403
404         result = rpccli_spoolss_openprinter_ex(pipe_hnd,
405                                                mem_ctx,
406                                                key_name,
407                                                MAXIMUM_ALLOWED_ACCESS,
408                                                &hnd);
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);
413         }
414
415         /* Create printer info level 2 */
416         ZERO_STRUCT(info2);
417         ZERO_STRUCT(devmode_ctr);
418         ZERO_STRUCT(secdesc_ctr);
419
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;
438
439         /* Create Device Mode */
440         if (r.devmode != NULL) {
441                 ZERO_STRUCT(dm);
442
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;
473
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;
478                 }
479
480                 devmode_ctr.devmode = &dm;
481
482                 info2.devmode_ptr = 1;
483         }
484
485         info_ctr.info.info2 = &info2;
486         info_ctr.level = 2;
487
488         status = dcerpc_spoolss_SetPrinter(b,
489                                            mem_ctx,
490                                            &hnd,
491                                            &info_ctr,
492                                            &devmode_ctr,
493                                            &secdesc_ctr,
494                                            0, /* command */
495                                            &result);
496         if (!NT_STATUS_IS_OK(status)) {
497                 d_printf(_("\tSetPrinter(%s) level 2 refused -- %s.\n"),
498                         key_name, nt_errstr(status));
499                 goto done;
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);
504                 goto done;
505         }
506
507         /* migrate printerdata */
508         for (j = 0; j < r.count; j++) {
509                 char *valuename;
510                 char *keyname;
511
512                 if (r.printer_data[j].type == REG_NONE) {
513                         continue;
514                 }
515
516                 keyname = discard_const_p(char, r.printer_data[j].name);
517                 valuename = strchr(keyname, '\\');
518                 if (valuename == NULL) {
519                         continue;
520                 } else {
521                         valuename[0] = '\0';
522                         valuename++;
523                 }
524
525                 printf("          data: %s\\%s\n", keyname, valuename);
526
527                 status = dcerpc_spoolss_SetPrinterDataEx(b,
528                                                          mem_ctx,
529                                                          &hnd,
530                                                          keyname,
531                                                          valuename,
532                                                          r.printer_data[j].type,
533                                                          r.printer_data[j].data.data,
534                                                          r.printer_data[j].data.length,
535                                                          &result);
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));
539                         break;
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);
544                         break;
545                 }
546         }
547
548  done:
549         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
550
551         return status;
552 }
553
554 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
555                                 struct rpc_pipe_client *pipe_hnd,
556                                 const char *key_name,
557                                 unsigned char *data,
558                                 size_t length)
559 {
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;
567         DATA_BLOB blob;
568         NTSTATUS status;
569         WERROR result;
570
571         if (strequal(key_name, "printers")) {
572                 return NT_STATUS_OK;
573         }
574
575         blob = data_blob_const(data, length);
576
577         ZERO_STRUCT(secdesc_ctr);
578
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;
585         }
586
587         d_printf(_("Migrating Security Descriptor: %s\n"), key_name);
588
589         result = rpccli_spoolss_openprinter_ex(pipe_hnd,
590                                                mem_ctx,
591                                                key_name,
592                                                MAXIMUM_ALLOWED_ACCESS,
593                                                &hnd);
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);
598         }
599
600         ZERO_STRUCT(devmode_ctr);
601
602         info3.sec_desc_ptr = 1;
603
604         info_ctr.info.info3 = &info3;
605         info_ctr.level = 3;
606
607         status = dcerpc_spoolss_SetPrinter(b,
608                                            mem_ctx,
609                                            &hnd,
610                                            &info_ctr,
611                                            &devmode_ctr,
612                                            &secdesc_ctr,
613                                            0, /* command */
614                                            &result);
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);
622         }
623
624         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
625
626         return status;
627 }
628
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,
634                                           TALLOC_CTX *mem_ctx,
635                                           int argc,
636                                           const char **argv)
637 {
638         TALLOC_CTX *tmp_ctx;
639         TDB_CONTEXT *tdb;
640         TDB_DATA kbuf, dbuf;
641         NTSTATUS status;
642
643         tmp_ctx = talloc_new(mem_ctx);
644         if (tmp_ctx == NULL) {
645                 return NT_STATUS_NO_MEMORY;
646         }
647
648         tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
649         if (tdb == NULL) {
650                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
651                 status = NT_STATUS_NO_SUCH_FILE;
652                 goto done;
653         }
654
655         for (kbuf = tdb_firstkey_compat(tdb);
656              kbuf.dptr;
657              kbuf = tdb_nextkey_compat(tdb, kbuf))
658         {
659                 dbuf = tdb_fetch_compat(tdb, kbuf);
660                 if (!dbuf.dptr) {
661                         continue;
662                 }
663
664                 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
665                         migrate_form(tmp_ctx,
666                                      pipe_hnd,
667                                      (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
668                                      dbuf.dptr,
669                                      dbuf.dsize);
670                         SAFE_FREE(dbuf.dptr);
671                         continue;
672                 }
673
674                 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
675                         migrate_driver(tmp_ctx,
676                                        pipe_hnd,
677                                        (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
678                                        dbuf.dptr,
679                                        dbuf.dsize);
680                         SAFE_FREE(dbuf.dptr);
681                         continue;
682                 }
683
684                 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
685                         migrate_printer(tmp_ctx,
686                                         pipe_hnd,
687                                         (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
688                                         dbuf.dptr,
689                                         dbuf.dsize);
690                         SAFE_FREE(dbuf.dptr);
691                         continue;
692                 }
693
694                 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
695                         migrate_secdesc(tmp_ctx,
696                                         pipe_hnd,
697                                         (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
698                                         dbuf.dptr,
699                                         dbuf.dsize);
700                         SAFE_FREE(dbuf.dptr);
701                         continue;
702                 }
703
704         }
705
706         status = NT_STATUS_OK;
707
708  done:
709         talloc_free(tmp_ctx);
710         return status;
711 }
712
713 static int net_printing_migrate(struct net_context *c,
714                                 int argc,
715                                 const char **argv)
716 {
717         if (argc < 1 || c->display_usage) {
718                 d_printf(  "%s\n"
719                            "net printing migrate <file.tdb>\n"
720                            "    %s\n",
721                          _("Usage:"),
722                          _("Migrate tdb printing files to new storage"));
723                 return 0;
724         }
725
726         return run_rpc_command(c,
727                                NULL,
728                                &ndr_table_spoolss.syntax_id,
729                                0,
730                                printing_migrate_internal,
731                                argc,
732                                argv);
733 }
734 /**
735  * 'net printing' entrypoint.
736  * @param argc  Standard main() style argc.
737  * @param argv  Standard main() style argv. Initial components are already
738  *              stripped.
739  **/
740
741 int net_printing(struct net_context *c, int argc, const char **argv)
742 {
743         int ret = -1;
744
745         struct functable func[] = {
746                 {
747                         "dump",
748                         net_printing_dump,
749                         NET_TRANSPORT_LOCAL,
750                         N_("Dump printer databases"),
751                         N_("net printing dump\n"
752                            "    Dump tdb printing file")
753                 },
754
755                 {
756                         "migrate",
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")
762                 },
763
764         { NULL, NULL, 0, NULL, NULL }
765         };
766
767         ret = net_run_function(c, argc, argv, "net printing", func);
768
769         return ret;
770 }