3ccaeef014362b7b92b2edd636619ea346381e97
[mat/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 #include "krb5_env.h"
29
30 #ifdef HAVE_ADS
31 /*****************************************************************
32  ****************************************************************/
33
34 static void store_printer_guid(struct messaging_context *msg_ctx,
35                                const char *printer, struct GUID guid)
36 {
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;
43
44         tmp_ctx = talloc_new(NULL);
45         if (!tmp_ctx) {
46                 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
47                 return;
48         }
49
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;
55         }
56
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;
61         }
62
63         /* We used to store this as a REG_BINARY but that causes
64            Vista to whine */
65
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;
71         }
72
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));
80         }
81
82 done:
83         talloc_free(tmp_ctx);
84 }
85
86 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
87                                      ADS_STRUCT *ads,
88                                      struct spoolss_PrinterInfo2 *pinfo2)
89 {
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;
101
102         /* build the ads mods */
103         ctx = talloc_init("nt_printer_publish_ads");
104         if (ctx == NULL) {
105                 return WERR_NOMEM;
106         }
107
108         DEBUG(5, ("publishing printer %s\n", printer));
109
110         /* figure out where to publish */
111         ads_find_machine_acct(ads, &res, global_myname());
112
113         /* We use ldap_get_dn here as we need the answer
114          * in utf8 to call ldap_explode_dn(). JRA. */
115
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;
120         }
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;
127         }
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;
134         }
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;
141         }
142
143         ldap_memfree(srv_dn_utf8);
144         ldap_memfree(srv_cn_utf8);
145
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;
150         }
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;
156         }
157
158         prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
159
160         SAFE_FREE(srv_cn_escaped);
161         SAFE_FREE(sharename_escaped);
162
163         mods = ads_init_mods(ctx);
164
165         if (mods == NULL) {
166                 SAFE_FREE(prt_dn);
167                 TALLOC_FREE(ctx);
168                 return WERR_NOMEM;
169         }
170
171         ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
172
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++)
178                         ;
179                 mods[i] = (LDAPMod *)-1;
180                 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
181         }
182
183         if (!ADS_ERR_OK(ads_rc)) {
184                 DEBUG(3, ("error publishing %s: %s\n",
185                           printer, ads_errstr(ads_rc)));
186         }
187
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);
196                 }
197         }
198         TALLOC_FREE(ctx);
199
200         return win_rc;
201 }
202
203 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
204                                        const char *printer)
205 {
206         ADS_STATUS ads_rc;
207         LDAPMessage *res = NULL;
208         char *prt_dn = NULL;
209
210         DEBUG(5, ("unpublishing printer %s\n", printer));
211
212         /* remove the printer from the directory */
213         ads_rc = ads_find_printer_on_server(ads, &res,
214                                             printer, global_myname());
215
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;
221                 }
222                 ads_rc = ads_del_dn(ads, prt_dn);
223                 TALLOC_FREE(prt_dn);
224         }
225
226         if (res) {
227                 ads_msgfree(ads, res);
228         }
229         return WERR_OK;
230 }
231
232 /****************************************************************************
233  * Publish a printer in the directory
234  *
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  ***************************************************************************/
241
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)
247 {
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;
253
254         sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
255         if (!sinfo2) {
256                 return WERR_NOMEM;
257         }
258
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;
270         }
271
272         sinfo2->attributes = pinfo2->attributes;
273
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;
280         }
281
282         TALLOC_FREE(sinfo2);
283
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;
289         }
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);
294
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;
301         }
302
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;
311         }
312
313 done:
314         ads_destroy(&ads);
315         return win_rc;
316 }
317
318 WERROR check_published_printers(struct messaging_context *msg_ctx)
319 {
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;
329
330         tmp_ctx = talloc_new(NULL);
331         if (!tmp_ctx) return WERR_NOMEM;
332
333         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
334         if (!ads) {
335                 DEBUG(3, ("ads_init() failed\n"));
336                 return WERR_SERVER_UNAVAILABLE;
337         }
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);
342
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;
349         }
350
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;
357         }
358
359         for (snum = 0; snum < n_services; snum++) {
360                 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
361                         continue;
362                 }
363
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;
369                 }
370
371                 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
372                         nt_printer_publish_ads(msg_ctx, ads, pinfo2);
373                 }
374
375                 TALLOC_FREE(pinfo2);
376         }
377
378         result = WERR_OK;
379 done:
380         ads_destroy(&ads);
381         ads_kdestroy("MEMORY:prtpub_cache");
382         talloc_free(tmp_ctx);
383         return result;
384 }
385
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)
391 {
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;
398
399         result = winreg_get_printer(mem_ctx, server_info, msg_ctx,
400                                     printer, &pinfo2);
401         if (!W_ERROR_IS_OK(result)) {
402                 return false;
403         }
404
405         if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
406                 TALLOC_FREE(pinfo2);
407                 return false;
408         }
409
410         if (!guid) {
411                 goto done;
412         }
413
414         /* fetching printer guids really ought to be a separate function. */
415
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;
423         }
424
425         /* We used to store the guid as REG_BINARY, then swapped
426            to REG_SZ for Vista compatibility so check for both */
427
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;
434                 }
435                 break;
436
437         case REG_BINARY:
438                 if (data_size != sizeof(struct GUID)) {
439                         TALLOC_FREE(pinfo2);
440                         return false;
441                 }
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;
448         }
449
450 done:
451         if (info2) {
452                 *info2 = talloc_move(mem_ctx, &pinfo2);
453         }
454         talloc_free(pinfo2);
455         return true;
456 }
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)
463 {
464         return WERR_OK;
465 }
466
467 WERROR check_published_printers(struct messaging_context *msg_ctx)
468 {
469         return WERR_OK;
470 }
471
472 bool is_printer_published(TALLOC_CTX *mem_ctx,
473                           const struct auth_serversupplied_info *server_info,
474                           struct messaging_context *msg_ctx,
475                           char *servername, char *printer, struct GUID *guid,
476                           struct spoolss_PrinterInfo2 **info2)
477 {
478         return False;
479 }
480 #endif /* HAVE_ADS */