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