s3-net: Add encoding=<CP> to 'net printing migrate'.
[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 {
117         enum ndr_err_code ndr_err;
118         DATA_BLOB blob;
119         char *s;
120         struct ntprinting_driver r;
121
122         printf("found driver: %s\n", key_name);
123
124         blob = data_blob_const(data, length);
125
126         ZERO_STRUCT(r);
127
128         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
129                    (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
130         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
131                 d_fprintf(stderr, _("driver pull failed: %s\n"),
132                           ndr_errstr(ndr_err));
133                 return;
134         }
135
136         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_driver, &r);
137         if (s) {
138                 printf("%s\n", s);
139         }
140 }
141
142 static void dump_printer(TALLOC_CTX *mem_ctx,
143                          const char *key_name,
144                          unsigned char *data,
145                          size_t length)
146 {
147         enum ndr_err_code ndr_err;
148         DATA_BLOB blob;
149         char *s;
150         struct ntprinting_printer r;
151
152         printf("found printer: %s\n", key_name);
153
154         blob = data_blob_const(data, length);
155
156         ZERO_STRUCT(r);
157
158         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
159                    (ndr_pull_flags_fn_t)ndr_pull_ntprinting_printer);
160         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
161                 d_fprintf(stderr, _("printer pull failed: %s\n"),
162                           ndr_errstr(ndr_err));
163                 return;
164         }
165
166         s = NDR_PRINT_STRUCT_STRING(mem_ctx, ntprinting_printer, &r);
167         if (s) {
168                 printf("%s\n", s);
169         }
170 }
171
172 static void dump_sd(TALLOC_CTX *mem_ctx,
173                     const char *key_name,
174                     unsigned char *data,
175                     size_t length)
176 {
177         enum ndr_err_code ndr_err;
178         DATA_BLOB blob;
179         char *s;
180         struct sec_desc_buf r;
181
182         printf("found security descriptor: %s\n", key_name);
183
184         blob = data_blob_const(data, length);
185
186         ZERO_STRUCT(r);
187
188         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
189                    (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
190         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
191                 d_fprintf(stderr, _("security descriptor pull failed: %s\n"),
192                           ndr_errstr(ndr_err));
193                 return;
194         }
195
196         s = NDR_PRINT_STRUCT_STRING(mem_ctx, sec_desc_buf, &r);
197         if (s) {
198                 printf("%s\n", s);
199         }
200 }
201
202
203 static int net_printing_dump(struct net_context *c, int argc,
204                              const char **argv)
205 {
206         int ret = -1;
207         TALLOC_CTX *ctx = talloc_stackframe();
208         TDB_CONTEXT *tdb;
209         TDB_DATA kbuf, dbuf;
210
211         if (argc < 1 || c->display_usage) {
212                 d_fprintf(stderr, "%s\nnet printing dump <file.tdb>\n",
213                           _("Usage:"));
214                 goto done;
215         }
216
217         tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0600);
218         if (!tdb) {
219                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), argv[0]);
220                 goto done;
221         }
222
223         for (kbuf = tdb_firstkey_compat(tdb);
224              kbuf.dptr;
225              kbuf = tdb_nextkey_compat(tdb, kbuf))
226         {
227                 dbuf = tdb_fetch_compat(tdb, kbuf);
228                 if (!dbuf.dptr) {
229                         continue;
230                 }
231
232                 if (strncmp((const char *)kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
233                         dump_form(ctx, (const char *)kbuf.dptr+strlen(FORMS_PREFIX), dbuf.dptr, dbuf.dsize);
234                         SAFE_FREE(dbuf.dptr);
235                         continue;
236                 }
237
238                 if (strncmp((const char *)kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
239                         dump_driver(ctx, (const char *)kbuf.dptr+strlen(DRIVERS_PREFIX), dbuf.dptr, dbuf.dsize);
240                         SAFE_FREE(dbuf.dptr);
241                         continue;
242                 }
243
244                 if (strncmp((const char *)kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
245                         dump_printer(ctx, (const char *)kbuf.dptr+strlen(PRINTERS_PREFIX), dbuf.dptr, dbuf.dsize);
246                         SAFE_FREE(dbuf.dptr);
247                         continue;
248                 }
249
250                 if (strncmp((const char *)kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
251                         dump_sd(ctx, (const char *)kbuf.dptr+strlen(SECDESC_PREFIX), dbuf.dptr, dbuf.dsize);
252                         SAFE_FREE(dbuf.dptr);
253                         continue;
254                 }
255
256         }
257
258         ret = 0;
259
260  done:
261         talloc_free(ctx);
262         return ret;
263 }
264
265 static NTSTATUS printing_migrate_internal(struct net_context *c,
266                                           const struct dom_sid *domain_sid,
267                                           const char *domain_name,
268                                           struct cli_state *cli,
269                                           struct rpc_pipe_client *winreg_pipe,
270                                           TALLOC_CTX *mem_ctx,
271                                           int argc,
272                                           const char **argv)
273 {
274         struct printing_opts *o;
275         TALLOC_CTX *tmp_ctx;
276         TDB_CONTEXT *tdb;
277         TDB_DATA kbuf, dbuf;
278         NTSTATUS status;
279         const char *save_dos_charset = lp_dos_charset();
280         bool do_string_conversion = false;
281
282         tmp_ctx = talloc_new(mem_ctx);
283         if (tmp_ctx == NULL) {
284                 return NT_STATUS_NO_MEMORY;
285         }
286
287         status = printing_parse_args(tmp_ctx, &o, argc, argv);
288         if (!NT_STATUS_IS_OK(status)) {
289                 d_fprintf(stderr, _("failed to parse arguments\n"));
290                 goto done;
291         }
292
293         tdb = tdb_open_log(o->tdb, 0, TDB_DEFAULT, O_RDONLY, 0600);
294         if (tdb == NULL) {
295                 d_fprintf(stderr, _("failed to open tdb file: %s\n"), o->tdb);
296                 status = NT_STATUS_NO_SUCH_FILE;
297                 goto done;
298         }
299
300         if (o->encoding != NULL) {
301                 lp_set_cmdline("dos charset", o->encoding);
302                 d_fprintf(stderr, _("do string conversion from %s to %s\n"),
303                                     lp_dos_charset(), lp_unix_charset());
304                 do_string_conversion = true;
305         }
306
307         for (kbuf = tdb_firstkey_compat(tdb);
308              kbuf.dptr;
309              kbuf = tdb_nextkey_compat(tdb, kbuf))
310         {
311                 dbuf = tdb_fetch_compat(tdb, kbuf);
312                 if (!dbuf.dptr) {
313                         continue;
314                 }
315
316                 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
317                         printing_tdb_migrate_form(tmp_ctx,
318                                      winreg_pipe,
319                                      (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
320                                      dbuf.dptr,
321                                      dbuf.dsize);
322                         SAFE_FREE(dbuf.dptr);
323                         continue;
324                 }
325
326                 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
327                         printing_tdb_migrate_driver(tmp_ctx,
328                                        winreg_pipe,
329                                        (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
330                                        dbuf.dptr,
331                                        dbuf.dsize,
332                                        do_string_conversion);
333                         SAFE_FREE(dbuf.dptr);
334                         continue;
335                 }
336
337                 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
338                         printing_tdb_migrate_printer(tmp_ctx,
339                                         winreg_pipe,
340                                         (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
341                                         dbuf.dptr,
342                                         dbuf.dsize,
343                                         do_string_conversion);
344                         SAFE_FREE(dbuf.dptr);
345                         continue;
346                 }
347                 SAFE_FREE(dbuf.dptr);
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, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
360                         printing_tdb_migrate_secdesc(tmp_ctx,
361                                         winreg_pipe,
362                                         (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
363                                         dbuf.dptr,
364                                         dbuf.dsize);
365                         SAFE_FREE(dbuf.dptr);
366                         continue;
367                 }
368                 SAFE_FREE(dbuf.dptr);
369
370         }
371
372         status = NT_STATUS_OK;
373
374  done:
375         lp_set_cmdline("dos charset", save_dos_charset);
376         talloc_free(tmp_ctx);
377         return status;
378 }
379
380 static int net_printing_migrate(struct net_context *c,
381                                 int argc,
382                                 const char **argv)
383 {
384         if (argc < 1 || c->display_usage) {
385                 d_printf(  "%s\n"
386                            "net printing migrate [options] <file.tdb>\n"
387                            "    %s\n",
388                          _("Usage:"),
389                          _("Migrate tdb printing files to new storage"));
390                 d_printf(_("Valid options:\n"));
391                 d_printf(_("    encoding=<CP>   Set the Code Page of the tdb file.\n"
392                            "                    See iconv -l for the list of CP values\n"
393                            "                    (CP1252 is Western latin1, CP1251 is Cyrillic).\n"));
394                 return 0;
395         }
396
397         return run_rpc_command(c,
398                                NULL,
399                                &ndr_table_winreg,
400                                0,
401                                printing_migrate_internal,
402                                argc,
403                                argv);
404 }
405 /**
406  * 'net printing' entrypoint.
407  * @param argc  Standard main() style argc.
408  * @param argv  Standard main() style argv. Initial components are already
409  *              stripped.
410  **/
411
412 int net_printing(struct net_context *c, int argc, const char **argv)
413 {
414         int ret = -1;
415
416         struct functable func[] = {
417                 {
418                         "dump",
419                         net_printing_dump,
420                         NET_TRANSPORT_LOCAL,
421                         N_("Dump printer databases"),
422                         N_("net printing dump\n"
423                            "    Dump tdb printing file")
424                 },
425
426                 {
427                         "migrate",
428                         net_printing_migrate,
429                         NET_TRANSPORT_LOCAL | NET_TRANSPORT_RPC,
430                         N_("Migrate printer databases"),
431                         N_("net printing migrate\n"
432                            "    Migrate tdb printing files to new storage")
433                 },
434
435         { NULL, NULL, 0, NULL, NULL }
436         };
437
438         ret = net_run_function(c, argc, argv, "net printing", func);
439
440         return ret;
441 }