s3: Fix an uninitialized variable
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing_migrate.c
blob624d24539db5b2f87bfb3b43d8e7c9abb4d2bbc7
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
5 * Copyright (c) Andreas Schneider 2010.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "printing/nt_printing_migrate.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 NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
35 struct rpc_pipe_client *pipe_hnd,
36 const char *key_name,
37 unsigned char *data,
38 size_t length)
40 struct spoolss_DevmodeContainer devmode_ctr;
41 struct policy_handle hnd;
42 enum ndr_err_code ndr_err;
43 struct ntprinting_form r;
44 union spoolss_AddFormInfo f;
45 struct spoolss_AddFormInfo1 f1;
46 const char *srv_name_slash;
47 DATA_BLOB blob;
48 NTSTATUS status;
49 WERROR result;
52 blob = data_blob_const(data, length);
54 ZERO_STRUCT(r);
56 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
57 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
58 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
59 DEBUG(2, ("Form pull failed: %s\n",
60 ndr_errstr(ndr_err)));
61 return NT_STATUS_NO_MEMORY;
64 /* Don't migrate builtin forms */
65 if (r.flag == SPOOLSS_FORM_BUILTIN) {
66 return NT_STATUS_OK;
69 DEBUG(2, ("Migrating Form: %s\n", key_name));
71 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
72 if (srv_name_slash == NULL) {
73 return NT_STATUS_NO_MEMORY;
76 ZERO_STRUCT(devmode_ctr);
78 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
79 mem_ctx,
80 srv_name_slash,
81 NULL,
82 devmode_ctr,
83 SEC_FLAG_MAXIMUM_ALLOWED,
84 &hnd,
85 &result);
86 if (!NT_STATUS_IS_OK(status)) {
87 if (!W_ERROR_IS_OK(result)) {
88 status = werror_to_ntstatus(result);
90 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
91 srv_name_slash, nt_errstr(status)));
92 return status;
95 f1.form_name = key_name;
96 f1.flags = r.flag;
98 f1.size.width = r.width;
99 f1.size.height = r.length;
101 f1.area.top = r.top;
102 f1.area.right = r.right;
103 f1.area.bottom = r.bottom;
104 f1.area.left = r.left;
106 f.info1 = &f1;
108 status = rpccli_spoolss_AddForm(pipe_hnd,
109 mem_ctx,
110 &hnd,
113 &result);
114 if (!NT_STATUS_IS_OK(status)) {
115 DEBUG(2, ("AddForm(%s) refused -- %s.\n",
116 f.info1->form_name, nt_errstr(status)));
119 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
121 return status;
124 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
125 struct rpc_pipe_client *pipe_hnd,
126 const char *key_name,
127 unsigned char *data,
128 size_t length)
130 const char *srv_name_slash;
131 enum ndr_err_code ndr_err;
132 struct ntprinting_driver r;
133 struct spoolss_AddDriverInfoCtr d;
134 struct spoolss_AddDriverInfo3 d3;
135 struct spoolss_StringArray a;
136 DATA_BLOB blob;
137 NTSTATUS status;
138 WERROR result;
140 blob = data_blob_const(data, length);
142 ZERO_STRUCT(r);
144 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
145 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
146 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
147 DEBUG(2, ("Driver pull failed: %s\n",
148 ndr_errstr(ndr_err)));
149 return NT_STATUS_NO_MEMORY;
152 DEBUG(2, ("Migrating Printer Driver: %s\n", key_name));
154 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
155 if (srv_name_slash == NULL) {
156 return NT_STATUS_NO_MEMORY;
159 ZERO_STRUCT(d3);
160 ZERO_STRUCT(a);
162 a.string = r.dependent_files;
164 d3.architecture = r.environment;
165 d3.config_file = r.configfile;
166 d3.data_file = r.datafile;
167 d3.default_datatype = r.defaultdatatype;
168 d3.dependent_files = &a;
169 d3.driver_path = r.driverpath;
170 d3.help_file = r.helpfile;
171 d3.monitor_name = r.monitorname;
172 d3.driver_name = r.name;
173 d3.version = r.version;
175 d.level = 3;
176 d.info.info3 = &d3;
178 status = rpccli_spoolss_AddPrinterDriver(pipe_hnd,
179 mem_ctx,
180 srv_name_slash,
182 &result);
183 if (!NT_STATUS_IS_OK(status)) {
184 if (!W_ERROR_IS_OK(result)) {
185 status = werror_to_ntstatus(result);
187 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
188 d3.driver_name, nt_errstr(status)));
191 return status;
194 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
195 struct rpc_pipe_client *pipe_hnd,
196 const char *key_name,
197 unsigned char *data,
198 size_t length)
200 struct policy_handle hnd;
201 enum ndr_err_code ndr_err;
202 struct ntprinting_printer r;
203 struct spoolss_SetPrinterInfo2 info2;
204 struct spoolss_DeviceMode dm;
205 struct spoolss_SetPrinterInfoCtr info_ctr;
206 struct spoolss_DevmodeContainer devmode_ctr;
207 struct sec_desc_buf secdesc_ctr;
208 DATA_BLOB blob;
209 NTSTATUS status;
210 WERROR result;
211 int j;
213 if (strequal(key_name, "printers")) {
214 return NT_STATUS_OK;
217 blob = data_blob_const(data, length);
219 ZERO_STRUCT(r);
221 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
222 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
223 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
224 DEBUG(2, ("printer pull failed: %s\n",
225 ndr_errstr(ndr_err)));
226 return NT_STATUS_NO_MEMORY;
229 DEBUG(2, ("Migrating Printer: %s\n", key_name));
231 ZERO_STRUCT(devmode_ctr);
233 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
234 mem_ctx,
235 key_name,
236 NULL,
237 devmode_ctr,
238 SEC_FLAG_MAXIMUM_ALLOWED,
239 &hnd,
240 &result);
241 if (!NT_STATUS_IS_OK(status)) {
242 if (!W_ERROR_IS_OK(result)) {
243 status = werror_to_ntstatus(result);
245 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
246 key_name, nt_errstr(status)));
247 return status;
250 /* Create printer info level 2 */
251 ZERO_STRUCT(info2);
252 ZERO_STRUCT(secdesc_ctr);
254 info2.attributes = r.info.attributes;
255 info2.averageppm = r.info.averageppm;
256 info2.cjobs = r.info.cjobs;
257 info2.comment = r.info.comment;
258 info2.datatype = r.info.datatype;
259 info2.defaultpriority = r.info.default_priority;
260 info2.drivername = r.info.drivername;
261 info2.location = r.info.location;
262 info2.parameters = r.info.parameters;
263 info2.portname = r.info.portname;
264 info2.printername = r.info.printername;
265 info2.printprocessor = r.info.printprocessor;
266 info2.priority = r.info.priority;
267 info2.sepfile = r.info.sepfile;
268 info2.sharename = r.info.sharename;
269 info2.starttime = r.info.starttime;
270 info2.status = r.info.status;
271 info2.untiltime = r.info.untiltime;
273 /* Create Device Mode */
274 if (r.devmode != NULL) {
275 ZERO_STRUCT(dm);
277 dm.bitsperpel = r.devmode->bitsperpel;
278 dm.collate = r.devmode->collate;
279 dm.color = r.devmode->color;
280 dm.copies = r.devmode->copies;
281 dm.defaultsource = r.devmode->defaultsource;
282 dm.devicename = r.devmode->devicename;
283 dm.displayflags = r.devmode->displayflags;
284 dm.displayfrequency = r.devmode->displayfrequency;
285 dm.dithertype = r.devmode->dithertype;
286 dm.driverversion = r.devmode->driverversion;
287 dm.duplex = r.devmode->duplex;
288 dm.fields = r.devmode->fields;
289 dm.formname = r.devmode->formname;
290 dm.icmintent = r.devmode->icmintent;
291 dm.icmmethod = r.devmode->icmmethod;
292 dm.logpixels = r.devmode->logpixels;
293 dm.mediatype = r.devmode->mediatype;
294 dm.orientation = r.devmode->orientation;
295 dm.panningheight = r.devmode->pelsheight;
296 dm.panningwidth = r.devmode->panningwidth;
297 dm.paperlength = r.devmode->paperlength;
298 dm.papersize = r.devmode->papersize;
299 dm.paperwidth = r.devmode->paperwidth;
300 dm.pelsheight = r.devmode->pelsheight;
301 dm.pelswidth = r.devmode->pelswidth;
302 dm.printquality = r.devmode->printquality;
303 dm.scale = r.devmode->scale;
304 dm.specversion = r.devmode->specversion;
305 dm.ttoption = r.devmode->ttoption;
306 dm.yresolution = r.devmode->yresolution;
308 if (r.devmode->nt_dev_private != NULL) {
309 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
310 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
311 dm.__driverextra_length = r.devmode->nt_dev_private->length;
314 devmode_ctr.devmode = &dm;
316 info2.devmode_ptr = 1;
319 info_ctr.info.info2 = &info2;
320 info_ctr.level = 2;
322 status = rpccli_spoolss_SetPrinter(pipe_hnd,
323 mem_ctx,
324 &hnd,
325 &info_ctr,
326 &devmode_ctr,
327 &secdesc_ctr,
328 0, /* command */
329 &result);
330 if (!NT_STATUS_IS_OK(status)) {
331 DEBUG(2, ("SetPrinter(%s) level 2 refused -- %s.\n",
332 key_name, nt_errstr(status)));
333 goto done;
336 /* migrate printerdata */
337 for (j = 0; j < r.count; j++) {
338 char *valuename;
339 char *keyname;
341 if (r.printer_data[j].type == REG_NONE) {
342 continue;
345 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
346 valuename = strchr(keyname, '\\');
347 if (valuename == NULL) {
348 continue;
349 } else {
350 valuename[0] = '\0';
351 valuename++;
354 status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd,
355 mem_ctx,
356 &hnd,
357 keyname,
358 valuename,
359 r.printer_data[j].type,
360 r.printer_data[j].data.data,
361 r.printer_data[j].data.length,
362 &result);
363 if (!NT_STATUS_IS_OK(status)) {
364 DEBUG(2, ("SetPrinterDataEx: printer [%s], keyname [%s], "
365 "valuename [%s] refused -- %s.\n",
366 key_name, keyname, valuename,
367 nt_errstr(status)));
368 break;
372 done:
373 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
375 return status;
378 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
379 struct rpc_pipe_client *pipe_hnd,
380 const char *key_name,
381 unsigned char *data,
382 size_t length)
384 struct policy_handle hnd;
385 enum ndr_err_code ndr_err;
386 struct sec_desc_buf secdesc_ctr;
387 struct spoolss_SetPrinterInfo3 info3;
388 struct spoolss_SetPrinterInfoCtr info_ctr;
389 struct spoolss_DevmodeContainer devmode_ctr;
390 DATA_BLOB blob;
391 NTSTATUS status;
392 WERROR result;
394 if (strequal(key_name, "printers")) {
395 return NT_STATUS_OK;
398 blob = data_blob_const(data, length);
400 ZERO_STRUCT(secdesc_ctr);
402 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
403 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
404 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
405 DEBUG(2, ("security descriptor pull failed: %s\n",
406 ndr_errstr(ndr_err)));
407 return NT_STATUS_NO_MEMORY;
410 DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name));
412 ZERO_STRUCT(devmode_ctr);
414 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
415 mem_ctx,
416 key_name,
417 NULL,
418 devmode_ctr,
419 SEC_FLAG_MAXIMUM_ALLOWED,
420 &hnd,
421 &result);
422 if (!NT_STATUS_IS_OK(status)) {
423 if (!W_ERROR_IS_OK(result)) {
424 status = werror_to_ntstatus(result);
426 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
427 key_name, nt_errstr(status)));
428 return status;
431 ZERO_STRUCT(devmode_ctr);
433 info3.sec_desc_ptr = 1;
435 info_ctr.info.info3 = &info3;
436 info_ctr.level = 3;
438 status = rpccli_spoolss_SetPrinter(pipe_hnd,
439 mem_ctx,
440 &hnd,
441 &info_ctr,
442 &devmode_ctr,
443 &secdesc_ctr,
444 0, /* command */
445 &result);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
448 key_name, nt_errstr(status)));
451 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
453 return status;
456 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
457 const char *path,
458 const char *suffix)
460 int rc = -1;
461 char *dst_path;
463 dst_path = talloc_asprintf(mem_ctx, "%s%s", path, suffix);
464 if (dst_path == NULL) {
465 DEBUG(3, ("error out of memory\n"));
466 return rc;
469 rc = (rename(path, dst_path) != 0);
471 if (rc == 0) {
472 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
473 } else if (errno == ENOENT) {
474 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
475 rc = 0;
476 } else {
477 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
478 strerror(errno)));
481 TALLOC_FREE(dst_path);
482 return rc;
485 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
486 const char *tdb_path,
487 struct rpc_pipe_client *pipe_hnd)
489 const char *backup_suffix = ".bak";
490 TDB_DATA kbuf, newkey, dbuf;
491 TDB_CONTEXT *tdb;
492 NTSTATUS status;
493 int rc;
495 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
496 if (tdb == NULL) {
497 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
498 return NT_STATUS_NO_SUCH_FILE;
501 for (kbuf = tdb_firstkey(tdb);
502 kbuf.dptr;
503 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
505 dbuf = tdb_fetch(tdb, kbuf);
506 if (!dbuf.dptr) {
507 continue;
510 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
511 status = migrate_form(mem_ctx,
512 pipe_hnd,
513 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
514 dbuf.dptr,
515 dbuf.dsize);
516 SAFE_FREE(dbuf.dptr);
517 if (!NT_STATUS_IS_OK(status)) {
518 tdb_close(tdb);
519 return status;
521 continue;
524 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
525 status = migrate_driver(mem_ctx,
526 pipe_hnd,
527 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
528 dbuf.dptr,
529 dbuf.dsize);
530 SAFE_FREE(dbuf.dptr);
531 if (!NT_STATUS_IS_OK(status)) {
532 tdb_close(tdb);
533 return status;
535 continue;
538 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
539 migrate_printer(mem_ctx,
540 pipe_hnd,
541 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
542 dbuf.dptr,
543 dbuf.dsize);
544 SAFE_FREE(dbuf.dptr);
545 if (!NT_STATUS_IS_OK(status)) {
546 tdb_close(tdb);
547 return status;
549 continue;
552 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
553 status = migrate_secdesc(mem_ctx,
554 pipe_hnd,
555 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
556 dbuf.dptr,
557 dbuf.dsize);
558 SAFE_FREE(dbuf.dptr);
559 if (!NT_STATUS_IS_OK(status)) {
560 tdb_close(tdb);
561 return status;
563 continue;
567 tdb_close(tdb);
569 rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix);
570 if (rc != 0) {
571 DEBUG(0, ("Error moving tdb to '%s%s'\n",
572 tdb_path, backup_suffix));
575 return NT_STATUS_OK;
578 bool nt_printing_tdb_migrate(void)
580 const char *drivers_path = state_path("ntdrivers.tdb");
581 const char *printers_path = state_path("ntprinters.tdb");
582 const char *forms_path = state_path("ntforms.tdb");
583 bool drivers_exists = file_exist(drivers_path);
584 bool printers_exists = file_exist(printers_path);
585 bool forms_exists = file_exist(forms_path);
586 struct auth_serversupplied_info *server_info;
587 struct rpc_pipe_client *spoolss_pipe = NULL;
588 TALLOC_CTX *tmp_ctx = talloc_stackframe();
589 NTSTATUS status;
591 if (!drivers_exists && !printers_exists && !forms_exists) {
592 return true;
595 status = make_server_info_system(tmp_ctx, &server_info);
596 if (!NT_STATUS_IS_OK(status)) {
597 DEBUG(0, ("Couldn't create server_info: %s\n",
598 nt_errstr(status)));
599 talloc_free(tmp_ctx);
600 return false;
603 status = rpc_pipe_open_internal(tmp_ctx,
604 &ndr_table_spoolss.syntax_id,
605 server_info,
606 &spoolss_pipe);
607 if (!NT_STATUS_IS_OK(status)) {
608 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
609 nt_errstr(status)));
610 talloc_free(tmp_ctx);
611 return false;
614 if (drivers_exists) {
615 status = migrate_internal(tmp_ctx, drivers_path, spoolss_pipe);
616 if (!NT_STATUS_IS_OK(status)) {
617 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
618 nt_errstr(status)));
619 talloc_free(tmp_ctx);
620 return false;
624 if (printers_exists) {
625 status = migrate_internal(tmp_ctx, printers_path, spoolss_pipe);
626 if (!NT_STATUS_IS_OK(status)) {
627 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
628 nt_errstr(status)));
629 talloc_free(tmp_ctx);
630 return false;
634 if (forms_exists) {
635 status = migrate_internal(tmp_ctx, forms_path, spoolss_pipe);
636 if (!NT_STATUS_IS_OK(status)) {
637 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
638 nt_errstr(status)));
639 talloc_free(tmp_ctx);
640 return false;
644 talloc_free(tmp_ctx);
645 return true;