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 static void store_printer_guid(struct messaging_context
*msg_ctx
,
39 const char *printer
, struct GUID guid
)
42 struct auth_session_info
*session_info
= NULL
;
48 tmp_ctx
= talloc_new(NULL
);
50 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
54 status
= make_session_info_system(tmp_ctx
, &session_info
);
55 if (!NT_STATUS_IS_OK(status
)) {
56 DEBUG(0, ("store_printer_guid: "
57 "Could not create system session_info\n"));
61 guid_str
= GUID_string(tmp_ctx
, &guid
);
63 DEBUG(0, ("store_printer_guid: 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, ("store_printer_guid: "
72 "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, ("store_printer_guid: "
83 "Failed to store GUID for printer %s\n", printer
));
90 static WERROR
nt_printer_info_to_mods(TALLOC_CTX
*ctx
,
91 struct spoolss_PrinterInfo2
*info2
,
96 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTERNAME
, info2
->sharename
);
97 ads_mod_str(ctx
, mods
, SPOOL_REG_SHORTSERVERNAME
, lp_netbios_name());
98 ads_mod_str(ctx
, mods
, SPOOL_REG_SERVERNAME
, get_mydnsfullname());
100 info_str
= talloc_asprintf(ctx
, "\\\\%s\\%s",
101 get_mydnsfullname(), info2
->sharename
);
102 if (info_str
== NULL
) {
105 ads_mod_str(ctx
, mods
, SPOOL_REG_UNCNAME
, info_str
);
107 info_str
= talloc_asprintf(ctx
, "%d", 4);
108 if (info_str
== NULL
) {
111 ads_mod_str(ctx
, mods
, SPOOL_REG_VERSIONNUMBER
, info_str
);
113 /* empty strings in the mods list result in an attrubute error */
114 if (strlen(info2
->drivername
) != 0)
115 ads_mod_str(ctx
, mods
, SPOOL_REG_DRIVERNAME
, info2
->drivername
);
116 if (strlen(info2
->location
) != 0)
117 ads_mod_str(ctx
, mods
, SPOOL_REG_LOCATION
, info2
->location
);
118 if (strlen(info2
->comment
) != 0)
119 ads_mod_str(ctx
, mods
, SPOOL_REG_DESCRIPTION
, info2
->comment
);
120 if (strlen(info2
->portname
) != 0)
121 ads_mod_str(ctx
, mods
, SPOOL_REG_PORTNAME
, info2
->portname
);
122 if (strlen(info2
->sepfile
) != 0)
123 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSEPARATORFILE
, info2
->sepfile
);
125 info_str
= talloc_asprintf(ctx
, "%u", info2
->starttime
);
126 if (info_str
== NULL
) {
129 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSTARTTIME
, info_str
);
131 info_str
= talloc_asprintf(ctx
, "%u", info2
->untiltime
);
132 if (info_str
== NULL
) {
135 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTENDTIME
, info_str
);
137 info_str
= talloc_asprintf(ctx
, "%u", info2
->priority
);
138 if (info_str
== NULL
) {
141 ads_mod_str(ctx
, mods
, SPOOL_REG_PRIORITY
, info_str
);
143 if (info2
->attributes
& PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
) {
144 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTKEEPPRINTEDJOBS
, "TRUE");
146 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTKEEPPRINTEDJOBS
, "FALSE");
149 switch (info2
->attributes
& 0x3) {
151 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
152 SPOOL_REGVAL_PRINTWHILESPOOLING
);
155 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
156 SPOOL_REGVAL_PRINTAFTERSPOOLED
);
159 ads_mod_str(ctx
, mods
, SPOOL_REG_PRINTSPOOLING
,
160 SPOOL_REGVAL_PRINTDIRECT
);
163 DEBUG(3, ("unsupported printer attributes %x\n",
170 static WERROR
nt_printer_publish_ads(struct messaging_context
*msg_ctx
,
172 struct spoolss_PrinterInfo2
*pinfo2
)
176 char *prt_dn
= NULL
, *srv_dn
, *srv_cn_0
, *srv_cn_escaped
, *sharename_escaped
;
177 char *srv_dn_utf8
, **srv_cn_utf8
;
180 const char *attrs
[] = {"objectGUID", NULL
};
182 WERROR win_rc
= WERR_OK
;
183 size_t converted_size
;
184 const char *printer
= pinfo2
->sharename
;
186 /* build the ads mods */
187 ctx
= talloc_init("nt_printer_publish_ads");
192 DEBUG(5, ("publishing printer %s\n", printer
));
194 /* figure out where to publish */
195 ads_find_machine_acct(ads
, &res
, lp_netbios_name());
197 /* We use ldap_get_dn here as we need the answer
198 * in utf8 to call ldap_explode_dn(). JRA. */
200 srv_dn_utf8
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
203 return WERR_SERVER_UNAVAILABLE
;
205 ads_msgfree(ads
, res
);
206 srv_cn_utf8
= ldap_explode_dn(srv_dn_utf8
, 1);
209 ldap_memfree(srv_dn_utf8
);
210 return WERR_SERVER_UNAVAILABLE
;
212 /* Now convert to CH_UNIX. */
213 if (!pull_utf8_talloc(ctx
, &srv_dn
, srv_dn_utf8
, &converted_size
)) {
215 ldap_memfree(srv_dn_utf8
);
216 ldap_memfree(srv_cn_utf8
);
217 return WERR_SERVER_UNAVAILABLE
;
219 if (!pull_utf8_talloc(ctx
, &srv_cn_0
, srv_cn_utf8
[0], &converted_size
)) {
221 ldap_memfree(srv_dn_utf8
);
222 ldap_memfree(srv_cn_utf8
);
224 return WERR_SERVER_UNAVAILABLE
;
227 ldap_memfree(srv_dn_utf8
);
228 ldap_memfree(srv_cn_utf8
);
230 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn_0
);
231 if (!srv_cn_escaped
) {
233 return WERR_SERVER_UNAVAILABLE
;
235 sharename_escaped
= escape_rdn_val_string_alloc(printer
);
236 if (!sharename_escaped
) {
237 SAFE_FREE(srv_cn_escaped
);
239 return WERR_SERVER_UNAVAILABLE
;
242 prt_dn
= talloc_asprintf(ctx
, "cn=%s-%s,%s", srv_cn_escaped
, sharename_escaped
, srv_dn
);
244 SAFE_FREE(srv_cn_escaped
);
245 SAFE_FREE(sharename_escaped
);
247 mods
= ads_init_mods(ctx
);
254 win_rc
= nt_printer_info_to_mods(ctx
, pinfo2
, &mods
);
255 if (!W_ERROR_IS_OK(win_rc
)) {
261 ads_rc
= ads_mod_printer_entry(ads
, prt_dn
, ctx
, &mods
);
262 if (ads_rc
.err
.rc
== LDAP_NO_SUCH_OBJECT
) {
264 for (i
=0; mods
[i
] != 0; i
++)
266 mods
[i
] = (LDAPMod
*)-1;
267 ads_rc
= ads_add_printer_entry(ads
, prt_dn
, ctx
, &mods
);
270 if (!ADS_ERR_OK(ads_rc
)) {
271 DEBUG(3, ("error publishing %s: %s\n",
272 printer
, ads_errstr(ads_rc
)));
275 /* retreive the guid and store it locally */
276 if (ADS_ERR_OK(ads_search_dn(ads
, &res
, prt_dn
, attrs
))) {
279 guid_ok
= ads_pull_guid(ads
, res
, &guid
);
280 ads_msgfree(ads
, res
);
282 store_printer_guid(msg_ctx
, printer
, guid
);
290 static WERROR
nt_printer_unpublish_ads(ADS_STRUCT
*ads
,
294 LDAPMessage
*res
= NULL
;
297 DEBUG(5, ("unpublishing printer %s\n", printer
));
299 /* remove the printer from the directory */
300 ads_rc
= ads_find_printer_on_server(ads
, &res
,
301 printer
, lp_netbios_name());
303 if (ADS_ERR_OK(ads_rc
) && res
&& ads_count_replies(ads
, res
)) {
304 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
306 ads_msgfree(ads
, res
);
309 ads_rc
= ads_del_dn(ads
, prt_dn
);
314 ads_msgfree(ads
, res
);
319 /****************************************************************************
320 * Publish a printer in the directory
322 * @param mem_ctx memory context
323 * @param session_info session_info to access winreg pipe
324 * @param pinfo2 printer information
325 * @param action publish/unpublish action
326 * @return WERROR indicating status of publishing
327 ***************************************************************************/
329 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
330 const struct auth_session_info
*session_info
,
331 struct messaging_context
*msg_ctx
,
332 struct spoolss_PrinterInfo2
*pinfo2
,
335 uint32_t info2_mask
= SPOOLSS_PRINTER_INFO_ATTRIBUTES
;
336 struct spoolss_SetPrinterInfo2
*sinfo2
;
338 ADS_STRUCT
*ads
= NULL
;
341 sinfo2
= talloc_zero(mem_ctx
, struct spoolss_SetPrinterInfo2
);
347 case DSPRINT_PUBLISH
:
349 pinfo2
->attributes
|= PRINTER_ATTRIBUTE_PUBLISHED
;
351 case DSPRINT_UNPUBLISH
:
352 pinfo2
->attributes
^= PRINTER_ATTRIBUTE_PUBLISHED
;
355 win_rc
= WERR_NOT_SUPPORTED
;
359 sinfo2
->attributes
= pinfo2
->attributes
;
361 win_rc
= winreg_update_printer_internal(mem_ctx
, session_info
, msg_ctx
,
362 pinfo2
->sharename
, info2_mask
,
364 if (!W_ERROR_IS_OK(win_rc
)) {
365 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc
)));
371 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
373 DEBUG(3, ("ads_init() failed\n"));
374 win_rc
= WERR_SERVER_UNAVAILABLE
;
377 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
378 SAFE_FREE(ads
->auth
.password
);
379 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
382 /* ads_connect() will find the DC for us */
383 ads_rc
= ads_connect(ads
);
384 if (!ADS_ERR_OK(ads_rc
)) {
385 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
386 win_rc
= WERR_ACCESS_DENIED
;
391 case DSPRINT_PUBLISH
:
393 win_rc
= nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
395 case DSPRINT_UNPUBLISH
:
396 win_rc
= nt_printer_unpublish_ads(ads
, pinfo2
->sharename
);
405 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
408 ADS_STRUCT
*ads
= NULL
;
410 int n_services
= lp_numservices();
411 TALLOC_CTX
*tmp_ctx
= NULL
;
412 struct auth_session_info
*session_info
= NULL
;
413 struct spoolss_PrinterInfo2
*pinfo2
;
417 tmp_ctx
= talloc_new(NULL
);
418 if (!tmp_ctx
) return WERR_NOMEM
;
420 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
422 DEBUG(3, ("ads_init() failed\n"));
423 return WERR_SERVER_UNAVAILABLE
;
425 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
426 SAFE_FREE(ads
->auth
.password
);
427 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
430 /* ads_connect() will find the DC for us */
431 ads_rc
= ads_connect(ads
);
432 if (!ADS_ERR_OK(ads_rc
)) {
433 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
434 result
= WERR_ACCESS_DENIED
;
438 status
= make_session_info_system(tmp_ctx
, &session_info
);
439 if (!NT_STATUS_IS_OK(status
)) {
440 DEBUG(0, ("check_published_printers: "
441 "Could not create system session_info\n"));
442 result
= WERR_ACCESS_DENIED
;
446 for (snum
= 0; snum
< n_services
; snum
++) {
447 if (!lp_snum_ok(snum
) || !lp_print_ok(snum
)) {
451 result
= winreg_get_printer_internal(tmp_ctx
, session_info
, msg_ctx
,
452 lp_servicename(talloc_tos(), snum
),
454 if (!W_ERROR_IS_OK(result
)) {
458 if (pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
) {
459 nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
468 ads_kdestroy("MEMORY:prtpub_cache");
469 talloc_free(tmp_ctx
);
473 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
474 const struct auth_session_info
*session_info
,
475 struct messaging_context
*msg_ctx
,
476 const char *servername
,
479 struct spoolss_PrinterInfo2
**info2
)
481 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
482 enum winreg_Type type
;
487 struct dcerpc_binding_handle
*b
;
489 result
= winreg_printer_binding_handle(mem_ctx
,
493 if (!W_ERROR_IS_OK(result
)) {
497 result
= winreg_get_printer(mem_ctx
, b
,
499 if (!W_ERROR_IS_OK(result
)) {
503 if (!(pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
)) {
512 /* fetching printer guids really ought to be a separate function. */
514 result
= winreg_get_printer_dataex(mem_ctx
, b
,
516 SPOOL_DSSPOOLER_KEY
, "objectGUID",
517 &type
, &data
, &data_size
);
518 if (!W_ERROR_IS_OK(result
)) {
523 /* We used to store the guid as REG_BINARY, then swapped
524 to REG_SZ for Vista compatibility so check for both */
528 status
= GUID_from_string((char *)data
, guid
);
529 if (!NT_STATUS_IS_OK(status
)) {
536 if (data_size
!= sizeof(struct GUID
)) {
540 memcpy(guid
, data
, sizeof(struct GUID
));
543 DEBUG(0,("is_printer_published: GUID value stored as "
544 "invaluid type (%d)\n", type
));
550 *info2
= talloc_move(mem_ctx
, &pinfo2
);
556 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
557 const struct auth_session_info
*session_info
,
558 struct messaging_context
*msg_ctx
,
559 struct spoolss_PrinterInfo2
*pinfo2
,
565 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
570 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
571 const struct auth_session_info
*session_info
,
572 struct messaging_context
*msg_ctx
,
573 const char *servername
,
576 struct spoolss_PrinterInfo2
**info2
)
580 #endif /* HAVE_ADS */