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