examples/VFS: fix skel_transparent.c in reference to shadow_copy changes
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing_ads.c
blob6290417260f1eb0f353fcf89d5e2e796fcf427c9
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"
33 #ifdef HAVE_ADS
34 /*****************************************************************
35 ****************************************************************/
37 static void store_printer_guid(struct messaging_context *msg_ctx,
38 const char *printer, struct GUID guid)
40 TALLOC_CTX *tmp_ctx;
41 struct auth_serversupplied_info *session_info = NULL;
42 const char *guid_str;
43 DATA_BLOB blob;
44 NTSTATUS status;
45 WERROR result;
47 tmp_ctx = talloc_new(NULL);
48 if (!tmp_ctx) {
49 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
50 return;
53 status = make_session_info_system(tmp_ctx, &session_info);
54 if (!NT_STATUS_IS_OK(status)) {
55 DEBUG(0, ("store_printer_guid: "
56 "Could not create system session_info\n"));
57 goto done;
60 guid_str = GUID_string(tmp_ctx, &guid);
61 if (!guid_str) {
62 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
63 goto done;
66 /* We used to store this as a REG_BINARY but that causes
67 Vista to whine */
69 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
70 DEBUG(0, ("store_printer_guid: "
71 "Could not marshall string %s for objectGUID\n",
72 guid_str));
73 goto done;
76 result = winreg_set_printer_dataex(tmp_ctx, session_info, msg_ctx,
77 printer,
78 SPOOL_DSSPOOLER_KEY, "objectGUID",
79 REG_SZ, blob.data, blob.length);
80 if (!W_ERROR_IS_OK(result)) {
81 DEBUG(0, ("store_printer_guid: "
82 "Failed to store GUID for printer %s\n", printer));
85 done:
86 talloc_free(tmp_ctx);
89 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
90 ADS_STRUCT *ads,
91 struct spoolss_PrinterInfo2 *pinfo2)
93 ADS_STATUS ads_rc;
94 LDAPMessage *res;
95 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
96 char *srv_dn_utf8, **srv_cn_utf8;
97 TALLOC_CTX *ctx;
98 ADS_MODLIST mods;
99 const char *attrs[] = {"objectGUID", NULL};
100 struct GUID guid;
101 WERROR win_rc = WERR_OK;
102 size_t converted_size;
103 const char *printer = pinfo2->sharename;
105 /* build the ads mods */
106 ctx = talloc_init("nt_printer_publish_ads");
107 if (ctx == NULL) {
108 return WERR_NOMEM;
111 DEBUG(5, ("publishing printer %s\n", printer));
113 /* figure out where to publish */
114 ads_find_machine_acct(ads, &res, lp_netbios_name());
116 /* We use ldap_get_dn here as we need the answer
117 * in utf8 to call ldap_explode_dn(). JRA. */
119 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
120 if (!srv_dn_utf8) {
121 TALLOC_FREE(ctx);
122 return WERR_SERVER_UNAVAILABLE;
124 ads_msgfree(ads, res);
125 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
126 if (!srv_cn_utf8) {
127 TALLOC_FREE(ctx);
128 ldap_memfree(srv_dn_utf8);
129 return WERR_SERVER_UNAVAILABLE;
131 /* Now convert to CH_UNIX. */
132 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
133 TALLOC_FREE(ctx);
134 ldap_memfree(srv_dn_utf8);
135 ldap_memfree(srv_cn_utf8);
136 return WERR_SERVER_UNAVAILABLE;
138 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
139 TALLOC_FREE(ctx);
140 ldap_memfree(srv_dn_utf8);
141 ldap_memfree(srv_cn_utf8);
142 TALLOC_FREE(srv_dn);
143 return WERR_SERVER_UNAVAILABLE;
146 ldap_memfree(srv_dn_utf8);
147 ldap_memfree(srv_cn_utf8);
149 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
150 if (!srv_cn_escaped) {
151 TALLOC_FREE(ctx);
152 return WERR_SERVER_UNAVAILABLE;
154 sharename_escaped = escape_rdn_val_string_alloc(printer);
155 if (!sharename_escaped) {
156 SAFE_FREE(srv_cn_escaped);
157 TALLOC_FREE(ctx);
158 return WERR_SERVER_UNAVAILABLE;
161 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
163 SAFE_FREE(srv_cn_escaped);
164 SAFE_FREE(sharename_escaped);
166 mods = ads_init_mods(ctx);
168 if (mods == NULL) {
169 SAFE_FREE(prt_dn);
170 TALLOC_FREE(ctx);
171 return WERR_NOMEM;
174 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
176 /* publish it */
177 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
178 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
179 int i;
180 for (i=0; mods[i] != 0; i++)
182 mods[i] = (LDAPMod *)-1;
183 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
186 if (!ADS_ERR_OK(ads_rc)) {
187 DEBUG(3, ("error publishing %s: %s\n",
188 printer, ads_errstr(ads_rc)));
191 /* retreive the guid and store it locally */
192 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
193 bool guid_ok;
194 ZERO_STRUCT(guid);
195 guid_ok = ads_pull_guid(ads, res, &guid);
196 ads_msgfree(ads, res);
197 if (guid_ok) {
198 store_printer_guid(msg_ctx, printer, guid);
201 TALLOC_FREE(ctx);
203 return win_rc;
206 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
207 const char *printer)
209 ADS_STATUS ads_rc;
210 LDAPMessage *res = NULL;
211 char *prt_dn = NULL;
213 DEBUG(5, ("unpublishing printer %s\n", printer));
215 /* remove the printer from the directory */
216 ads_rc = ads_find_printer_on_server(ads, &res,
217 printer, lp_netbios_name());
219 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
220 prt_dn = ads_get_dn(ads, talloc_tos(), res);
221 if (!prt_dn) {
222 ads_msgfree(ads, res);
223 return WERR_NOMEM;
225 ads_rc = ads_del_dn(ads, prt_dn);
226 TALLOC_FREE(prt_dn);
229 if (res) {
230 ads_msgfree(ads, res);
232 return WERR_OK;
235 /****************************************************************************
236 * Publish a printer in the directory
238 * @param mem_ctx memory context
239 * @param session_info session_info to access winreg pipe
240 * @param pinfo2 printer information
241 * @param action publish/unpublish action
242 * @return WERROR indicating status of publishing
243 ***************************************************************************/
245 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
246 const struct auth_serversupplied_info *session_info,
247 struct messaging_context *msg_ctx,
248 struct spoolss_PrinterInfo2 *pinfo2,
249 int action)
251 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
252 struct spoolss_SetPrinterInfo2 *sinfo2;
253 ADS_STATUS ads_rc;
254 ADS_STRUCT *ads = NULL;
255 WERROR win_rc;
257 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
258 if (!sinfo2) {
259 return WERR_NOMEM;
262 switch (action) {
263 case DSPRINT_PUBLISH:
264 case DSPRINT_UPDATE:
265 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
266 break;
267 case DSPRINT_UNPUBLISH:
268 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
269 break;
270 default:
271 win_rc = WERR_NOT_SUPPORTED;
272 goto done;
275 sinfo2->attributes = pinfo2->attributes;
277 win_rc = winreg_update_printer(mem_ctx, session_info, msg_ctx,
278 pinfo2->sharename, info2_mask,
279 sinfo2, NULL, NULL);
280 if (!W_ERROR_IS_OK(win_rc)) {
281 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
282 goto done;
285 TALLOC_FREE(sinfo2);
287 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
288 if (!ads) {
289 DEBUG(3, ("ads_init() failed\n"));
290 win_rc = WERR_SERVER_UNAVAILABLE;
291 goto done;
293 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
294 SAFE_FREE(ads->auth.password);
295 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
296 NULL, NULL);
298 /* ads_connect() will find the DC for us */
299 ads_rc = ads_connect(ads);
300 if (!ADS_ERR_OK(ads_rc)) {
301 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
302 win_rc = WERR_ACCESS_DENIED;
303 goto done;
306 switch (action) {
307 case DSPRINT_PUBLISH:
308 case DSPRINT_UPDATE:
309 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
310 break;
311 case DSPRINT_UNPUBLISH:
312 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
313 break;
316 done:
317 ads_destroy(&ads);
318 return win_rc;
321 WERROR check_published_printers(struct messaging_context *msg_ctx)
323 ADS_STATUS ads_rc;
324 ADS_STRUCT *ads = NULL;
325 int snum;
326 int n_services = lp_numservices();
327 TALLOC_CTX *tmp_ctx = NULL;
328 struct auth_serversupplied_info *session_info = NULL;
329 struct spoolss_PrinterInfo2 *pinfo2;
330 NTSTATUS status;
331 WERROR result;
333 tmp_ctx = talloc_new(NULL);
334 if (!tmp_ctx) return WERR_NOMEM;
336 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
337 if (!ads) {
338 DEBUG(3, ("ads_init() failed\n"));
339 return WERR_SERVER_UNAVAILABLE;
341 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
342 SAFE_FREE(ads->auth.password);
343 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
344 NULL, NULL);
346 /* ads_connect() will find the DC for us */
347 ads_rc = ads_connect(ads);
348 if (!ADS_ERR_OK(ads_rc)) {
349 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
350 result = WERR_ACCESS_DENIED;
351 goto done;
354 status = make_session_info_system(tmp_ctx, &session_info);
355 if (!NT_STATUS_IS_OK(status)) {
356 DEBUG(0, ("check_published_printers: "
357 "Could not create system session_info\n"));
358 result = WERR_ACCESS_DENIED;
359 goto done;
362 for (snum = 0; snum < n_services; snum++) {
363 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
364 continue;
367 result = winreg_get_printer(tmp_ctx, session_info, msg_ctx,
368 lp_servicename(snum),
369 &pinfo2);
370 if (!W_ERROR_IS_OK(result)) {
371 continue;
374 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
375 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
378 TALLOC_FREE(pinfo2);
381 result = WERR_OK;
382 done:
383 ads_destroy(&ads);
384 ads_kdestroy("MEMORY:prtpub_cache");
385 talloc_free(tmp_ctx);
386 return result;
389 bool is_printer_published(TALLOC_CTX *mem_ctx,
390 const struct auth_serversupplied_info *session_info,
391 struct messaging_context *msg_ctx,
392 const char *servername, char *printer, struct GUID *guid,
393 struct spoolss_PrinterInfo2 **info2)
395 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
396 enum winreg_Type type;
397 uint8_t *data;
398 uint32_t data_size;
399 WERROR result;
400 NTSTATUS status;
402 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
403 printer, &pinfo2);
404 if (!W_ERROR_IS_OK(result)) {
405 return false;
408 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
409 TALLOC_FREE(pinfo2);
410 return false;
413 if (!guid) {
414 goto done;
417 /* fetching printer guids really ought to be a separate function. */
419 result = winreg_get_printer_dataex(mem_ctx, session_info, msg_ctx,
420 printer,
421 SPOOL_DSSPOOLER_KEY, "objectGUID",
422 &type, &data, &data_size);
423 if (!W_ERROR_IS_OK(result)) {
424 TALLOC_FREE(pinfo2);
425 return false;
428 /* We used to store the guid as REG_BINARY, then swapped
429 to REG_SZ for Vista compatibility so check for both */
431 switch (type) {
432 case REG_SZ:
433 status = GUID_from_string((char *)data, guid);
434 if (!NT_STATUS_IS_OK(status)) {
435 TALLOC_FREE(pinfo2);
436 return false;
438 break;
440 case REG_BINARY:
441 if (data_size != sizeof(struct GUID)) {
442 TALLOC_FREE(pinfo2);
443 return false;
445 memcpy(guid, data, sizeof(struct GUID));
446 break;
447 default:
448 DEBUG(0,("is_printer_published: GUID value stored as "
449 "invaluid type (%d)\n", type));
450 break;
453 done:
454 if (info2) {
455 *info2 = talloc_move(mem_ctx, &pinfo2);
457 talloc_free(pinfo2);
458 return true;
460 #else
461 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
462 const struct auth_serversupplied_info *session_info,
463 struct messaging_context *msg_ctx,
464 struct spoolss_PrinterInfo2 *pinfo2,
465 int action)
467 return WERR_OK;
470 WERROR check_published_printers(struct messaging_context *msg_ctx)
472 return WERR_OK;
475 bool is_printer_published(TALLOC_CTX *mem_ctx,
476 const struct auth_serversupplied_info *session_info,
477 struct messaging_context *msg_ctx,
478 const char *servername, char *printer, struct GUID *guid,
479 struct spoolss_PrinterInfo2 **info2)
481 return False;
483 #endif /* HAVE_ADS */