s3: Lift the smbd_messaging_context from check_published_printers
[Samba/gbeck.git] / source3 / printing / nt_printing_ads.c
blobf0d568b8bf04bfe0a3ed415497d919580ba25ece
1 /*
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/>.
22 #include "includes.h"
23 #include "../librpc/gen_ndr/spoolss.h"
24 #include "rpc_server/srv_spoolss_util.h"
25 #include "nt_printing.h"
26 #include "ads.h"
27 #include "secrets.h"
29 #ifdef HAVE_ADS
30 /*****************************************************************
31 ****************************************************************/
33 static void store_printer_guid(struct messaging_context *msg_ctx,
34 const char *printer, struct GUID guid)
36 TALLOC_CTX *tmp_ctx;
37 struct auth_serversupplied_info *server_info = NULL;
38 const char *guid_str;
39 DATA_BLOB blob;
40 NTSTATUS status;
41 WERROR result;
43 tmp_ctx = talloc_new(NULL);
44 if (!tmp_ctx) {
45 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
46 return;
49 status = make_server_info_system(tmp_ctx, &server_info);
50 if (!NT_STATUS_IS_OK(status)) {
51 DEBUG(0, ("store_printer_guid: "
52 "Could not create system server_info\n"));
53 goto done;
56 guid_str = GUID_string(tmp_ctx, &guid);
57 if (!guid_str) {
58 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
59 goto done;
62 /* We used to store this as a REG_BINARY but that causes
63 Vista to whine */
65 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
66 DEBUG(0, ("store_printer_guid: "
67 "Could not marshall string %s for objectGUID\n",
68 guid_str));
69 goto done;
72 result = winreg_set_printer_dataex(tmp_ctx, server_info, msg_ctx,
73 printer,
74 SPOOL_DSSPOOLER_KEY, "objectGUID",
75 REG_SZ, blob.data, blob.length);
76 if (!W_ERROR_IS_OK(result)) {
77 DEBUG(0, ("store_printer_guid: "
78 "Failed to store GUID for printer %s\n", printer));
81 done:
82 talloc_free(tmp_ctx);
85 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
86 ADS_STRUCT *ads,
87 struct spoolss_PrinterInfo2 *pinfo2)
89 ADS_STATUS ads_rc;
90 LDAPMessage *res;
91 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
92 char *srv_dn_utf8, **srv_cn_utf8;
93 TALLOC_CTX *ctx;
94 ADS_MODLIST mods;
95 const char *attrs[] = {"objectGUID", NULL};
96 struct GUID guid;
97 WERROR win_rc = WERR_OK;
98 size_t converted_size;
99 const char *printer = pinfo2->sharename;
101 /* build the ads mods */
102 ctx = talloc_init("nt_printer_publish_ads");
103 if (ctx == NULL) {
104 return WERR_NOMEM;
107 DEBUG(5, ("publishing printer %s\n", printer));
109 /* figure out where to publish */
110 ads_find_machine_acct(ads, &res, global_myname());
112 /* We use ldap_get_dn here as we need the answer
113 * in utf8 to call ldap_explode_dn(). JRA. */
115 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
116 if (!srv_dn_utf8) {
117 TALLOC_FREE(ctx);
118 return WERR_SERVER_UNAVAILABLE;
120 ads_msgfree(ads, res);
121 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
122 if (!srv_cn_utf8) {
123 TALLOC_FREE(ctx);
124 ldap_memfree(srv_dn_utf8);
125 return WERR_SERVER_UNAVAILABLE;
127 /* Now convert to CH_UNIX. */
128 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
129 TALLOC_FREE(ctx);
130 ldap_memfree(srv_dn_utf8);
131 ldap_memfree(srv_cn_utf8);
132 return WERR_SERVER_UNAVAILABLE;
134 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
135 TALLOC_FREE(ctx);
136 ldap_memfree(srv_dn_utf8);
137 ldap_memfree(srv_cn_utf8);
138 TALLOC_FREE(srv_dn);
139 return WERR_SERVER_UNAVAILABLE;
142 ldap_memfree(srv_dn_utf8);
143 ldap_memfree(srv_cn_utf8);
145 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
146 if (!srv_cn_escaped) {
147 TALLOC_FREE(ctx);
148 return WERR_SERVER_UNAVAILABLE;
150 sharename_escaped = escape_rdn_val_string_alloc(printer);
151 if (!sharename_escaped) {
152 SAFE_FREE(srv_cn_escaped);
153 TALLOC_FREE(ctx);
154 return WERR_SERVER_UNAVAILABLE;
157 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
159 SAFE_FREE(srv_cn_escaped);
160 SAFE_FREE(sharename_escaped);
162 mods = ads_init_mods(ctx);
164 if (mods == NULL) {
165 SAFE_FREE(prt_dn);
166 TALLOC_FREE(ctx);
167 return WERR_NOMEM;
170 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
172 /* publish it */
173 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
174 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
175 int i;
176 for (i=0; mods[i] != 0; i++)
178 mods[i] = (LDAPMod *)-1;
179 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
182 if (!ADS_ERR_OK(ads_rc)) {
183 DEBUG(3, ("error publishing %s: %s\n",
184 printer, ads_errstr(ads_rc)));
187 /* retreive the guid and store it locally */
188 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
189 ZERO_STRUCT(guid);
190 ads_pull_guid(ads, res, &guid);
191 ads_msgfree(ads, res);
192 store_printer_guid(msg_ctx, printer, guid);
194 TALLOC_FREE(ctx);
196 return win_rc;
199 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
200 const char *printer)
202 ADS_STATUS ads_rc;
203 LDAPMessage *res = NULL;
204 char *prt_dn = NULL;
206 DEBUG(5, ("unpublishing printer %s\n", printer));
208 /* remove the printer from the directory */
209 ads_rc = ads_find_printer_on_server(ads, &res,
210 printer, global_myname());
212 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
213 prt_dn = ads_get_dn(ads, talloc_tos(), res);
214 if (!prt_dn) {
215 ads_msgfree(ads, res);
216 return WERR_NOMEM;
218 ads_rc = ads_del_dn(ads, prt_dn);
219 TALLOC_FREE(prt_dn);
222 if (res) {
223 ads_msgfree(ads, res);
225 return WERR_OK;
228 /****************************************************************************
229 * Publish a printer in the directory
231 * @param mem_ctx memory context
232 * @param server_info server_info to access winreg pipe
233 * @param pinfo2 printer information
234 * @param action publish/unpublish action
235 * @return WERROR indicating status of publishing
236 ***************************************************************************/
238 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
239 struct auth_serversupplied_info *server_info,
240 struct messaging_context *msg_ctx,
241 struct spoolss_PrinterInfo2 *pinfo2,
242 int action)
244 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
245 struct spoolss_SetPrinterInfo2 *sinfo2;
246 ADS_STATUS ads_rc;
247 ADS_STRUCT *ads = NULL;
248 WERROR win_rc;
250 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
251 if (!sinfo2) {
252 return WERR_NOMEM;
255 switch (action) {
256 case DSPRINT_PUBLISH:
257 case DSPRINT_UPDATE:
258 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
259 break;
260 case DSPRINT_UNPUBLISH:
261 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
262 break;
263 default:
264 win_rc = WERR_NOT_SUPPORTED;
265 goto done;
268 sinfo2->attributes = pinfo2->attributes;
270 win_rc = winreg_update_printer(mem_ctx, server_info, msg_ctx,
271 pinfo2->sharename, info2_mask,
272 sinfo2, NULL, NULL);
273 if (!W_ERROR_IS_OK(win_rc)) {
274 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
275 goto done;
278 TALLOC_FREE(sinfo2);
280 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
281 if (!ads) {
282 DEBUG(3, ("ads_init() failed\n"));
283 win_rc = WERR_SERVER_UNAVAILABLE;
284 goto done;
286 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
287 SAFE_FREE(ads->auth.password);
288 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
289 NULL, NULL);
291 /* ads_connect() will find the DC for us */
292 ads_rc = ads_connect(ads);
293 if (!ADS_ERR_OK(ads_rc)) {
294 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
295 win_rc = WERR_ACCESS_DENIED;
296 goto done;
299 switch (action) {
300 case DSPRINT_PUBLISH:
301 case DSPRINT_UPDATE:
302 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
303 break;
304 case DSPRINT_UNPUBLISH:
305 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
306 break;
309 done:
310 ads_destroy(&ads);
311 return win_rc;
314 WERROR check_published_printers(struct messaging_context *msg_ctx)
316 ADS_STATUS ads_rc;
317 ADS_STRUCT *ads = NULL;
318 int snum;
319 int n_services = lp_numservices();
320 TALLOC_CTX *tmp_ctx = NULL;
321 struct auth_serversupplied_info *server_info = NULL;
322 struct spoolss_PrinterInfo2 *pinfo2;
323 NTSTATUS status;
324 WERROR result;
326 tmp_ctx = talloc_new(NULL);
327 if (!tmp_ctx) return WERR_NOMEM;
329 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
330 if (!ads) {
331 DEBUG(3, ("ads_init() failed\n"));
332 return WERR_SERVER_UNAVAILABLE;
334 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
335 SAFE_FREE(ads->auth.password);
336 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
337 NULL, NULL);
339 /* ads_connect() will find the DC for us */
340 ads_rc = ads_connect(ads);
341 if (!ADS_ERR_OK(ads_rc)) {
342 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
343 result = WERR_ACCESS_DENIED;
344 goto done;
347 status = make_server_info_system(tmp_ctx, &server_info);
348 if (!NT_STATUS_IS_OK(status)) {
349 DEBUG(0, ("check_published_printers: "
350 "Could not create system server_info\n"));
351 result = WERR_ACCESS_DENIED;
352 goto done;
355 for (snum = 0; snum < n_services; snum++) {
356 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
357 continue;
360 result = winreg_get_printer(tmp_ctx, server_info, msg_ctx,
361 NULL, lp_servicename(snum),
362 &pinfo2);
363 if (!W_ERROR_IS_OK(result)) {
364 continue;
367 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
368 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
371 TALLOC_FREE(pinfo2);
374 result = WERR_OK;
375 done:
376 ads_destroy(&ads);
377 ads_kdestroy("MEMORY:prtpub_cache");
378 talloc_free(tmp_ctx);
379 return result;
382 bool is_printer_published(TALLOC_CTX *mem_ctx,
383 struct auth_serversupplied_info *server_info,
384 char *servername, char *printer, struct GUID *guid,
385 struct spoolss_PrinterInfo2 **info2)
387 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
388 enum winreg_Type type;
389 uint8_t *data;
390 uint32_t data_size;
391 WERROR result;
392 NTSTATUS status;
394 result = winreg_get_printer(mem_ctx, server_info,
395 smbd_messaging_context(),
396 servername, printer, &pinfo2);
397 if (!W_ERROR_IS_OK(result)) {
398 return false;
401 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
402 TALLOC_FREE(pinfo2);
403 return false;
406 if (!guid) {
407 goto done;
410 /* fetching printer guids really ought to be a separate function. */
412 result = winreg_get_printer_dataex(mem_ctx, server_info,
413 smbd_messaging_context(), printer,
414 SPOOL_DSSPOOLER_KEY, "objectGUID",
415 &type, &data, &data_size);
416 if (!W_ERROR_IS_OK(result)) {
417 TALLOC_FREE(pinfo2);
418 return false;
421 /* We used to store the guid as REG_BINARY, then swapped
422 to REG_SZ for Vista compatibility so check for both */
424 switch (type) {
425 case REG_SZ:
426 status = GUID_from_string((char *)data, guid);
427 if (!NT_STATUS_IS_OK(status)) {
428 TALLOC_FREE(pinfo2);
429 return false;
431 break;
433 case REG_BINARY:
434 if (data_size != sizeof(struct GUID)) {
435 TALLOC_FREE(pinfo2);
436 return false;
438 memcpy(guid, data, sizeof(struct GUID));
439 break;
440 default:
441 DEBUG(0,("is_printer_published: GUID value stored as "
442 "invaluid type (%d)\n", type));
443 break;
446 done:
447 if (info2) {
448 *info2 = talloc_move(mem_ctx, &pinfo2);
450 talloc_free(pinfo2);
451 return true;
453 #else
454 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
455 struct auth_serversupplied_info *server_info,
456 struct spoolss_PrinterInfo2 *pinfo2,
457 int action)
459 return WERR_OK;
462 WERROR check_published_printers(void)
464 return WERR_OK;
467 bool is_printer_published(TALLOC_CTX *mem_ctx,
468 struct auth_serversupplied_info *server_info,
469 char *servername, char *printer, struct GUID *guid,
470 struct spoolss_PrinterInfo2 **info2)
472 return False;
474 #endif /* HAVE_ADS */