source: trunk/server/source3/printing/nt_printing_ads.c

Last change on this file was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 16.1 KB
Line 
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.
7 *
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.
12 *
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.
17 *
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/>.
20 */
21
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"
33
34#ifdef HAVE_ADS
35/*****************************************************************
36 ****************************************************************/
37
38static void store_printer_guid(struct messaging_context *msg_ctx,
39 const char *printer, struct GUID guid)
40{
41 TALLOC_CTX *tmp_ctx;
42 struct auth_serversupplied_info *session_info = NULL;
43 const char *guid_str;
44 DATA_BLOB blob;
45 NTSTATUS status;
46 WERROR result;
47
48 tmp_ctx = talloc_new(NULL);
49 if (!tmp_ctx) {
50 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
51 return;
52 }
53
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;
59 }
60
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;
65 }
66
67 /* We used to store this as a REG_BINARY but that causes
68 Vista to whine */
69
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;
75 }
76
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));
84 }
85
86done:
87 talloc_free(tmp_ctx);
88}
89
90WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
91 const struct auth_serversupplied_info *session_info,
92 struct messaging_context *msg_ctx,
93 const char *printer, struct GUID *guid)
94{
95 TALLOC_CTX *tmp_ctx;
96 enum winreg_Type type;
97 DATA_BLOB blob;
98 uint32_t len;
99 NTSTATUS status;
100 WERROR result;
101
102 tmp_ctx = talloc_new(mem_ctx);
103 if (tmp_ctx == NULL) {
104 DEBUG(0, ("out of memory?!\n"));
105 return WERR_NOMEM;
106 }
107
108 result = winreg_get_printer_dataex_internal(tmp_ctx, session_info,
109 msg_ctx, printer,
110 SPOOL_DSSPOOLER_KEY,
111 "objectGUID",
112 &type,
113 &blob.data,
114 &len);
115 if (!W_ERROR_IS_OK(result)) {
116 DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
117 goto out_ctx_free;
118 }
119 blob.length = (size_t)len;
120
121 /* We used to store the guid as REG_BINARY, then swapped
122 to REG_SZ for Vista compatibility so check for both */
123
124 switch (type) {
125 case REG_SZ: {
126 bool ok;
127 const char *guid_str;
128 ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
129 if (!ok) {
130 DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
131 printer));
132 result = WERR_REG_CORRUPT;
133 goto out_ctx_free;
134 }
135 status = GUID_from_string(guid_str, guid);
136 if (!NT_STATUS_IS_OK(status)) {
137 DEBUG(0, ("bad GUID for printer %s\n", printer));
138 result = ntstatus_to_werror(status);
139 goto out_ctx_free;
140 }
141 break;
142 }
143 case REG_BINARY:
144 if (blob.length != sizeof(struct GUID)) {
145 DEBUG(0, ("bad GUID for printer %s\n", printer));
146 result = WERR_REG_CORRUPT;
147 goto out_ctx_free;
148 }
149 memcpy(guid, blob.data, sizeof(struct GUID));
150 break;
151 default:
152 DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
153 result = WERR_REG_CORRUPT;
154 goto out_ctx_free;
155 break;
156 }
157 result = WERR_OK;
158
159out_ctx_free:
160 talloc_free(tmp_ctx);
161 return result;
162}
163
164static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
165 struct spoolss_PrinterInfo2 *info2,
166 ADS_MODLIST *mods)
167{
168 char *info_str;
169
170 ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
171 ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, global_myname());
172 ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
173
174 info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
175 get_mydnsfullname(), info2->sharename);
176 if (info_str == NULL) {
177 return WERR_NOMEM;
178 }
179 ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
180
181 info_str = talloc_asprintf(ctx, "%d", 4);
182 if (info_str == NULL) {
183 return WERR_NOMEM;
184 }
185 ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
186
187 /* empty strings in the mods list result in an attrubute error */
188 if (strlen(info2->drivername) != 0)
189 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
190 if (strlen(info2->location) != 0)
191 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
192 if (strlen(info2->comment) != 0)
193 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
194 if (strlen(info2->portname) != 0)
195 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
196 if (strlen(info2->sepfile) != 0)
197 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
198
199 info_str = talloc_asprintf(ctx, "%u", info2->starttime);
200 if (info_str == NULL) {
201 return WERR_NOMEM;
202 }
203 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
204
205 info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
206 if (info_str == NULL) {
207 return WERR_NOMEM;
208 }
209 ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
210
211 info_str = talloc_asprintf(ctx, "%u", info2->priority);
212 if (info_str == NULL) {
213 return WERR_NOMEM;
214 }
215 ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
216
217 if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
218 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
219 } else {
220 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
221 }
222
223 switch (info2->attributes & 0x3) {
224 case 0:
225 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
226 SPOOL_REGVAL_PRINTWHILESPOOLING);
227 break;
228 case 1:
229 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
230 SPOOL_REGVAL_PRINTAFTERSPOOLED);
231 break;
232 case 2:
233 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
234 SPOOL_REGVAL_PRINTDIRECT);
235 break;
236 default:
237 DEBUG(3, ("unsupported printer attributes %x\n",
238 info2->attributes));
239 }
240
241 return WERR_OK;
242}
243
244static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
245 ADS_STRUCT *ads,
246 struct spoolss_PrinterInfo2 *pinfo2)
247{
248 ADS_STATUS ads_rc;
249 LDAPMessage *res;
250 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
251 char *srv_dn_utf8, **srv_cn_utf8;
252 TALLOC_CTX *ctx;
253 ADS_MODLIST mods;
254 const char *attrs[] = {"objectGUID", NULL};
255 struct GUID guid;
256 WERROR win_rc = WERR_OK;
257 size_t converted_size;
258 const char *printer = pinfo2->sharename;
259
260 /* build the ads mods */
261 ctx = talloc_init("nt_printer_publish_ads");
262 if (ctx == NULL) {
263 return WERR_NOMEM;
264 }
265
266 DEBUG(5, ("publishing printer %s\n", printer));
267
268 /* figure out where to publish */
269 ads_rc = ads_find_machine_acct(ads, &res, global_myname());
270 if (!ADS_ERR_OK(ads_rc)) {
271 DEBUG(0, ("failed to find machine account for %s\n",
272 global_myname()));
273 TALLOC_FREE(ctx);
274 return WERR_NOT_FOUND;
275 }
276
277 /* We use ldap_get_dn here as we need the answer
278 * in utf8 to call ldap_explode_dn(). JRA. */
279
280 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
281 ads_msgfree(ads, res);
282 if (!srv_dn_utf8) {
283 TALLOC_FREE(ctx);
284 return WERR_SERVER_UNAVAILABLE;
285 }
286 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
287 if (!srv_cn_utf8) {
288 TALLOC_FREE(ctx);
289 ldap_memfree(srv_dn_utf8);
290 return WERR_SERVER_UNAVAILABLE;
291 }
292 /* Now convert to CH_UNIX. */
293 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
294 TALLOC_FREE(ctx);
295 ldap_memfree(srv_dn_utf8);
296 ldap_memfree(srv_cn_utf8);
297 return WERR_SERVER_UNAVAILABLE;
298 }
299 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
300 TALLOC_FREE(ctx);
301 ldap_memfree(srv_dn_utf8);
302 ldap_memfree(srv_cn_utf8);
303 TALLOC_FREE(srv_dn);
304 return WERR_SERVER_UNAVAILABLE;
305 }
306
307 ldap_memfree(srv_dn_utf8);
308 ldap_memfree(srv_cn_utf8);
309
310 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
311 if (!srv_cn_escaped) {
312 TALLOC_FREE(ctx);
313 return WERR_SERVER_UNAVAILABLE;
314 }
315 sharename_escaped = escape_rdn_val_string_alloc(printer);
316 if (!sharename_escaped) {
317 SAFE_FREE(srv_cn_escaped);
318 TALLOC_FREE(ctx);
319 return WERR_SERVER_UNAVAILABLE;
320 }
321
322 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
323
324 SAFE_FREE(srv_cn_escaped);
325 SAFE_FREE(sharename_escaped);
326
327 mods = ads_init_mods(ctx);
328
329 if (mods == NULL) {
330 TALLOC_FREE(ctx);
331 return WERR_NOMEM;
332 }
333
334 win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
335 if (!W_ERROR_IS_OK(win_rc)) {
336 TALLOC_FREE(ctx);
337 return win_rc;
338 }
339
340 /* publish it */
341 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
342 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
343 int i;
344 for (i=0; mods[i] != 0; i++)
345 ;
346 mods[i] = (LDAPMod *)-1;
347 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
348 }
349
350 if (!ADS_ERR_OK(ads_rc)) {
351 DEBUG(3, ("error publishing %s: %s\n",
352 printer, ads_errstr(ads_rc)));
353 }
354
355 /* retreive the guid and store it locally */
356 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
357 bool guid_ok;
358 ZERO_STRUCT(guid);
359 guid_ok = ads_pull_guid(ads, res, &guid);
360 ads_msgfree(ads, res);
361 if (guid_ok) {
362 store_printer_guid(msg_ctx, printer, guid);
363 }
364 }
365 TALLOC_FREE(ctx);
366
367 return win_rc;
368}
369
370static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
371 const char *printer)
372{
373 ADS_STATUS ads_rc;
374 LDAPMessage *res = NULL;
375 char *prt_dn = NULL;
376
377 DEBUG(5, ("unpublishing printer %s\n", printer));
378
379 /* remove the printer from the directory */
380 ads_rc = ads_find_printer_on_server(ads, &res,
381 printer, global_myname());
382
383 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
384 prt_dn = ads_get_dn(ads, talloc_tos(), res);
385 if (!prt_dn) {
386 ads_msgfree(ads, res);
387 return WERR_NOMEM;
388 }
389 ads_rc = ads_del_dn(ads, prt_dn);
390 TALLOC_FREE(prt_dn);
391 }
392
393 if (res) {
394 ads_msgfree(ads, res);
395 }
396 return WERR_OK;
397}
398
399/****************************************************************************
400 * Publish a printer in the directory
401 *
402 * @param mem_ctx memory context
403 * @param session_info session_info to access winreg pipe
404 * @param pinfo2 printer information
405 * @param action publish/unpublish action
406 * @return WERROR indicating status of publishing
407 ***************************************************************************/
408
409WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
410 const struct auth_serversupplied_info *session_info,
411 struct messaging_context *msg_ctx,
412 struct spoolss_PrinterInfo2 *pinfo2,
413 int action)
414{
415 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
416 struct spoolss_SetPrinterInfo2 *sinfo2;
417 ADS_STATUS ads_rc;
418 ADS_STRUCT *ads = NULL;
419 WERROR win_rc;
420
421 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
422 if (!sinfo2) {
423 return WERR_NOMEM;
424 }
425
426 switch (action) {
427 case DSPRINT_PUBLISH:
428 case DSPRINT_UPDATE:
429 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
430 break;
431 case DSPRINT_UNPUBLISH:
432 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
433 break;
434 default:
435 win_rc = WERR_NOT_SUPPORTED;
436 goto done;
437 }
438
439 sinfo2->attributes = pinfo2->attributes;
440
441 win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
442 pinfo2->sharename, info2_mask,
443 sinfo2, NULL, NULL);
444 if (!W_ERROR_IS_OK(win_rc)) {
445 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
446 goto done;
447 }
448
449 TALLOC_FREE(sinfo2);
450
451 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
452 if (!ads) {
453 DEBUG(3, ("ads_init() failed\n"));
454 win_rc = WERR_SERVER_UNAVAILABLE;
455 goto done;
456 }
457 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
458 SAFE_FREE(ads->auth.password);
459 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
460 NULL, NULL);
461
462 /* ads_connect() will find the DC for us */
463 ads_rc = ads_connect(ads);
464 if (!ADS_ERR_OK(ads_rc)) {
465 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
466 win_rc = WERR_ACCESS_DENIED;
467 goto done;
468 }
469
470 switch (action) {
471 case DSPRINT_PUBLISH:
472 case DSPRINT_UPDATE:
473 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
474 break;
475 case DSPRINT_UNPUBLISH:
476 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
477 break;
478 }
479
480done:
481 ads_destroy(&ads);
482 return win_rc;
483}
484
485WERROR check_published_printers(struct messaging_context *msg_ctx)
486{
487 ADS_STATUS ads_rc;
488 ADS_STRUCT *ads = NULL;
489 int snum;
490 int n_services = lp_numservices();
491 TALLOC_CTX *tmp_ctx = NULL;
492 struct auth_serversupplied_info *session_info = NULL;
493 struct spoolss_PrinterInfo2 *pinfo2;
494 NTSTATUS status;
495 WERROR result;
496
497 tmp_ctx = talloc_new(NULL);
498 if (!tmp_ctx) return WERR_NOMEM;
499
500 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
501 if (!ads) {
502 DEBUG(3, ("ads_init() failed\n"));
503 return WERR_SERVER_UNAVAILABLE;
504 }
505 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
506 SAFE_FREE(ads->auth.password);
507 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
508 NULL, NULL);
509
510 /* ads_connect() will find the DC for us */
511 ads_rc = ads_connect(ads);
512 if (!ADS_ERR_OK(ads_rc)) {
513 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
514 result = WERR_ACCESS_DENIED;
515 goto done;
516 }
517
518 status = make_session_info_system(tmp_ctx, &session_info);
519 if (!NT_STATUS_IS_OK(status)) {
520 DEBUG(0, ("check_published_printers: "
521 "Could not create system session_info\n"));
522 result = WERR_ACCESS_DENIED;
523 goto done;
524 }
525
526 for (snum = 0; snum < n_services; snum++) {
527 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
528 continue;
529 }
530
531 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
532 lp_servicename(snum),
533 &pinfo2);
534 if (!W_ERROR_IS_OK(result)) {
535 continue;
536 }
537
538 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
539 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
540 }
541
542 TALLOC_FREE(pinfo2);
543 }
544
545 result = WERR_OK;
546done:
547 ads_destroy(&ads);
548 ads_kdestroy("MEMORY:prtpub_cache");
549 talloc_free(tmp_ctx);
550 return result;
551}
552
553bool is_printer_published(TALLOC_CTX *mem_ctx,
554 const struct auth_serversupplied_info *session_info,
555 struct messaging_context *msg_ctx,
556 const char *servername,
557 const char *printer,
558 struct spoolss_PrinterInfo2 **info2)
559{
560 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
561 WERROR result;
562 struct dcerpc_binding_handle *b;
563
564 result = winreg_printer_binding_handle(mem_ctx,
565 session_info,
566 msg_ctx,
567 &b);
568 if (!W_ERROR_IS_OK(result)) {
569 return false;
570 }
571
572 result = winreg_get_printer(mem_ctx, b,
573 printer, &pinfo2);
574 if (!W_ERROR_IS_OK(result)) {
575 return false;
576 }
577
578 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
579 TALLOC_FREE(pinfo2);
580 return false;
581 }
582
583 if (info2) {
584 *info2 = talloc_move(mem_ctx, &pinfo2);
585 }
586 talloc_free(pinfo2);
587 return true;
588}
589#else
590WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
591 const struct auth_serversupplied_info *session_info,
592 struct messaging_context *msg_ctx,
593 const char *printer, struct GUID *guid)
594{
595 return WERR_NOT_SUPPORTED;
596}
597
598WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
599 const struct auth_serversupplied_info *session_info,
600 struct messaging_context *msg_ctx,
601 struct spoolss_PrinterInfo2 *pinfo2,
602 int action)
603{
604 return WERR_OK;
605}
606
607WERROR check_published_printers(struct messaging_context *msg_ctx)
608{
609 return WERR_OK;
610}
611
612bool is_printer_published(TALLOC_CTX *mem_ctx,
613 const struct auth_serversupplied_info *session_info,
614 struct messaging_context *msg_ctx,
615 const char *servername,
616 const char *printer,
617 struct spoolss_PrinterInfo2 **info2)
618{
619 return False;
620}
621#endif /* HAVE_ADS */
Note: See TracBrowser for help on using the repository browser.