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