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