2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "../librpc/gen_ndr/spoolss.h"
24 #include "rpc_server/spoolss/srv_spoolss_util.h"
25 #include "nt_printing.h"
29 #include "../libcli/registry/util_reg.h"
31 #include "../librpc/ndr/libndr.h"
32 #include "rpc_client/cli_winreg_spoolss.h"
35 /*****************************************************************
36 ****************************************************************/
38 WERROR
nt_printer_guid_store(struct messaging_context
*msg_ctx
,
39 const char *printer
, struct GUID guid
)
42 const struct auth_session_info
*session_info
;
47 tmp_ctx
= talloc_new(NULL
);
49 DEBUG(0, ("Out of memory?!\n"));
53 session_info
= get_session_info_system();
54 if (session_info
== NULL
) {
55 DEBUG(0, ("Could not get system session_info\n"));
60 guid_str
= GUID_string(tmp_ctx
, &guid
);
62 DEBUG(0, ("Out of memory?!\n"));
67 /* We used to store this as a REG_BINARY but that causes
70 if (!push_reg_sz(tmp_ctx
, &blob
, guid_str
)) {
71 DEBUG(0, ("Could not marshall string %s for objectGUID\n",
77 result
= winreg_set_printer_dataex_internal(tmp_ctx
, session_info
, msg_ctx
,
79 SPOOL_DSSPOOLER_KEY
, "objectGUID",
80 REG_SZ
, blob
.data
, blob
.length
);
81 if (!W_ERROR_IS_OK(result
)) {
82 DEBUG(0, ("Failed to store GUID for printer %s\n", printer
));
93 static WERROR
nt_printer_dn_lookup(TALLOC_CTX
*mem_ctx
,
98 char *printer_dn
= NULL
;
100 char *srv_cn_0
= NULL
;
101 char *srv_cn_escaped
= NULL
;
102 char *sharename_escaped
= NULL
;
103 char *srv_dn_utf8
= NULL
;
104 char **srv_cn_utf8
= NULL
;
105 size_t converted_size
;
106 ADS_STATUS ads_status
;
111 ads_status
= ads_find_machine_acct(ads
, &res
, lp_netbios_name());
112 if (!ADS_ERR_OK(ads_status
)) {
113 DEBUG(2, ("Failed to find machine account for %s\n",
115 result
= WERR_NOT_FOUND
;
120 * We use ldap_get_dn here as we need the answer in utf8 to call
121 * ldap_explode_dn(). JRA.
123 srv_dn_utf8
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
124 ads_msgfree(ads
, res
);
125 if (srv_dn_utf8
== NULL
) {
126 result
= WERR_SERVER_UNAVAILABLE
;
130 srv_cn_utf8
= ldap_explode_dn(srv_dn_utf8
, 1);
131 if (srv_cn_utf8
== NULL
) {
132 ldap_memfree(srv_dn_utf8
);
133 result
= WERR_SERVER_UNAVAILABLE
;
137 /* Now convert to CH_UNIX. */
138 ok
= pull_utf8_talloc(mem_ctx
, &srv_dn
, srv_dn_utf8
, &converted_size
);
139 ldap_memfree(srv_dn_utf8
);
141 ldap_memfree(srv_cn_utf8
);
142 result
= WERR_SERVER_UNAVAILABLE
;
146 ok
= pull_utf8_talloc(mem_ctx
, &srv_cn_0
, srv_cn_utf8
[0], &converted_size
);
147 ldap_memfree(srv_cn_utf8
);
149 result
= WERR_SERVER_UNAVAILABLE
;
153 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn_0
);
154 if (srv_cn_escaped
== NULL
) {
155 result
= WERR_SERVER_UNAVAILABLE
;
159 sharename_escaped
= escape_rdn_val_string_alloc(printer
);
160 if (sharename_escaped
== NULL
) {
161 result
= WERR_SERVER_UNAVAILABLE
;
165 printer_dn
= talloc_asprintf(mem_ctx
,
170 if (printer_dn
== NULL
) {
175 *pprinter_dn
= printer_dn
;
179 SAFE_FREE(sharename_escaped
);
180 SAFE_FREE(srv_cn_escaped
);
181 TALLOC_FREE(srv_cn_0
);
186 static WERROR
nt_printer_guid_retrieve_internal(ADS_STRUCT
*ads
,
187 const char *printer_dn
,
190 ADS_STATUS ads_status
;
192 const char *attrs
[] = {"objectGUID", NULL
};
196 ads_status
= ads_search_dn(ads
, &res
, printer_dn
, attrs
);
197 if (!ADS_ERR_OK(ads_status
)) {
198 DEBUG(2, ("Failed to retrieve GUID from DC - %s\n",
199 ads_errstr(ads_status
)));
204 ok
= ads_pull_guid(ads
, res
, &guid
);
205 ads_msgfree(ads
, res
);
215 WERROR
nt_printer_guid_retrieve(TALLOC_CTX
*mem_ctx
, const char *printer
,
218 ADS_STRUCT
*ads
= NULL
;
219 char *old_krb5ccname
= NULL
;
222 ADS_STATUS ads_status
;
225 tmp_ctx
= talloc_new(mem_ctx
);
226 if (tmp_ctx
== NULL
) {
230 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
232 result
= WERR_SERVER_UNAVAILABLE
;
236 old_krb5ccname
= getenv(KRB5_ENV_CCNAME
);
237 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
238 SAFE_FREE(ads
->auth
.password
);
239 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
242 ads_status
= ads_connect(ads
);
243 if (!ADS_ERR_OK(ads_status
)) {
244 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status
)));
245 result
= WERR_ACCESS_DENIED
;
249 result
= nt_printer_dn_lookup(tmp_ctx
, ads
, printer
, &printer_dn
);
250 if (!W_ERROR_IS_OK(result
)) {
254 result
= nt_printer_guid_retrieve_internal(ads
, printer_dn
, pguid
);
256 TALLOC_FREE(tmp_ctx
);
258 ads_kdestroy("MEMORY:prtpub_cache");
259 unsetenv(KRB5_ENV_CCNAME
);
260 if (old_krb5ccname
!= NULL
) {
261 setenv(KRB5_ENV_CCNAME
, old_krb5ccname
, 0);
267 WERROR
nt_printer_guid_get(TALLOC_CTX
*mem_ctx
,
268 const struct auth_session_info
*session_info
,
269 struct messaging_context
*msg_ctx
,
270 const char *printer
, struct GUID
*guid
)
273 enum winreg_Type type
;
279 tmp_ctx
= talloc_new(mem_ctx
);
280 if (tmp_ctx
== NULL
) {
281 DEBUG(0, ("out of memory?!\n"));
285 result
= winreg_get_printer_dataex_internal(tmp_ctx
, session_info
,
292 if (!W_ERROR_IS_OK(result
)) {
293 DEBUG(0, ("Failed to get GUID for printer %s\n", printer
));
296 blob
.length
= (size_t)len
;
298 /* We used to store the guid as REG_BINARY, then swapped
299 to REG_SZ for Vista compatibility so check for both */
304 const char *guid_str
;
305 ok
= pull_reg_sz(tmp_ctx
, &blob
, &guid_str
);
307 DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
309 result
= WERR_REG_CORRUPT
;
312 status
= GUID_from_string(guid_str
, guid
);
313 if (!NT_STATUS_IS_OK(status
)) {
314 DEBUG(0, ("bad GUID for printer %s\n", printer
));
315 result
= ntstatus_to_werror(status
);
321 if (blob
.length
!= sizeof(struct GUID
)) {
322 DEBUG(0, ("bad GUID for printer %s\n", printer
));
323 result
= WERR_REG_CORRUPT
;
326 memcpy(guid
, blob
.data
, sizeof(struct GUID
));
329 DEBUG(0,("GUID value stored as invalid type (%d)\n", type
));
330 result
= WERR_REG_CORRUPT
;
337 talloc_free(tmp_ctx
);
341 static WERROR
nt_printer_info_to_mods(TALLOC_CTX
*ctx
,
342 struct spoolss_PrinterInfo2
*info2
,
347 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTERNAME
, info2
->sharename
);
348 ads_mod_str(ctx
, mods
, SPOOL_REG_SHORTSERVERNAME
, lp_netbios_name());
349 ads_mod_str(ctx
, mods
, SPOOL_REG_SERVERNAME
, get_mydnsfullname());
351 info_str
= talloc_asprintf(ctx
, "\\\\%s\\%s",
352 get_mydnsfullname(), info2
->sharename
);
353 if (info_str
== NULL
) {
356 ads_mod_str(ctx
, mods
, SPOOL_REG_UNCNAME
, info_str
);
358 info_str
= talloc_asprintf(ctx
, "%d", 4);
359 if (info_str
== NULL
) {
362 ads_mod_str(ctx
, mods
, SPOOL_REG_VERSIONNUMBER
, info_str
);
364 /* empty strings in the mods list result in an attrubute error */
365 if (strlen(info2
->drivername
) != 0)
366 ads_mod_str(ctx
, mods
, SPOOL_REG_DRIVERNAME
, info2
->drivername
);
367 if (strlen(info2
->location
) != 0)
368 ads_mod_str(ctx
, mods
, SPOOL_REG_LOCATION
, info2
->location
);
369 if (strlen(info2
->comment
) != 0)
370 ads_mod_str(ctx
, mods
, SPOOL_REG_DESCRIPTION
, info2
->comment
);
371 if (strlen(info2
->portname
) != 0)
372 ads_mod_str(ctx
, mods
, SPOOL_REG_PORTNAME
, info2
->portname
);
373 if (strlen(info2
->sepfile
) != 0)
374 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSEPARATORFILE
, info2
->sepfile
);
376 info_str
= talloc_asprintf(ctx
, "%u", info2
->starttime
);
377 if (info_str
== NULL
) {
380 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSTARTTIME
, info_str
);
382 info_str
= talloc_asprintf(ctx
, "%u", info2
->untiltime
);
383 if (info_str
== NULL
) {
386 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTENDTIME
, info_str
);
388 info_str
= talloc_asprintf(ctx
, "%u", info2
->priority
);
389 if (info_str
== NULL
) {
392 ads_mod_str(ctx
, mods
, SPOOL_REG_PRIORITY
, info_str
);
394 if (info2
->attributes
& PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
) {
395 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTKEEPPRINTEDJOBS
, "TRUE");
397 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTKEEPPRINTEDJOBS
, "FALSE");
400 switch (info2
->attributes
& 0x3) {
402 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
403 SPOOL_REGVAL_PRINTWHILESPOOLING
);
406 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
407 SPOOL_REGVAL_PRINTAFTERSPOOLED
);
410 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
411 SPOOL_REGVAL_PRINTDIRECT
);
414 DEBUG(3, ("unsupported printer attributes %x\n",
421 static WERROR
nt_printer_publish_ads(struct messaging_context
*msg_ctx
,
423 struct spoolss_PrinterInfo2
*pinfo2
)
429 WERROR win_rc
= WERR_OK
;
430 const char *printer
= pinfo2
->sharename
;
431 char *printer_dn
= NULL
;
433 /* build the ads mods */
434 ctx
= talloc_init("nt_printer_publish_ads");
439 DEBUG(5, ("publishing printer %s\n", printer
));
441 win_rc
= nt_printer_dn_lookup(ctx
, ads
, printer
, &printer_dn
);
442 if (!W_ERROR_IS_OK(win_rc
)) {
443 DEBUG(2, ("Failed to create printer dn\n"));
448 mods
= ads_init_mods(ctx
);
455 win_rc
= nt_printer_info_to_mods(ctx
, pinfo2
, &mods
);
456 if (!W_ERROR_IS_OK(win_rc
)) {
462 ads_rc
= ads_mod_printer_entry(ads
, printer_dn
, ctx
, &mods
);
463 if (ads_rc
.err
.rc
== LDAP_NO_SUCH_OBJECT
) {
465 for (i
=0; mods
[i
] != 0; i
++)
467 mods
[i
] = (LDAPMod
*)-1;
468 ads_rc
= ads_add_printer_entry(ads
, printer_dn
, ctx
, &mods
);
471 if (!ADS_ERR_OK(ads_rc
)) {
472 DEBUG(3, ("error publishing %s: %s\n",
473 printer
, ads_errstr(ads_rc
)));
474 /* XXX failed to publish, so no guid to retrieve */
477 win_rc
= nt_printer_guid_retrieve_internal(ads
, printer_dn
, &guid
);
478 if (!W_ERROR_IS_OK(win_rc
)) {
483 win_rc
= nt_printer_guid_store(msg_ctx
, printer
, guid
);
484 if (!W_ERROR_IS_OK(win_rc
)) {
485 DEBUG(3, ("failed to store printer %s guid\n",
487 /* not catastrophic, retrieve on next use */
496 static WERROR
nt_printer_unpublish_ads(ADS_STRUCT
*ads
,
500 LDAPMessage
*res
= NULL
;
503 DEBUG(5, ("unpublishing printer %s\n", printer
));
505 /* remove the printer from the directory */
506 ads_rc
= ads_find_printer_on_server(ads
, &res
,
507 printer
, lp_netbios_name());
509 if (ADS_ERR_OK(ads_rc
) && res
&& ads_count_replies(ads
, res
)) {
510 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
512 ads_msgfree(ads
, res
);
515 ads_rc
= ads_del_dn(ads
, prt_dn
);
520 ads_msgfree(ads
, res
);
525 /****************************************************************************
526 * Publish a printer in the directory
528 * @param mem_ctx memory context
529 * @param session_info session_info to access winreg pipe
530 * @param pinfo2 printer information
531 * @param action publish/unpublish action
532 * @return WERROR indicating status of publishing
533 ***************************************************************************/
535 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
536 const struct auth_session_info
*session_info
,
537 struct messaging_context
*msg_ctx
,
538 struct spoolss_PrinterInfo2
*pinfo2
,
541 uint32_t info2_mask
= SPOOLSS_PRINTER_INFO_ATTRIBUTES
;
542 struct spoolss_SetPrinterInfo2
*sinfo2
;
544 ADS_STRUCT
*ads
= NULL
;
546 char *old_krb5ccname
= NULL
;
548 sinfo2
= talloc_zero(mem_ctx
, struct spoolss_SetPrinterInfo2
);
554 case DSPRINT_PUBLISH
:
556 pinfo2
->attributes
|= PRINTER_ATTRIBUTE_PUBLISHED
;
558 case DSPRINT_UNPUBLISH
:
559 pinfo2
->attributes
&= (~PRINTER_ATTRIBUTE_PUBLISHED
);
562 win_rc
= WERR_NOT_SUPPORTED
;
566 sinfo2
->attributes
= pinfo2
->attributes
;
568 win_rc
= winreg_update_printer_internal(mem_ctx
, session_info
, msg_ctx
,
569 pinfo2
->sharename
, info2_mask
,
571 if (!W_ERROR_IS_OK(win_rc
)) {
572 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc
)));
578 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
580 DEBUG(3, ("ads_init() failed\n"));
581 win_rc
= WERR_SERVER_UNAVAILABLE
;
584 old_krb5ccname
= getenv(KRB5_ENV_CCNAME
);
585 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
586 SAFE_FREE(ads
->auth
.password
);
587 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
590 /* ads_connect() will find the DC for us */
591 ads_rc
= ads_connect(ads
);
592 if (!ADS_ERR_OK(ads_rc
)) {
593 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
594 win_rc
= WERR_ACCESS_DENIED
;
599 case DSPRINT_PUBLISH
:
601 win_rc
= nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
603 case DSPRINT_UNPUBLISH
:
604 win_rc
= nt_printer_unpublish_ads(ads
, pinfo2
->sharename
);
610 ads_kdestroy("MEMORY:prtpub_cache");
611 unsetenv(KRB5_ENV_CCNAME
);
612 if (old_krb5ccname
) {
613 setenv(KRB5_ENV_CCNAME
, old_krb5ccname
, 0);
618 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
621 ADS_STRUCT
*ads
= NULL
;
623 int n_services
= lp_numservices();
624 TALLOC_CTX
*tmp_ctx
= NULL
;
625 struct auth_session_info
*session_info
= NULL
;
626 struct spoolss_PrinterInfo2
*pinfo2
;
629 char *old_krb5ccname
= NULL
;
631 tmp_ctx
= talloc_new(NULL
);
632 if (!tmp_ctx
) return WERR_NOMEM
;
634 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
636 DEBUG(3, ("ads_init() failed\n"));
637 return WERR_SERVER_UNAVAILABLE
;
639 old_krb5ccname
= getenv(KRB5_ENV_CCNAME
);
640 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
641 SAFE_FREE(ads
->auth
.password
);
642 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
645 /* ads_connect() will find the DC for us */
646 ads_rc
= ads_connect(ads
);
647 if (!ADS_ERR_OK(ads_rc
)) {
648 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
649 result
= WERR_ACCESS_DENIED
;
653 status
= make_session_info_system(tmp_ctx
, &session_info
);
654 if (!NT_STATUS_IS_OK(status
)) {
655 DEBUG(0, ("check_published_printers: "
656 "Could not create system session_info\n"));
657 result
= WERR_ACCESS_DENIED
;
661 for (snum
= 0; snum
< n_services
; snum
++) {
662 if (!lp_snum_ok(snum
) || !lp_printable(snum
)) {
666 result
= winreg_get_printer_internal(tmp_ctx
, session_info
, msg_ctx
,
667 lp_servicename(talloc_tos(), snum
),
669 if (!W_ERROR_IS_OK(result
)) {
673 if (pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
) {
674 nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
683 ads_kdestroy("MEMORY:prtpub_cache");
684 unsetenv(KRB5_ENV_CCNAME
);
685 if (old_krb5ccname
) {
686 setenv(KRB5_ENV_CCNAME
, old_krb5ccname
, 0);
688 talloc_free(tmp_ctx
);
692 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
693 const struct auth_session_info
*session_info
,
694 struct messaging_context
*msg_ctx
,
695 const char *servername
,
697 struct spoolss_PrinterInfo2
**info2
)
699 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
701 struct dcerpc_binding_handle
*b
;
703 result
= winreg_printer_binding_handle(mem_ctx
,
707 if (!W_ERROR_IS_OK(result
)) {
711 result
= winreg_get_printer(mem_ctx
, b
,
713 if (!W_ERROR_IS_OK(result
)) {
717 if (!(pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
)) {
723 *info2
= talloc_move(mem_ctx
, &pinfo2
);
729 WERROR
nt_printer_guid_store(struct messaging_context
*msg_ctx
,
730 const char *printer
, struct GUID guid
)
732 return WERR_NOT_SUPPORTED
;
735 WERROR
nt_printer_guid_retrieve(TALLOC_CTX
*mem_ctx
, const char *printer
,
738 return WERR_NOT_SUPPORTED
;
741 WERROR
nt_printer_guid_get(TALLOC_CTX
*mem_ctx
,
742 const struct auth_session_info
*session_info
,
743 struct messaging_context
*msg_ctx
,
744 const char *printer
, struct GUID
*guid
)
746 return WERR_NOT_SUPPORTED
;
749 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
750 const struct auth_session_info
*session_info
,
751 struct messaging_context
*msg_ctx
,
752 struct spoolss_PrinterInfo2
*pinfo2
,
758 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
763 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
764 const struct auth_session_info
*session_info
,
765 struct messaging_context
*msg_ctx
,
766 const char *servername
,
768 struct spoolss_PrinterInfo2
**info2
)
772 #endif /* HAVE_ADS */