2588e1de7e778e0be0926dd165cbf03315490b1d
[metze/samba/wip.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 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
39                              const char *printer, struct GUID guid)
40 {
41         TALLOC_CTX *tmp_ctx;
42         const struct auth_session_info *session_info;
43         const char *guid_str;
44         DATA_BLOB blob;
45         WERROR result;
46
47         tmp_ctx = talloc_new(NULL);
48         if (!tmp_ctx) {
49                 DEBUG(0, ("Out of memory?!\n"));
50                 return WERR_NOT_ENOUGH_MEMORY;
51         }
52
53         session_info = get_session_info_system();
54         if (session_info == NULL) {
55                 DEBUG(0, ("Could not get system session_info\n"));
56                 result = WERR_NOT_ENOUGH_MEMORY;
57                 goto done;
58         }
59
60         guid_str = GUID_string(tmp_ctx, &guid);
61         if (!guid_str) {
62                 DEBUG(0, ("Out of memory?!\n"));
63                 result = WERR_NOT_ENOUGH_MEMORY;
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, ("Could not marshall string %s for objectGUID\n",
72                           guid_str));
73                 result = WERR_NOT_ENOUGH_MEMORY;
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, ("Failed to store GUID for printer %s\n", printer));
83                 goto done;
84         }
85
86         result = WERR_OK;
87 done:
88         talloc_free(tmp_ctx);
89
90         return result;
91 }
92
93 static WERROR nt_printer_dn_lookup(TALLOC_CTX *mem_ctx,
94                                    ADS_STRUCT *ads,
95                                    const char *printer,
96                                    char **pprinter_dn)
97 {
98         char *printer_dn = NULL;
99         char *srv_dn = NULL;
100         char *srv_cn_0 = NULL;
101         char *srv_cn_escaped = NULL;
102         char *sharename_escaped = NULL;
103         char *srv_dn_utf8 = NULL;
104         char **srv_cn_utf8 = NULL;
105         size_t converted_size;
106         ADS_STATUS ads_status;
107         LDAPMessage *res;
108         WERROR result;
109         bool ok;
110
111         ads_status = ads_find_machine_acct(ads, &res, lp_netbios_name());
112         if (!ADS_ERR_OK(ads_status)) {
113                 DEBUG(2, ("Failed to find machine account for %s\n",
114                           lp_netbios_name()));
115                 result = WERR_NOT_FOUND;
116                 goto err_out;
117         }
118
119         /*
120          * We use ldap_get_dn here as we need the answer in utf8 to call
121          * ldap_explode_dn(). JRA.
122          */
123         srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
124         ads_msgfree(ads, res);
125         if (srv_dn_utf8 == NULL) {
126                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
127                 goto err_out;
128         }
129
130         srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
131         if (srv_cn_utf8 == NULL) {
132                 ldap_memfree(srv_dn_utf8);
133                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
134                 goto err_out;
135         }
136
137         /* Now convert to CH_UNIX. */
138         ok = pull_utf8_talloc(mem_ctx, &srv_dn, srv_dn_utf8, &converted_size);
139         ldap_memfree(srv_dn_utf8);
140         if (!ok) {
141                 ldap_memfree(srv_cn_utf8);
142                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
143                 goto err_out;
144         }
145
146         ok = pull_utf8_talloc(mem_ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size);
147         ldap_memfree(srv_cn_utf8);
148         if (!ok) {
149                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
150                 goto err_out;
151         }
152
153         srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
154         if (srv_cn_escaped == NULL) {
155                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
156                 goto err_out;
157         }
158
159         sharename_escaped = escape_rdn_val_string_alloc(printer);
160         if (sharename_escaped == NULL) {
161                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
162                 goto err_out;
163         }
164
165         printer_dn = talloc_asprintf(mem_ctx,
166                                      "cn=%s-%s,%s",
167                                      srv_cn_escaped,
168                                      sharename_escaped,
169                                      srv_dn);
170         if (printer_dn == NULL) {
171                 result = WERR_NOT_ENOUGH_MEMORY;
172                 goto err_out;
173         }
174
175         *pprinter_dn = printer_dn;
176
177         result = WERR_OK;
178 err_out:
179         SAFE_FREE(sharename_escaped);
180         SAFE_FREE(srv_cn_escaped);
181         TALLOC_FREE(srv_cn_0);
182         TALLOC_FREE(srv_dn);
183         return result;
184 }
185
186 static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads,
187                                                 const char *printer_dn,
188                                                 struct GUID *pguid)
189 {
190         ADS_STATUS ads_status;
191         LDAPMessage *res;
192         const char *attrs[] = {"objectGUID", NULL};
193         struct GUID guid;
194         bool ok;
195
196         ads_status = ads_search_dn(ads, &res, printer_dn, attrs);
197         if (!ADS_ERR_OK(ads_status)) {
198                 DEBUG(2, ("Failed to retrieve GUID from DC - %s\n",
199                           ads_errstr(ads_status)));
200                 return WERR_FILE_NOT_FOUND;
201         }
202
203         ZERO_STRUCT(guid);
204         ok = ads_pull_guid(ads, res, &guid);
205         ads_msgfree(ads, res);
206         if (!ok) {
207                 return WERR_NOT_ENOUGH_MEMORY;
208         }
209
210         *pguid = guid;
211
212         return WERR_OK;
213 }
214
215 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
216                                 struct GUID *pguid)
217 {
218         ADS_STRUCT *ads = NULL;
219         char *old_krb5ccname = NULL;
220         char *printer_dn;
221         WERROR result;
222         ADS_STATUS ads_status;
223         TALLOC_CTX *tmp_ctx;
224
225         tmp_ctx = talloc_new(mem_ctx);
226         if (tmp_ctx == NULL) {
227                 return WERR_NOT_ENOUGH_MEMORY;
228         }
229
230         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
231         if (ads == NULL) {
232                 result = WERR_RPC_S_SERVER_UNAVAILABLE;
233                 goto out;
234         }
235
236         old_krb5ccname = getenv(KRB5_ENV_CCNAME);
237         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
238         SAFE_FREE(ads->auth.password);
239         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
240                                                             NULL, NULL);
241
242         ads_status = ads_connect(ads);
243         if (!ADS_ERR_OK(ads_status)) {
244                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status)));
245                 result = WERR_ACCESS_DENIED;
246                 goto out;
247         }
248
249         result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn);
250         if (!W_ERROR_IS_OK(result)) {
251                 goto out;
252         }
253
254         result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid);
255 out:
256         TALLOC_FREE(tmp_ctx);
257         ads_destroy(&ads);
258         ads_kdestroy("MEMORY:prtpub_cache");
259         unsetenv(KRB5_ENV_CCNAME);
260         if (old_krb5ccname != NULL) {
261                 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
262         }
263
264         return result;
265 }
266
267 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
268                            const struct auth_session_info *session_info,
269                            struct messaging_context *msg_ctx,
270                            const char *printer, struct GUID *guid)
271 {
272         TALLOC_CTX *tmp_ctx;
273         enum winreg_Type type;
274         DATA_BLOB blob;
275         uint32_t len;
276         NTSTATUS status;
277         WERROR result;
278
279         tmp_ctx = talloc_new(mem_ctx);
280         if (tmp_ctx == NULL) {
281                 DEBUG(0, ("out of memory?!\n"));
282                 return WERR_NOT_ENOUGH_MEMORY;
283         }
284
285         result = winreg_get_printer_dataex_internal(tmp_ctx, session_info,
286                                                     msg_ctx, printer,
287                                                     SPOOL_DSSPOOLER_KEY,
288                                                     "objectGUID",
289                                                     &type,
290                                                     &blob.data,
291                                                     &len);
292         if (!W_ERROR_IS_OK(result)) {
293                 DEBUG(0, ("Failed to get GUID for printer %s\n", printer));
294                 goto out_ctx_free;
295         }
296         blob.length = (size_t)len;
297
298         /* We used to store the guid as REG_BINARY, then swapped
299            to REG_SZ for Vista compatibility so check for both */
300
301         switch (type) {
302         case REG_SZ: {
303                 bool ok;
304                 const char *guid_str;
305                 ok = pull_reg_sz(tmp_ctx, &blob, &guid_str);
306                 if (!ok) {
307                         DEBUG(0, ("Failed to unmarshall GUID for printer %s\n",
308                                   printer));
309                         result = WERR_REGISTRY_CORRUPT;
310                         goto out_ctx_free;
311                 }
312                 status = GUID_from_string(guid_str, guid);
313                 if (!NT_STATUS_IS_OK(status)) {
314                         DEBUG(0, ("bad GUID for printer %s\n", printer));
315                         result = ntstatus_to_werror(status);
316                         goto out_ctx_free;
317                 }
318                 break;
319         }
320         case REG_BINARY:
321                 if (blob.length != sizeof(struct GUID)) {
322                         DEBUG(0, ("bad GUID for printer %s\n", printer));
323                         result = WERR_REGISTRY_CORRUPT;
324                         goto out_ctx_free;
325                 }
326                 memcpy(guid, blob.data, sizeof(struct GUID));
327                 break;
328         default:
329                 DEBUG(0,("GUID value stored as invalid type (%d)\n", type));
330                 result = WERR_REGISTRY_CORRUPT;
331                 goto out_ctx_free;
332                 break;
333         }
334         result = WERR_OK;
335
336 out_ctx_free:
337         talloc_free(tmp_ctx);
338         return result;
339 }
340
341 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
342                                       struct spoolss_PrinterInfo2 *info2,
343                                       ADS_MODLIST *mods)
344 {
345         char *info_str;
346
347         ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
348         ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
349         ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
350
351         info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
352                                    get_mydnsfullname(), info2->sharename);
353         if (info_str == NULL) {
354                 return WERR_NOT_ENOUGH_MEMORY;
355         }
356         ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
357
358         info_str = talloc_asprintf(ctx, "%d", 4);
359         if (info_str == NULL) {
360                 return WERR_NOT_ENOUGH_MEMORY;
361         }
362         ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
363
364         /* empty strings in the mods list result in an attrubute error */
365         if (strlen(info2->drivername) != 0)
366                 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
367         if (strlen(info2->location) != 0)
368                 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
369         if (strlen(info2->comment) != 0)
370                 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
371         if (strlen(info2->portname) != 0)
372                 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
373         if (strlen(info2->sepfile) != 0)
374                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
375
376         info_str = talloc_asprintf(ctx, "%u", info2->starttime);
377         if (info_str == NULL) {
378                 return WERR_NOT_ENOUGH_MEMORY;
379         }
380         ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
381
382         info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
383         if (info_str == NULL) {
384                 return WERR_NOT_ENOUGH_MEMORY;
385         }
386         ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
387
388         info_str = talloc_asprintf(ctx, "%u", info2->priority);
389         if (info_str == NULL) {
390                 return WERR_NOT_ENOUGH_MEMORY;
391         }
392         ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
393
394         if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
395                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
396         } else {
397                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
398         }
399
400         switch (info2->attributes & 0x3) {
401         case 0:
402                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
403                             SPOOL_REGVAL_PRINTWHILESPOOLING);
404                 break;
405         case 1:
406                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
407                             SPOOL_REGVAL_PRINTAFTERSPOOLED);
408                 break;
409         case 2:
410                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
411                             SPOOL_REGVAL_PRINTDIRECT);
412                 break;
413         default:
414                 DEBUG(3, ("unsupported printer attributes %x\n",
415                           info2->attributes));
416         }
417
418         return WERR_OK;
419 }
420
421 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
422                                      ADS_STRUCT *ads,
423                                      struct spoolss_PrinterInfo2 *pinfo2)
424 {
425         ADS_STATUS ads_rc;
426         TALLOC_CTX *ctx;
427         ADS_MODLIST mods;
428         struct GUID guid;
429         WERROR win_rc = WERR_OK;
430         const char *printer = pinfo2->sharename;
431         char *printer_dn = NULL;
432
433         /* build the ads mods */
434         ctx = talloc_init("nt_printer_publish_ads");
435         if (ctx == NULL) {
436                 return WERR_NOT_ENOUGH_MEMORY;
437         }
438
439         DEBUG(5, ("publishing printer %s\n", printer));
440
441         win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn);
442         if (!W_ERROR_IS_OK(win_rc)) {
443                 DEBUG(2, ("Failed to create printer dn\n"));
444                 TALLOC_FREE(ctx);
445                 return win_rc;
446         }
447
448         mods = ads_init_mods(ctx);
449
450         if (mods == NULL) {
451                 TALLOC_FREE(ctx);
452                 return WERR_NOT_ENOUGH_MEMORY;
453         }
454
455         win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
456         if (!W_ERROR_IS_OK(win_rc)) {
457                 TALLOC_FREE(ctx);
458                 return win_rc;
459         }
460
461         /* publish it */
462         ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods);
463         if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
464                 int i;
465                 for (i=0; mods[i] != 0; i++)
466                         ;
467                 mods[i] = (LDAPMod *)-1;
468                 ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods);
469         }
470
471         if (!ADS_ERR_OK(ads_rc)) {
472                 DEBUG(3, ("error publishing %s: %s\n",
473                           printer, ads_errstr(ads_rc)));
474                 /* XXX failed to publish, so no guid to retrieve */
475         }
476
477         win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid);
478         if (!W_ERROR_IS_OK(win_rc)) {
479                 TALLOC_FREE(ctx);
480                 return win_rc;
481         }
482
483         win_rc = nt_printer_guid_store(msg_ctx, printer, guid);
484         if (!W_ERROR_IS_OK(win_rc)) {
485                 DEBUG(3, ("failed to store printer %s guid\n",
486                           printer));
487                 /* not catastrophic, retrieve on next use */
488                 win_rc = WERR_OK;
489         }
490
491         TALLOC_FREE(ctx);
492
493         return win_rc;
494 }
495
496 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
497                                        const char *printer)
498 {
499         ADS_STATUS ads_rc;
500         LDAPMessage *res = NULL;
501         char *prt_dn = NULL;
502
503         DEBUG(5, ("unpublishing printer %s\n", printer));
504
505         /* remove the printer from the directory */
506         ads_rc = ads_find_printer_on_server(ads, &res,
507                                             printer, lp_netbios_name());
508
509         if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
510                 prt_dn = ads_get_dn(ads, talloc_tos(), res);
511                 if (!prt_dn) {
512                         ads_msgfree(ads, res);
513                         return WERR_NOT_ENOUGH_MEMORY;
514                 }
515                 ads_rc = ads_del_dn(ads, prt_dn);
516                 TALLOC_FREE(prt_dn);
517         }
518
519         if (res) {
520                 ads_msgfree(ads, res);
521         }
522         return WERR_OK;
523 }
524
525 /****************************************************************************
526  * Publish a printer in the directory
527  *
528  * @param mem_ctx      memory context
529  * @param session_info  session_info to access winreg pipe
530  * @param pinfo2       printer information
531  * @param action       publish/unpublish action
532  * @return WERROR indicating status of publishing
533  ***************************************************************************/
534
535 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
536                           const struct auth_session_info *session_info,
537                           struct messaging_context *msg_ctx,
538                           struct spoolss_PrinterInfo2 *pinfo2,
539                           int action)
540 {
541         uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
542         struct spoolss_SetPrinterInfo2 *sinfo2;
543         ADS_STATUS ads_rc;
544         ADS_STRUCT *ads = NULL;
545         WERROR win_rc;
546         char *old_krb5ccname = NULL;
547
548         sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
549         if (!sinfo2) {
550                 return WERR_NOT_ENOUGH_MEMORY;
551         }
552
553         switch (action) {
554         case DSPRINT_PUBLISH:
555         case DSPRINT_UPDATE:
556                 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
557                 break;
558         case DSPRINT_UNPUBLISH:
559                 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
560                 break;
561         default:
562                 win_rc = WERR_NOT_SUPPORTED;
563                 goto done;
564         }
565
566         sinfo2->attributes = pinfo2->attributes;
567
568         win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
569                                         pinfo2->sharename, info2_mask,
570                                         sinfo2, NULL, NULL);
571         if (!W_ERROR_IS_OK(win_rc)) {
572                 DBG_NOTICE("Failed to update data for printer [%s] - %s\n",
573                            pinfo2->sharename,
574                            win_errstr(win_rc));
575                 goto done;
576         }
577
578         TALLOC_FREE(sinfo2);
579
580         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
581         if (!ads) {
582                 DEBUG(3, ("ads_init() failed\n"));
583                 win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
584                 goto done;
585         }
586         old_krb5ccname = getenv(KRB5_ENV_CCNAME);
587         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
588         SAFE_FREE(ads->auth.password);
589         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
590                 NULL, NULL);
591
592         /* ads_connect() will find the DC for us */
593         ads_rc = ads_connect(ads);
594         if (!ADS_ERR_OK(ads_rc)) {
595                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
596                 win_rc = WERR_ACCESS_DENIED;
597                 goto done;
598         }
599
600         switch (action) {
601         case DSPRINT_PUBLISH:
602         case DSPRINT_UPDATE:
603                 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
604                 break;
605         case DSPRINT_UNPUBLISH:
606                 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
607                 break;
608         }
609
610 done:
611         ads_destroy(&ads);
612         ads_kdestroy("MEMORY:prtpub_cache");
613         unsetenv(KRB5_ENV_CCNAME);
614         if (old_krb5ccname) {
615                 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
616         }
617         return win_rc;
618 }
619
620 WERROR check_published_printers(struct messaging_context *msg_ctx)
621 {
622         ADS_STATUS ads_rc;
623         ADS_STRUCT *ads = NULL;
624         int snum;
625         int n_services = lp_numservices();
626         TALLOC_CTX *tmp_ctx = NULL;
627         struct auth_session_info *session_info = NULL;
628         struct spoolss_PrinterInfo2 *pinfo2;
629         NTSTATUS status;
630         WERROR result;
631         char *old_krb5ccname = NULL;
632
633         tmp_ctx = talloc_new(NULL);
634         if (!tmp_ctx) return WERR_NOT_ENOUGH_MEMORY;
635
636         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
637         if (!ads) {
638                 DEBUG(3, ("ads_init() failed\n"));
639                 return WERR_RPC_S_SERVER_UNAVAILABLE;
640         }
641         old_krb5ccname = getenv(KRB5_ENV_CCNAME);
642         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
643         SAFE_FREE(ads->auth.password);
644         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
645                 NULL, NULL);
646
647         /* ads_connect() will find the DC for us */
648         ads_rc = ads_connect(ads);
649         if (!ADS_ERR_OK(ads_rc)) {
650                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
651                 result = WERR_ACCESS_DENIED;
652                 goto done;
653         }
654
655         status = make_session_info_system(tmp_ctx, &session_info);
656         if (!NT_STATUS_IS_OK(status)) {
657                 DEBUG(0, ("check_published_printers: "
658                           "Could not create system session_info\n"));
659                 result = WERR_ACCESS_DENIED;
660                 goto done;
661         }
662
663         for (snum = 0; snum < n_services; snum++) {
664                 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
665                         continue;
666                 }
667
668                 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
669                                             lp_servicename(talloc_tos(), snum),
670                                             &pinfo2);
671                 if (!W_ERROR_IS_OK(result)) {
672                         continue;
673                 }
674
675                 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
676                         nt_printer_publish_ads(msg_ctx, ads, pinfo2);
677                 }
678
679                 TALLOC_FREE(pinfo2);
680         }
681
682         result = WERR_OK;
683 done:
684         ads_destroy(&ads);
685         ads_kdestroy("MEMORY:prtpub_cache");
686         unsetenv(KRB5_ENV_CCNAME);
687         if (old_krb5ccname) {
688                 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
689         }
690         talloc_free(tmp_ctx);
691         return result;
692 }
693
694 bool is_printer_published(TALLOC_CTX *mem_ctx,
695                           const struct auth_session_info *session_info,
696                           struct messaging_context *msg_ctx,
697                           const char *servername,
698                           const char *printer,
699                           struct spoolss_PrinterInfo2 **info2)
700 {
701         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
702         WERROR result;
703         struct dcerpc_binding_handle *b;
704
705         result = winreg_printer_binding_handle(mem_ctx,
706                                                session_info,
707                                                msg_ctx,
708                                                &b);
709         if (!W_ERROR_IS_OK(result)) {
710                 return false;
711         }
712
713         result = winreg_get_printer(mem_ctx, b,
714                                     printer, &pinfo2);
715         if (!W_ERROR_IS_OK(result)) {
716                 return false;
717         }
718
719         if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
720                 TALLOC_FREE(pinfo2);
721                 return false;
722         }
723
724         if (info2) {
725                 *info2 = talloc_move(mem_ctx, &pinfo2);
726         }
727         talloc_free(pinfo2);
728         return true;
729 }
730 #else
731 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
732                            const char *printer, struct GUID guid)
733 {
734         return WERR_NOT_SUPPORTED;
735 }
736
737 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
738                                 struct GUID *pguid)
739 {
740         return WERR_NOT_SUPPORTED;
741 }
742
743 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
744                            const struct auth_session_info *session_info,
745                            struct messaging_context *msg_ctx,
746                            const char *printer, struct GUID *guid)
747 {
748         return WERR_NOT_SUPPORTED;
749 }
750
751 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
752                           const struct auth_session_info *session_info,
753                           struct messaging_context *msg_ctx,
754                           struct spoolss_PrinterInfo2 *pinfo2,
755                           int action)
756 {
757         return WERR_OK;
758 }
759
760 WERROR check_published_printers(struct messaging_context *msg_ctx)
761 {
762         return WERR_OK;
763 }
764
765 bool is_printer_published(TALLOC_CTX *mem_ctx,
766                           const struct auth_session_info *session_info,
767                           struct messaging_context *msg_ctx,
768                           const char *servername,
769                           const char *printer,
770                           struct spoolss_PrinterInfo2 **info2)
771 {
772         return False;
773 }
774 #endif /* HAVE_ADS */