Split the ACE flag mapping between nfs4 and Windows into two separate functions rathe...
[Samba.git] / source3 / printing / nt_printing_migrate.c
blobf56fa9a2f08f67283fc064b9de4c8a2097c87669
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 "system/filesys.h"
23 #include "printing/nt_printing_migrate.h"
25 #include "rpc_client/rpc_client.h"
26 #include "librpc/gen_ndr/ndr_ntprinting.h"
27 #include "librpc/gen_ndr/ndr_spoolss_c.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "rpc_server/rpc_ncacn_np.h"
30 #include "auth.h"
31 #include "util_tdb.h"
33 #define FORMS_PREFIX "FORMS/"
34 #define DRIVERS_PREFIX "DRIVERS/"
35 #define PRINTERS_PREFIX "PRINTERS/"
36 #define SECDESC_PREFIX "SECDESC/"
38 static NTSTATUS migrate_form(TALLOC_CTX *mem_ctx,
39 struct rpc_pipe_client *pipe_hnd,
40 const char *key_name,
41 unsigned char *data,
42 size_t length)
44 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
45 struct spoolss_DevmodeContainer devmode_ctr;
46 struct policy_handle hnd;
47 enum ndr_err_code ndr_err;
48 struct ntprinting_form r;
49 union spoolss_AddFormInfo f;
50 struct spoolss_AddFormInfo1 f1;
51 const char *srv_name_slash;
52 DATA_BLOB blob;
53 NTSTATUS status;
54 WERROR result;
57 blob = data_blob_const(data, length);
59 ZERO_STRUCT(r);
61 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
62 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
63 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
64 DEBUG(2, ("Form pull failed: %s\n",
65 ndr_errstr(ndr_err)));
66 return NT_STATUS_NO_MEMORY;
69 /* Don't migrate builtin forms */
70 if (r.flag == SPOOLSS_FORM_BUILTIN) {
71 return NT_STATUS_OK;
74 DEBUG(2, ("Migrating Form: %s\n", key_name));
76 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
77 if (srv_name_slash == NULL) {
78 return NT_STATUS_NO_MEMORY;
81 ZERO_STRUCT(devmode_ctr);
83 status = dcerpc_spoolss_OpenPrinter(b,
84 mem_ctx,
85 srv_name_slash,
86 NULL,
87 devmode_ctr,
88 SEC_FLAG_MAXIMUM_ALLOWED,
89 &hnd,
90 &result);
91 if (!NT_STATUS_IS_OK(status)) {
92 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
93 srv_name_slash, nt_errstr(status)));
94 return status;
96 if (!W_ERROR_IS_OK(result)) {
97 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
98 srv_name_slash, win_errstr(result)));
99 status = werror_to_ntstatus(result);
100 return status;
103 f1.form_name = key_name;
104 f1.flags = r.flag;
106 f1.size.width = r.width;
107 f1.size.height = r.length;
109 f1.area.top = r.top;
110 f1.area.right = r.right;
111 f1.area.bottom = r.bottom;
112 f1.area.left = r.left;
114 f.info1 = &f1;
116 status = dcerpc_spoolss_AddForm(b,
117 mem_ctx,
118 &hnd,
121 &result);
122 if (!NT_STATUS_IS_OK(status)) {
123 DEBUG(2, ("dcerpc_spoolss_AddForm(%s) refused -- %s.\n",
124 f.info1->form_name, nt_errstr(status)));
125 } else if (!W_ERROR_IS_OK(result)) {
126 DEBUG(2, ("AddForm(%s) refused -- %s.\n",
127 f.info1->form_name, win_errstr(result)));
128 status = werror_to_ntstatus(result);
131 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
133 return status;
136 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
137 struct rpc_pipe_client *pipe_hnd,
138 const char *key_name,
139 unsigned char *data,
140 size_t length)
142 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
143 const char *srv_name_slash;
144 enum ndr_err_code ndr_err;
145 struct ntprinting_driver r;
146 struct spoolss_AddDriverInfoCtr d;
147 struct spoolss_AddDriverInfo3 d3;
148 struct spoolss_StringArray a;
149 DATA_BLOB blob;
150 NTSTATUS status;
151 WERROR result;
153 blob = data_blob_const(data, length);
155 ZERO_STRUCT(r);
157 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
158 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160 DEBUG(2, ("Driver pull failed: %s\n",
161 ndr_errstr(ndr_err)));
162 return NT_STATUS_NO_MEMORY;
165 DEBUG(2, ("Migrating Printer Driver: %s\n", key_name));
167 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
168 if (srv_name_slash == NULL) {
169 return NT_STATUS_NO_MEMORY;
172 ZERO_STRUCT(d3);
173 ZERO_STRUCT(a);
175 a.string = r.dependent_files;
177 d3.architecture = r.environment;
178 d3.config_file = r.configfile;
179 d3.data_file = r.datafile;
180 d3.default_datatype = r.defaultdatatype;
181 d3.dependent_files = &a;
182 d3.driver_path = r.driverpath;
183 d3.help_file = r.helpfile;
184 d3.monitor_name = r.monitorname;
185 d3.driver_name = r.name;
186 d3.version = r.version;
188 d.level = 3;
189 d.info.info3 = &d3;
191 status = dcerpc_spoolss_AddPrinterDriver(b,
192 mem_ctx,
193 srv_name_slash,
195 &result);
196 if (!NT_STATUS_IS_OK(status)) {
197 DEBUG(2, ("dcerpc_spoolss_AddPrinterDriver(%s) refused -- %s.\n",
198 d3.driver_name, nt_errstr(status)));
199 } else if (!W_ERROR_IS_OK(result)) {
200 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
201 d3.driver_name, win_errstr(result)));
202 status = werror_to_ntstatus(result);
205 return status;
208 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
209 struct rpc_pipe_client *pipe_hnd,
210 const char *key_name,
211 unsigned char *data,
212 size_t length)
214 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
215 struct policy_handle hnd;
216 enum ndr_err_code ndr_err;
217 struct ntprinting_printer r;
218 struct spoolss_SetPrinterInfo2 info2;
219 struct spoolss_DeviceMode dm;
220 struct spoolss_SetPrinterInfoCtr info_ctr;
221 struct spoolss_DevmodeContainer devmode_ctr;
222 struct sec_desc_buf secdesc_ctr;
223 DATA_BLOB blob;
224 NTSTATUS status;
225 WERROR result;
226 int j;
228 if (strequal(key_name, "printers")) {
229 return NT_STATUS_OK;
232 blob = data_blob_const(data, length);
234 ZERO_STRUCT(r);
236 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
237 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
238 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
239 DEBUG(2, ("printer pull failed: %s\n",
240 ndr_errstr(ndr_err)));
241 return NT_STATUS_NO_MEMORY;
244 DEBUG(2, ("Migrating Printer: %s\n", key_name));
246 ZERO_STRUCT(devmode_ctr);
248 status = dcerpc_spoolss_OpenPrinter(b,
249 mem_ctx,
250 key_name,
251 NULL,
252 devmode_ctr,
253 SEC_FLAG_MAXIMUM_ALLOWED,
254 &hnd,
255 &result);
256 if (!NT_STATUS_IS_OK(status)) {
257 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
258 key_name, nt_errstr(status)));
259 return status;
261 if (!W_ERROR_IS_OK(result)) {
262 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
263 key_name, win_errstr(result)));
264 status = werror_to_ntstatus(result);
265 return status;
268 /* Create printer info level 2 */
269 ZERO_STRUCT(info2);
270 ZERO_STRUCT(secdesc_ctr);
272 info2.attributes = r.info.attributes;
273 info2.averageppm = r.info.averageppm;
274 info2.cjobs = r.info.cjobs;
275 info2.comment = r.info.comment;
276 info2.datatype = r.info.datatype;
277 info2.defaultpriority = r.info.default_priority;
278 info2.drivername = r.info.drivername;
279 info2.location = r.info.location;
280 info2.parameters = r.info.parameters;
281 info2.portname = r.info.portname;
282 info2.printername = r.info.printername;
283 info2.printprocessor = r.info.printprocessor;
284 info2.priority = r.info.priority;
285 info2.sepfile = r.info.sepfile;
286 info2.sharename = r.info.sharename;
287 info2.starttime = r.info.starttime;
288 info2.status = r.info.status;
289 info2.untiltime = r.info.untiltime;
291 /* Create Device Mode */
292 if (r.devmode != NULL) {
293 ZERO_STRUCT(dm);
295 dm.bitsperpel = r.devmode->bitsperpel;
296 dm.collate = r.devmode->collate;
297 dm.color = r.devmode->color;
298 dm.copies = r.devmode->copies;
299 dm.defaultsource = r.devmode->defaultsource;
300 dm.devicename = r.devmode->devicename;
301 dm.displayflags = r.devmode->displayflags;
302 dm.displayfrequency = r.devmode->displayfrequency;
303 dm.dithertype = r.devmode->dithertype;
304 dm.driverversion = r.devmode->driverversion;
305 dm.duplex = r.devmode->duplex;
306 dm.fields = r.devmode->fields;
307 dm.formname = r.devmode->formname;
308 dm.icmintent = r.devmode->icmintent;
309 dm.icmmethod = r.devmode->icmmethod;
310 dm.logpixels = r.devmode->logpixels;
311 dm.mediatype = r.devmode->mediatype;
312 dm.orientation = r.devmode->orientation;
313 dm.panningheight = r.devmode->pelsheight;
314 dm.panningwidth = r.devmode->panningwidth;
315 dm.paperlength = r.devmode->paperlength;
316 dm.papersize = r.devmode->papersize;
317 dm.paperwidth = r.devmode->paperwidth;
318 dm.pelsheight = r.devmode->pelsheight;
319 dm.pelswidth = r.devmode->pelswidth;
320 dm.printquality = r.devmode->printquality;
321 dm.scale = r.devmode->scale;
322 dm.specversion = r.devmode->specversion;
323 dm.ttoption = r.devmode->ttoption;
324 dm.yresolution = r.devmode->yresolution;
326 if (r.devmode->nt_dev_private != NULL) {
327 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
328 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
329 dm.__driverextra_length = r.devmode->nt_dev_private->length;
332 devmode_ctr.devmode = &dm;
334 info2.devmode_ptr = 1;
337 info_ctr.info.info2 = &info2;
338 info_ctr.level = 2;
340 status = dcerpc_spoolss_SetPrinter(b,
341 mem_ctx,
342 &hnd,
343 &info_ctr,
344 &devmode_ctr,
345 &secdesc_ctr,
346 0, /* command */
347 &result);
348 if (!NT_STATUS_IS_OK(status)) {
349 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 2 refused -- %s.\n",
350 key_name, nt_errstr(status)));
351 goto done;
353 if (!W_ERROR_IS_OK(result)) {
354 DEBUG(2, ("SetPrinter(%s) level 2 refused -- %s.\n",
355 key_name, win_errstr(result)));
356 status = werror_to_ntstatus(result);
357 goto done;
360 /* migrate printerdata */
361 for (j = 0; j < r.count; j++) {
362 char *valuename;
363 char *keyname;
365 if (r.printer_data[j].type == REG_NONE) {
366 continue;
369 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
370 valuename = strchr(keyname, '\\');
371 if (valuename == NULL) {
372 continue;
373 } else {
374 valuename[0] = '\0';
375 valuename++;
378 status = dcerpc_spoolss_SetPrinterDataEx(b,
379 mem_ctx,
380 &hnd,
381 keyname,
382 valuename,
383 r.printer_data[j].type,
384 r.printer_data[j].data.data,
385 r.printer_data[j].data.length,
386 &result);
387 if (!NT_STATUS_IS_OK(status)) {
388 DEBUG(2, ("dcerpc_spoolss_SetPrinterDataEx: "
389 "printer [%s], keyname [%s], "
390 "valuename [%s] refused -- %s.\n",
391 key_name, keyname, valuename,
392 nt_errstr(status)));
393 break;
395 if (!W_ERROR_IS_OK(result)) {
396 DEBUG(2, ("SetPrinterDataEx: printer [%s], keyname [%s], "
397 "valuename [%s] refused -- %s.\n",
398 key_name, keyname, valuename,
399 win_errstr(result)));
400 status = werror_to_ntstatus(result);
401 break;
405 done:
406 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
408 return status;
411 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
412 struct rpc_pipe_client *pipe_hnd,
413 const char *key_name,
414 unsigned char *data,
415 size_t length)
417 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
418 struct policy_handle hnd;
419 enum ndr_err_code ndr_err;
420 struct sec_desc_buf secdesc_ctr;
421 struct spoolss_SetPrinterInfo3 info3;
422 struct spoolss_SetPrinterInfoCtr info_ctr;
423 struct spoolss_DevmodeContainer devmode_ctr;
424 DATA_BLOB blob;
425 NTSTATUS status;
426 WERROR result;
428 if (strequal(key_name, "printers")) {
429 return NT_STATUS_OK;
432 blob = data_blob_const(data, length);
434 ZERO_STRUCT(secdesc_ctr);
436 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
437 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
438 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
439 DEBUG(2, ("security descriptor pull failed: %s\n",
440 ndr_errstr(ndr_err)));
441 return NT_STATUS_NO_MEMORY;
444 DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name));
446 ZERO_STRUCT(devmode_ctr);
448 status = dcerpc_spoolss_OpenPrinter(b,
449 mem_ctx,
450 key_name,
451 NULL,
452 devmode_ctr,
453 SEC_FLAG_MAXIMUM_ALLOWED,
454 &hnd,
455 &result);
456 if (!NT_STATUS_IS_OK(status)) {
457 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
458 key_name, nt_errstr(status)));
459 return status;
461 if (W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME, result)) {
462 DEBUG(3, ("Ignoring missing printer %s\n", key_name));
463 return NT_STATUS_OK;
465 if (!W_ERROR_IS_OK(result)) {
466 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
467 key_name, win_errstr(result)));
468 status = werror_to_ntstatus(result);
469 return status;
472 ZERO_STRUCT(devmode_ctr);
474 info3.sec_desc_ptr = 1;
476 info_ctr.info.info3 = &info3;
477 info_ctr.level = 3;
479 status = dcerpc_spoolss_SetPrinter(b,
480 mem_ctx,
481 &hnd,
482 &info_ctr,
483 &devmode_ctr,
484 &secdesc_ctr,
485 0, /* command */
486 &result);
487 if (!NT_STATUS_IS_OK(status)) {
488 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 3 refused -- %s.\n",
489 key_name, nt_errstr(status)));
490 } else if (!W_ERROR_IS_OK(result)) {
491 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
492 key_name, win_errstr(result)));
493 status = werror_to_ntstatus(result);
496 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
498 return status;
501 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
502 const char *path,
503 const char *suffix)
505 int rc = -1;
506 char *dst_path;
508 dst_path = talloc_asprintf(mem_ctx, "%s%s", path, suffix);
509 if (dst_path == NULL) {
510 DEBUG(3, ("error out of memory\n"));
511 return rc;
514 rc = (rename(path, dst_path) != 0);
516 if (rc == 0) {
517 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
518 } else if (errno == ENOENT) {
519 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
520 rc = 0;
521 } else {
522 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
523 strerror(errno)));
526 TALLOC_FREE(dst_path);
527 return rc;
530 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
531 const char *tdb_path,
532 struct rpc_pipe_client *pipe_hnd)
534 const char *backup_suffix = ".bak";
535 TDB_DATA kbuf, newkey, dbuf;
536 TDB_CONTEXT *tdb;
537 NTSTATUS status;
538 int rc;
540 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
541 if (tdb == NULL && errno == ENOENT) {
542 /* if we have no printers database then migration is
543 considered successful */
544 DEBUG(4, ("No printers database to migrate in %s\n", tdb_path));
545 return NT_STATUS_OK;
547 if (tdb == NULL) {
548 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
549 return NT_STATUS_NO_SUCH_FILE;
552 for (kbuf = tdb_firstkey(tdb);
553 kbuf.dptr;
554 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
556 dbuf = tdb_fetch(tdb, kbuf);
557 if (!dbuf.dptr) {
558 continue;
561 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
562 status = migrate_form(mem_ctx,
563 pipe_hnd,
564 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
565 dbuf.dptr,
566 dbuf.dsize);
567 SAFE_FREE(dbuf.dptr);
568 if (!NT_STATUS_IS_OK(status)) {
569 tdb_close(tdb);
570 return status;
572 continue;
575 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
576 status = migrate_driver(mem_ctx,
577 pipe_hnd,
578 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
579 dbuf.dptr,
580 dbuf.dsize);
581 SAFE_FREE(dbuf.dptr);
582 if (!NT_STATUS_IS_OK(status)) {
583 tdb_close(tdb);
584 return status;
586 continue;
589 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
590 status = migrate_printer(mem_ctx,
591 pipe_hnd,
592 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
593 dbuf.dptr,
594 dbuf.dsize);
595 SAFE_FREE(dbuf.dptr);
596 if (!NT_STATUS_IS_OK(status)) {
597 tdb_close(tdb);
598 return status;
600 continue;
603 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
604 status = migrate_secdesc(mem_ctx,
605 pipe_hnd,
606 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
607 dbuf.dptr,
608 dbuf.dsize);
609 SAFE_FREE(dbuf.dptr);
610 if (!NT_STATUS_IS_OK(status)) {
611 tdb_close(tdb);
612 return status;
614 continue;
618 tdb_close(tdb);
620 rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix);
621 if (rc != 0) {
622 DEBUG(0, ("Error moving tdb to '%s%s'\n",
623 tdb_path, backup_suffix));
626 return NT_STATUS_OK;
629 bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
631 const char *drivers_path = state_path("ntdrivers.tdb");
632 const char *printers_path = state_path("ntprinters.tdb");
633 const char *forms_path = state_path("ntforms.tdb");
634 bool drivers_exists = file_exist(drivers_path);
635 bool printers_exists = file_exist(printers_path);
636 bool forms_exists = file_exist(forms_path);
637 struct auth_serversupplied_info *session_info;
638 struct rpc_pipe_client *spoolss_pipe = NULL;
639 TALLOC_CTX *tmp_ctx = talloc_stackframe();
640 NTSTATUS status;
642 if (!drivers_exists && !printers_exists && !forms_exists) {
643 return true;
646 status = make_session_info_system(tmp_ctx, &session_info);
647 if (!NT_STATUS_IS_OK(status)) {
648 DEBUG(0, ("Couldn't create session_info: %s\n",
649 nt_errstr(status)));
650 talloc_free(tmp_ctx);
651 return false;
654 status = rpc_pipe_open_interface(tmp_ctx,
655 &ndr_table_spoolss.syntax_id,
656 session_info,
657 NULL,
658 msg_ctx,
659 &spoolss_pipe);
660 if (!NT_STATUS_IS_OK(status)) {
661 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
662 nt_errstr(status)));
663 talloc_free(tmp_ctx);
664 return false;
667 if (drivers_exists) {
668 status = migrate_internal(tmp_ctx, drivers_path, spoolss_pipe);
669 if (!NT_STATUS_IS_OK(status)) {
670 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
671 nt_errstr(status)));
672 talloc_free(tmp_ctx);
673 return false;
677 if (printers_exists) {
678 status = migrate_internal(tmp_ctx, printers_path, spoolss_pipe);
679 if (!NT_STATUS_IS_OK(status)) {
680 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
681 nt_errstr(status)));
682 talloc_free(tmp_ctx);
683 return false;
687 if (forms_exists) {
688 status = migrate_internal(tmp_ctx, forms_path, spoolss_pipe);
689 if (!NT_STATUS_IS_OK(status)) {
690 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
691 nt_errstr(status)));
692 talloc_free(tmp_ctx);
693 return false;
697 talloc_free(tmp_ctx);
698 return true;