s3-dcerpc: Pull packet in the caller, before validation
[Samba.git] / source3 / printing / nt_printing_migrate.c
blob7b37926486d1886742c2f85fa9c954127f06173e
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_EQUAL(WERR_INVALID_PRINTER_NAME, result)) {
424 DEBUG(3, ("Ignoring missing printer %s\n", key_name));
425 return NT_STATUS_OK;
427 if (!W_ERROR_IS_OK(result)) {
428 status = werror_to_ntstatus(result);
430 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
431 key_name, nt_errstr(status)));
432 return status;
435 ZERO_STRUCT(devmode_ctr);
437 info3.sec_desc_ptr = 1;
439 info_ctr.info.info3 = &info3;
440 info_ctr.level = 3;
442 status = rpccli_spoolss_SetPrinter(pipe_hnd,
443 mem_ctx,
444 &hnd,
445 &info_ctr,
446 &devmode_ctr,
447 &secdesc_ctr,
448 0, /* command */
449 &result);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
452 key_name, nt_errstr(status)));
455 rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
457 return status;
460 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
461 const char *path,
462 const char *suffix)
464 int rc = -1;
465 char *dst_path;
467 dst_path = talloc_asprintf(mem_ctx, "%s%s", path, suffix);
468 if (dst_path == NULL) {
469 DEBUG(3, ("error out of memory\n"));
470 return rc;
473 rc = (rename(path, dst_path) != 0);
475 if (rc == 0) {
476 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
477 } else if (errno == ENOENT) {
478 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
479 rc = 0;
480 } else {
481 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
482 strerror(errno)));
485 TALLOC_FREE(dst_path);
486 return rc;
489 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
490 const char *tdb_path,
491 struct rpc_pipe_client *pipe_hnd)
493 const char *backup_suffix = ".bak";
494 TDB_DATA kbuf, newkey, dbuf;
495 TDB_CONTEXT *tdb;
496 NTSTATUS status;
497 int rc;
499 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
500 if (tdb == NULL && errno == ENOENT) {
501 /* if we have no printers database then migration is
502 considered successful */
503 DEBUG(4, ("No printers database to migrate in %s\n", tdb_path));
504 return NT_STATUS_OK;
506 if (tdb == NULL) {
507 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
508 return NT_STATUS_NO_SUCH_FILE;
511 for (kbuf = tdb_firstkey(tdb);
512 kbuf.dptr;
513 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
515 dbuf = tdb_fetch(tdb, kbuf);
516 if (!dbuf.dptr) {
517 continue;
520 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
521 status = migrate_form(mem_ctx,
522 pipe_hnd,
523 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
524 dbuf.dptr,
525 dbuf.dsize);
526 SAFE_FREE(dbuf.dptr);
527 if (!NT_STATUS_IS_OK(status)) {
528 tdb_close(tdb);
529 return status;
531 continue;
534 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
535 status = migrate_driver(mem_ctx,
536 pipe_hnd,
537 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
538 dbuf.dptr,
539 dbuf.dsize);
540 SAFE_FREE(dbuf.dptr);
541 if (!NT_STATUS_IS_OK(status)) {
542 tdb_close(tdb);
543 return status;
545 continue;
548 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
549 status = migrate_printer(mem_ctx,
550 pipe_hnd,
551 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
552 dbuf.dptr,
553 dbuf.dsize);
554 SAFE_FREE(dbuf.dptr);
555 if (!NT_STATUS_IS_OK(status)) {
556 tdb_close(tdb);
557 return status;
559 continue;
562 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
563 status = migrate_secdesc(mem_ctx,
564 pipe_hnd,
565 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
566 dbuf.dptr,
567 dbuf.dsize);
568 SAFE_FREE(dbuf.dptr);
569 if (!NT_STATUS_IS_OK(status)) {
570 tdb_close(tdb);
571 return status;
573 continue;
577 tdb_close(tdb);
579 rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix);
580 if (rc != 0) {
581 DEBUG(0, ("Error moving tdb to '%s%s'\n",
582 tdb_path, backup_suffix));
585 return NT_STATUS_OK;
588 bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
590 const char *drivers_path = state_path("ntdrivers.tdb");
591 const char *printers_path = state_path("ntprinters.tdb");
592 const char *forms_path = state_path("ntforms.tdb");
593 bool drivers_exists = file_exist(drivers_path);
594 bool printers_exists = file_exist(printers_path);
595 bool forms_exists = file_exist(forms_path);
596 struct auth_serversupplied_info *server_info;
597 struct rpc_pipe_client *spoolss_pipe = NULL;
598 TALLOC_CTX *tmp_ctx = talloc_stackframe();
599 NTSTATUS status;
601 if (!drivers_exists && !printers_exists && !forms_exists) {
602 return true;
605 status = make_server_info_system(tmp_ctx, &server_info);
606 if (!NT_STATUS_IS_OK(status)) {
607 DEBUG(0, ("Couldn't create server_info: %s\n",
608 nt_errstr(status)));
609 talloc_free(tmp_ctx);
610 return false;
613 status = rpc_pipe_open_internal(tmp_ctx,
614 &ndr_table_spoolss.syntax_id,
615 server_info,
616 msg_ctx,
617 &spoolss_pipe);
618 if (!NT_STATUS_IS_OK(status)) {
619 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
620 nt_errstr(status)));
621 talloc_free(tmp_ctx);
622 return false;
625 if (drivers_exists) {
626 status = migrate_internal(tmp_ctx, drivers_path, spoolss_pipe);
627 if (!NT_STATUS_IS_OK(status)) {
628 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
629 nt_errstr(status)));
630 talloc_free(tmp_ctx);
631 return false;
635 if (printers_exists) {
636 status = migrate_internal(tmp_ctx, printers_path, spoolss_pipe);
637 if (!NT_STATUS_IS_OK(status)) {
638 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
639 nt_errstr(status)));
640 talloc_free(tmp_ctx);
641 return false;
645 if (forms_exists) {
646 status = migrate_internal(tmp_ctx, forms_path, spoolss_pipe);
647 if (!NT_STATUS_IS_OK(status)) {
648 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
649 nt_errstr(status)));
650 talloc_free(tmp_ctx);
651 return false;
655 talloc_free(tmp_ctx);
656 return true;