WHATSNEW: Add changes since pre3.
[Samba.git] / source3 / printing / nt_printing_ads.c
blobea4147161360613a403efd4d61b754fb6b253600
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"
32 #ifdef HAVE_ADS
33 /*****************************************************************
34 ****************************************************************/
36 static void store_printer_guid(struct messaging_context *msg_ctx,
37 const char *printer, struct GUID guid)
39 TALLOC_CTX *tmp_ctx;
40 struct auth_serversupplied_info *session_info = NULL;
41 const char *guid_str;
42 DATA_BLOB blob;
43 NTSTATUS status;
44 WERROR result;
46 tmp_ctx = talloc_new(NULL);
47 if (!tmp_ctx) {
48 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
49 return;
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"));
56 goto done;
59 guid_str = GUID_string(tmp_ctx, &guid);
60 if (!guid_str) {
61 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
62 goto done;
65 /* We used to store this as a REG_BINARY but that causes
66 Vista to whine */
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",
71 guid_str));
72 goto done;
75 result = winreg_set_printer_dataex(tmp_ctx, session_info, msg_ctx,
76 printer,
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));
84 done:
85 talloc_free(tmp_ctx);
88 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
89 ADS_STRUCT *ads,
90 struct spoolss_PrinterInfo2 *pinfo2)
92 ADS_STATUS ads_rc;
93 LDAPMessage *res;
94 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
95 char *srv_dn_utf8, **srv_cn_utf8;
96 TALLOC_CTX *ctx;
97 ADS_MODLIST mods;
98 const char *attrs[] = {"objectGUID", NULL};
99 struct GUID guid;
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");
106 if (ctx == NULL) {
107 return WERR_NOMEM;
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);
119 if (!srv_dn_utf8) {
120 TALLOC_FREE(ctx);
121 return WERR_SERVER_UNAVAILABLE;
123 ads_msgfree(ads, res);
124 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
125 if (!srv_cn_utf8) {
126 TALLOC_FREE(ctx);
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)) {
132 TALLOC_FREE(ctx);
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)) {
138 TALLOC_FREE(ctx);
139 ldap_memfree(srv_dn_utf8);
140 ldap_memfree(srv_cn_utf8);
141 TALLOC_FREE(srv_dn);
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) {
150 TALLOC_FREE(ctx);
151 return WERR_SERVER_UNAVAILABLE;
153 sharename_escaped = escape_rdn_val_string_alloc(printer);
154 if (!sharename_escaped) {
155 SAFE_FREE(srv_cn_escaped);
156 TALLOC_FREE(ctx);
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);
167 if (mods == NULL) {
168 SAFE_FREE(prt_dn);
169 TALLOC_FREE(ctx);
170 return WERR_NOMEM;
173 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
175 /* publish it */
176 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
177 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
178 int i;
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))) {
192 bool guid_ok;
193 ZERO_STRUCT(guid);
194 guid_ok = ads_pull_guid(ads, res, &guid);
195 ads_msgfree(ads, res);
196 if (guid_ok) {
197 store_printer_guid(msg_ctx, printer, guid);
200 TALLOC_FREE(ctx);
202 return win_rc;
205 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
206 const char *printer)
208 ADS_STATUS ads_rc;
209 LDAPMessage *res = NULL;
210 char *prt_dn = 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);
220 if (!prt_dn) {
221 ads_msgfree(ads, res);
222 return WERR_NOMEM;
224 ads_rc = ads_del_dn(ads, prt_dn);
225 TALLOC_FREE(prt_dn);
228 if (res) {
229 ads_msgfree(ads, res);
231 return WERR_OK;
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,
248 int action)
250 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
251 struct spoolss_SetPrinterInfo2 *sinfo2;
252 ADS_STATUS ads_rc;
253 ADS_STRUCT *ads = NULL;
254 WERROR win_rc;
256 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
257 if (!sinfo2) {
258 return WERR_NOMEM;
261 switch (action) {
262 case DSPRINT_PUBLISH:
263 case DSPRINT_UPDATE:
264 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
265 break;
266 case DSPRINT_UNPUBLISH:
267 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
268 break;
269 default:
270 win_rc = WERR_NOT_SUPPORTED;
271 goto done;
274 sinfo2->attributes = pinfo2->attributes;
276 win_rc = winreg_update_printer(mem_ctx, session_info, msg_ctx,
277 pinfo2->sharename, info2_mask,
278 sinfo2, NULL, NULL);
279 if (!W_ERROR_IS_OK(win_rc)) {
280 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
281 goto done;
284 TALLOC_FREE(sinfo2);
286 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
287 if (!ads) {
288 DEBUG(3, ("ads_init() failed\n"));
289 win_rc = WERR_SERVER_UNAVAILABLE;
290 goto done;
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(),
295 NULL, NULL);
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;
302 goto done;
305 switch (action) {
306 case DSPRINT_PUBLISH:
307 case DSPRINT_UPDATE:
308 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
309 break;
310 case DSPRINT_UNPUBLISH:
311 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
312 break;
315 done:
316 ads_destroy(&ads);
317 return win_rc;
320 WERROR check_published_printers(struct messaging_context *msg_ctx)
322 ADS_STATUS ads_rc;
323 ADS_STRUCT *ads = NULL;
324 int snum;
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;
329 NTSTATUS status;
330 WERROR result;
332 tmp_ctx = talloc_new(NULL);
333 if (!tmp_ctx) return WERR_NOMEM;
335 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
336 if (!ads) {
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(),
343 NULL, NULL);
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;
350 goto done;
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;
358 goto done;
361 for (snum = 0; snum < n_services; snum++) {
362 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
363 continue;
366 result = winreg_get_printer(tmp_ctx, session_info, msg_ctx,
367 lp_servicename(snum),
368 &pinfo2);
369 if (!W_ERROR_IS_OK(result)) {
370 continue;
373 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
374 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
377 TALLOC_FREE(pinfo2);
380 result = WERR_OK;
381 done:
382 ads_destroy(&ads);
383 ads_kdestroy("MEMORY:prtpub_cache");
384 talloc_free(tmp_ctx);
385 return result;
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;
396 uint8_t *data;
397 uint32_t data_size;
398 WERROR result;
399 NTSTATUS status;
401 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
402 printer, &pinfo2);
403 if (!W_ERROR_IS_OK(result)) {
404 return false;
407 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
408 TALLOC_FREE(pinfo2);
409 return false;
412 if (!guid) {
413 goto done;
416 /* fetching printer guids really ought to be a separate function. */
418 result = winreg_get_printer_dataex(mem_ctx, session_info, msg_ctx,
419 printer,
420 SPOOL_DSSPOOLER_KEY, "objectGUID",
421 &type, &data, &data_size);
422 if (!W_ERROR_IS_OK(result)) {
423 TALLOC_FREE(pinfo2);
424 return false;
427 /* We used to store the guid as REG_BINARY, then swapped
428 to REG_SZ for Vista compatibility so check for both */
430 switch (type) {
431 case REG_SZ:
432 status = GUID_from_string((char *)data, guid);
433 if (!NT_STATUS_IS_OK(status)) {
434 TALLOC_FREE(pinfo2);
435 return false;
437 break;
439 case REG_BINARY:
440 if (data_size != sizeof(struct GUID)) {
441 TALLOC_FREE(pinfo2);
442 return false;
444 memcpy(guid, data, sizeof(struct GUID));
445 break;
446 default:
447 DEBUG(0,("is_printer_published: GUID value stored as "
448 "invaluid type (%d)\n", type));
449 break;
452 done:
453 if (info2) {
454 *info2 = talloc_move(mem_ctx, &pinfo2);
456 talloc_free(pinfo2);
457 return true;
459 #else
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,
464 int action)
466 return WERR_OK;
469 WERROR check_published_printers(struct messaging_context *msg_ctx)
471 return WERR_OK;
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)
480 return False;
482 #endif /* HAVE_ADS */