s3-net: Add encoding=<CP> to 'net printing dump'.
[mat/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 "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_ntprinting.h"
28 #include "librpc/gen_ndr/ndr_spoolss.h"
29 #include "../libcli/security/security.h"
30 #include "../librpc/gen_ndr/ndr_security.h"
31 #include "../librpc/gen_ndr/ndr_winreg.h"
32 #include "util_tdb.h"
33 #include "printing/nt_printing_migrate.h"
34
35 #define FORMS_PREFIX "FORMS/"
36 #define DRIVERS_PREFIX "DRIVERS/"
37 #define PRINTERS_PREFIX "PRINTERS/"
38 #define SECDESC_PREFIX "SECDESC/"
39
40 #define ARG_ENCODING "encoding="
41
42 struct printing_opts {
43         const char *encoding;
44         const char *tdb;
45 };
46
47 static NTSTATUS printing_parse_args(TALLOC_CTX *mem_ctx,
48                                     struct printing_opts **popts,
49                                     int argc, const char **argv)
50 {
51         size_t c;
52         struct printing_opts *o;
53
54         if (argc == 0) {
55                 return NT_STATUS_INVALID_PARAMETER;
56         }
57
58         o = talloc_zero(mem_ctx, struct printing_opts);
59         if (o == NULL) {
60                 return NT_STATUS_INVALID_PARAMETER;
61         }
62
63         for (c = 0; c < argc; c++) {
64                 if (strnequal(argv[c], ARG_ENCODING, sizeof(ARG_ENCODING) - 1)) {
65                         o->encoding = talloc_strdup(o,
66                                         argv[c] + sizeof(ARG_ENCODING) - 1);
67                         if (o->encoding == NULL) {
68                                 return NT_STATUS_NO_MEMORY;
69                         }
70                 } else {
71                         o->tdb = talloc_strdup(o, argv[c]);
72                         if (o->tdb == NULL) {
73                                 return NT_STATUS_NO_MEMORY;
74                         }
75                 }
76         }
77
78         *popts = o;
79         return NT_STATUS_OK;
80 }
81
82 static void dump_form(TALLOC_CTX *mem_ctx,
83                       const char *key_name,
84                       unsigned char *data,
85                       size_t length)
86 {
87         enum ndr_err_code ndr_err;
88         DATA_BLOB blob;
89         char *s;
90         struct ntprinting_form r;
91
92         printf("found form: %s\n", key_name);
93
94         blob = data_blob_const(data, length);
95
96         ZERO_STRUCT(r);
97
98         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
99                    (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
100         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
101                 d_fprintf(stderr, _("form pull failed: %s\n"),
102                           ndr_errstr(ndr_err));
103                 return;
104         }
105
106         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_form, &r);
107         if (s) {
108                 printf("%s\n", s);
109         }
110 }
111
112 static void dump_driver(TALLOC_CTX *mem_ctx,
113                         const char *key_name,
114                         unsigned char *data,
115                         size_t length,
116                         bool do_string_conversion)
117 {
118         enum ndr_err_code ndr_err;
119         DATA_BLOB blob;
120         char *s;
121         struct ntprinting_driver r;
122
123         printf("found driver: %s\n", key_name);
124
125         blob = data_blob_const(data, length);
126
127         ZERO_STRUCT(r);
128
129         if (do_string_conversion) {
130                 r.string_flags = LIBNDR_FLAG_STR_ASCII;
131         }
132
133         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
134                    (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
135         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
136                 d_fprintf(stderr, _("driver pull failed: %s\n"),
137                           ndr_errstr(ndr_err));
138                 return;
139         }
140
141         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
142         if (s) {
143                 printf("%s\n", s);
144         }
145 }
146
147 static void dump_printer(TALLOC_CTX *mem_ctx,
148                          const char *key_name,
149                          unsigned char *data,
150                          size_t length,
151                          bool do_string_conversion)
152 {
153         enum ndr_err_code ndr_err;
154         DATA_BLOB blob;
155         char *s;
156         struct ntprinting_printer r;
157
158         printf("found printer: %s\n", key_name);
159
160         blob = data_blob_const(data, length);
161
162         ZERO_STRUCT(r);
163
164         if (do_string_conversion) {
165                 r.info.string_flags = LIBNDR_FLAG_STR_ASCII;
166         }
167
168         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
169                    (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
170         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
171                 d_fprintf(stderr, _("printer pull failed: %s\n"),
172                           ndr_errstr(ndr_err));
173                 return;
174         }
175
176         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
177         if (s) {
178                 printf("%s\n", s);
179         }
180 }
181
182 static void dump_sd(TALLOC_CTX *mem_ctx,
183                     const char *key_name,
184                     unsigned char *data,
185                     size_t length)
186 {
187         enum ndr_err_code ndr_err;
188         DATA_BLOB blob;
189         char *s;
190         struct sec_desc_buf r;
191
192         printf("found security descriptor: %s\n", key_name);
193
194         blob = data_blob_const(data, length);
195
196         ZERO_STRUCT(r);
197
198         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
199                    (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
200         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
201                 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
202                           ndr_errstr(ndr_err));
203                 return;
204         }
205
206         s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
207         if (s) {
208                 printf("%s\n", s);
209         }
210 }
211
212
213 static int net_printing_dump(struct net_context *c, int argc,
214                              const char **argv)
215 {
216         int ret = -1;
217         TALLOC_CTX *ctx = talloc_stackframe();
218         TDB_CONTEXT *tdb;
219         TDB_DATA kbuf, dbuf;
220         struct printing_opts *o;
221         const char *save_dos_charset = lp_dos_charset();
222         bool do_string_conversion = false;
223         NTSTATUS status;
224
225         if (argc < 1 || c->display_usage) {
226                 d_printf(  "%s\n"
227                            "net printing dump [options] <file.tdb>\n"
228                            "    %s\n",
229                          _("Usage:"),
230                          _("Dump formated printer information of the tdb."));
231                 d_printf(_("Valid options:\n"));
232                 d_printf(_("    encoding=<CP>   Set the Code Page of the tdb file.\n"
233                            "                    See iconv -l for the list of CP values\n"
234                            "                    (CP1252 is Western latin1, CP1251 is Cyrillic).\n"));
235                 goto done;
236         }
237
238         status = printing_parse_args(ctx, &o, argc, argv);
239         if (!NT_STATUS_IS_OK(status)) {
240                 d_fprintf(stderr, _("failed to parse arguments\n"));
241                 goto done;
242         }
243
244         tdb = tdb_open_log(o->tdb, 0, TDB_DEFAULT, O_RDONLY, 0600);
245         if (!tdb) {
246                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), o->tdb);
247                 goto done;
248         }
249
250         if (o->encoding != NULL) {
251                 lp_set_cmdline("dos charset", o->encoding);
252                 d_fprintf(stderr, _("do string conversion from %s to %s\n"),
253                                     lp_dos_charset(), lp_unix_charset());
254                 do_string_conversion = true;
255         }
256
257         for (kbuf = tdb_firstkey_compat(tdb);
258              kbuf.dptr;
259              kbuf = tdb_nextkey_compat(tdb, kbuf))
260         {
261                 dbuf = tdb_fetch_compat(tdb, kbuf);
262                 if (!dbuf.dptr) {
263                         continue;
264                 }
265
266                 if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
267                         dump_form(ctx, (const char *)kbuf.dptr+strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize);
268                         SAFE_FREE(dbuf.dptr);
269                         continue;
270                 }
271
272                 if (strncmp((const char *)kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
273                         dump_driver(ctx,
274                                     (const char *)kbuf.dptr+strlen(DRIVERS_PREFIX),
275                                     dbuf.dptr,
276                                     dbuf.dsize,
277                                     do_string_conversion);
278                         SAFE_FREE(dbuf.dptr);
279                         continue;
280                 }
281
282                 if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
283                         dump_printer(ctx,
284                                      (const char *)kbuf.dptr+strlen(PRINTERS_PREFIX),
285                                      dbuf.dptr,
286                                      dbuf.dsize,
287                                      do_string_conversion);
288                         SAFE_FREE(dbuf.dptr);
289                         continue;
290                 }
291
292                 if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
293                         dump_sd(ctx, (const char *)kbuf.dptr+strlen(SECDESC_PREFIX), dbuf.dptr, dbuf.dsize);
294                         SAFE_FREE(dbuf.dptr);
295                         continue;
296                 }
297
298         }
299
300         ret = 0;
301
302  done:
303         lp_set_cmdline("dos charset", save_dos_charset);
304         talloc_free(ctx);
305         return ret;
306 }
307
308 static NTSTATUS printing_migrate_internal(struct net_context *c,
309                                           const struct dom_sid *domain_sid,
310                                           const char *domain_name,
311                                           struct cli_state *cli,
312                                           struct rpc_pipe_client *winreg_pipe,
313                                           TALLOC_CTX *mem_ctx,
314                                           int argc,
315                                           const char **argv)
316 {
317         struct printing_opts *o;
318         TALLOC_CTX *tmp_ctx;
319         TDB_CONTEXT *tdb;
320         TDB_DATA kbuf, dbuf;
321         NTSTATUS status;
322         const char *save_dos_charset = lp_dos_charset();
323         bool do_string_conversion = false;
324
325         tmp_ctx = talloc_new(mem_ctx);
326         if (tmp_ctx == NULL) {
327                 return NT_STATUS_NO_MEMORY;
328         }
329
330         status = printing_parse_args(tmp_ctx, &o, argc, argv);
331         if (!NT_STATUS_IS_OK(status)) {
332                 d_fprintf(stderr, _("failed to parse arguments\n"));
333                 goto done;
334         }
335
336         tdb = tdb_open_log(o->tdb, 0, TDB_DEFAULT, O_RDONLY, 0600);
337         if (tdb == NULL) {
338                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), o->tdb);
339                 status = NT_STATUS_NO_SUCH_FILE;
340                 goto done;
341         }
342
343         if (o->encoding != NULL) {
344                 lp_set_cmdline("dos charset", o->encoding);
345                 d_fprintf(stderr, _("do string conversion from %s to %s\n"),
346                                     lp_dos_charset(), lp_unix_charset());
347                 do_string_conversion = true;
348         }
349
350         for (kbuf = tdb_firstkey_compat(tdb);
351              kbuf.dptr;
352              kbuf = tdb_nextkey_compat(tdb, kbuf))
353         {
354                 dbuf = tdb_fetch_compat(tdb, kbuf);
355                 if (!dbuf.dptr) {
356                         continue;
357                 }
358
359                 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
360                         printing_tdb_migrate_form(tmp_ctx,
361                                      winreg_pipe,
362                                      (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
363                                      dbuf.dptr,
364                                      dbuf.dsize);
365                         SAFE_FREE(dbuf.dptr);
366                         continue;
367                 }
368
369                 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
370                         printing_tdb_migrate_driver(tmp_ctx,
371                                        winreg_pipe,
372                                        (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
373                                        dbuf.dptr,
374                                        dbuf.dsize,
375                                        do_string_conversion);
376                         SAFE_FREE(dbuf.dptr);
377                         continue;
378                 }
379
380                 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
381                         printing_tdb_migrate_printer(tmp_ctx,
382                                         winreg_pipe,
383                                         (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
384                                         dbuf.dptr,
385                                         dbuf.dsize,
386                                         do_string_conversion);
387                         SAFE_FREE(dbuf.dptr);
388                         continue;
389                 }
390                 SAFE_FREE(dbuf.dptr);
391         }
392
393         for (kbuf = tdb_firstkey_compat(tdb);
394              kbuf.dptr;
395              kbuf = tdb_nextkey_compat(tdb, kbuf))
396         {
397                 dbuf = tdb_fetch_compat(tdb, kbuf);
398                 if (!dbuf.dptr) {
399                         continue;
400                 }
401
402                 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
403                         printing_tdb_migrate_secdesc(tmp_ctx,
404                                         winreg_pipe,
405                                         (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
406                                         dbuf.dptr,
407                                         dbuf.dsize);
408                         SAFE_FREE(dbuf.dptr);
409                         continue;
410                 }
411                 SAFE_FREE(dbuf.dptr);
412
413         }
414
415         status = NT_STATUS_OK;
416
417  done:
418         lp_set_cmdline("dos charset", save_dos_charset);
419         talloc_free(tmp_ctx);
420         return status;
421 }
422
423 static int net_printing_migrate(struct net_context *c,
424                                 int argc,
425                                 const char **argv)
426 {
427         if (argc < 1 || c->display_usage) {
428                 d_printf(  "%s\n"
429                            "net printing migrate [options] <file.tdb>\n"
430                            "    %s\n",
431                          _("Usage:"),
432                          _("Migrate tdb printing files to new storage"));
433                 d_printf(_("Valid options:\n"));
434                 d_printf(_("    encoding=<CP>   Set the Code Page of the tdb file.\n"
435                            "                    See iconv -l for the list of CP values\n"
436                            "                    (CP1252 is Western latin1, CP1251 is Cyrillic).\n"));
437                 return 0;
438         }
439
440         return run_rpc_command(c,
441                                NULL,
442                                &ndr_table_winreg,
443                                0,
444                                printing_migrate_internal,
445                                argc,
446                                argv);
447 }
448 /**
449  * 'net printing' entrypoint.
450  * @param argc  Standard main() style argc.
451  * @param argv  Standard main() style argv. Initial components are already
452  *              stripped.
453  **/
454
455 int net_printing(struct net_context *c, int argc, const char **argv)
456 {
457         int ret = -1;
458
459         struct functable func[] = {
460                 {
461                         "dump",
462                         net_printing_dump,
463                         NET_TRANSPORT_LOCAL,
464                         N_("Dump printer databases"),
465                         N_("net printing dump\n"
466                            "    Dump tdb printing file")
467                 },
468
469                 {
470                         "migrate",
471                         net_printing_migrate,
472                         NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC,
473                         N_("Migrate printer databases"),
474                         N_("net printing migrate\n"
475                            "    Migrate tdb printing files to new storage")
476                 },
477
478         { NULL, NULL, 0, NULL, NULL }
479         };
480
481         ret = net_run_function(c, argc, argv, "net printing", func);
482
483         return ret;
484 }