dcerpc: we do not need these as public headers
[Samba.git] / source3 / printing / nt_printing_migrate.c
blob59fd04067b5f669977c5bf6e8154ca49d6e4ab49
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/ndr_spoolss_c.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 dcerpc_binding_handle *b = pipe_hnd->binding_handle;
42 struct spoolss_DevmodeContainer devmode_ctr;
43 struct policy_handle hnd;
44 enum ndr_err_code ndr_err;
45 struct ntprinting_form r;
46 union spoolss_AddFormInfo f;
47 struct spoolss_AddFormInfo1 f1;
48 const char *srv_name_slash;
49 DATA_BLOB blob;
50 NTSTATUS status;
51 WERROR result;
54 blob = data_blob_const(data, length);
56 ZERO_STRUCT(r);
58 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
59 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_form);
60 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
61 DEBUG(2, ("Form pull failed: %s\n",
62 ndr_errstr(ndr_err)));
63 return NT_STATUS_NO_MEMORY;
66 /* Don't migrate builtin forms */
67 if (r.flag == SPOOLSS_FORM_BUILTIN) {
68 return NT_STATUS_OK;
71 DEBUG(2, ("Migrating Form: %s\n", key_name));
73 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
74 if (srv_name_slash == NULL) {
75 return NT_STATUS_NO_MEMORY;
78 ZERO_STRUCT(devmode_ctr);
80 status = dcerpc_spoolss_OpenPrinter(b,
81 mem_ctx,
82 srv_name_slash,
83 NULL,
84 devmode_ctr,
85 SEC_FLAG_MAXIMUM_ALLOWED,
86 &hnd,
87 &result);
88 if (!NT_STATUS_IS_OK(status)) {
89 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
90 srv_name_slash, nt_errstr(status)));
91 return status;
93 if (!W_ERROR_IS_OK(result)) {
94 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
95 srv_name_slash, win_errstr(result)));
96 status = werror_to_ntstatus(result);
97 return status;
100 f1.form_name = key_name;
101 f1.flags = r.flag;
103 f1.size.width = r.width;
104 f1.size.height = r.length;
106 f1.area.top = r.top;
107 f1.area.right = r.right;
108 f1.area.bottom = r.bottom;
109 f1.area.left = r.left;
111 f.info1 = &f1;
113 status = dcerpc_spoolss_AddForm(b,
114 mem_ctx,
115 &hnd,
118 &result);
119 if (!NT_STATUS_IS_OK(status)) {
120 DEBUG(2, ("dcerpc_spoolss_AddForm(%s) refused -- %s.\n",
121 f.info1->form_name, nt_errstr(status)));
122 } else if (!W_ERROR_IS_OK(result)) {
123 DEBUG(2, ("AddForm(%s) refused -- %s.\n",
124 f.info1->form_name, win_errstr(result)));
125 status = werror_to_ntstatus(result);
128 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
130 return status;
133 static NTSTATUS migrate_driver(TALLOC_CTX *mem_ctx,
134 struct rpc_pipe_client *pipe_hnd,
135 const char *key_name,
136 unsigned char *data,
137 size_t length)
139 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
140 const char *srv_name_slash;
141 enum ndr_err_code ndr_err;
142 struct ntprinting_driver r;
143 struct spoolss_AddDriverInfoCtr d;
144 struct spoolss_AddDriverInfo3 d3;
145 struct spoolss_StringArray a;
146 DATA_BLOB blob;
147 NTSTATUS status;
148 WERROR result;
150 blob = data_blob_const(data, length);
152 ZERO_STRUCT(r);
154 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
155 (ndr_pull_flags_fn_t)ndr_pull_ntprinting_driver);
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 DEBUG(2, ("Driver pull failed: %s\n",
158 ndr_errstr(ndr_err)));
159 return NT_STATUS_NO_MEMORY;
162 DEBUG(2, ("Migrating Printer Driver: %s\n", key_name));
164 srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
165 if (srv_name_slash == NULL) {
166 return NT_STATUS_NO_MEMORY;
169 ZERO_STRUCT(d3);
170 ZERO_STRUCT(a);
172 a.string = r.dependent_files;
174 d3.architecture = r.environment;
175 d3.config_file = r.configfile;
176 d3.data_file = r.datafile;
177 d3.default_datatype = r.defaultdatatype;
178 d3.dependent_files = &a;
179 d3.driver_path = r.driverpath;
180 d3.help_file = r.helpfile;
181 d3.monitor_name = r.monitorname;
182 d3.driver_name = r.name;
183 d3.version = r.version;
185 d.level = 3;
186 d.info.info3 = &d3;
188 status = dcerpc_spoolss_AddPrinterDriver(b,
189 mem_ctx,
190 srv_name_slash,
192 &result);
193 if (!NT_STATUS_IS_OK(status)) {
194 DEBUG(2, ("dcerpc_spoolss_AddPrinterDriver(%s) refused -- %s.\n",
195 d3.driver_name, nt_errstr(status)));
196 } else if (!W_ERROR_IS_OK(result)) {
197 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
198 d3.driver_name, win_errstr(result)));
199 status = werror_to_ntstatus(result);
202 return status;
205 static NTSTATUS migrate_printer(TALLOC_CTX *mem_ctx,
206 struct rpc_pipe_client *pipe_hnd,
207 const char *key_name,
208 unsigned char *data,
209 size_t length)
211 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
212 struct policy_handle hnd;
213 enum ndr_err_code ndr_err;
214 struct ntprinting_printer r;
215 struct spoolss_SetPrinterInfo2 info2;
216 struct spoolss_DeviceMode dm;
217 struct spoolss_SetPrinterInfoCtr info_ctr;
218 struct spoolss_DevmodeContainer devmode_ctr;
219 struct sec_desc_buf secdesc_ctr;
220 DATA_BLOB blob;
221 NTSTATUS status;
222 WERROR result;
223 int j;
225 if (strequal(key_name, "printers")) {
226 return NT_STATUS_OK;
229 blob = data_blob_const(data, length);
231 ZERO_STRUCT(r);
233 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r,
234 (ndr_pull_flags_fn_t) ndr_pull_ntprinting_printer);
235 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
236 DEBUG(2, ("printer pull failed: %s\n",
237 ndr_errstr(ndr_err)));
238 return NT_STATUS_NO_MEMORY;
241 DEBUG(2, ("Migrating Printer: %s\n", key_name));
243 ZERO_STRUCT(devmode_ctr);
245 status = dcerpc_spoolss_OpenPrinter(b,
246 mem_ctx,
247 key_name,
248 NULL,
249 devmode_ctr,
250 SEC_FLAG_MAXIMUM_ALLOWED,
251 &hnd,
252 &result);
253 if (!NT_STATUS_IS_OK(status)) {
254 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
255 key_name, nt_errstr(status)));
256 return status;
258 if (!W_ERROR_IS_OK(result)) {
259 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
260 key_name, win_errstr(result)));
261 status = werror_to_ntstatus(result);
262 return status;
265 /* Create printer info level 2 */
266 ZERO_STRUCT(info2);
267 ZERO_STRUCT(secdesc_ctr);
269 info2.attributes = r.info.attributes;
270 info2.averageppm = r.info.averageppm;
271 info2.cjobs = r.info.cjobs;
272 info2.comment = r.info.comment;
273 info2.datatype = r.info.datatype;
274 info2.defaultpriority = r.info.default_priority;
275 info2.drivername = r.info.drivername;
276 info2.location = r.info.location;
277 info2.parameters = r.info.parameters;
278 info2.portname = r.info.portname;
279 info2.printername = r.info.printername;
280 info2.printprocessor = r.info.printprocessor;
281 info2.priority = r.info.priority;
282 info2.sepfile = r.info.sepfile;
283 info2.sharename = r.info.sharename;
284 info2.starttime = r.info.starttime;
285 info2.status = r.info.status;
286 info2.untiltime = r.info.untiltime;
288 /* Create Device Mode */
289 if (r.devmode != NULL) {
290 ZERO_STRUCT(dm);
292 dm.bitsperpel = r.devmode->bitsperpel;
293 dm.collate = r.devmode->collate;
294 dm.color = r.devmode->color;
295 dm.copies = r.devmode->copies;
296 dm.defaultsource = r.devmode->defaultsource;
297 dm.devicename = r.devmode->devicename;
298 dm.displayflags = r.devmode->displayflags;
299 dm.displayfrequency = r.devmode->displayfrequency;
300 dm.dithertype = r.devmode->dithertype;
301 dm.driverversion = r.devmode->driverversion;
302 dm.duplex = r.devmode->duplex;
303 dm.fields = r.devmode->fields;
304 dm.formname = r.devmode->formname;
305 dm.icmintent = r.devmode->icmintent;
306 dm.icmmethod = r.devmode->icmmethod;
307 dm.logpixels = r.devmode->logpixels;
308 dm.mediatype = r.devmode->mediatype;
309 dm.orientation = r.devmode->orientation;
310 dm.panningheight = r.devmode->pelsheight;
311 dm.panningwidth = r.devmode->panningwidth;
312 dm.paperlength = r.devmode->paperlength;
313 dm.papersize = r.devmode->papersize;
314 dm.paperwidth = r.devmode->paperwidth;
315 dm.pelsheight = r.devmode->pelsheight;
316 dm.pelswidth = r.devmode->pelswidth;
317 dm.printquality = r.devmode->printquality;
318 dm.scale = r.devmode->scale;
319 dm.specversion = r.devmode->specversion;
320 dm.ttoption = r.devmode->ttoption;
321 dm.yresolution = r.devmode->yresolution;
323 if (r.devmode->nt_dev_private != NULL) {
324 dm.driverextra_data.data = r.devmode->nt_dev_private->data;
325 dm.driverextra_data.length = r.devmode->nt_dev_private->length;
326 dm.__driverextra_length = r.devmode->nt_dev_private->length;
329 devmode_ctr.devmode = &dm;
331 info2.devmode_ptr = 1;
334 info_ctr.info.info2 = &info2;
335 info_ctr.level = 2;
337 status = dcerpc_spoolss_SetPrinter(b,
338 mem_ctx,
339 &hnd,
340 &info_ctr,
341 &devmode_ctr,
342 &secdesc_ctr,
343 0, /* command */
344 &result);
345 if (!NT_STATUS_IS_OK(status)) {
346 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 2 refused -- %s.\n",
347 key_name, nt_errstr(status)));
348 goto done;
350 if (!W_ERROR_IS_OK(result)) {
351 DEBUG(2, ("SetPrinter(%s) level 2 refused -- %s.\n",
352 key_name, win_errstr(result)));
353 status = werror_to_ntstatus(result);
354 goto done;
357 /* migrate printerdata */
358 for (j = 0; j < r.count; j++) {
359 char *valuename;
360 char *keyname;
362 if (r.printer_data[j].type == REG_NONE) {
363 continue;
366 keyname = CONST_DISCARD(char *, r.printer_data[j].name);
367 valuename = strchr(keyname, '\\');
368 if (valuename == NULL) {
369 continue;
370 } else {
371 valuename[0] = '\0';
372 valuename++;
375 status = dcerpc_spoolss_SetPrinterDataEx(b,
376 mem_ctx,
377 &hnd,
378 keyname,
379 valuename,
380 r.printer_data[j].type,
381 r.printer_data[j].data.data,
382 r.printer_data[j].data.length,
383 &result);
384 if (!NT_STATUS_IS_OK(status)) {
385 DEBUG(2, ("dcerpc_spoolss_SetPrinterDataEx: "
386 "printer [%s], keyname [%s], "
387 "valuename [%s] refused -- %s.\n",
388 key_name, keyname, valuename,
389 nt_errstr(status)));
390 break;
392 if (!W_ERROR_IS_OK(result)) {
393 DEBUG(2, ("SetPrinterDataEx: printer [%s], keyname [%s], "
394 "valuename [%s] refused -- %s.\n",
395 key_name, keyname, valuename,
396 win_errstr(result)));
397 status = werror_to_ntstatus(result);
398 break;
402 done:
403 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
405 return status;
408 static NTSTATUS migrate_secdesc(TALLOC_CTX *mem_ctx,
409 struct rpc_pipe_client *pipe_hnd,
410 const char *key_name,
411 unsigned char *data,
412 size_t length)
414 struct dcerpc_binding_handle *b = pipe_hnd->binding_handle;
415 struct policy_handle hnd;
416 enum ndr_err_code ndr_err;
417 struct sec_desc_buf secdesc_ctr;
418 struct spoolss_SetPrinterInfo3 info3;
419 struct spoolss_SetPrinterInfoCtr info_ctr;
420 struct spoolss_DevmodeContainer devmode_ctr;
421 DATA_BLOB blob;
422 NTSTATUS status;
423 WERROR result;
425 if (strequal(key_name, "printers")) {
426 return NT_STATUS_OK;
429 blob = data_blob_const(data, length);
431 ZERO_STRUCT(secdesc_ctr);
433 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &secdesc_ctr,
434 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
435 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
436 DEBUG(2, ("security descriptor pull failed: %s\n",
437 ndr_errstr(ndr_err)));
438 return NT_STATUS_NO_MEMORY;
441 DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name));
443 ZERO_STRUCT(devmode_ctr);
445 status = dcerpc_spoolss_OpenPrinter(b,
446 mem_ctx,
447 key_name,
448 NULL,
449 devmode_ctr,
450 SEC_FLAG_MAXIMUM_ALLOWED,
451 &hnd,
452 &result);
453 if (!NT_STATUS_IS_OK(status)) {
454 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
455 key_name, nt_errstr(status)));
456 return status;
458 if (W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME, result)) {
459 DEBUG(3, ("Ignoring missing printer %s\n", key_name));
460 return NT_STATUS_OK;
462 if (!W_ERROR_IS_OK(result)) {
463 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
464 key_name, win_errstr(result)));
465 status = werror_to_ntstatus(result);
466 return status;
469 ZERO_STRUCT(devmode_ctr);
471 info3.sec_desc_ptr = 1;
473 info_ctr.info.info3 = &info3;
474 info_ctr.level = 3;
476 status = dcerpc_spoolss_SetPrinter(b,
477 mem_ctx,
478 &hnd,
479 &info_ctr,
480 &devmode_ctr,
481 &secdesc_ctr,
482 0, /* command */
483 &result);
484 if (!NT_STATUS_IS_OK(status)) {
485 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 3 refused -- %s.\n",
486 key_name, nt_errstr(status)));
487 } else if (!W_ERROR_IS_OK(result)) {
488 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
489 key_name, win_errstr(result)));
490 status = werror_to_ntstatus(result);
493 dcerpc_spoolss_ClosePrinter(b, mem_ctx, &hnd, &result);
495 return status;
498 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
499 const char *path,
500 const char *suffix)
502 int rc = -1;
503 char *dst_path;
505 dst_path = talloc_asprintf(mem_ctx, "%s%s", path, suffix);
506 if (dst_path == NULL) {
507 DEBUG(3, ("error out of memory\n"));
508 return rc;
511 rc = (rename(path, dst_path) != 0);
513 if (rc == 0) {
514 DEBUG(5, ("moved '%s' to '%s'\n", path, dst_path));
515 } else if (errno == ENOENT) {
516 DEBUG(3, ("file '%s' does not exist - so not moved\n", path));
517 rc = 0;
518 } else {
519 DEBUG(3, ("error renaming %s to %s: %s\n", path, dst_path,
520 strerror(errno)));
523 TALLOC_FREE(dst_path);
524 return rc;
527 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
528 const char *tdb_path,
529 struct rpc_pipe_client *pipe_hnd)
531 const char *backup_suffix = ".bak";
532 TDB_DATA kbuf, newkey, dbuf;
533 TDB_CONTEXT *tdb;
534 NTSTATUS status;
535 int rc;
537 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0600);
538 if (tdb == NULL && errno == ENOENT) {
539 /* if we have no printers database then migration is
540 considered successful */
541 DEBUG(4, ("No printers database to migrate in %s\n", tdb_path));
542 return NT_STATUS_OK;
544 if (tdb == NULL) {
545 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
546 return NT_STATUS_NO_SUCH_FILE;
549 for (kbuf = tdb_firstkey(tdb);
550 kbuf.dptr;
551 newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
553 dbuf = tdb_fetch(tdb, kbuf);
554 if (!dbuf.dptr) {
555 continue;
558 if (strncmp((const char *) kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
559 status = migrate_form(mem_ctx,
560 pipe_hnd,
561 (const char *) kbuf.dptr + strlen(FORMS_PREFIX),
562 dbuf.dptr,
563 dbuf.dsize);
564 SAFE_FREE(dbuf.dptr);
565 if (!NT_STATUS_IS_OK(status)) {
566 tdb_close(tdb);
567 return status;
569 continue;
572 if (strncmp((const char *) kbuf.dptr, DRIVERS_PREFIX, strlen(DRIVERS_PREFIX)) == 0) {
573 status = migrate_driver(mem_ctx,
574 pipe_hnd,
575 (const char *) kbuf.dptr + strlen(DRIVERS_PREFIX),
576 dbuf.dptr,
577 dbuf.dsize);
578 SAFE_FREE(dbuf.dptr);
579 if (!NT_STATUS_IS_OK(status)) {
580 tdb_close(tdb);
581 return status;
583 continue;
586 if (strncmp((const char *) kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
587 status = migrate_printer(mem_ctx,
588 pipe_hnd,
589 (const char *) kbuf.dptr + strlen(PRINTERS_PREFIX),
590 dbuf.dptr,
591 dbuf.dsize);
592 SAFE_FREE(dbuf.dptr);
593 if (!NT_STATUS_IS_OK(status)) {
594 tdb_close(tdb);
595 return status;
597 continue;
600 if (strncmp((const char *) kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
601 status = migrate_secdesc(mem_ctx,
602 pipe_hnd,
603 (const char *) kbuf.dptr + strlen(SECDESC_PREFIX),
604 dbuf.dptr,
605 dbuf.dsize);
606 SAFE_FREE(dbuf.dptr);
607 if (!NT_STATUS_IS_OK(status)) {
608 tdb_close(tdb);
609 return status;
611 continue;
615 tdb_close(tdb);
617 rc = rename_file_with_suffix(mem_ctx, tdb_path, backup_suffix);
618 if (rc != 0) {
619 DEBUG(0, ("Error moving tdb to '%s%s'\n",
620 tdb_path, backup_suffix));
623 return NT_STATUS_OK;
626 bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
628 const char *drivers_path = state_path("ntdrivers.tdb");
629 const char *printers_path = state_path("ntprinters.tdb");
630 const char *forms_path = state_path("ntforms.tdb");
631 bool drivers_exists = file_exist(drivers_path);
632 bool printers_exists = file_exist(printers_path);
633 bool forms_exists = file_exist(forms_path);
634 struct auth_serversupplied_info *session_info;
635 struct rpc_pipe_client *spoolss_pipe = NULL;
636 TALLOC_CTX *tmp_ctx = talloc_stackframe();
637 NTSTATUS status;
639 if (!drivers_exists && !printers_exists && !forms_exists) {
640 return true;
643 status = make_session_info_system(tmp_ctx, &session_info);
644 if (!NT_STATUS_IS_OK(status)) {
645 DEBUG(0, ("Couldn't create session_info: %s\n",
646 nt_errstr(status)));
647 talloc_free(tmp_ctx);
648 return false;
651 status = rpc_pipe_open_internal(tmp_ctx,
652 &ndr_table_spoolss.syntax_id,
653 session_info,
654 NULL,
655 msg_ctx,
656 &spoolss_pipe);
657 if (!NT_STATUS_IS_OK(status)) {
658 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
659 nt_errstr(status)));
660 talloc_free(tmp_ctx);
661 return false;
664 if (drivers_exists) {
665 status = migrate_internal(tmp_ctx, drivers_path, spoolss_pipe);
666 if (!NT_STATUS_IS_OK(status)) {
667 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
668 nt_errstr(status)));
669 talloc_free(tmp_ctx);
670 return false;
674 if (printers_exists) {
675 status = migrate_internal(tmp_ctx, printers_path, spoolss_pipe);
676 if (!NT_STATUS_IS_OK(status)) {
677 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
678 nt_errstr(status)));
679 talloc_free(tmp_ctx);
680 return false;
684 if (forms_exists) {
685 status = migrate_internal(tmp_ctx, forms_path, spoolss_pipe);
686 if (!NT_STATUS_IS_OK(status)) {
687 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
688 nt_errstr(status)));
689 talloc_free(tmp_ctx);
690 return false;
694 talloc_free(tmp_ctx);
695 return true;