c6466767e58335560d1df08d17cd9d9221433aae
[kai/samba.git] / source3 / printing / nt_printing_migrate.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *
5  *  Copyright (c) Andreas Schneider            2010.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include "includes.h"
22 #include "printing/nt_printing_migrate.h"
23
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"
29
30 #define FORMS_PREFIX "FORMS/"
31 #define DRIVERS_PREFIX "DRIVERS/"
32 #define PRINTERS_PREFIX "PRINTERS/"
33 #define SECDESC_PREFIX "SECDESC/"
34
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)
40 {
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;
51
52
53         blob = data_blob_const(data, length);
54
55         ZERO_STRUCT(r);
56
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;
63         }
64
65         /* Don't migrate builtin forms */
66         if (r.flag == SPOOLSS_FORM_BUILTIN) {
67                 return NT_STATUS_OK;
68         }
69
70         DEBUG(2, ("Migrating Form: %s\n", key_name));
71
72         srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
73         if (srv_name_slash == NULL) {
74                 return NT_STATUS_NO_MEMORY;
75         }
76
77         ZERO_STRUCT(devmode_ctr);
78
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);
90                 }
91                 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
92                           srv_name_slash, nt_errstr(status)));
93                 return status;
94         }
95
96         f1.form_name = key_name;
97         f1.flags = r.flag;
98
99         f1.size.width = r.width;
100         f1.size.height = r.length;
101
102         f1.area.top = r.top;
103         f1.area.right = r.right;
104         f1.area.bottom = r.bottom;
105         f1.area.left = r.left;
106
107         f.info1 = &f1;
108
109         status = rpccli_spoolss_AddForm(pipe_hnd,
110                                         mem_ctx,
111                                         &hnd,
112                                         1,
113                                         f,
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)));
118         }
119
120         rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
121
122         return status;
123 }
124
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)
130 {
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;
140
141         blob = data_blob_const(data, length);
142
143         ZERO_STRUCT(r);
144
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;
151         }
152
153         DEBUG(2, ("Migrating Printer Driver: %s\n", key_name));
154
155         srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", global_myname());
156         if (srv_name_slash == NULL) {
157                 return NT_STATUS_NO_MEMORY;
158         }
159
160         ZERO_STRUCT(d3);
161         ZERO_STRUCT(a);
162
163         a.string = r.dependent_files;
164
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;
175
176         d.level = 3;
177         d.info.info3 = &d3;
178
179         status = rpccli_spoolss_AddPrinterDriver(pipe_hnd,
180                                                  mem_ctx,
181                                                  srv_name_slash,
182                                                  &d,
183                                                  &result);
184         if (!NT_STATUS_IS_OK(status)) {
185                 if (!W_ERROR_IS_OK(result)) {
186                         status = werror_to_ntstatus(result);
187                 }
188                 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
189                           d3.driver_name, nt_errstr(status)));
190         }
191
192         return status;
193 }
194
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)
200 {
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;
213
214         if (strequal(key_name, "printers")) {
215                 return NT_STATUS_OK;
216         }
217
218         blob = data_blob_const(data, length);
219
220         ZERO_STRUCT(r);
221
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;
228         }
229
230         DEBUG(2, ("Migrating Printer: %s\n", key_name));
231
232         ZERO_STRUCT(devmode_ctr);
233
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);
245                 }
246                 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
247                           key_name, win_errstr(result)));
248                 return status;
249         }
250
251         /* Create printer info level 2 */
252         ZERO_STRUCT(info2);
253         ZERO_STRUCT(secdesc_ctr);
254
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;
273
274         /* Create Device Mode */
275         if (r.devmode != NULL) {
276                 ZERO_STRUCT(dm);
277
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;
308
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;
313                 }
314
315                 devmode_ctr.devmode = &dm;
316
317                 info2.devmode_ptr = 1;
318         }
319
320         info_ctr.info.info2 = &info2;
321         info_ctr.level = 2;
322
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;
335         }
336
337         /* migrate printerdata */
338         for (j = 0; j < r.count; j++) {
339                 char *valuename;
340                 char *keyname;
341
342                 if (r.printer_data[j].type == REG_NONE) {
343                         continue;
344                 }
345
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++;
353                 }
354
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;
370                 }
371         }
372
373  done:
374         rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
375
376         return status;
377 }
378
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)
384 {
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;
394
395         if (strequal(key_name, "printers")) {
396                 return NT_STATUS_OK;
397         }
398
399         blob = data_blob_const(data, length);
400
401         ZERO_STRUCT(secdesc_ctr);
402
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;
409         }
410
411         DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name));
412
413         ZERO_STRUCT(devmode_ctr);
414
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;
427                 }
428                 if (!W_ERROR_IS_OK(result)) {
429                         status = werror_to_ntstatus(result);
430                 }
431                 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
432                           key_name, nt_errstr(status)));
433                 return status;
434         }
435
436         ZERO_STRUCT(devmode_ctr);
437
438         info3.sec_desc_ptr = 1;
439
440         info_ctr.info.info3 = &info3;
441         info_ctr.level = 3;
442
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)));
454         }
455
456         rpccli_spoolss_ClosePrinter(pipe_hnd, mem_ctx, &hnd, NULL);
457
458         return status;
459 }
460
461 static int rename_file_with_suffix(TALLOC_CTX *mem_ctx,
462                                    const char *path,
463                                    const char *suffix)
464 {
465         int rc = -1;
466         char *dst_path;
467
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;
472         }
473
474         rc = (rename(path, dst_path) != 0);
475
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)));
484         }
485
486         TALLOC_FREE(dst_path);
487         return rc;
488 }
489
490 static NTSTATUS migrate_internal(TALLOC_CTX *mem_ctx,
491                                  const char *tdb_path,
492                                  struct rpc_pipe_client *pipe_hnd)
493 {
494         const char *backup_suffix = ".bak";
495         TDB_DATA kbuf, newkey, dbuf;
496         TDB_CONTEXT *tdb;
497         NTSTATUS status;
498         int rc;
499
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;
506         }
507         if (tdb == NULL) {
508                 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path));
509                 return NT_STATUS_NO_SUCH_FILE;
510         }
511
512         for (kbuf = tdb_firstkey(tdb);
513              kbuf.dptr;
514              newkey = tdb_nextkey(tdb, kbuf), free(kbuf.dptr), kbuf = newkey)
515         {
516                 dbuf = tdb_fetch(tdb, kbuf);
517                 if (!dbuf.dptr) {
518                         continue;
519                 }
520
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;
531                         }
532                         continue;
533                 }
534
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;
545                         }
546                         continue;
547                 }
548
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;
559                         }
560                         continue;
561                 }
562
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;
573                         }
574                         continue;
575                 }
576         }
577
578         tdb_close(tdb);
579
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));
584         }
585
586         return NT_STATUS_OK;
587 }
588
589 bool nt_printing_tdb_migrate(struct messaging_context *msg_ctx)
590 {
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;
601
602         if (!drivers_exists && !printers_exists && !forms_exists) {
603                 return true;
604         }
605
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;
612         }
613
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;
625         }
626
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;
634                 }
635         }
636
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;
644                 }
645         }
646
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;
654                 }
655         }
656
657         talloc_free(tmp_ctx);
658         return true;
659 }