ndr: Another try to support the build on non-IPv6 systems
[Samba.git] / source3 / printing / nt_printing_ads.c
blob6f71ce08b1e1d9ae976c451926c86a1ea4f0c336
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"
28 #include "krb5_env.h"
30 #ifdef HAVE_ADS
31 /*****************************************************************
32 ****************************************************************/
34 static void store_printer_guid(struct messaging_context *msg_ctx,
35 const char *printer, struct GUID guid)
37 TALLOC_CTX *tmp_ctx;
38 struct auth_serversupplied_info *server_info = NULL;
39 const char *guid_str;
40 DATA_BLOB blob;
41 NTSTATUS status;
42 WERROR result;
44 tmp_ctx = talloc_new(NULL);
45 if (!tmp_ctx) {
46 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
47 return;
50 status = make_server_info_system(tmp_ctx, &server_info);
51 if (!NT_STATUS_IS_OK(status)) {
52 DEBUG(0, ("store_printer_guid: "
53 "Could not create system server_info\n"));
54 goto done;
57 guid_str = GUID_string(tmp_ctx, &guid);
58 if (!guid_str) {
59 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
60 goto done;
63 /* We used to store this as a REG_BINARY but that causes
64 Vista to whine */
66 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
67 DEBUG(0, ("store_printer_guid: "
68 "Could not marshall string %s for objectGUID\n",
69 guid_str));
70 goto done;
73 result = winreg_set_printer_dataex(tmp_ctx, server_info, msg_ctx,
74 printer,
75 SPOOL_DSSPOOLER_KEY, "objectGUID",
76 REG_SZ, blob.data, blob.length);
77 if (!W_ERROR_IS_OK(result)) {
78 DEBUG(0, ("store_printer_guid: "
79 "Failed to store GUID for printer %s\n", printer));
82 done:
83 talloc_free(tmp_ctx);
86 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
87 ADS_STRUCT *ads,
88 struct spoolss_PrinterInfo2 *pinfo2)
90 ADS_STATUS ads_rc;
91 LDAPMessage *res;
92 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
93 char *srv_dn_utf8, **srv_cn_utf8;
94 TALLOC_CTX *ctx;
95 ADS_MODLIST mods;
96 const char *attrs[] = {"objectGUID", NULL};
97 struct GUID guid;
98 WERROR win_rc = WERR_OK;
99 size_t converted_size;
100 const char *printer = pinfo2->sharename;
102 /* build the ads mods */
103 ctx = talloc_init("nt_printer_publish_ads");
104 if (ctx == NULL) {
105 return WERR_NOMEM;
108 DEBUG(5, ("publishing printer %s\n", printer));
110 /* figure out where to publish */
111 ads_find_machine_acct(ads, &res, global_myname());
113 /* We use ldap_get_dn here as we need the answer
114 * in utf8 to call ldap_explode_dn(). JRA. */
116 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
117 if (!srv_dn_utf8) {
118 TALLOC_FREE(ctx);
119 return WERR_SERVER_UNAVAILABLE;
121 ads_msgfree(ads, res);
122 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
123 if (!srv_cn_utf8) {
124 TALLOC_FREE(ctx);
125 ldap_memfree(srv_dn_utf8);
126 return WERR_SERVER_UNAVAILABLE;
128 /* Now convert to CH_UNIX. */
129 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
130 TALLOC_FREE(ctx);
131 ldap_memfree(srv_dn_utf8);
132 ldap_memfree(srv_cn_utf8);
133 return WERR_SERVER_UNAVAILABLE;
135 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
136 TALLOC_FREE(ctx);
137 ldap_memfree(srv_dn_utf8);
138 ldap_memfree(srv_cn_utf8);
139 TALLOC_FREE(srv_dn);
140 return WERR_SERVER_UNAVAILABLE;
143 ldap_memfree(srv_dn_utf8);
144 ldap_memfree(srv_cn_utf8);
146 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
147 if (!srv_cn_escaped) {
148 TALLOC_FREE(ctx);
149 return WERR_SERVER_UNAVAILABLE;
151 sharename_escaped = escape_rdn_val_string_alloc(printer);
152 if (!sharename_escaped) {
153 SAFE_FREE(srv_cn_escaped);
154 TALLOC_FREE(ctx);
155 return WERR_SERVER_UNAVAILABLE;
158 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
160 SAFE_FREE(srv_cn_escaped);
161 SAFE_FREE(sharename_escaped);
163 mods = ads_init_mods(ctx);
165 if (mods == NULL) {
166 SAFE_FREE(prt_dn);
167 TALLOC_FREE(ctx);
168 return WERR_NOMEM;
171 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
173 /* publish it */
174 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
175 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
176 int i;
177 for (i=0; mods[i] != 0; i++)
179 mods[i] = (LDAPMod *)-1;
180 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
183 if (!ADS_ERR_OK(ads_rc)) {
184 DEBUG(3, ("error publishing %s: %s\n",
185 printer, ads_errstr(ads_rc)));
188 /* retreive the guid and store it locally */
189 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
190 bool guid_ok;
191 ZERO_STRUCT(guid);
192 guid_ok = ads_pull_guid(ads, res, &guid);
193 ads_msgfree(ads, res);
194 if (guid_ok) {
195 store_printer_guid(msg_ctx, printer, guid);
198 TALLOC_FREE(ctx);
200 return win_rc;
203 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
204 const char *printer)
206 ADS_STATUS ads_rc;
207 LDAPMessage *res = NULL;
208 char *prt_dn = NULL;
210 DEBUG(5, ("unpublishing printer %s\n", printer));
212 /* remove the printer from the directory */
213 ads_rc = ads_find_printer_on_server(ads, &res,
214 printer, global_myname());
216 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
217 prt_dn = ads_get_dn(ads, talloc_tos(), res);
218 if (!prt_dn) {
219 ads_msgfree(ads, res);
220 return WERR_NOMEM;
222 ads_rc = ads_del_dn(ads, prt_dn);
223 TALLOC_FREE(prt_dn);
226 if (res) {
227 ads_msgfree(ads, res);
229 return WERR_OK;
232 /****************************************************************************
233 * Publish a printer in the directory
235 * @param mem_ctx memory context
236 * @param server_info server_info to access winreg pipe
237 * @param pinfo2 printer information
238 * @param action publish/unpublish action
239 * @return WERROR indicating status of publishing
240 ***************************************************************************/
242 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
243 const struct auth_serversupplied_info *server_info,
244 struct messaging_context *msg_ctx,
245 struct spoolss_PrinterInfo2 *pinfo2,
246 int action)
248 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
249 struct spoolss_SetPrinterInfo2 *sinfo2;
250 ADS_STATUS ads_rc;
251 ADS_STRUCT *ads = NULL;
252 WERROR win_rc;
254 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
255 if (!sinfo2) {
256 return WERR_NOMEM;
259 switch (action) {
260 case DSPRINT_PUBLISH:
261 case DSPRINT_UPDATE:
262 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
263 break;
264 case DSPRINT_UNPUBLISH:
265 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
266 break;
267 default:
268 win_rc = WERR_NOT_SUPPORTED;
269 goto done;
272 sinfo2->attributes = pinfo2->attributes;
274 win_rc = winreg_update_printer(mem_ctx, server_info, msg_ctx,
275 pinfo2->sharename, info2_mask,
276 sinfo2, NULL, NULL);
277 if (!W_ERROR_IS_OK(win_rc)) {
278 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
279 goto done;
282 TALLOC_FREE(sinfo2);
284 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
285 if (!ads) {
286 DEBUG(3, ("ads_init() failed\n"));
287 win_rc = WERR_SERVER_UNAVAILABLE;
288 goto done;
290 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
291 SAFE_FREE(ads->auth.password);
292 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
293 NULL, NULL);
295 /* ads_connect() will find the DC for us */
296 ads_rc = ads_connect(ads);
297 if (!ADS_ERR_OK(ads_rc)) {
298 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
299 win_rc = WERR_ACCESS_DENIED;
300 goto done;
303 switch (action) {
304 case DSPRINT_PUBLISH:
305 case DSPRINT_UPDATE:
306 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
307 break;
308 case DSPRINT_UNPUBLISH:
309 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
310 break;
313 done:
314 ads_destroy(&ads);
315 return win_rc;
318 WERROR check_published_printers(struct messaging_context *msg_ctx)
320 ADS_STATUS ads_rc;
321 ADS_STRUCT *ads = NULL;
322 int snum;
323 int n_services = lp_numservices();
324 TALLOC_CTX *tmp_ctx = NULL;
325 struct auth_serversupplied_info *server_info = NULL;
326 struct spoolss_PrinterInfo2 *pinfo2;
327 NTSTATUS status;
328 WERROR result;
330 tmp_ctx = talloc_new(NULL);
331 if (!tmp_ctx) return WERR_NOMEM;
333 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
334 if (!ads) {
335 DEBUG(3, ("ads_init() failed\n"));
336 return WERR_SERVER_UNAVAILABLE;
338 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
339 SAFE_FREE(ads->auth.password);
340 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
341 NULL, NULL);
343 /* ads_connect() will find the DC for us */
344 ads_rc = ads_connect(ads);
345 if (!ADS_ERR_OK(ads_rc)) {
346 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
347 result = WERR_ACCESS_DENIED;
348 goto done;
351 status = make_server_info_system(tmp_ctx, &server_info);
352 if (!NT_STATUS_IS_OK(status)) {
353 DEBUG(0, ("check_published_printers: "
354 "Could not create system server_info\n"));
355 result = WERR_ACCESS_DENIED;
356 goto done;
359 for (snum = 0; snum < n_services; snum++) {
360 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
361 continue;
364 result = winreg_get_printer(tmp_ctx, server_info, msg_ctx,
365 lp_servicename(snum),
366 &pinfo2);
367 if (!W_ERROR_IS_OK(result)) {
368 continue;
371 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
372 nt_printer_publish_ads(msg_ctx, ads, pinfo2);
375 TALLOC_FREE(pinfo2);
378 result = WERR_OK;
379 done:
380 ads_destroy(&ads);
381 ads_kdestroy("MEMORY:prtpub_cache");
382 talloc_free(tmp_ctx);
383 return result;
386 bool is_printer_published(TALLOC_CTX *mem_ctx,
387 const struct auth_serversupplied_info *server_info,
388 struct messaging_context *msg_ctx,
389 const char *servername, char *printer, struct GUID *guid,
390 struct spoolss_PrinterInfo2 **info2)
392 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
393 enum winreg_Type type;
394 uint8_t *data;
395 uint32_t data_size;
396 WERROR result;
397 NTSTATUS status;
399 result = winreg_get_printer(mem_ctx, server_info, msg_ctx,
400 printer, &pinfo2);
401 if (!W_ERROR_IS_OK(result)) {
402 return false;
405 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
406 TALLOC_FREE(pinfo2);
407 return false;
410 if (!guid) {
411 goto done;
414 /* fetching printer guids really ought to be a separate function. */
416 result = winreg_get_printer_dataex(mem_ctx, server_info, msg_ctx,
417 printer,
418 SPOOL_DSSPOOLER_KEY, "objectGUID",
419 &type, &data, &data_size);
420 if (!W_ERROR_IS_OK(result)) {
421 TALLOC_FREE(pinfo2);
422 return false;
425 /* We used to store the guid as REG_BINARY, then swapped
426 to REG_SZ for Vista compatibility so check for both */
428 switch (type) {
429 case REG_SZ:
430 status = GUID_from_string((char *)data, guid);
431 if (!NT_STATUS_IS_OK(status)) {
432 TALLOC_FREE(pinfo2);
433 return false;
435 break;
437 case REG_BINARY:
438 if (data_size != sizeof(struct GUID)) {
439 TALLOC_FREE(pinfo2);
440 return false;
442 memcpy(guid, data, sizeof(struct GUID));
443 break;
444 default:
445 DEBUG(0,("is_printer_published: GUID value stored as "
446 "invaluid type (%d)\n", type));
447 break;
450 done:
451 if (info2) {
452 *info2 = talloc_move(mem_ctx, &pinfo2);
454 talloc_free(pinfo2);
455 return true;
457 #else
458 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
459 const struct auth_serversupplied_info *server_info,
460 struct messaging_context *msg_ctx,
461 struct spoolss_PrinterInfo2 *pinfo2,
462 int action)
464 return WERR_OK;
467 WERROR check_published_printers(struct messaging_context *msg_ctx)
469 return WERR_OK;
472 bool is_printer_published(TALLOC_CTX *mem_ctx,
473 const struct auth_serversupplied_info *server_info,
474 struct messaging_context *msg_ctx,
475 const char *servername, char *printer, struct GUID *guid,
476 struct spoolss_PrinterInfo2 **info2)
478 return False;
480 #endif /* HAVE_ADS */