s4-drepl: User working schema for commiting objects when replicating Schema NC
[Samba.git] / source3 / printing / nt_printing_migrate.c
blobc6466767e58335560d1df08d17cd9d9221433aae
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"
28 #include "rpc_server/rpc_ncacn_np.h"
30 #define FORMS_PREFIX "FORMS/"
31 #define DRIVERS_PREFIX "DRIVERS/"
32 #define PRINTERS_PREFIX "PRINTERS/"
33 #define SECDESC_PREFIX "SECDESC/"
35 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
36 struct rpc_pipe_client *pipe_hnd,
37 const char *key_name,
38 unsigned char *data,
39 size_t length)
41 struct spoolss_DevmodeContainer devmode_ctr;
42 struct policy_handle hnd;
43 enum ndr_err_code ndr_err;
44 struct ntprinting_form r;
45 union spoolss_AddFormInfo f;
46 struct spoolss_AddFormInfo1 f1;
47 const char *srv_name_slash;
48 DATA_BLOB blob;
49 NTSTATUS status;
50 WERROR result;
53 blob = data_blob_const(data, length);
55 ZERO_STRUCT(r);
57 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
58 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
59 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
60 DEBUG(2, ("Form pull failed: %s\n",
61 ndr_errstr(ndr_err)));
62 return NT_STATUS_NO_MEMORY;
65 /* Don't migrate builtin forms */
66 if (r.flag == SPOOLSS_FORM_BUILTIN) {
67 return NT_STATUS_OK;
70 DEBUG(2, ("Migrating Form: %s\n", key_name));
72 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
73 if (srv_name_slash == NULL) {
74 return NT_STATUS_NO_MEMORY;
77 ZERO_STRUCT(devmode_ctr);
79 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
80 mem_ctx,
81 srv_name_slash,
82 NULL,
83 devmode_ctr,
84 SEC_FLAG_MAXIMUM_ALLOWED,
85 &hnd,
86 &result);
87 if (!NT_STATUS_IS_OK(status)) {
88 if (!W_ERROR_IS_OK(result)) {
89 status = werror_to_ntstatus(result);
91 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
92 srv_name_slash, nt_errstr(status)));
93 return status;
96 f1.form_name = key_name;
97 f1.flags = r.flag;
99 f1.size.width = r.width;
100 f1.size.height = r.length;
102 f1.area.top = r.top;
103 f1.area.right = r.right;
104 f1.area.bottom = r.bottom;
105 f1.area.left = r.left;
107 f.info1 = &f1;
109 status = rpccli_spoolss_AddForm(pipe_hnd,
110 mem_ctx,
111 &hnd,
114 &result);
115 if (!NT_STATUS_IS_OK(status)) {
116 DEBUG(2, ("AddForm(%s) refused -- %s.\n",
117 f.info1->form_name, nt_errstr(status)));
120 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
122 return status;
125 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
126 struct rpc_pipe_client *pipe_hnd,
127 const char *key_name,
128 unsigned char *data,
129 size_t length)
131 const char *srv_name_slash;
132 enum ndr_err_code ndr_err;
133 struct ntprinting_driver r;
134 struct spoolss_AddDriverInfoCtr d;
135 struct spoolss_AddDriverInfo3 d3;
136 struct spoolss_StringArray a;
137 DATA_BLOB blob;
138 NTSTATUS status;
139 WERROR result;
141 blob = data_blob_const(data, length);
143 ZERO_STRUCT(r);
145 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
146 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
147 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
148 DEBUG(2, ("Driver pull failed: %s\n",
149 ndr_errstr(ndr_err)));
150 return NT_STATUS_NO_MEMORY;
153 DEBUG(2, ("Migrating Printer Driver: %s\n", key_name));
155 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
156 if (srv_name_slash == NULL) {
157 return NT_STATUS_NO_MEMORY;
160 ZERO_STRUCT(d3);
161 ZERO_STRUCT(a);
163 a.string = r.dependent_files;
165 d3.architecture = r.environment;
166 d3.config_file = r.configfile;
167 d3.data_file = r.datafile;
168 d3.default_datatype = r.defaultdatatype;
169 d3.dependent_files = &a;
170 d3.driver_path = r.driverpath;
171 d3.help_file = r.helpfile;
172 d3.monitor_name = r.monitorname;
173 d3.driver_name = r.name;
174 d3.version = r.version;
176 d.level = 3;
177 d.info.info3 = &d3;
179 status = rpccli_spoolss_AddPrinterDriver(pipe_hnd,
180 mem_ctx,
181 srv_name_slash,
183 &result);
184 if (!NT_STATUS_IS_OK(status)) {
185 if (!W_ERROR_IS_OK(result)) {
186 status = werror_to_ntstatus(result);
188 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
189 d3.driver_name, nt_errstr(status)));
192 return status;
195 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
196 struct rpc_pipe_client *pipe_hnd,
197 const char *key_name,
198 unsigned char *data,
199 size_t length)
201 struct policy_handle hnd;
202 enum ndr_err_code ndr_err;
203 struct ntprinting_printer r;
204 struct spoolss_SetPrinterInfo2 info2;
205 struct spoolss_DeviceMode dm;
206 struct spoolss_SetPrinterInfoCtr info_ctr;
207 struct spoolss_DevmodeContainer devmode_ctr;
208 struct sec_desc_buf secdesc_ctr;
209 DATA_BLOB blob;
210 NTSTATUS status;
211 WERROR result;
212 int j;
214 if (strequal(key_name, "printers")) {
215 return NT_STATUS_OK;
218 blob = data_blob_const(data, length);
220 ZERO_STRUCT(r);
222 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
223 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
224 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
225 DEBUG(2, ("printer pull failed: %s\n",
226 ndr_errstr(ndr_err)));
227 return NT_STATUS_NO_MEMORY;
230 DEBUG(2, ("Migrating Printer: %s\n", key_name));
232 ZERO_STRUCT(devmode_ctr);
234 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
235 mem_ctx,
236 key_name,
237 NULL,
238 devmode_ctr,
239 SEC_FLAG_MAXIMUM_ALLOWED,
240 &hnd,
241 &result);
242 if (!NT_STATUS_IS_OK(status)) {
243 if (!W_ERROR_IS_OK(result)) {
244 status = werror_to_ntstatus(result);
246 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
247 key_name, win_errstr(result)));
248 return status;
251 /* Create printer info level 2 */
252 ZERO_STRUCT(info2);
253 ZERO_STRUCT(secdesc_ctr);
255 info2.attributes = r.info.attributes;
256 info2.averageppm = r.info.averageppm;
257 info2.cjobs = r.info.cjobs;
258 info2.comment = r.info.comment;
259 info2.datatype = r.info.datatype;
260 info2.defaultpriority = r.info.default_priority;
261 info2.drivername = r.info.drivername;
262 info2.location = r.info.location;
263 info2.parameters = r.info.parameters;
264 info2.portname = r.info.portname;
265 info2.printername = r.info.printername;
266 info2.printprocessor = r.info.printprocessor;
267 info2.priority = r.info.priority;
268 info2.sepfile = r.info.sepfile;
269 info2.sharename = r.info.sharename;
270 info2.starttime = r.info.starttime;
271 info2.status = r.info.status;
272 info2.untiltime = r.info.untiltime;
274 /* Create Device Mode */
275 if (r.devmode != NULL) {
276 ZERO_STRUCT(dm);
278 dm.bitsperpel = r.devmode->bitsperpel;
279 dm.collate = r.devmode->collate;
280 dm.color = r.devmode->color;
281 dm.copies = r.devmode->copies;
282 dm.defaultsource = r.devmode->defaultsource;
283 dm.devicename = r.devmode->devicename;
284 dm.displayflags = r.devmode->displayflags;
285 dm.displayfrequency = r.devmode->displayfrequency;
286 dm.dithertype = r.devmode->dithertype;
287 dm.driverversion = r.devmode->driverversion;
288 dm.duplex = r.devmode->duplex;
289 dm.fields = r.devmode->fields;
290 dm.formname = r.devmode->formname;
291 dm.icmintent = r.devmode->icmintent;
292 dm.icmmethod = r.devmode->icmmethod;
293 dm.logpixels = r.devmode->logpixels;
294 dm.mediatype = r.devmode->mediatype;
295 dm.orientation = r.devmode->orientation;
296 dm.panningheight = r.devmode->pelsheight;
297 dm.panningwidth = r.devmode->panningwidth;
298 dm.paperlength = r.devmode->paperlength;
299 dm.papersize = r.devmode->papersize;
300 dm.paperwidth = r.devmode->paperwidth;
301 dm.pelsheight = r.devmode->pelsheight;
302 dm.pelswidth = r.devmode->pelswidth;
303 dm.printquality = r.devmode->printquality;
304 dm.scale = r.devmode->scale;
305 dm.specversion = r.devmode->specversion;
306 dm.ttoption = r.devmode->ttoption;
307 dm.yresolution = r.devmode->yresolution;
309 if (r.devmode->nt_dev_private != NULL) {
310 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
311 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
312 dm.__driverextra_length = r.devmode->nt_dev_private->length;
315 devmode_ctr.devmode = &dm;
317 info2.devmode_ptr = 1;
320 info_ctr.info.info2 = &info2;
321 info_ctr.level = 2;
323 status = rpccli_spoolss_SetPrinter(pipe_hnd,
324 mem_ctx,
325 &hnd,
326 &info_ctr,
327 &devmode_ctr,
328 &secdesc_ctr,
329 0, /* command */
330 &result);
331 if (!NT_STATUS_IS_OK(status)) {
332 DEBUG(2, ("SetPrinter(%s) level 2 refused -- %s.\n",
333 key_name, nt_errstr(status)));
334 goto done;
337 /* migrate printerdata */
338 for (j = 0; j < r.count; j++) {
339 char *valuename;
340 char *keyname;
342 if (r.printer_data[j].type == REG_NONE) {
343 continue;
346 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
347 valuename = strchr(keyname, '\\');
348 if (valuename == NULL) {
349 continue;
350 } else {
351 valuename[0] = '\0';
352 valuename++;
355 status = rpccli_spoolss_SetPrinterDataEx(pipe_hnd,
356 mem_ctx,
357 &hnd,
358 keyname,
359 valuename,
360 r.printer_data[j].type,
361 r.printer_data[j].data.data,
362 r.printer_data[j].data.length,
363 &result);
364 if (!NT_STATUS_IS_OK(status)) {
365 DEBUG(2, ("SetPrinterDataEx: printer [%s], keyname [%s], "
366 "valuename [%s] refused -- %s.\n",
367 key_name, keyname, valuename,
368 nt_errstr(status)));
369 break;
373 done:
374 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
376 return status;
379 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
380 struct rpc_pipe_client *pipe_hnd,
381 const char *key_name,
382 unsigned char *data,
383 size_t length)
385 struct policy_handle hnd;
386 enum ndr_err_code ndr_err;
387 struct sec_desc_buf secdesc_ctr;
388 struct spoolss_SetPrinterInfo3 info3;
389 struct spoolss_SetPrinterInfoCtr info_ctr;
390 struct spoolss_DevmodeContainer devmode_ctr;
391 DATA_BLOB blob;
392 NTSTATUS status;
393 WERROR result;
395 if (strequal(key_name, "printers")) {
396 return NT_STATUS_OK;
399 blob = data_blob_const(data, length);
401 ZERO_STRUCT(secdesc_ctr);
403 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
404 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
405 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
406 DEBUG(2, ("security descriptor pull failed: %s\n",
407 ndr_errstr(ndr_err)));
408 return NT_STATUS_NO_MEMORY;
411 DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name));
413 ZERO_STRUCT(devmode_ctr);
415 status = rpccli_spoolss_OpenPrinter(pipe_hnd,
416 mem_ctx,
417 key_name,
418 NULL,
419 devmode_ctr,
420 SEC_FLAG_MAXIMUM_ALLOWED,
421 &hnd,
422 &result);
423 if (!NT_STATUS_IS_OK(status)) {
424 if (W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME, result)) {
425 DEBUG(3, ("Ignoring missing printer %s\n", key_name));
426 return NT_STATUS_OK;
428 if (!W_ERROR_IS_OK(result)) {
429 status = werror_to_ntstatus(result);
431 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
432 key_name, nt_errstr(status)));
433 return status;
436 ZERO_STRUCT(devmode_ctr);
438 info3.sec_desc_ptr = 1;
440 info_ctr.info.info3 = &info3;
441 info_ctr.level = 3;
443 status = rpccli_spoolss_SetPrinter(pipe_hnd,
444 mem_ctx,
445 &hnd,
446 &info_ctr,
447 &devmode_ctr,
448 &secdesc_ctr,
449 0, /* command */
450 &result);
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
453 key_name, nt_errstr(status)));
456 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
458 return status;
461 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
462 const char *path,
463 const char *suffix)
465 int rc = -1;
466 char *dst_path;
468 dst_path = talloc_asprintf(mem_ctx, "%s%s", path, suffix);
469 if (dst_path == NULL) {
470 DEBUG(3, ("error out of memory\n"));
471 return rc;
474 rc = (rename(path, dst_path) != 0);
476 if (rc == 0) {
477 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
478 } else if (errno == ENOENT) {
479 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
480 rc = 0;
481 } else {
482 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
483 strerror(errno)));
486 TALLOC_FREE(dst_path);
487 return rc;
490 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
491 const char *tdb_path,
492 struct rpc_pipe_client *pipe_hnd)
494 const char *backup_suffix = ".bak";
495 TDB_DATA kbuf, newkey, dbuf;
496 TDB_CONTEXT *tdb;
497 NTSTATUS status;
498 int rc;
500 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
501 if (tdb == NULL && errno == ENOENT) {
502 /* if we have no printers database then migration is
503 considered successful */
504 DEBUG(4, ("No printers database to migrate in %s\n", tdb_path));
505 return NT_STATUS_OK;
507 if (tdb == NULL) {
508 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
509 return NT_STATUS_NO_SUCH_FILE;
512 for (kbuf = tdb_firstkey(tdb);
513 kbuf.dptr;
514 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
516 dbuf = tdb_fetch(tdb, kbuf);
517 if (!dbuf.dptr) {
518 continue;
521 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
522 status = migrate_form(mem_ctx,
523 pipe_hnd,
524 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
525 dbuf.dptr,
526 dbuf.dsize);
527 SAFE_FREE(dbuf.dptr);
528 if (!NT_STATUS_IS_OK(status)) {
529 tdb_close(tdb);
530 return status;
532 continue;
535 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
536 status = migrate_driver(mem_ctx,
537 pipe_hnd,
538 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
539 dbuf.dptr,
540 dbuf.dsize);
541 SAFE_FREE(dbuf.dptr);
542 if (!NT_STATUS_IS_OK(status)) {
543 tdb_close(tdb);
544 return status;
546 continue;
549 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
550 status = migrate_printer(mem_ctx,
551 pipe_hnd,
552 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
553 dbuf.dptr,
554 dbuf.dsize);
555 SAFE_FREE(dbuf.dptr);
556 if (!NT_STATUS_IS_OK(status)) {
557 tdb_close(tdb);
558 return status;
560 continue;
563 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
564 status = migrate_secdesc(mem_ctx,
565 pipe_hnd,
566 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
567 dbuf.dptr,
568 dbuf.dsize);
569 SAFE_FREE(dbuf.dptr);
570 if (!NT_STATUS_IS_OK(status)) {
571 tdb_close(tdb);
572 return status;
574 continue;
578 tdb_close(tdb);
580 rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix);
581 if (rc != 0) {
582 DEBUG(0, ("Error moving tdb to '%s%s'\n",
583 tdb_path, backup_suffix));
586 return NT_STATUS_OK;
589 bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
591 const char *drivers_path = state_path("ntdrivers.tdb");
592 const char *printers_path = state_path("ntprinters.tdb");
593 const char *forms_path = state_path("ntforms.tdb");
594 bool drivers_exists = file_exist(drivers_path);
595 bool printers_exists = file_exist(printers_path);
596 bool forms_exists = file_exist(forms_path);
597 struct auth_serversupplied_info *server_info;
598 struct rpc_pipe_client *spoolss_pipe = NULL;
599 TALLOC_CTX *tmp_ctx = talloc_stackframe();
600 NTSTATUS status;
602 if (!drivers_exists && !printers_exists && !forms_exists) {
603 return true;
606 status = make_server_info_system(tmp_ctx, &server_info);
607 if (!NT_STATUS_IS_OK(status)) {
608 DEBUG(0, ("Couldn't create server_info: %s\n",
609 nt_errstr(status)));
610 talloc_free(tmp_ctx);
611 return false;
614 status = rpc_pipe_open_internal(tmp_ctx,
615 &ndr_table_spoolss.syntax_id,
616 server_info,
617 NULL,
618 msg_ctx,
619 &spoolss_pipe);
620 if (!NT_STATUS_IS_OK(status)) {
621 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
622 nt_errstr(status)));
623 talloc_free(tmp_ctx);
624 return false;
627 if (drivers_exists) {
628 status = migrate_internal(tmp_ctx, drivers_path, spoolss_pipe);
629 if (!NT_STATUS_IS_OK(status)) {
630 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
631 nt_errstr(status)));
632 talloc_free(tmp_ctx);
633 return false;
637 if (printers_exists) {
638 status = migrate_internal(tmp_ctx, printers_path, spoolss_pipe);
639 if (!NT_STATUS_IS_OK(status)) {
640 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
641 nt_errstr(status)));
642 talloc_free(tmp_ctx);
643 return false;
647 if (forms_exists) {
648 status = migrate_internal(tmp_ctx, forms_path, spoolss_pipe);
649 if (!NT_STATUS_IS_OK(status)) {
650 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
651 nt_errstr(status)));
652 talloc_free(tmp_ctx);
653 return false;
657 talloc_free(tmp_ctx);
658 return true;