samba-bgqd: fix startup and logging
[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 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, ADS_SASL_PLAIN);
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_devmode_to_mods(TALLOC_CTX *ctx,
342                                         struct spoolss_DeviceMode *devmode,
343                                         ADS_MODLIST *mods)
344 {
345         char *str = NULL;
346         ADS_STATUS status;
347
348         /*
349            the device mode fields bits allow us to make an educated guess if a
350            printer feature is supported. For sure a feature must be unsupported if
351            the fields bit is not set. Device Mode Extra Data and FeatureOptionPairs
352            might help to figure out more information here. Common attributes, that
353            we can't handle yet:
354                 SPOOL_REG_PRINTBINNAMES - printBinNames
355                 SPOOL_REG_PRINTMAXXEXTENT - printMaxXExtent
356                 SPOOL_REG_PRINTMAXYEXTENT - printMaxYExtent
357                 SPOOL_REG_PRINTMINXEXTENT - printMinXExtent
358                 SPOOL_REG_PRINTMINYEXTENT - printMinYExtent
359                 SPOOL_REG_PRINTSTAPLINGSUPPORTED - printStaplingSupported
360                 SPOOL_REG_PRINTPAGESPERMINUTE - printPagesPerMinute
361                 SPOOL_REG_PRINTRATE - printRate
362                 SPOOL_REG_PRINTRATEUNIT - printRateUnit
363                 SPOOL_REG_PRINTMEDIAREADY - printMediaReady
364                 SPOOL_REG_PRINTMEDIASUPPORTED - printMediaSupported
365                 SPOOL_REG_PRINTNUMBERUP - printNumberUp
366                 SPOOL_REG_PRINTMAXCOPIES - printMaxCopies
367         */
368         if (devmode->fields & DEVMODE_COLOR) {
369                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "TRUE");
370         } else {
371                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLOR, "FALSE");
372         }
373         if (!ADS_ERR_OK(status)) {
374                 return WERR_NOT_ENOUGH_MEMORY;
375         }
376
377         if (devmode->fields & DEVMODE_DUPLEX) {
378                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "TRUE");
379         } else {
380                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTDUPLEXSUPPORTED, "FALSE");
381         }
382         if (!ADS_ERR_OK(status)) {
383                 return WERR_NOT_ENOUGH_MEMORY;
384         }
385
386         if (devmode->fields & DEVMODE_COLLATE) {
387                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "TRUE");
388         } else {
389                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTCOLLATE, "FALSE");
390         }
391         if (!ADS_ERR_OK(status)) {
392                 return WERR_NOT_ENOUGH_MEMORY;
393         }
394
395         /* portrait mode is always supported, LANDSCAPE is optional */
396         status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "PORTRAIT");
397         if (!ADS_ERR_OK(status)) {
398                 return WERR_NOT_ENOUGH_MEMORY;
399         }
400         if (devmode->fields & DEVMODE_ORIENTATION) {
401                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTORIENTATIONSSUPPORTED, "LANDSCAPE");
402                 if (!ADS_ERR_OK(status)) {
403                         return WERR_NOT_ENOUGH_MEMORY;
404                 }
405         }
406
407         /* the driverVersion attribute in AD contains actually specversion */
408         str = talloc_asprintf(ctx, "%u", devmode->specversion);
409         if (str == NULL) {
410                 return WERR_NOT_ENOUGH_MEMORY;
411         }
412         if (strlen(str) != 0) {
413                 status = ads_mod_str(ctx, mods, SPOOL_REG_DRIVERVERSION, str);
414                 if (!ADS_ERR_OK(status)) {
415                         return WERR_NOT_ENOUGH_MEMORY;
416                 }
417         }
418
419         /* devmode->yresolution is a good candidate for printMaxResolutionSupported */
420         str = talloc_asprintf(ctx, "%u", devmode->yresolution);
421         if (str == NULL) {
422                 return WERR_NOT_ENOUGH_MEMORY;
423         }
424         if (strlen(str) != 0) {
425                 status = ads_mod_str(ctx, mods, SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, str);
426                 if (!ADS_ERR_OK(status)) {
427                         return WERR_NOT_ENOUGH_MEMORY;
428                 }
429         }
430
431         return WERR_OK;
432 }
433
434
435
436 static WERROR nt_printer_info_to_mods(TALLOC_CTX *ctx,
437                                       struct spoolss_PrinterInfo2 *info2,
438                                       ADS_MODLIST *mods)
439 {
440         char *info_str;
441
442         ads_mod_str(ctx, mods, SPOOL_REG_PRINTERNAME, info2->sharename);
443         ads_mod_str(ctx, mods, SPOOL_REG_PRINTSHARENAME, info2->sharename);
444         ads_mod_str(ctx, mods, SPOOL_REG_SHORTSERVERNAME, lp_netbios_name());
445         ads_mod_str(ctx, mods, SPOOL_REG_SERVERNAME, get_mydnsfullname());
446
447         info_str = talloc_asprintf(ctx, "\\\\%s\\%s",
448                                    get_mydnsfullname(), info2->sharename);
449         if (info_str == NULL) {
450                 return WERR_NOT_ENOUGH_MEMORY;
451         }
452         ads_mod_str(ctx, mods, SPOOL_REG_UNCNAME, info_str);
453
454         info_str = talloc_asprintf(ctx, "%d", 4);
455         if (info_str == NULL) {
456                 return WERR_NOT_ENOUGH_MEMORY;
457         }
458         ads_mod_str(ctx, mods, SPOOL_REG_VERSIONNUMBER, info_str);
459
460         /* empty strings in the mods list result in an attrubute error */
461         if (strlen(info2->drivername) != 0)
462                 ads_mod_str(ctx, mods, SPOOL_REG_DRIVERNAME, info2->drivername);
463         if (strlen(info2->location) != 0)
464                 ads_mod_str(ctx, mods, SPOOL_REG_LOCATION, info2->location);
465         if (strlen(info2->comment) != 0)
466                 ads_mod_str(ctx, mods, SPOOL_REG_DESCRIPTION, info2->comment);
467         if (strlen(info2->portname) != 0)
468                 ads_mod_str(ctx, mods, SPOOL_REG_PORTNAME, info2->portname);
469         if (strlen(info2->sepfile) != 0)
470                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
471
472         info_str = talloc_asprintf(ctx, "%u", info2->starttime);
473         if (info_str == NULL) {
474                 return WERR_NOT_ENOUGH_MEMORY;
475         }
476         ads_mod_str(ctx, mods, SPOOL_REG_PRINTSTARTTIME, info_str);
477
478         info_str = talloc_asprintf(ctx, "%u", info2->untiltime);
479         if (info_str == NULL) {
480                 return WERR_NOT_ENOUGH_MEMORY;
481         }
482         ads_mod_str(ctx, mods, SPOOL_REG_PRINTENDTIME, info_str);
483
484         info_str = talloc_asprintf(ctx, "%u", info2->priority);
485         if (info_str == NULL) {
486                 return WERR_NOT_ENOUGH_MEMORY;
487         }
488         ads_mod_str(ctx, mods, SPOOL_REG_PRIORITY, info_str);
489
490         if (info2->attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) {
491                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "TRUE");
492         } else {
493                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTKEEPPRINTEDJOBS, "FALSE");
494         }
495
496         switch (info2->attributes & 0x3) {
497         case 0:
498                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
499                             SPOOL_REGVAL_PRINTWHILESPOOLING);
500                 break;
501         case 1:
502                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
503                             SPOOL_REGVAL_PRINTAFTERSPOOLED);
504                 break;
505         case 2:
506                 ads_mod_str(ctx, mods, SPOOL_REG_PRINTSPOOLING,
507                             SPOOL_REGVAL_PRINTDIRECT);
508                 break;
509         default:
510                 DEBUG(3, ("unsupported printer attributes %x\n",
511                           info2->attributes));
512         }
513
514         if (info2->devmode != NULL) {
515                 WERROR werr;
516                 werr = nt_printer_devmode_to_mods(ctx, info2->devmode, mods);
517                 if (!W_ERROR_IS_OK(werr)) {
518                         return werr;
519                 }
520         }
521
522         return WERR_OK;
523 }
524
525 static WERROR nt_printer_publish_ads(struct messaging_context *msg_ctx,
526                                      ADS_STRUCT *ads,
527                                      struct spoolss_PrinterInfo2 *pinfo2)
528 {
529         ADS_STATUS ads_rc;
530         TALLOC_CTX *ctx;
531         ADS_MODLIST mods;
532         struct GUID guid;
533         WERROR win_rc = WERR_OK;
534         const char *printer = pinfo2->sharename;
535         char *printer_dn = NULL;
536
537         /* build the ads mods */
538         ctx = talloc_init("nt_printer_publish_ads");
539         if (ctx == NULL) {
540                 return WERR_NOT_ENOUGH_MEMORY;
541         }
542
543         DEBUG(5, ("publishing printer %s\n", printer));
544
545         win_rc = nt_printer_dn_lookup(ctx, ads, printer, &printer_dn);
546         if (!W_ERROR_IS_OK(win_rc)) {
547                 DEBUG(2, ("Failed to create printer dn\n"));
548                 TALLOC_FREE(ctx);
549                 return win_rc;
550         }
551
552         mods = ads_init_mods(ctx);
553
554         if (mods == NULL) {
555                 TALLOC_FREE(ctx);
556                 return WERR_NOT_ENOUGH_MEMORY;
557         }
558
559         win_rc = nt_printer_info_to_mods(ctx, pinfo2, &mods);
560         if (!W_ERROR_IS_OK(win_rc)) {
561                 TALLOC_FREE(ctx);
562                 return win_rc;
563         }
564
565         /* publish it */
566         ads_rc = ads_mod_printer_entry(ads, printer_dn, ctx, &mods);
567         if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
568                 int i;
569                 for (i=0; mods[i] != 0; i++)
570                         ;
571                 mods[i] = (LDAPMod *)-1;
572                 ads_rc = ads_add_printer_entry(ads, printer_dn, ctx, &mods);
573         }
574
575         if (!ADS_ERR_OK(ads_rc)) {
576                 DEBUG(3, ("error publishing %s: %s\n",
577                           printer, ads_errstr(ads_rc)));
578                 /* XXX failed to publish, so no guid to retrieve */
579         }
580
581         win_rc = nt_printer_guid_retrieve_internal(ads, printer_dn, &guid);
582         if (!W_ERROR_IS_OK(win_rc)) {
583                 TALLOC_FREE(ctx);
584                 return win_rc;
585         }
586
587         win_rc = nt_printer_guid_store(msg_ctx, printer, guid);
588         if (!W_ERROR_IS_OK(win_rc)) {
589                 DEBUG(3, ("failed to store printer %s guid\n",
590                           printer));
591                 /* not catastrophic, retrieve on next use */
592                 win_rc = WERR_OK;
593         }
594
595         TALLOC_FREE(ctx);
596
597         return win_rc;
598 }
599
600 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
601                                        const char *printer)
602 {
603         ADS_STATUS ads_rc;
604         LDAPMessage *res = NULL;
605         char *prt_dn = NULL;
606
607         DEBUG(5, ("unpublishing printer %s\n", printer));
608
609         /* remove the printer from the directory */
610         ads_rc = ads_find_printer_on_server(ads, &res,
611                                             printer, lp_netbios_name());
612
613         if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
614                 prt_dn = ads_get_dn(ads, talloc_tos(), res);
615                 if (!prt_dn) {
616                         ads_msgfree(ads, res);
617                         return WERR_NOT_ENOUGH_MEMORY;
618                 }
619                 ads_rc = ads_del_dn(ads, prt_dn);
620                 TALLOC_FREE(prt_dn);
621         }
622
623         if (res) {
624                 ads_msgfree(ads, res);
625         }
626         return WERR_OK;
627 }
628
629 /****************************************************************************
630  * Publish a printer in the directory
631  *
632  * @param mem_ctx      memory context
633  * @param session_info  session_info to access winreg pipe
634  * @param pinfo2       printer information
635  * @param action       publish/unpublish action
636  * @return WERROR indicating status of publishing
637  ***************************************************************************/
638
639 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
640                           const struct auth_session_info *session_info,
641                           struct messaging_context *msg_ctx,
642                           struct spoolss_PrinterInfo2 *pinfo2,
643                           int action)
644 {
645         uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
646         struct spoolss_SetPrinterInfo2 *sinfo2;
647         ADS_STATUS ads_rc;
648         ADS_STRUCT *ads = NULL;
649         WERROR win_rc;
650         char *old_krb5ccname = NULL;
651
652         sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
653         if (!sinfo2) {
654                 return WERR_NOT_ENOUGH_MEMORY;
655         }
656
657         switch (action) {
658         case DSPRINT_PUBLISH:
659         case DSPRINT_UPDATE:
660                 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
661                 break;
662         case DSPRINT_UNPUBLISH:
663                 pinfo2->attributes &= (~PRINTER_ATTRIBUTE_PUBLISHED);
664                 break;
665         default:
666                 win_rc = WERR_NOT_SUPPORTED;
667                 goto done;
668         }
669
670         sinfo2->attributes = pinfo2->attributes;
671
672         win_rc = winreg_update_printer_internal(mem_ctx, session_info, msg_ctx,
673                                         pinfo2->sharename, info2_mask,
674                                         sinfo2, NULL, NULL);
675         if (!W_ERROR_IS_OK(win_rc)) {
676                 DBG_NOTICE("Failed to update data for printer [%s] - %s\n",
677                            pinfo2->sharename,
678                            win_errstr(win_rc));
679                 goto done;
680         }
681
682         TALLOC_FREE(sinfo2);
683
684         ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
685         if (!ads) {
686                 DEBUG(3, ("ads_init() failed\n"));
687                 win_rc = WERR_RPC_S_SERVER_UNAVAILABLE;
688                 goto done;
689         }
690         old_krb5ccname = getenv(KRB5_ENV_CCNAME);
691         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
692         SAFE_FREE(ads->auth.password);
693         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
694                 NULL, NULL);
695
696         /* ads_connect() will find the DC for us */
697         ads_rc = ads_connect(ads);
698         if (!ADS_ERR_OK(ads_rc)) {
699                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
700                 win_rc = WERR_ACCESS_DENIED;
701                 goto done;
702         }
703
704         switch (action) {
705         case DSPRINT_PUBLISH:
706         case DSPRINT_UPDATE:
707                 win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2);
708                 break;
709         case DSPRINT_UNPUBLISH:
710                 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
711                 break;
712         }
713
714 done:
715         ads_destroy(&ads);
716         ads_kdestroy("MEMORY:prtpub_cache");
717         unsetenv(KRB5_ENV_CCNAME);
718         if (old_krb5ccname) {
719                 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
720         }
721         return win_rc;
722 }
723
724 WERROR check_published_printers(struct messaging_context *msg_ctx)
725 {
726         const struct loadparm_substitution *lp_sub =
727                 loadparm_s3_global_substitution();
728         ADS_STATUS ads_rc;
729         ADS_STRUCT *ads = NULL;
730         int snum;
731         int n_services = lp_numservices();
732         TALLOC_CTX *tmp_ctx = NULL;
733         struct auth_session_info *session_info = NULL;
734         struct spoolss_PrinterInfo2 *pinfo2;
735         NTSTATUS status;
736         WERROR result;
737         char *old_krb5ccname = NULL;
738
739         tmp_ctx = talloc_new(NULL);
740         if (!tmp_ctx) return WERR_NOT_ENOUGH_MEMORY;
741
742         ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN);
743         if (!ads) {
744                 DEBUG(3, ("ads_init() failed\n"));
745                 return WERR_RPC_S_SERVER_UNAVAILABLE;
746         }
747         old_krb5ccname = getenv(KRB5_ENV_CCNAME);
748         setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
749         SAFE_FREE(ads->auth.password);
750         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
751                 NULL, NULL);
752
753         /* ads_connect() will find the DC for us */
754         ads_rc = ads_connect(ads);
755         if (!ADS_ERR_OK(ads_rc)) {
756                 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
757                 result = WERR_ACCESS_DENIED;
758                 goto done;
759         }
760
761         status = make_session_info_system(tmp_ctx, &session_info);
762         if (!NT_STATUS_IS_OK(status)) {
763                 DEBUG(0, ("check_published_printers: "
764                           "Could not create system session_info\n"));
765                 result = WERR_ACCESS_DENIED;
766                 goto done;
767         }
768
769         for (snum = 0; snum < n_services; snum++) {
770                 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
771                         continue;
772                 }
773
774                 result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx,
775                                             lp_servicename(talloc_tos(), lp_sub, snum),
776                                             &pinfo2);
777                 if (!W_ERROR_IS_OK(result)) {
778                         continue;
779                 }
780
781                 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
782                         nt_printer_publish_ads(msg_ctx, ads, pinfo2);
783                 }
784
785                 TALLOC_FREE(pinfo2);
786         }
787
788         result = WERR_OK;
789 done:
790         ads_destroy(&ads);
791         ads_kdestroy("MEMORY:prtpub_cache");
792         unsetenv(KRB5_ENV_CCNAME);
793         if (old_krb5ccname) {
794                 setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0);
795         }
796         talloc_free(tmp_ctx);
797         return result;
798 }
799
800 bool is_printer_published(TALLOC_CTX *mem_ctx,
801                           const struct auth_session_info *session_info,
802                           struct messaging_context *msg_ctx,
803                           const char *servername,
804                           const char *printer,
805                           struct spoolss_PrinterInfo2 **info2)
806 {
807         struct spoolss_PrinterInfo2 *pinfo2 = NULL;
808         WERROR result;
809         struct dcerpc_binding_handle *b;
810
811         result = winreg_printer_binding_handle(mem_ctx,
812                                                session_info,
813                                                msg_ctx,
814                                                &b);
815         if (!W_ERROR_IS_OK(result)) {
816                 return false;
817         }
818
819         result = winreg_get_printer(mem_ctx, b,
820                                     printer, &pinfo2);
821         if (!W_ERROR_IS_OK(result)) {
822                 return false;
823         }
824
825         if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
826                 TALLOC_FREE(pinfo2);
827                 return false;
828         }
829
830         if (info2) {
831                 *info2 = talloc_move(mem_ctx, &pinfo2);
832         }
833         talloc_free(pinfo2);
834         return true;
835 }
836 #else
837 WERROR nt_printer_guid_store(struct messaging_context *msg_ctx,
838                            const char *printer, struct GUID guid)
839 {
840         return WERR_NOT_SUPPORTED;
841 }
842
843 WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer,
844                                 struct GUID *pguid)
845 {
846         return WERR_NOT_SUPPORTED;
847 }
848
849 WERROR nt_printer_guid_get(TALLOC_CTX *mem_ctx,
850                            const struct auth_session_info *session_info,
851                            struct messaging_context *msg_ctx,
852                            const char *printer, struct GUID *guid)
853 {
854         return WERR_NOT_SUPPORTED;
855 }
856
857 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
858                           const struct auth_session_info *session_info,
859                           struct messaging_context *msg_ctx,
860                           struct spoolss_PrinterInfo2 *pinfo2,
861                           int action)
862 {
863         return WERR_OK;
864 }
865
866 WERROR check_published_printers(struct messaging_context *msg_ctx)
867 {
868         return WERR_OK;
869 }
870
871 bool is_printer_published(TALLOC_CTX *mem_ctx,
872                           const struct auth_session_info *session_info,
873                           struct messaging_context *msg_ctx,
874                           const char *servername,
875                           const char *printer,
876                           struct spoolss_PrinterInfo2 **info2)
877 {
878         return False;
879 }
880 #endif /* HAVE_ADS */