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"
33 /*****************************************************************
34 ****************************************************************/
36 static void store_printer_guid(struct messaging_context
*msg_ctx
,
37 const char *printer
, struct GUID guid
)
40 struct auth_serversupplied_info
*session_info
= NULL
;
46 tmp_ctx
= talloc_new(NULL
);
48 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
52 status
= make_session_info_system(tmp_ctx
, &session_info
);
53 if (!NT_STATUS_IS_OK(status
)) {
54 DEBUG(0, ("store_printer_guid: "
55 "Could not create system session_info\n"));
59 guid_str
= GUID_string(tmp_ctx
, &guid
);
61 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
65 /* We used to store this as a REG_BINARY but that causes
68 if (!push_reg_sz(tmp_ctx
, &blob
, guid_str
)) {
69 DEBUG(0, ("store_printer_guid: "
70 "Could not marshall string %s for objectGUID\n",
75 result
= winreg_set_printer_dataex(tmp_ctx
, session_info
, msg_ctx
,
77 SPOOL_DSSPOOLER_KEY
, "objectGUID",
78 REG_SZ
, blob
.data
, blob
.length
);
79 if (!W_ERROR_IS_OK(result
)) {
80 DEBUG(0, ("store_printer_guid: "
81 "Failed to store GUID for printer %s\n", printer
));
88 static WERROR
nt_printer_publish_ads(struct messaging_context
*msg_ctx
,
90 struct spoolss_PrinterInfo2
*pinfo2
)
94 char *prt_dn
= NULL
, *srv_dn
, *srv_cn_0
, *srv_cn_escaped
, *sharename_escaped
;
95 char *srv_dn_utf8
, **srv_cn_utf8
;
98 const char *attrs
[] = {"objectGUID", NULL
};
100 WERROR win_rc
= WERR_OK
;
101 size_t converted_size
;
102 const char *printer
= pinfo2
->sharename
;
104 /* build the ads mods */
105 ctx
= talloc_init("nt_printer_publish_ads");
110 DEBUG(5, ("publishing printer %s\n", printer
));
112 /* figure out where to publish */
113 ads_find_machine_acct(ads
, &res
, global_myname());
115 /* We use ldap_get_dn here as we need the answer
116 * in utf8 to call ldap_explode_dn(). JRA. */
118 srv_dn_utf8
= ldap_get_dn((LDAP
*)ads
->ldap
.ld
, (LDAPMessage
*)res
);
121 return WERR_SERVER_UNAVAILABLE
;
123 ads_msgfree(ads
, res
);
124 srv_cn_utf8
= ldap_explode_dn(srv_dn_utf8
, 1);
127 ldap_memfree(srv_dn_utf8
);
128 return WERR_SERVER_UNAVAILABLE
;
130 /* Now convert to CH_UNIX. */
131 if (!pull_utf8_talloc(ctx
, &srv_dn
, srv_dn_utf8
, &converted_size
)) {
133 ldap_memfree(srv_dn_utf8
);
134 ldap_memfree(srv_cn_utf8
);
135 return WERR_SERVER_UNAVAILABLE
;
137 if (!pull_utf8_talloc(ctx
, &srv_cn_0
, srv_cn_utf8
[0], &converted_size
)) {
139 ldap_memfree(srv_dn_utf8
);
140 ldap_memfree(srv_cn_utf8
);
142 return WERR_SERVER_UNAVAILABLE
;
145 ldap_memfree(srv_dn_utf8
);
146 ldap_memfree(srv_cn_utf8
);
148 srv_cn_escaped
= escape_rdn_val_string_alloc(srv_cn_0
);
149 if (!srv_cn_escaped
) {
151 return WERR_SERVER_UNAVAILABLE
;
153 sharename_escaped
= escape_rdn_val_string_alloc(printer
);
154 if (!sharename_escaped
) {
155 SAFE_FREE(srv_cn_escaped
);
157 return WERR_SERVER_UNAVAILABLE
;
160 prt_dn
= talloc_asprintf(ctx
, "cn=%s-%s,%s", srv_cn_escaped
, sharename_escaped
, srv_dn
);
162 SAFE_FREE(srv_cn_escaped
);
163 SAFE_FREE(sharename_escaped
);
165 mods
= ads_init_mods(ctx
);
173 ads_mod_str(ctx
, &mods
, SPOOL_REG_PRINTERNAME
, printer
);
176 ads_rc
= ads_mod_printer_entry(ads
, prt_dn
, ctx
, &mods
);
177 if (ads_rc
.err
.rc
== LDAP_NO_SUCH_OBJECT
) {
179 for (i
=0; mods
[i
] != 0; i
++)
181 mods
[i
] = (LDAPMod
*)-1;
182 ads_rc
= ads_add_printer_entry(ads
, prt_dn
, ctx
, &mods
);
185 if (!ADS_ERR_OK(ads_rc
)) {
186 DEBUG(3, ("error publishing %s: %s\n",
187 printer
, ads_errstr(ads_rc
)));
190 /* retreive the guid and store it locally */
191 if (ADS_ERR_OK(ads_search_dn(ads
, &res
, prt_dn
, attrs
))) {
194 guid_ok
= ads_pull_guid(ads
, res
, &guid
);
195 ads_msgfree(ads
, res
);
197 store_printer_guid(msg_ctx
, printer
, guid
);
205 static WERROR
nt_printer_unpublish_ads(ADS_STRUCT
*ads
,
209 LDAPMessage
*res
= NULL
;
212 DEBUG(5, ("unpublishing printer %s\n", printer
));
214 /* remove the printer from the directory */
215 ads_rc
= ads_find_printer_on_server(ads
, &res
,
216 printer
, global_myname());
218 if (ADS_ERR_OK(ads_rc
) && res
&& ads_count_replies(ads
, res
)) {
219 prt_dn
= ads_get_dn(ads
, talloc_tos(), res
);
221 ads_msgfree(ads
, res
);
224 ads_rc
= ads_del_dn(ads
, prt_dn
);
229 ads_msgfree(ads
, res
);
234 /****************************************************************************
235 * Publish a printer in the directory
237 * @param mem_ctx memory context
238 * @param session_info session_info to access winreg pipe
239 * @param pinfo2 printer information
240 * @param action publish/unpublish action
241 * @return WERROR indicating status of publishing
242 ***************************************************************************/
244 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
245 const struct auth_serversupplied_info
*session_info
,
246 struct messaging_context
*msg_ctx
,
247 struct spoolss_PrinterInfo2
*pinfo2
,
250 uint32_t info2_mask
= SPOOLSS_PRINTER_INFO_ATTRIBUTES
;
251 struct spoolss_SetPrinterInfo2
*sinfo2
;
253 ADS_STRUCT
*ads
= NULL
;
256 sinfo2
= talloc_zero(mem_ctx
, struct spoolss_SetPrinterInfo2
);
262 case DSPRINT_PUBLISH
:
264 pinfo2
->attributes
|= PRINTER_ATTRIBUTE_PUBLISHED
;
266 case DSPRINT_UNPUBLISH
:
267 pinfo2
->attributes
^= PRINTER_ATTRIBUTE_PUBLISHED
;
270 win_rc
= WERR_NOT_SUPPORTED
;
274 sinfo2
->attributes
= pinfo2
->attributes
;
276 win_rc
= winreg_update_printer(mem_ctx
, session_info
, msg_ctx
,
277 pinfo2
->sharename
, info2_mask
,
279 if (!W_ERROR_IS_OK(win_rc
)) {
280 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc
)));
286 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
288 DEBUG(3, ("ads_init() failed\n"));
289 win_rc
= WERR_SERVER_UNAVAILABLE
;
292 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
293 SAFE_FREE(ads
->auth
.password
);
294 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
297 /* ads_connect() will find the DC for us */
298 ads_rc
= ads_connect(ads
);
299 if (!ADS_ERR_OK(ads_rc
)) {
300 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
301 win_rc
= WERR_ACCESS_DENIED
;
306 case DSPRINT_PUBLISH
:
308 win_rc
= nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
310 case DSPRINT_UNPUBLISH
:
311 win_rc
= nt_printer_unpublish_ads(ads
, pinfo2
->sharename
);
320 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
323 ADS_STRUCT
*ads
= NULL
;
325 int n_services
= lp_numservices();
326 TALLOC_CTX
*tmp_ctx
= NULL
;
327 struct auth_serversupplied_info
*session_info
= NULL
;
328 struct spoolss_PrinterInfo2
*pinfo2
;
332 tmp_ctx
= talloc_new(NULL
);
333 if (!tmp_ctx
) return WERR_NOMEM
;
335 ads
= ads_init(lp_realm(), lp_workgroup(), NULL
);
337 DEBUG(3, ("ads_init() failed\n"));
338 return WERR_SERVER_UNAVAILABLE
;
340 setenv(KRB5_ENV_CCNAME
, "MEMORY:prtpub_cache", 1);
341 SAFE_FREE(ads
->auth
.password
);
342 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(),
345 /* ads_connect() will find the DC for us */
346 ads_rc
= ads_connect(ads
);
347 if (!ADS_ERR_OK(ads_rc
)) {
348 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc
)));
349 result
= WERR_ACCESS_DENIED
;
353 status
= make_session_info_system(tmp_ctx
, &session_info
);
354 if (!NT_STATUS_IS_OK(status
)) {
355 DEBUG(0, ("check_published_printers: "
356 "Could not create system session_info\n"));
357 result
= WERR_ACCESS_DENIED
;
361 for (snum
= 0; snum
< n_services
; snum
++) {
362 if (!lp_snum_ok(snum
) || !lp_print_ok(snum
)) {
366 result
= winreg_get_printer(tmp_ctx
, session_info
, msg_ctx
,
367 lp_servicename(snum
),
369 if (!W_ERROR_IS_OK(result
)) {
373 if (pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
) {
374 nt_printer_publish_ads(msg_ctx
, ads
, pinfo2
);
383 ads_kdestroy("MEMORY:prtpub_cache");
384 talloc_free(tmp_ctx
);
388 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
389 const struct auth_serversupplied_info
*session_info
,
390 struct messaging_context
*msg_ctx
,
391 const char *servername
, char *printer
, struct GUID
*guid
,
392 struct spoolss_PrinterInfo2
**info2
)
394 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
395 enum winreg_Type type
;
401 result
= winreg_get_printer(mem_ctx
, session_info
, msg_ctx
,
403 if (!W_ERROR_IS_OK(result
)) {
407 if (!(pinfo2
->attributes
& PRINTER_ATTRIBUTE_PUBLISHED
)) {
416 /* fetching printer guids really ought to be a separate function. */
418 result
= winreg_get_printer_dataex(mem_ctx
, session_info
, msg_ctx
,
420 SPOOL_DSSPOOLER_KEY
, "objectGUID",
421 &type
, &data
, &data_size
);
422 if (!W_ERROR_IS_OK(result
)) {
427 /* We used to store the guid as REG_BINARY, then swapped
428 to REG_SZ for Vista compatibility so check for both */
432 status
= GUID_from_string((char *)data
, guid
);
433 if (!NT_STATUS_IS_OK(status
)) {
440 if (data_size
!= sizeof(struct GUID
)) {
444 memcpy(guid
, data
, sizeof(struct GUID
));
447 DEBUG(0,("is_printer_published: GUID value stored as "
448 "invaluid type (%d)\n", type
));
454 *info2
= talloc_move(mem_ctx
, &pinfo2
);
460 WERROR
nt_printer_publish(TALLOC_CTX
*mem_ctx
,
461 const struct auth_serversupplied_info
*session_info
,
462 struct messaging_context
*msg_ctx
,
463 struct spoolss_PrinterInfo2
*pinfo2
,
469 WERROR
check_published_printers(struct messaging_context
*msg_ctx
)
474 bool is_printer_published(TALLOC_CTX
*mem_ctx
,
475 const struct auth_serversupplied_info
*session_info
,
476 struct messaging_context
*msg_ctx
,
477 const char *servername
, char *printer
, struct GUID
*guid
,
478 struct spoolss_PrinterInfo2
**info2
)
482 #endif /* HAVE_ADS */