printing: explicitly clear PUBLISHED attribute
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing_ads.c
blob86ea8f7a8588aa8a953a54bad01a1b05b882ffde
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/spoolss/srv_spoolss_util.h"
25 #include "nt_printing.h"
26 #include "ads.h"
27 #include "secrets.h"
28 #include "krb5_env.h"
29 #include "../libcli/registry/util_reg.h"
30 #include "auth.h"
31 #include "../librpc/ndr/libndr.h"
32 #include "rpc_client/cli_winreg_spoolss.h"
34 #ifdef HAVE_ADS
35 /*****************************************************************
36 ****************************************************************/
38 static void store_printer_guid(struct messaging_context *msg_ctx,
39 const char *printer, struct GUID guid)
41 TALLOC_CTX *tmp_ctx;
42 struct auth_session_info *session_info = NULL;
43 const char *guid_str;
44 DATA_BLOB blob;
45 NTSTATUS status;
46 WERROR result;
48 tmp_ctx = talloc_new(NULL);
49 if (!tmp_ctx) {
50 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
51 return;
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"));
58 goto done;
61 guid_str = GUID_string(tmp_ctx, &guid);
62 if (!guid_str) {
63 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
64 goto done;
67 /* We used to store this as a REG_BINARY but that causes
68 Vista to whine */
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",
73 guid_str));
74 goto done;
77 result = winreg_set_printer_dataex_internal(tmp_ctx, session_info, msg_ctx,
78 printer,
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));
86 done:
87 talloc_free(tmp_ctx);
90 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
91 struct spoolss_PrinterInfo2 *info2,
92 ADS_MODLIST *mods)
94 char *info_str;
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) {
103 return WERR_NOMEM;
105 ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
107 info_str = talloc_asprintf(ctx, "%d", 4);
108 if (info_str == NULL) {
109 return WERR_NOMEM;
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) {
127 return WERR_NOMEM;
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) {
133 return WERR_NOMEM;
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) {
139 return WERR_NOMEM;
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");
145 } else {
146 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
149 switch (info2->attributes & 0x3) {
150 case 0:
151 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
152 SPOOL_REGVAL_PRINTWHILESPOOLING);
153 break;
154 case 1:
155 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
156 SPOOL_REGVAL_PRINTAFTERSPOOLED);
157 break;
158 case 2:
159 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
160 SPOOL_REGVAL_PRINTDIRECT);
161 break;
162 default:
163 DEBUG(3, ("unsupported printer attributes %x\n",
164 info2->attributes));
167 return WERR_OK;
170 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
171 ADS_STRUCT *ads,
172 struct spoolss_PrinterInfo2 *pinfo2)
174 ADS_STATUS ads_rc;
175 LDAPMessage *res;
176 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
177 char *srv_dn_utf8, **srv_cn_utf8;
178 TALLOC_CTX *ctx;
179 ADS_MODLIST mods;
180 const char *attrs[] = {"objectGUID", NULL};
181 struct GUID guid;
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");
188 if (ctx == NULL) {
189 return WERR_NOMEM;
192 DEBUG(5, ("publishing printer %s\n", printer));
194 /* figure out where to publish */
195 ads_rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
196 if (!ADS_ERR_OK(ads_rc)) {
197 DEBUG(0, ("failed to find machine account for %s\n",
198 lp_netbios_name()));
199 TALLOC_FREE(ctx);
200 return WERR_NOT_FOUND;
203 /* We use ldap_get_dn here as we need the answer
204 * in utf8 to call ldap_explode_dn(). JRA. */
206 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
207 ads_msgfree(ads, res);
208 if (!srv_dn_utf8) {
209 TALLOC_FREE(ctx);
210 return WERR_SERVER_UNAVAILABLE;
212 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
213 if (!srv_cn_utf8) {
214 TALLOC_FREE(ctx);
215 ldap_memfree(srv_dn_utf8);
216 return WERR_SERVER_UNAVAILABLE;
218 /* Now convert to CH_UNIX. */
219 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
220 TALLOC_FREE(ctx);
221 ldap_memfree(srv_dn_utf8);
222 ldap_memfree(srv_cn_utf8);
223 return WERR_SERVER_UNAVAILABLE;
225 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
226 TALLOC_FREE(ctx);
227 ldap_memfree(srv_dn_utf8);
228 ldap_memfree(srv_cn_utf8);
229 TALLOC_FREE(srv_dn);
230 return WERR_SERVER_UNAVAILABLE;
233 ldap_memfree(srv_dn_utf8);
234 ldap_memfree(srv_cn_utf8);
236 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
237 if (!srv_cn_escaped) {
238 TALLOC_FREE(ctx);
239 return WERR_SERVER_UNAVAILABLE;
241 sharename_escaped = escape_rdn_val_string_alloc(printer);
242 if (!sharename_escaped) {
243 SAFE_FREE(srv_cn_escaped);
244 TALLOC_FREE(ctx);
245 return WERR_SERVER_UNAVAILABLE;
248 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
250 SAFE_FREE(srv_cn_escaped);
251 SAFE_FREE(sharename_escaped);
253 mods = ads_init_mods(ctx);
255 if (mods == NULL) {
256 TALLOC_FREE(ctx);
257 return WERR_NOMEM;
260 win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
261 if (!W_ERROR_IS_OK(win_rc)) {
262 TALLOC_FREE(ctx);
263 return win_rc;
266 /* publish it */
267 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
268 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
269 int i;
270 for (i=0; mods[i] != 0; i++)
272 mods[i] = (LDAPMod *)-1;
273 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
276 if (!ADS_ERR_OK(ads_rc)) {
277 DEBUG(3, ("error publishing %s: %s\n",
278 printer, ads_errstr(ads_rc)));
281 /* retreive the guid and store it locally */
282 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
283 bool guid_ok;
284 ZERO_STRUCT(guid);
285 guid_ok = ads_pull_guid(ads, res, &guid);
286 ads_msgfree(ads, res);
287 if (guid_ok) {
288 store_printer_guid(msg_ctx, printer, guid);
291 TALLOC_FREE(ctx);
293 return win_rc;
296 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
297 const char *printer)
299 ADS_STATUS ads_rc;
300 LDAPMessage *res = NULL;
301 char *prt_dn = NULL;
303 DEBUG(5, ("unpublishing printer %s\n", printer));
305 /* remove the printer from the directory */
306 ads_rc = ads_find_printer_on_server(ads, &res,
307 printer, lp_netbios_name());
309 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
310 prt_dn = ads_get_dn(ads, talloc_tos(), res);
311 if (!prt_dn) {
312 ads_msgfree(ads, res);
313 return WERR_NOMEM;
315 ads_rc = ads_del_dn(ads, prt_dn);
316 TALLOC_FREE(prt_dn);
319 if (res) {
320 ads_msgfree(ads, res);
322 return WERR_OK;
325 /****************************************************************************
326 * Publish a printer in the directory
328 * @param mem_ctx memory context
329 * @param session_info session_info to access winreg pipe
330 * @param pinfo2 printer information
331 * @param action publish/unpublish action
332 * @return WERROR indicating status of publishing
333 ***************************************************************************/
335 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
336 const struct auth_session_info *session_info,
337 struct messaging_context *msg_ctx,
338 struct spoolss_PrinterInfo2 *pinfo2,
339 int action)
341 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
342 struct spoolss_SetPrinterInfo2 *sinfo2;
343 ADS_STATUS ads_rc;
344 ADS_STRUCT *ads = NULL;
345 WERROR win_rc;
347 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
348 if (!sinfo2) {
349 return WERR_NOMEM;
352 switch (action) {
353 case DSPRINT_PUBLISH:
354 case DSPRINT_UPDATE:
355 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
356 break;
357 case DSPRINT_UNPUBLISH:
358 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
359 break;
360 default:
361 win_rc = WERR_NOT_SUPPORTED;
362 goto done;
365 sinfo2->attributes = pinfo2->attributes;
367 win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
368 pinfo2->sharename, info2_mask,
369 sinfo2, NULL, NULL);
370 if (!W_ERROR_IS_OK(win_rc)) {
371 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
372 goto done;
375 TALLOC_FREE(sinfo2);
377 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
378 if (!ads) {
379 DEBUG(3, ("ads_init() failed\n"));
380 win_rc = WERR_SERVER_UNAVAILABLE;
381 goto done;
383 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
384 SAFE_FREE(ads->auth.password);
385 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
386 NULL, NULL);
388 /* ads_connect() will find the DC for us */
389 ads_rc = ads_connect(ads);
390 if (!ADS_ERR_OK(ads_rc)) {
391 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
392 win_rc = WERR_ACCESS_DENIED;
393 goto done;
396 switch (action) {
397 case DSPRINT_PUBLISH:
398 case DSPRINT_UPDATE:
399 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
400 break;
401 case DSPRINT_UNPUBLISH:
402 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
403 break;
406 done:
407 ads_destroy(&ads);
408 return win_rc;
411 WERROR check_published_printers(struct messaging_context *msg_ctx)
413 ADS_STATUS ads_rc;
414 ADS_STRUCT *ads = NULL;
415 int snum;
416 int n_services = lp_numservices();
417 TALLOC_CTX *tmp_ctx = NULL;
418 struct auth_session_info *session_info = NULL;
419 struct spoolss_PrinterInfo2 *pinfo2;
420 NTSTATUS status;
421 WERROR result;
423 tmp_ctx = talloc_new(NULL);
424 if (!tmp_ctx) return WERR_NOMEM;
426 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
427 if (!ads) {
428 DEBUG(3, ("ads_init() failed\n"));
429 return WERR_SERVER_UNAVAILABLE;
431 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
432 SAFE_FREE(ads->auth.password);
433 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
434 NULL, NULL);
436 /* ads_connect() will find the DC for us */
437 ads_rc = ads_connect(ads);
438 if (!ADS_ERR_OK(ads_rc)) {
439 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
440 result = WERR_ACCESS_DENIED;
441 goto done;
444 status = make_session_info_system(tmp_ctx, &session_info);
445 if (!NT_STATUS_IS_OK(status)) {
446 DEBUG(0, ("check_published_printers: "
447 "Could not create system session_info\n"));
448 result = WERR_ACCESS_DENIED;
449 goto done;
452 for (snum = 0; snum < n_services; snum++) {
453 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
454 continue;
457 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
458 lp_servicename(talloc_tos(), snum),
459 &pinfo2);
460 if (!W_ERROR_IS_OK(result)) {
461 continue;
464 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
465 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
468 TALLOC_FREE(pinfo2);
471 result = WERR_OK;
472 done:
473 ads_destroy(&ads);
474 ads_kdestroy("MEMORY:prtpub_cache");
475 talloc_free(tmp_ctx);
476 return result;
479 bool is_printer_published(TALLOC_CTX *mem_ctx,
480 const struct auth_session_info *session_info,
481 struct messaging_context *msg_ctx,
482 const char *servername,
483 const char *printer,
484 struct GUID *guid,
485 struct spoolss_PrinterInfo2 **info2)
487 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
488 enum winreg_Type type;
489 uint8_t *data;
490 uint32_t data_size;
491 WERROR result;
492 NTSTATUS status;
493 struct dcerpc_binding_handle *b;
495 result = winreg_printer_binding_handle(mem_ctx,
496 session_info,
497 msg_ctx,
498 &b);
499 if (!W_ERROR_IS_OK(result)) {
500 return false;
503 result = winreg_get_printer(mem_ctx, b,
504 printer, &pinfo2);
505 if (!W_ERROR_IS_OK(result)) {
506 return false;
509 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
510 TALLOC_FREE(pinfo2);
511 return false;
514 if (!guid) {
515 goto done;
518 /* fetching printer guids really ought to be a separate function. */
520 result = winreg_get_printer_dataex(mem_ctx, b,
521 printer,
522 SPOOL_DSSPOOLER_KEY, "objectGUID",
523 &type, &data, &data_size);
524 if (!W_ERROR_IS_OK(result)) {
525 TALLOC_FREE(pinfo2);
526 return false;
529 /* We used to store the guid as REG_BINARY, then swapped
530 to REG_SZ for Vista compatibility so check for both */
532 switch (type) {
533 case REG_SZ:
534 status = GUID_from_string((char *)data, guid);
535 if (!NT_STATUS_IS_OK(status)) {
536 TALLOC_FREE(pinfo2);
537 return false;
539 break;
541 case REG_BINARY:
542 if (data_size != sizeof(struct GUID)) {
543 TALLOC_FREE(pinfo2);
544 return false;
546 memcpy(guid, data, sizeof(struct GUID));
547 break;
548 default:
549 DEBUG(0,("is_printer_published: GUID value stored as "
550 "invaluid type (%d)\n", type));
551 break;
554 done:
555 if (info2) {
556 *info2 = talloc_move(mem_ctx, &pinfo2);
558 talloc_free(pinfo2);
559 return true;
561 #else
562 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
563 const struct auth_session_info *session_info,
564 struct messaging_context *msg_ctx,
565 struct spoolss_PrinterInfo2 *pinfo2,
566 int action)
568 return WERR_OK;
571 WERROR check_published_printers(struct messaging_context *msg_ctx)
573 return WERR_OK;
576 bool is_printer_published(TALLOC_CTX *mem_ctx,
577 const struct auth_session_info *session_info,
578 struct messaging_context *msg_ctx,
579 const char *servername,
580 const char *printer,
581 struct GUID *guid,
582 struct spoolss_PrinterInfo2 **info2)
584 return False;
586 #endif /* HAVE_ADS */