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/>.
22 #include "system/filesys.h"
23 #include "printing/nt_printing_migrate.h"
25 #include "librpc/gen_ndr/ndr_ntprinting.h"
26 #include "librpc/gen_ndr/ndr_spoolss_c.h"
27 #include "rpc_client/cli_spoolss.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "rpc_server/rpc_ncacn_np.h"
32 #define FORMS_PREFIX "FORMS/"
33 #define DRIVERS_PREFIX "DRIVERS/"
34 #define PRINTERS_PREFIX "PRINTERS/"
35 #define SECDESC_PREFIX "SECDESC/"
37 static NTSTATUS
migrate_form(TALLOC_CTX
*mem_ctx
,
38 struct rpc_pipe_client
*pipe_hnd
,
43 struct dcerpc_binding_handle
*b
= pipe_hnd
->binding_handle
;
44 struct spoolss_DevmodeContainer devmode_ctr
;
45 struct policy_handle hnd
;
46 enum ndr_err_code ndr_err
;
47 struct ntprinting_form r
;
48 union spoolss_AddFormInfo f
;
49 struct spoolss_AddFormInfo1 f1
;
50 const char *srv_name_slash
;
56 blob
= data_blob_const(data
, length
);
60 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
61 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_form
);
62 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
63 DEBUG(2, ("Form pull failed: %s\n",
64 ndr_errstr(ndr_err
)));
65 return NT_STATUS_NO_MEMORY
;
68 /* Don't migrate builtin forms */
69 if (r
.flag
== SPOOLSS_FORM_BUILTIN
) {
73 DEBUG(2, ("Migrating Form: %s\n", key_name
));
75 srv_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", global_myname());
76 if (srv_name_slash
== NULL
) {
77 return NT_STATUS_NO_MEMORY
;
80 ZERO_STRUCT(devmode_ctr
);
82 status
= dcerpc_spoolss_OpenPrinter(b
,
87 SEC_FLAG_MAXIMUM_ALLOWED
,
90 if (!NT_STATUS_IS_OK(status
)) {
91 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
92 srv_name_slash
, nt_errstr(status
)));
95 if (!W_ERROR_IS_OK(result
)) {
96 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
97 srv_name_slash
, win_errstr(result
)));
98 status
= werror_to_ntstatus(result
);
102 f1
.form_name
= key_name
;
105 f1
.size
.width
= r
.width
;
106 f1
.size
.height
= r
.length
;
109 f1
.area
.right
= r
.right
;
110 f1
.area
.bottom
= r
.bottom
;
111 f1
.area
.left
= r
.left
;
115 status
= dcerpc_spoolss_AddForm(b
,
121 if (!NT_STATUS_IS_OK(status
)) {
122 DEBUG(2, ("dcerpc_spoolss_AddForm(%s) refused -- %s.\n",
123 f
.info1
->form_name
, nt_errstr(status
)));
124 } else if (!W_ERROR_IS_OK(result
)) {
125 DEBUG(2, ("AddForm(%s) refused -- %s.\n",
126 f
.info1
->form_name
, win_errstr(result
)));
127 status
= werror_to_ntstatus(result
);
130 dcerpc_spoolss_ClosePrinter(b
, mem_ctx
, &hnd
, &result
);
135 static NTSTATUS
migrate_driver(TALLOC_CTX
*mem_ctx
,
136 struct rpc_pipe_client
*pipe_hnd
,
137 const char *key_name
,
141 struct dcerpc_binding_handle
*b
= pipe_hnd
->binding_handle
;
142 const char *srv_name_slash
;
143 enum ndr_err_code ndr_err
;
144 struct ntprinting_driver r
;
145 struct spoolss_AddDriverInfoCtr d
;
146 struct spoolss_AddDriverInfo3 d3
;
147 struct spoolss_StringArray a
;
152 blob
= data_blob_const(data
, length
);
156 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
157 (ndr_pull_flags_fn_t
)ndr_pull_ntprinting_driver
);
158 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
159 DEBUG(2, ("Driver pull failed: %s\n",
160 ndr_errstr(ndr_err
)));
161 return NT_STATUS_NO_MEMORY
;
164 DEBUG(2, ("Migrating Printer Driver: %s\n", key_name
));
166 srv_name_slash
= talloc_asprintf(mem_ctx
, "\\\\%s", global_myname());
167 if (srv_name_slash
== NULL
) {
168 return NT_STATUS_NO_MEMORY
;
174 a
.string
= r
.dependent_files
;
176 d3
.architecture
= r
.environment
;
177 d3
.config_file
= r
.configfile
;
178 d3
.data_file
= r
.datafile
;
179 d3
.default_datatype
= r
.defaultdatatype
;
180 d3
.dependent_files
= &a
;
181 d3
.driver_path
= r
.driverpath
;
182 d3
.help_file
= r
.helpfile
;
183 d3
.monitor_name
= r
.monitorname
;
184 d3
.driver_name
= r
.name
;
185 d3
.version
= r
.version
;
190 status
= dcerpc_spoolss_AddPrinterDriver(b
,
195 if (!NT_STATUS_IS_OK(status
)) {
196 DEBUG(2, ("dcerpc_spoolss_AddPrinterDriver(%s) refused -- %s.\n",
197 d3
.driver_name
, nt_errstr(status
)));
198 } else if (!W_ERROR_IS_OK(result
)) {
199 DEBUG(2, ("AddPrinterDriver(%s) refused -- %s.\n",
200 d3
.driver_name
, win_errstr(result
)));
201 status
= werror_to_ntstatus(result
);
207 static NTSTATUS
migrate_printer(TALLOC_CTX
*mem_ctx
,
208 struct rpc_pipe_client
*pipe_hnd
,
209 const char *key_name
,
213 struct dcerpc_binding_handle
*b
= pipe_hnd
->binding_handle
;
214 struct policy_handle hnd
;
215 enum ndr_err_code ndr_err
;
216 struct ntprinting_printer r
;
217 struct spoolss_SetPrinterInfo2 info2
;
218 struct spoolss_DeviceMode dm
;
219 struct spoolss_SetPrinterInfoCtr info_ctr
;
220 struct spoolss_DevmodeContainer devmode_ctr
;
221 struct sec_desc_buf secdesc_ctr
;
227 if (strequal(key_name
, "printers")) {
231 blob
= data_blob_const(data
, length
);
235 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &r
,
236 (ndr_pull_flags_fn_t
) ndr_pull_ntprinting_printer
);
237 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
238 DEBUG(2, ("printer pull failed: %s\n",
239 ndr_errstr(ndr_err
)));
240 return NT_STATUS_NO_MEMORY
;
243 DEBUG(2, ("Migrating Printer: %s\n", key_name
));
245 ZERO_STRUCT(devmode_ctr
);
247 status
= dcerpc_spoolss_OpenPrinter(b
,
252 SEC_FLAG_MAXIMUM_ALLOWED
,
255 if (!NT_STATUS_IS_OK(status
)) {
256 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
257 key_name
, nt_errstr(status
)));
260 if (!W_ERROR_IS_OK(result
)) {
261 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
262 key_name
, win_errstr(result
)));
263 status
= werror_to_ntstatus(result
);
267 /* Create printer info level 2 */
269 ZERO_STRUCT(secdesc_ctr
);
271 info2
.attributes
= r
.info
.attributes
;
272 info2
.averageppm
= r
.info
.averageppm
;
273 info2
.cjobs
= r
.info
.cjobs
;
274 info2
.comment
= r
.info
.comment
;
275 info2
.datatype
= r
.info
.datatype
;
276 info2
.defaultpriority
= r
.info
.default_priority
;
277 info2
.drivername
= r
.info
.drivername
;
278 info2
.location
= r
.info
.location
;
279 info2
.parameters
= r
.info
.parameters
;
280 info2
.portname
= r
.info
.portname
;
281 info2
.printername
= r
.info
.printername
;
282 info2
.printprocessor
= r
.info
.printprocessor
;
283 info2
.priority
= r
.info
.priority
;
284 info2
.sepfile
= r
.info
.sepfile
;
285 info2
.sharename
= r
.info
.sharename
;
286 info2
.starttime
= r
.info
.starttime
;
287 info2
.status
= r
.info
.status
;
288 info2
.untiltime
= r
.info
.untiltime
;
290 /* Create Device Mode */
291 if (r
.devmode
!= NULL
) {
294 dm
.bitsperpel
= r
.devmode
->bitsperpel
;
295 dm
.collate
= r
.devmode
->collate
;
296 dm
.color
= r
.devmode
->color
;
297 dm
.copies
= r
.devmode
->copies
;
298 dm
.defaultsource
= r
.devmode
->defaultsource
;
299 dm
.devicename
= r
.devmode
->devicename
;
300 dm
.displayflags
= r
.devmode
->displayflags
;
301 dm
.displayfrequency
= r
.devmode
->displayfrequency
;
302 dm
.dithertype
= r
.devmode
->dithertype
;
303 dm
.driverversion
= r
.devmode
->driverversion
;
304 dm
.duplex
= r
.devmode
->duplex
;
305 dm
.fields
= r
.devmode
->fields
;
306 dm
.formname
= r
.devmode
->formname
;
307 dm
.icmintent
= r
.devmode
->icmintent
;
308 dm
.icmmethod
= r
.devmode
->icmmethod
;
309 dm
.logpixels
= r
.devmode
->logpixels
;
310 dm
.mediatype
= r
.devmode
->mediatype
;
311 dm
.orientation
= r
.devmode
->orientation
;
312 dm
.panningheight
= r
.devmode
->pelsheight
;
313 dm
.panningwidth
= r
.devmode
->panningwidth
;
314 dm
.paperlength
= r
.devmode
->paperlength
;
315 dm
.papersize
= r
.devmode
->papersize
;
316 dm
.paperwidth
= r
.devmode
->paperwidth
;
317 dm
.pelsheight
= r
.devmode
->pelsheight
;
318 dm
.pelswidth
= r
.devmode
->pelswidth
;
319 dm
.printquality
= r
.devmode
->printquality
;
320 dm
.scale
= r
.devmode
->scale
;
321 dm
.specversion
= r
.devmode
->specversion
;
322 dm
.ttoption
= r
.devmode
->ttoption
;
323 dm
.yresolution
= r
.devmode
->yresolution
;
325 if (r
.devmode
->nt_dev_private
!= NULL
) {
326 dm
.driverextra_data
.data
= r
.devmode
->nt_dev_private
->data
;
327 dm
.driverextra_data
.length
= r
.devmode
->nt_dev_private
->length
;
328 dm
.__driverextra_length
= r
.devmode
->nt_dev_private
->length
;
331 devmode_ctr
.devmode
= &dm
;
333 info2
.devmode_ptr
= 1;
336 info_ctr
.info
.info2
= &info2
;
339 status
= dcerpc_spoolss_SetPrinter(b
,
347 if (!NT_STATUS_IS_OK(status
)) {
348 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 2 refused -- %s.\n",
349 key_name
, nt_errstr(status
)));
352 if (!W_ERROR_IS_OK(result
)) {
353 DEBUG(2, ("SetPrinter(%s) level 2 refused -- %s.\n",
354 key_name
, win_errstr(result
)));
355 status
= werror_to_ntstatus(result
);
359 /* migrate printerdata */
360 for (j
= 0; j
< r
.count
; j
++) {
364 if (r
.printer_data
[j
].type
== REG_NONE
) {
368 keyname
= CONST_DISCARD(char *, r
.printer_data
[j
].name
);
369 valuename
= strchr(keyname
, '\\');
370 if (valuename
== NULL
) {
377 status
= dcerpc_spoolss_SetPrinterDataEx(b
,
382 r
.printer_data
[j
].type
,
383 r
.printer_data
[j
].data
.data
,
384 r
.printer_data
[j
].data
.length
,
386 if (!NT_STATUS_IS_OK(status
)) {
387 DEBUG(2, ("dcerpc_spoolss_SetPrinterDataEx: "
388 "printer [%s], keyname [%s], "
389 "valuename [%s] refused -- %s.\n",
390 key_name
, keyname
, valuename
,
394 if (!W_ERROR_IS_OK(result
)) {
395 DEBUG(2, ("SetPrinterDataEx: printer [%s], keyname [%s], "
396 "valuename [%s] refused -- %s.\n",
397 key_name
, keyname
, valuename
,
398 win_errstr(result
)));
399 status
= werror_to_ntstatus(result
);
405 dcerpc_spoolss_ClosePrinter(b
, mem_ctx
, &hnd
, &result
);
410 static NTSTATUS
migrate_secdesc(TALLOC_CTX
*mem_ctx
,
411 struct rpc_pipe_client
*pipe_hnd
,
412 const char *key_name
,
416 struct dcerpc_binding_handle
*b
= pipe_hnd
->binding_handle
;
417 struct policy_handle hnd
;
418 enum ndr_err_code ndr_err
;
419 struct sec_desc_buf secdesc_ctr
;
420 struct spoolss_SetPrinterInfo3 info3
;
421 struct spoolss_SetPrinterInfoCtr info_ctr
;
422 struct spoolss_DevmodeContainer devmode_ctr
;
427 if (strequal(key_name
, "printers")) {
431 blob
= data_blob_const(data
, length
);
433 ZERO_STRUCT(secdesc_ctr
);
435 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, &secdesc_ctr
,
436 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
437 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
438 DEBUG(2, ("security descriptor pull failed: %s\n",
439 ndr_errstr(ndr_err
)));
440 return NT_STATUS_NO_MEMORY
;
443 DEBUG(2, ("Migrating Security Descriptor: %s\n", key_name
));
445 ZERO_STRUCT(devmode_ctr
);
447 status
= dcerpc_spoolss_OpenPrinter(b
,
452 SEC_FLAG_MAXIMUM_ALLOWED
,
455 if (!NT_STATUS_IS_OK(status
)) {
456 DEBUG(2, ("dcerpc_spoolss_OpenPrinter(%s) failed: %s\n",
457 key_name
, nt_errstr(status
)));
460 if (W_ERROR_EQUAL(WERR_INVALID_PRINTER_NAME
, result
)) {
461 DEBUG(3, ("Ignoring missing printer %s\n", key_name
));
464 if (!W_ERROR_IS_OK(result
)) {
465 DEBUG(2, ("OpenPrinter(%s) failed: %s\n",
466 key_name
, win_errstr(result
)));
467 status
= werror_to_ntstatus(result
);
471 ZERO_STRUCT(devmode_ctr
);
473 info3
.sec_desc_ptr
= 1;
475 info_ctr
.info
.info3
= &info3
;
478 status
= dcerpc_spoolss_SetPrinter(b
,
486 if (!NT_STATUS_IS_OK(status
)) {
487 DEBUG(2, ("dcerpc_spoolss_SetPrinter(%s) level 3 refused -- %s.\n",
488 key_name
, nt_errstr(status
)));
489 } else if (!W_ERROR_IS_OK(result
)) {
490 DEBUG(2, ("SetPrinter(%s) level 3 refused -- %s.\n",
491 key_name
, win_errstr(result
)));
492 status
= werror_to_ntstatus(result
);
495 dcerpc_spoolss_ClosePrinter(b
, mem_ctx
, &hnd
, &result
);
500 static int rename_file_with_suffix(TALLOC_CTX
*mem_ctx
,
507 dst_path
= talloc_asprintf(mem_ctx
, "%s%s", path
, suffix
);
508 if (dst_path
== NULL
) {
509 DEBUG(3, ("error out of memory\n"));
513 rc
= (rename(path
, dst_path
) != 0);
516 DEBUG(5, ("moved '%s' to '%s'\n", path
, dst_path
));
517 } else if (errno
== ENOENT
) {
518 DEBUG(3, ("file '%s' does not exist - so not moved\n", path
));
521 DEBUG(3, ("error renaming %s to %s: %s\n", path
, dst_path
,
525 TALLOC_FREE(dst_path
);
529 static NTSTATUS
migrate_internal(TALLOC_CTX
*mem_ctx
,
530 const char *tdb_path
,
531 struct rpc_pipe_client
*pipe_hnd
)
533 const char *backup_suffix
= ".bak";
534 TDB_DATA kbuf
, newkey
, dbuf
;
539 tdb
= tdb_open_log(tdb_path
, 0, TDB_DEFAULT
, O_RDONLY
, 0600);
540 if (tdb
== NULL
&& errno
== ENOENT
) {
541 /* if we have no printers database then migration is
542 considered successful */
543 DEBUG(4, ("No printers database to migrate in %s\n", tdb_path
));
547 DEBUG(2, ("Failed to open tdb file: %s\n", tdb_path
));
548 return NT_STATUS_NO_SUCH_FILE
;
551 for (kbuf
= tdb_firstkey(tdb
);
553 newkey
= tdb_nextkey(tdb
, kbuf
), free(kbuf
.dptr
), kbuf
= newkey
)
555 dbuf
= tdb_fetch(tdb
, kbuf
);
560 if (strncmp((const char *) kbuf
.dptr
, FORMS_PREFIX
, strlen(FORMS_PREFIX
)) == 0) {
561 status
= migrate_form(mem_ctx
,
563 (const char *) kbuf
.dptr
+ strlen(FORMS_PREFIX
),
566 SAFE_FREE(dbuf
.dptr
);
567 if (!NT_STATUS_IS_OK(status
)) {
574 if (strncmp((const char *) kbuf
.dptr
, DRIVERS_PREFIX
, strlen(DRIVERS_PREFIX
)) == 0) {
575 status
= migrate_driver(mem_ctx
,
577 (const char *) kbuf
.dptr
+ strlen(DRIVERS_PREFIX
),
580 SAFE_FREE(dbuf
.dptr
);
581 if (!NT_STATUS_IS_OK(status
)) {
588 if (strncmp((const char *) kbuf
.dptr
, PRINTERS_PREFIX
, strlen(PRINTERS_PREFIX
)) == 0) {
589 status
= migrate_printer(mem_ctx
,
591 (const char *) kbuf
.dptr
+ strlen(PRINTERS_PREFIX
),
594 SAFE_FREE(dbuf
.dptr
);
595 if (!NT_STATUS_IS_OK(status
)) {
602 if (strncmp((const char *) kbuf
.dptr
, SECDESC_PREFIX
, strlen(SECDESC_PREFIX
)) == 0) {
603 status
= migrate_secdesc(mem_ctx
,
605 (const char *) kbuf
.dptr
+ strlen(SECDESC_PREFIX
),
608 SAFE_FREE(dbuf
.dptr
);
609 if (!NT_STATUS_IS_OK(status
)) {
619 rc
= rename_file_with_suffix(mem_ctx
, tdb_path
, backup_suffix
);
621 DEBUG(0, ("Error moving tdb to '%s%s'\n",
622 tdb_path
, backup_suffix
));
628 bool nt_printing_tdb_migrate(struct messaging_context
*msg_ctx
)
630 const char *drivers_path
= state_path("ntdrivers.tdb");
631 const char *printers_path
= state_path("ntprinters.tdb");
632 const char *forms_path
= state_path("ntforms.tdb");
633 bool drivers_exists
= file_exist(drivers_path
);
634 bool printers_exists
= file_exist(printers_path
);
635 bool forms_exists
= file_exist(forms_path
);
636 struct auth_serversupplied_info
*session_info
;
637 struct rpc_pipe_client
*spoolss_pipe
= NULL
;
638 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
641 if (!drivers_exists
&& !printers_exists
&& !forms_exists
) {
645 status
= make_session_info_system(tmp_ctx
, &session_info
);
646 if (!NT_STATUS_IS_OK(status
)) {
647 DEBUG(0, ("Couldn't create session_info: %s\n",
649 talloc_free(tmp_ctx
);
653 status
= rpc_pipe_open_internal(tmp_ctx
,
654 &ndr_table_spoolss
.syntax_id
,
659 if (!NT_STATUS_IS_OK(status
)) {
660 DEBUG(0, ("Couldn't open internal spoolss pipe: %s\n",
662 talloc_free(tmp_ctx
);
666 if (drivers_exists
) {
667 status
= migrate_internal(tmp_ctx
, drivers_path
, spoolss_pipe
);
668 if (!NT_STATUS_IS_OK(status
)) {
669 DEBUG(0, ("Couldn't migrate drivers tdb file: %s\n",
671 talloc_free(tmp_ctx
);
676 if (printers_exists
) {
677 status
= migrate_internal(tmp_ctx
, printers_path
, spoolss_pipe
);
678 if (!NT_STATUS_IS_OK(status
)) {
679 DEBUG(0, ("Couldn't migrate printers tdb file: %s\n",
681 talloc_free(tmp_ctx
);
687 status
= migrate_internal(tmp_ctx
, forms_path
, spoolss_pipe
);
688 if (!NT_STATUS_IS_OK(status
)) {
689 DEBUG(0, ("Couldn't migrate forms tdb file: %s\n",
691 talloc_free(tmp_ctx
);
696 talloc_free(tmp_ctx
);