Fix bug 9900: is_printer_published GUID retrieval
[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/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_session_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 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
91                            const struct auth_session_info *session_info,
92                            struct messaging_context *msg_ctx,
93                            const char *printer, struct GUID *guid)
94 {
95         TALLOC_CTX *tmp_ctx;
96         enum winreg_Type type;
97         DATA_BLOB blob;
98         uint32_t len;
99         NTSTATUS status;
100         WERROR result;
101
102         tmp_ctx = talloc_new(mem_ctx);
103         if (tmp_ctx == NULL) {
104                 DEBUG(0, ("out of memory?!\n"));
105                 return WERR_NOMEM;
106         }
107
108         result = winreg_get_printer_dataex_internal(tmp_ctx, session_info,
109                                                     msg_ctx, printer,
110                                                     SPOOL_DSSPOOLER_KEY,
111                                                     "objectGUID",
112                                                     &type,
113                                                     &blob.data,
114                                                     &len);
115         if (!W_ERROR_IS_OK(result)) {
116                 DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
117                 goto out_ctx_free;
118         }
119         blob.length = (size_t)len;
120
121         /* We used to store the guid as REG_BINARY, then swapped
122            to REG_SZ for Vista compatibility so check for both */
123
124         switch (type) {
125         case REG_SZ: {
126                 bool ok;
127                 const char *guid_str;
128                 ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
129                 if (!ok) {
130                         DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
131                                   printer));
132                         result = WERR_REG_CORRUPT;
133                         goto out_ctx_free;
134                 }
135                 status = GUID_from_string(guid_str, guid);
136                 if (!NT_STATUS_IS_OK(status)) {
137                         DEBUG(0, ("bad GUID for printer %s\n", printer));
138                         result = ntstatus_to_werror(status);
139                         goto out_ctx_free;
140                 }
141                 break;
142         }
143         case REG_BINARY:
144                 if (blob.length != sizeof(struct GUID)) {
145                         DEBUG(0, ("bad GUID for printer %s\n", printer));
146                         result = WERR_REG_CORRUPT;
147                         goto out_ctx_free;
148                 }
149                 memcpy(guid, blob.data, sizeof(struct GUID));
150                 break;
151         default:
152                 DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
153                 result = WERR_REG_CORRUPT;
154                 goto out_ctx_free;
155                 break;
156         }
157         result = WERR_OK;
158
159 out_ctx_free:
160         talloc_free(tmp_ctx);
161         return result;
162 }
163
164 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
165                                       struct spoolss_PrinterInfo2 *info2,
166                                       ADS_MODLIST *mods)
167 {
168         char *info_str;
169
170         ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
171         ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
172         ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
173
174         info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
175                                    get_mydnsfullname(), info2->sharename);
176         if (info_str == NULL) {
177                 return WERR_NOMEM;
178         }
179         ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
180
181         info_str = talloc_asprintf(ctx, "%d", 4);
182         if (info_str == NULL) {
183                 return WERR_NOMEM;
184         }
185         ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
186
187         /* empty strings in the mods list result in an attrubute error */
188         if (strlen(info2->drivername) != 0)
189                 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
190         if (strlen(info2->location) != 0)
191                 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
192         if (strlen(info2->comment) != 0)
193                 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
194         if (strlen(info2->portname) != 0)
195                 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
196         if (strlen(info2->sepfile) != 0)
197                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
198
199         info_str = talloc_asprintf(ctx, "%u", info2->starttime);
200         if (info_str == NULL) {
201                 return WERR_NOMEM;
202         }
203         ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
204
205         info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
206         if (info_str == NULL) {
207                 return WERR_NOMEM;
208         }
209         ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
210
211         info_str = talloc_asprintf(ctx, "%u", info2->priority);
212         if (info_str == NULL) {
213                 return WERR_NOMEM;
214         }
215         ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
216
217         if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
218                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
219         } else {
220                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
221         }
222
223         switch (info2->attributes & 0x3) {
224         case 0:
225                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
226                             SPOOL_REGVAL_PRINTWHILESPOOLING);
227                 break;
228         case 1:
229                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
230                             SPOOL_REGVAL_PRINTAFTERSPOOLED);
231                 break;
232         case 2:
233                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
234                             SPOOL_REGVAL_PRINTDIRECT);
235                 break;
236         default:
237                 DEBUG(3, ("unsupported printer attributes %x\n",
238                           info2->attributes));
239         }
240
241         return WERR_OK;
242 }
243
244 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
245                                      ADS_STRUCT *ads,
246                                      struct spoolss_PrinterInfo2 *pinfo2)
247 {
248         ADS_STATUS ads_rc;
249         LDAPMessage *res;
250         char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
251         char *srv_dn_utf8, **srv_cn_utf8;
252         TALLOC_CTX *ctx;
253         ADS_MODLIST mods;
254         const char *attrs[] = {"objectGUID", NULL};
255         struct GUID guid;
256         WERROR win_rc = WERR_OK;
257         size_t converted_size;
258         const char *printer = pinfo2->sharename;
259
260         /* build the ads mods */
261         ctx = talloc_init("nt_printer_publish_ads");
262         if (ctx == NULL) {
263                 return WERR_NOMEM;
264         }
265
266         DEBUG(5, ("publishing printer %s\n", printer));
267
268         /* figure out where to publish */
269         ads_rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
270         if (!ADS_ERR_OK(ads_rc)) {
271                 DEBUG(0, ("failed to find machine account for %s\n",
272                           lp_netbios_name()));
273                 TALLOC_FREE(ctx);
274                 return WERR_NOT_FOUND;
275         }
276
277         /* We use ldap_get_dn here as we need the answer
278          * in utf8 to call ldap_explode_dn(). JRA. */
279
280         srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
281         ads_msgfree(ads, res);
282         if (!srv_dn_utf8) {
283                 TALLOC_FREE(ctx);
284                 return WERR_SERVER_UNAVAILABLE;
285         }
286         srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
287         if (!srv_cn_utf8) {
288                 TALLOC_FREE(ctx);
289                 ldap_memfree(srv_dn_utf8);
290                 return WERR_SERVER_UNAVAILABLE;
291         }
292         /* Now convert to CH_UNIX. */
293         if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
294                 TALLOC_FREE(ctx);
295                 ldap_memfree(srv_dn_utf8);
296                 ldap_memfree(srv_cn_utf8);
297                 return WERR_SERVER_UNAVAILABLE;
298         }
299         if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
300                 TALLOC_FREE(ctx);
301                 ldap_memfree(srv_dn_utf8);
302                 ldap_memfree(srv_cn_utf8);
303                 TALLOC_FREE(srv_dn);
304                 return WERR_SERVER_UNAVAILABLE;
305         }
306
307         ldap_memfree(srv_dn_utf8);
308         ldap_memfree(srv_cn_utf8);
309
310         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
311         if (!srv_cn_escaped) {
312                 TALLOC_FREE(ctx);
313                 return WERR_SERVER_UNAVAILABLE;
314         }
315         sharename_escaped = escape_rdn_val_string_alloc(printer);
316         if (!sharename_escaped) {
317                 SAFE_FREE(srv_cn_escaped);
318                 TALLOC_FREE(ctx);
319                 return WERR_SERVER_UNAVAILABLE;
320         }
321
322         prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
323
324         SAFE_FREE(srv_cn_escaped);
325         SAFE_FREE(sharename_escaped);
326
327         mods = ads_init_mods(ctx);
328
329         if (mods == NULL) {
330                 TALLOC_FREE(ctx);
331                 return WERR_NOMEM;
332         }
333
334         win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
335         if (!W_ERROR_IS_OK(win_rc)) {
336                 TALLOC_FREE(ctx);
337                 return win_rc;
338         }
339
340         /* publish it */
341         ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
342         if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
343                 int i;
344                 for (i=0; mods[i] != 0; i++)
345                         ;
346                 mods[i] = (LDAPMod *)-1;
347                 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
348         }
349
350         if (!ADS_ERR_OK(ads_rc)) {
351                 DEBUG(3, ("error publishing %s: %s\n",
352                           printer, ads_errstr(ads_rc)));
353         }
354
355         /* retreive the guid and store it locally */
356         if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
357                 bool guid_ok;
358                 ZERO_STRUCT(guid);
359                 guid_ok = ads_pull_guid(ads, res, &guid);
360                 ads_msgfree(ads, res);
361                 if (guid_ok) {
362                         store_printer_guid(msg_ctx, printer, guid);
363                 }
364         }
365         TALLOC_FREE(ctx);
366
367         return win_rc;
368 }
369
370 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
371                                        const char *printer)
372 {
373         ADS_STATUS ads_rc;
374         LDAPMessage *res = NULL;
375         char *prt_dn = NULL;
376
377         DEBUG(5, ("unpublishing printer %s\n", printer));
378
379         /* remove the printer from the directory */
380         ads_rc = ads_find_printer_on_server(ads, &res,
381                                             printer, lp_netbios_name());
382
383         if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
384                 prt_dn = ads_get_dn(ads, talloc_tos(), res);
385                 if (!prt_dn) {
386                         ads_msgfree(ads, res);
387                         return WERR_NOMEM;
388                 }
389                 ads_rc = ads_del_dn(ads, prt_dn);
390                 TALLOC_FREE(prt_dn);
391         }
392
393         if (res) {
394                 ads_msgfree(ads, res);
395         }
396         return WERR_OK;
397 }
398
399 /****************************************************************************
400  * Publish a printer in the directory
401  *
402  * @param mem_ctx      memory context
403  * @param session_info  session_info to access winreg pipe
404  * @param pinfo2       printer information
405  * @param action       publish/unpublish action
406  * @return WERROR indicating status of publishing
407  ***************************************************************************/
408
409 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
410                           const struct auth_session_info *session_info,
411                           struct messaging_context *msg_ctx,
412                           struct spoolss_PrinterInfo2 *pinfo2,
413                           int action)
414 {
415         uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
416         struct spoolss_SetPrinterInfo2 *sinfo2;
417         ADS_STATUS ads_rc;
418         ADS_STRUCT *ads = NULL;
419         WERROR win_rc;
420
421         sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
422         if (!sinfo2) {
423                 return WERR_NOMEM;
424         }
425
426         switch (action) {
427         case DSPRINT_PUBLISH:
428         case DSPRINT_UPDATE:
429                 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
430                 break;
431         case DSPRINT_UNPUBLISH:
432                 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
433                 break;
434         default:
435                 win_rc = WERR_NOT_SUPPORTED;
436                 goto done;
437         }
438
439         sinfo2->attributes = pinfo2->attributes;
440
441         win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
442                                         pinfo2->sharename, info2_mask,
443                                         sinfo2, NULL, NULL);
444         if (!W_ERROR_IS_OK(win_rc)) {
445                 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
446                 goto done;
447         }
448
449         TALLOC_FREE(sinfo2);
450
451         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
452         if (!ads) {
453                 DEBUG(3, ("ads_init() failed\n"));
454                 win_rc = WERR_SERVER_UNAVAILABLE;
455                 goto done;
456         }
457         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
458         SAFE_FREE(ads->auth.password);
459         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
460                 NULL, NULL);
461
462         /* ads_connect() will find the DC for us */
463         ads_rc = ads_connect(ads);
464         if (!ADS_ERR_OK(ads_rc)) {
465                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
466                 win_rc = WERR_ACCESS_DENIED;
467                 goto done;
468         }
469
470         switch (action) {
471         case DSPRINT_PUBLISH:
472         case DSPRINT_UPDATE:
473                 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
474                 break;
475         case DSPRINT_UNPUBLISH:
476                 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
477                 break;
478         }
479
480 done:
481         ads_destroy(&ads);
482         return win_rc;
483 }
484
485 WERROR check_published_printers(struct messaging_context *msg_ctx)
486 {
487         ADS_STATUS ads_rc;
488         ADS_STRUCT *ads = NULL;
489         int snum;
490         int n_services = lp_numservices();
491         TALLOC_CTX *tmp_ctx = NULL;
492         struct auth_session_info *session_info = NULL;
493         struct spoolss_PrinterInfo2 *pinfo2;
494         NTSTATUS status;
495         WERROR result;
496
497         tmp_ctx = talloc_new(NULL);
498         if (!tmp_ctx) return WERR_NOMEM;
499
500         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
501         if (!ads) {
502                 DEBUG(3, ("ads_init() failed\n"));
503                 return WERR_SERVER_UNAVAILABLE;
504         }
505         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
506         SAFE_FREE(ads->auth.password);
507         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
508                 NULL, NULL);
509
510         /* ads_connect() will find the DC for us */
511         ads_rc = ads_connect(ads);
512         if (!ADS_ERR_OK(ads_rc)) {
513                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
514                 result = WERR_ACCESS_DENIED;
515                 goto done;
516         }
517
518         status = make_session_info_system(tmp_ctx, &session_info);
519         if (!NT_STATUS_IS_OK(status)) {
520                 DEBUG(0, ("check_published_printers: "
521                           "Could not create system session_info\n"));
522                 result = WERR_ACCESS_DENIED;
523                 goto done;
524         }
525
526         for (snum = 0; snum < n_services; snum++) {
527                 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
528                         continue;
529                 }
530
531                 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
532                                             lp_servicename(talloc_tos(), snum),
533                                             &pinfo2);
534                 if (!W_ERROR_IS_OK(result)) {
535                         continue;
536                 }
537
538                 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
539                         nt_printer_publish_ads(msg_ctx, ads, pinfo2);
540                 }
541
542                 TALLOC_FREE(pinfo2);
543         }
544
545         result = WERR_OK;
546 done:
547         ads_destroy(&ads);
548         ads_kdestroy("MEMORY:prtpub_cache");
549         talloc_free(tmp_ctx);
550         return result;
551 }
552
553 bool is_printer_published(TALLOC_CTX *mem_ctx,
554                           const struct auth_session_info *session_info,
555                           struct messaging_context *msg_ctx,
556                           const char *servername,
557                           const char *printer,
558                           struct spoolss_PrinterInfo2 **info2)
559 {
560         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
561         WERROR result;
562         struct dcerpc_binding_handle *b;
563
564         result = winreg_printer_binding_handle(mem_ctx,
565                                                session_info,
566                                                msg_ctx,
567                                                &b);
568         if (!W_ERROR_IS_OK(result)) {
569                 return false;
570         }
571
572         result = winreg_get_printer(mem_ctx, b,
573                                     printer, &pinfo2);
574         if (!W_ERROR_IS_OK(result)) {
575                 return false;
576         }
577
578         if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
579                 TALLOC_FREE(pinfo2);
580                 return false;
581         }
582
583         if (info2) {
584                 *info2 = talloc_move(mem_ctx, &pinfo2);
585         }
586         talloc_free(pinfo2);
587         return true;
588 }
589 #else
590 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
591                            const struct auth_session_info *session_info,
592                            struct messaging_context *msg_ctx,
593                            const char *printer, struct GUID *guid)
594 {
595         return WERR_NOT_SUPPORTED;
596 }
597
598 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
599                           const struct auth_session_info *session_info,
600                           struct messaging_context *msg_ctx,
601                           struct spoolss_PrinterInfo2 *pinfo2,
602                           int action)
603 {
604         return WERR_OK;
605 }
606
607 WERROR check_published_printers(struct messaging_context *msg_ctx)
608 {
609         return WERR_OK;
610 }
611
612 bool is_printer_published(TALLOC_CTX *mem_ctx,
613                           const struct auth_session_info *session_info,
614                           struct messaging_context *msg_ctx,
615                           const char *servername,
616                           const char *printer,
617                           struct spoolss_PrinterInfo2 **info2)
618 {
619         return False;
620 }
621 #endif /* HAVE_ADS */