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