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"
32 /*****************************************************************
33 ****************************************************************/
35 static void store_printer_guid(struct messaging_context *msg_ctx,
36 const char *printer, struct GUID guid)
39 struct auth_serversupplied_info *session_info = NULL;
45 tmp_ctx = talloc_new(NULL);
47 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
51 status = make_session_info_system(tmp_ctx, &session_info);
52 if (!NT_STATUS_IS_OK(status)) {
53 DEBUG(0, ("store_printer_guid: "
54 "Could not create system session_info\n"));
58 guid_str = GUID_string(tmp_ctx, &guid);
60 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
64 /* We used to store this as a REG_BINARY but that causes
67 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
68 DEBUG(0, ("store_printer_guid: "
69 "Could not marshall string %s for objectGUID\n",
74 result = winreg_set_printer_dataex(tmp_ctx, session_info, msg_ctx,
76 SPOOL_DSSPOOLER_KEY, "objectGUID",
77 REG_SZ, blob.data, blob.length);
78 if (!W_ERROR_IS_OK(result)) {
79 DEBUG(0, ("store_printer_guid: "
80 "Failed to store GUID for printer %s\n", printer));
87 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
89 struct spoolss_PrinterInfo2 *pinfo2)
93 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
94 char *srv_dn_utf8, **srv_cn_utf8;
97 const char *attrs[] = {"objectGUID", NULL};
99 WERROR win_rc = WERR_OK;
100 size_t converted_size;
101 const char *printer = pinfo2->sharename;
103 /* build the ads mods */
104 ctx = talloc_init("nt_printer_publish_ads");
109 DEBUG(5, ("publishing printer %s\n", printer));
111 /* figure out where to publish */
112 ads_find_machine_acct(ads, &res, global_myname());
114 /* We use ldap_get_dn here as we need the answer
115 * in utf8 to call ldap_explode_dn(). JRA. */
117 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
120 return WERR_SERVER_UNAVAILABLE;
122 ads_msgfree(ads, res);
123 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
126 ldap_memfree(srv_dn_utf8);
127 return WERR_SERVER_UNAVAILABLE;
129 /* Now convert to CH_UNIX. */
130 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
132 ldap_memfree(srv_dn_utf8);
133 ldap_memfree(srv_cn_utf8);
134 return WERR_SERVER_UNAVAILABLE;
136 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
138 ldap_memfree(srv_dn_utf8);
139 ldap_memfree(srv_cn_utf8);
141 return WERR_SERVER_UNAVAILABLE;
144 ldap_memfree(srv_dn_utf8);
145 ldap_memfree(srv_cn_utf8);
147 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
148 if (!srv_cn_escaped) {
150 return WERR_SERVER_UNAVAILABLE;
152 sharename_escaped = escape_rdn_val_string_alloc(printer);
153 if (!sharename_escaped) {
154 SAFE_FREE(srv_cn_escaped);
156 return WERR_SERVER_UNAVAILABLE;
159 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
161 SAFE_FREE(srv_cn_escaped);
162 SAFE_FREE(sharename_escaped);
164 mods = ads_init_mods(ctx);
172 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
175 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
176 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
178 for (i=0; mods[i] != 0; i++)
180 mods[i] = (LDAPMod *)-1;
181 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
184 if (!ADS_ERR_OK(ads_rc)) {
185 DEBUG(3, ("error publishing %s: %s\n",
186 printer, ads_errstr(ads_rc)));
189 /* retreive the guid and store it locally */
190 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
193 guid_ok = ads_pull_guid(ads, res, &guid);
194 ads_msgfree(ads, res);
196 store_printer_guid(msg_ctx, printer, guid);
204 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
208 LDAPMessage *res = NULL;
211 DEBUG(5, ("unpublishing printer %s\n", printer));
213 /* remove the printer from the directory */
214 ads_rc = ads_find_printer_on_server(ads, &res,
215 printer, global_myname());
217 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
218 prt_dn = ads_get_dn(ads, talloc_tos(), res);
220 ads_msgfree(ads, res);
223 ads_rc = ads_del_dn(ads, prt_dn);
228 ads_msgfree(ads, res);
233 /****************************************************************************
234 * Publish a printer in the directory
236 * @param mem_ctx memory context
237 * @param session_info session_info to access winreg pipe
238 * @param pinfo2 printer information
239 * @param action publish/unpublish action
240 * @return WERROR indicating status of publishing
241 ***************************************************************************/
243 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
244 const struct auth_serversupplied_info *session_info,
245 struct messaging_context *msg_ctx,
246 struct spoolss_PrinterInfo2 *pinfo2,
249 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
250 struct spoolss_SetPrinterInfo2 *sinfo2;
252 ADS_STRUCT *ads = NULL;
255 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
261 case DSPRINT_PUBLISH:
263 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
265 case DSPRINT_UNPUBLISH:
266 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
269 win_rc = WERR_NOT_SUPPORTED;
273 sinfo2->attributes = pinfo2->attributes;
275 win_rc = winreg_update_printer(mem_ctx, session_info, msg_ctx,
276 pinfo2->sharename, info2_mask,
278 if (!W_ERROR_IS_OK(win_rc)) {
279 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
285 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
287 DEBUG(3, ("ads_init() failed\n"));
288 win_rc = WERR_SERVER_UNAVAILABLE;
291 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
292 SAFE_FREE(ads->auth.password);
293 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
296 /* ads_connect() will find the DC for us */
297 ads_rc = ads_connect(ads);
298 if (!ADS_ERR_OK(ads_rc)) {
299 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
300 win_rc = WERR_ACCESS_DENIED;
305 case DSPRINT_PUBLISH:
307 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
309 case DSPRINT_UNPUBLISH:
310 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
319 WERROR check_published_printers(struct messaging_context *msg_ctx)
322 ADS_STRUCT *ads = NULL;
324 int n_services = lp_numservices();
325 TALLOC_CTX *tmp_ctx = NULL;
326 struct auth_serversupplied_info *session_info = NULL;
327 struct spoolss_PrinterInfo2 *pinfo2;
331 tmp_ctx = talloc_new(NULL);
332 if (!tmp_ctx) return WERR_NOMEM;
334 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
336 DEBUG(3, ("ads_init() failed\n"));
337 return WERR_SERVER_UNAVAILABLE;
339 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
340 SAFE_FREE(ads->auth.password);
341 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
344 /* ads_connect() will find the DC for us */
345 ads_rc = ads_connect(ads);
346 if (!ADS_ERR_OK(ads_rc)) {
347 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
348 result = WERR_ACCESS_DENIED;
352 status = make_session_info_system(tmp_ctx, &session_info);
353 if (!NT_STATUS_IS_OK(status)) {
354 DEBUG(0, ("check_published_printers: "
355 "Could not create system session_info\n"));
356 result = WERR_ACCESS_DENIED;
360 for (snum = 0; snum < n_services; snum++) {
361 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
365 result = winreg_get_printer(tmp_ctx, session_info, msg_ctx,
366 lp_servicename(snum),
368 if (!W_ERROR_IS_OK(result)) {
372 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
373 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
382 ads_kdestroy("MEMORY:prtpub_cache");
383 talloc_free(tmp_ctx);
387 bool is_printer_published(TALLOC_CTX *mem_ctx,
388 const struct auth_serversupplied_info *session_info,
389 struct messaging_context *msg_ctx,
390 const char *servername, char *printer, struct GUID *guid,
391 struct spoolss_PrinterInfo2 **info2)
393 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
394 enum winreg_Type type;
400 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
402 if (!W_ERROR_IS_OK(result)) {
406 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
415 /* fetching printer guids really ought to be a separate function. */
417 result = winreg_get_printer_dataex(mem_ctx, session_info, msg_ctx,
419 SPOOL_DSSPOOLER_KEY, "objectGUID",
420 &type, &data, &data_size);
421 if (!W_ERROR_IS_OK(result)) {
426 /* We used to store the guid as REG_BINARY, then swapped
427 to REG_SZ for Vista compatibility so check for both */
431 status = GUID_from_string((char *)data, guid);
432 if (!NT_STATUS_IS_OK(status)) {
439 if (data_size != sizeof(struct GUID)) {
443 memcpy(guid, data, sizeof(struct GUID));
446 DEBUG(0,("is_printer_published: GUID value stored as "
447 "invaluid type (%d)\n", type));
453 *info2 = talloc_move(mem_ctx, &pinfo2);
459 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
460 const struct auth_serversupplied_info *session_info,
461 struct messaging_context *msg_ctx,
462 struct spoolss_PrinterInfo2 *pinfo2,
468 WERROR check_published_printers(struct messaging_context *msg_ctx)
473 bool is_printer_published(TALLOC_CTX *mem_ctx,
474 const struct auth_serversupplied_info *session_info,
475 struct messaging_context *msg_ctx,
476 const char *servername, char *printer, struct GUID *guid,
477 struct spoolss_PrinterInfo2 **info2)
481 #endif /* HAVE_ADS */