s3: Lift the smbd_messaging_context from nt_printer_publish_ads
[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(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 spoolss_PrinterInfo2 *pinfo2,
241                           int action)
242 {
243         uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
244         struct spoolss_SetPrinterInfo2 *sinfo2;
245         ADS_STATUS ads_rc;
246         ADS_STRUCT *ads = NULL;
247         WERROR win_rc;
248
249         sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
250         if (!sinfo2) {
251                 return WERR_NOMEM;
252         }
253
254         switch (action) {
255         case DSPRINT_PUBLISH:
256         case DSPRINT_UPDATE:
257                 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
258                 break;
259         case DSPRINT_UNPUBLISH:
260                 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
261                 break;
262         default:
263                 win_rc = WERR_NOT_SUPPORTED;
264                 goto done;
265         }
266
267         sinfo2->attributes = pinfo2->attributes;
268
269         win_rc = winreg_update_printer(mem_ctx, server_info,
270                                         smbd_messaging_context(),
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(smbd_messaging_context(),
303                                                 ads, pinfo2);
304                 break;
305         case DSPRINT_UNPUBLISH:
306                 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
307                 break;
308         }
309
310 done:
311         ads_destroy(&ads);
312         return win_rc;
313 }
314
315 WERROR check_published_printers(void)
316 {
317         ADS_STATUS ads_rc;
318         ADS_STRUCT *ads = NULL;
319         int snum;
320         int n_services = lp_numservices();
321         TALLOC_CTX *tmp_ctx = NULL;
322         struct auth_serversupplied_info *server_info = NULL;
323         struct spoolss_PrinterInfo2 *pinfo2;
324         NTSTATUS status;
325         WERROR result;
326
327         tmp_ctx = talloc_new(NULL);
328         if (!tmp_ctx) return WERR_NOMEM;
329
330         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
331         if (!ads) {
332                 DEBUG(3, ("ads_init() failed\n"));
333                 return WERR_SERVER_UNAVAILABLE;
334         }
335         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
336         SAFE_FREE(ads->auth.password);
337         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
338                 NULL, NULL);
339
340         /* ads_connect() will find the DC for us */
341         ads_rc = ads_connect(ads);
342         if (!ADS_ERR_OK(ads_rc)) {
343                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
344                 result = WERR_ACCESS_DENIED;
345                 goto done;
346         }
347
348         status = make_server_info_system(tmp_ctx, &server_info);
349         if (!NT_STATUS_IS_OK(status)) {
350                 DEBUG(0, ("check_published_printers: "
351                           "Could not create system server_info\n"));
352                 result = WERR_ACCESS_DENIED;
353                 goto done;
354         }
355
356         for (snum = 0; snum < n_services; snum++) {
357                 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
358                         continue;
359                 }
360
361                 result = winreg_get_printer(tmp_ctx, server_info,
362                                             smbd_messaging_context(), NULL,
363                                             lp_servicename(snum), &pinfo2);
364                 if (!W_ERROR_IS_OK(result)) {
365                         continue;
366                 }
367
368                 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
369                         nt_printer_publish_ads(smbd_messaging_context(),
370                                                ads, pinfo2);
371                 }
372
373                 TALLOC_FREE(pinfo2);
374         }
375
376         result = WERR_OK;
377 done:
378         ads_destroy(&ads);
379         ads_kdestroy("MEMORY:prtpub_cache");
380         talloc_free(tmp_ctx);
381         return result;
382 }
383
384 bool is_printer_published(TALLOC_CTX *mem_ctx,
385                           struct auth_serversupplied_info *server_info,
386                           char *servername, char *printer, struct GUID *guid,
387                           struct spoolss_PrinterInfo2 **info2)
388 {
389         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
390         enum winreg_Type type;
391         uint8_t *data;
392         uint32_t data_size;
393         WERROR result;
394         NTSTATUS status;
395
396         result = winreg_get_printer(mem_ctx, server_info,
397                                     smbd_messaging_context(),
398                                     servername, printer, &pinfo2);
399         if (!W_ERROR_IS_OK(result)) {
400                 return false;
401         }
402
403         if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
404                 TALLOC_FREE(pinfo2);
405                 return false;
406         }
407
408         if (!guid) {
409                 goto done;
410         }
411
412         /* fetching printer guids really ought to be a separate function. */
413
414         result = winreg_get_printer_dataex(mem_ctx, server_info,
415                                            smbd_messaging_context(), printer,
416                                            SPOOL_DSSPOOLER_KEY, "objectGUID",
417                                            &type, &data, &data_size);
418         if (!W_ERROR_IS_OK(result)) {
419                 TALLOC_FREE(pinfo2);
420                 return false;
421         }
422
423         /* We used to store the guid as REG_BINARY, then swapped
424            to REG_SZ for Vista compatibility so check for both */
425
426         switch (type) {
427         case REG_SZ:
428                 status = GUID_from_string((char *)data, guid);
429                 if (!NT_STATUS_IS_OK(status)) {
430                         TALLOC_FREE(pinfo2);
431                         return false;
432                 }
433                 break;
434
435         case REG_BINARY:
436                 if (data_size != sizeof(struct GUID)) {
437                         TALLOC_FREE(pinfo2);
438                         return false;
439                 }
440                 memcpy(guid, data, sizeof(struct GUID));
441                 break;
442         default:
443                 DEBUG(0,("is_printer_published: GUID value stored as "
444                          "invaluid type (%d)\n", type));
445                 break;
446         }
447
448 done:
449         if (info2) {
450                 *info2 = talloc_move(mem_ctx, &pinfo2);
451         }
452         talloc_free(pinfo2);
453         return true;
454 }
455 #else
456 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
457                           struct auth_serversupplied_info *server_info,
458                           struct spoolss_PrinterInfo2 *pinfo2,
459                           int action)
460 {
461         return WERR_OK;
462 }
463
464 WERROR check_published_printers(void)
465 {
466         return WERR_OK;
467 }
468
469 bool is_printer_published(TALLOC_CTX *mem_ctx,
470                           struct auth_serversupplied_info *server_info,
471                           char *servername, char *printer, struct GUID *guid,
472                           struct spoolss_PrinterInfo2 **info2)
473 {
474         return False;
475 }
476 #endif /* HAVE_ADS */