s3: avoid global include of ads.h.
[samba.git] / source3 / libads / ldap_printer.c
1 /* 
2    Unix SMB/CIFS implementation.
3    ads (active directory) printer utility library
4    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "ads.h"
22 #include "../librpc/gen_ndr/cli_spoolss.h"
23 #include "rpc_client/cli_spoolss.h"
24 #include "registry.h"
25 #include "registry/reg_objects.h"
26 #include "nt_printing.h"
27
28 #ifdef HAVE_ADS
29
30 /*
31   find a printer given the name and the hostname
32     Note that results "res" may be allocated on return so that the
33     results can be used.  It should be freed using ads_msgfree.
34 */
35  ADS_STATUS ads_find_printer_on_server(ADS_STRUCT *ads, LDAPMessage **res,
36                                        const char *printer,
37                                        const char *servername)
38 {
39         ADS_STATUS status;
40         char *srv_dn, **srv_cn, *s = NULL;
41         const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
42
43         status = ads_find_machine_acct(ads, res, servername);
44         if (!ADS_ERR_OK(status)) {
45                 DEBUG(1, ("ads_find_printer_on_server: cannot find host %s in ads\n",
46                           servername));
47                 return status;
48         }
49         if (ads_count_replies(ads, *res) != 1) {
50                 if (res) {
51                         ads_msgfree(ads, *res);
52                         *res = NULL;
53                 }
54                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
55         }
56         srv_dn = ldap_get_dn(ads->ldap.ld, *res);
57         if (srv_dn == NULL) {
58                 if (res) {
59                         ads_msgfree(ads, *res);
60                         *res = NULL;
61                 }
62                 return ADS_ERROR(LDAP_NO_MEMORY);
63         }
64         srv_cn = ldap_explode_dn(srv_dn, 1);
65         if (srv_cn == NULL) {
66                 ldap_memfree(srv_dn);
67                 if (res) {
68                         ads_msgfree(ads, *res);
69                         *res = NULL;
70                 }
71                 return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
72         }
73         if (res) {
74                 ads_msgfree(ads, *res);
75                 *res = NULL;
76         }
77
78         if (asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer) == -1) {
79                 ldap_memfree(srv_dn);
80                 return ADS_ERROR(LDAP_NO_MEMORY);
81         }
82         status = ads_search(ads, res, s, attrs);
83
84         ldap_memfree(srv_dn);
85         ldap_value_free(srv_cn);
86         SAFE_FREE(s);
87         return status;  
88 }
89
90  ADS_STATUS ads_find_printers(ADS_STRUCT *ads, LDAPMessage **res)
91 {
92         const char *ldap_expr;
93         const char *attrs[] = { "objectClass", "printerName", "location", "driverName",
94                                 "serverName", "description", NULL };
95
96         /* For the moment only display all printers */
97
98         ldap_expr = "(&(!(showInAdvancedViewOnly=TRUE))(uncName=*)"
99                 "(objectCategory=printQueue))";
100
101         return ads_search(ads, res, ldap_expr, attrs);
102 }
103
104 /*
105   modify a printer entry in the directory
106 */
107 ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn,
108                                  TALLOC_CTX *ctx, const ADS_MODLIST *mods)
109 {
110         return ads_gen_mod(ads, prt_dn, *mods);
111 }
112
113 /*
114   add a printer to the directory
115 */
116 ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn,
117                                         TALLOC_CTX *ctx, ADS_MODLIST *mods)
118 {
119         ads_mod_str(ctx, mods, "objectClass", "printQueue");
120         return ads_gen_add(ads, prt_dn, *mods);
121 }
122
123 /*
124   map a REG_SZ to an ldap mod
125 */
126 static bool map_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
127                    struct regval_blob *value)
128 {
129         char *str_value = NULL;
130         size_t converted_size;
131         ADS_STATUS status;
132
133         if (regval_type(value) != REG_SZ)
134                 return false;
135
136         if (regval_size(value) && *((smb_ucs2_t *) regval_data_p(value))) {
137                 if (!pull_ucs2_talloc(ctx, &str_value,
138                                       (const smb_ucs2_t *) regval_data_p(value),
139                                       &converted_size))
140                 {
141                         return false;
142                 }
143                 status = ads_mod_str(ctx, mods, regval_name(value), str_value);
144                 return ADS_ERR_OK(status);
145         }
146         return true;
147                 
148 }
149
150 /*
151   map a REG_DWORD to an ldap mod
152 */
153 static bool map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
154                       struct regval_blob *value)
155 {
156         char *str_value = NULL;
157         ADS_STATUS status;
158
159         if (regval_type(value) != REG_DWORD)
160                 return False;
161         str_value = talloc_asprintf(ctx, "%d", *((uint32 *) regval_data_p(value)));
162         if (!str_value) {
163                 return False;
164         }
165         status = ads_mod_str(ctx, mods, regval_name(value), str_value);
166         return ADS_ERR_OK(status);
167 }
168
169 /*
170   map a boolean REG_BINARY to an ldap mod
171 */
172 static bool map_bool(TALLOC_CTX *ctx, ADS_MODLIST *mods,
173                      struct regval_blob *value)
174 {
175         char *str_value;
176         ADS_STATUS status;
177
178         if ((regval_type(value) != REG_BINARY) || (regval_size(value) != 1))
179                 return False;
180         str_value =  talloc_asprintf(ctx, "%s", 
181                                      *(regval_data_p(value)) ? "TRUE" : "FALSE");
182         if (!str_value) {
183                 return False;
184         }
185         status = ads_mod_str(ctx, mods, regval_name(value), str_value);
186         return ADS_ERR_OK(status);
187 }
188
189 /*
190   map a REG_MULTI_SZ to an ldap mod
191 */
192 static bool map_multi_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
193                          struct regval_blob *value)
194 {
195         char **str_values = NULL;
196         size_t converted_size;
197         smb_ucs2_t *cur_str = (smb_ucs2_t *) regval_data_p(value);
198         uint32 size = 0, num_vals = 0, i=0;
199         ADS_STATUS status;
200
201         if (regval_type(value) != REG_MULTI_SZ)
202                 return False;
203
204         while(cur_str && *cur_str && (size < regval_size(value))) {
205                 size += 2 * (strlen_w(cur_str) + 1);
206                 cur_str += strlen_w(cur_str) + 1;
207                 num_vals++;
208         };
209
210         if (num_vals) {
211                 str_values = TALLOC_ARRAY(ctx, char *, num_vals + 1);
212                 if (!str_values) {
213                         return False;
214                 }
215                 memset(str_values, '\0', 
216                        (num_vals + 1) * sizeof(char *));
217
218                 cur_str = (smb_ucs2_t *) regval_data_p(value);
219                 for (i=0; i < num_vals; i++) {
220                         cur_str += pull_ucs2_talloc(ctx, &str_values[i],
221                                                     cur_str, &converted_size) ?
222                             converted_size : (size_t)-1;
223                 }
224
225                 status = ads_mod_strlist(ctx, mods, regval_name(value),
226                                          (const char **) str_values);
227                 return ADS_ERR_OK(status);
228         } 
229         return True;
230 }
231
232 struct valmap_to_ads {
233         const char *valname;
234         bool (*fn)(TALLOC_CTX *, ADS_MODLIST *, struct regval_blob *);
235 };
236
237 /*
238   map a REG_SZ to an ldap mod
239 */
240 static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
241                               struct regval_blob *value)
242 {
243         const struct valmap_to_ads map[] = {
244                 {SPOOL_REG_ASSETNUMBER, map_sz},
245                 {SPOOL_REG_BYTESPERMINUTE, map_dword},
246                 {SPOOL_REG_DEFAULTPRIORITY, map_dword},
247                 {SPOOL_REG_DESCRIPTION, map_sz},
248                 {SPOOL_REG_DRIVERNAME, map_sz},
249                 {SPOOL_REG_DRIVERVERSION, map_dword},
250                 {SPOOL_REG_FLAGS, map_dword},
251                 {SPOOL_REG_LOCATION, map_sz},
252                 {SPOOL_REG_OPERATINGSYSTEM, map_sz},
253                 {SPOOL_REG_OPERATINGSYSTEMHOTFIX, map_sz},
254                 {SPOOL_REG_OPERATINGSYSTEMSERVICEPACK, map_sz},
255                 {SPOOL_REG_OPERATINGSYSTEMVERSION, map_sz},
256                 {SPOOL_REG_PORTNAME, map_multi_sz},
257                 {SPOOL_REG_PRINTATTRIBUTES, map_dword},
258                 {SPOOL_REG_PRINTBINNAMES, map_multi_sz},
259                 {SPOOL_REG_PRINTCOLLATE, map_bool},
260                 {SPOOL_REG_PRINTCOLOR, map_bool},
261                 {SPOOL_REG_PRINTDUPLEXSUPPORTED, map_bool},
262                 {SPOOL_REG_PRINTENDTIME, map_dword},
263                 {SPOOL_REG_PRINTFORMNAME, map_sz},
264                 {SPOOL_REG_PRINTKEEPPRINTEDJOBS, map_bool},
265                 {SPOOL_REG_PRINTLANGUAGE, map_multi_sz},
266                 {SPOOL_REG_PRINTMACADDRESS, map_sz},
267                 {SPOOL_REG_PRINTMAXCOPIES, map_sz},
268                 {SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, map_dword},
269                 {SPOOL_REG_PRINTMAXXEXTENT, map_dword},
270                 {SPOOL_REG_PRINTMAXYEXTENT, map_dword},
271                 {SPOOL_REG_PRINTMEDIAREADY, map_multi_sz},
272                 {SPOOL_REG_PRINTMEDIASUPPORTED, map_multi_sz},
273                 {SPOOL_REG_PRINTMEMORY, map_dword},
274                 {SPOOL_REG_PRINTMINXEXTENT, map_dword},
275                 {SPOOL_REG_PRINTMINYEXTENT, map_dword},
276                 {SPOOL_REG_PRINTNETWORKADDRESS, map_sz},
277                 {SPOOL_REG_PRINTNOTIFY, map_sz},
278                 {SPOOL_REG_PRINTNUMBERUP, map_dword},
279                 {SPOOL_REG_PRINTORIENTATIONSSUPPORTED, map_multi_sz},
280                 {SPOOL_REG_PRINTOWNER, map_sz},
281                 {SPOOL_REG_PRINTPAGESPERMINUTE, map_dword},
282                 {SPOOL_REG_PRINTRATE, map_dword},
283                 {SPOOL_REG_PRINTRATEUNIT, map_sz},
284                 {SPOOL_REG_PRINTSEPARATORFILE, map_sz},
285                 {SPOOL_REG_PRINTSHARENAME, map_sz},
286                 {SPOOL_REG_PRINTSPOOLING, map_sz},
287                 {SPOOL_REG_PRINTSTAPLINGSUPPORTED, map_bool},
288                 {SPOOL_REG_PRINTSTARTTIME, map_dword},
289                 {SPOOL_REG_PRINTSTATUS, map_sz},
290                 {SPOOL_REG_PRIORITY, map_dword},
291                 {SPOOL_REG_SERVERNAME, map_sz},
292                 {SPOOL_REG_SHORTSERVERNAME, map_sz},
293                 {SPOOL_REG_UNCNAME, map_sz},
294                 {SPOOL_REG_URL, map_sz},
295                 {SPOOL_REG_VERSIONNUMBER, map_dword},
296                 {NULL, NULL}
297         };
298         int i;
299
300         for (i=0; map[i].valname; i++) {
301                 if (StrCaseCmp(map[i].valname, regval_name(value)) == 0) {
302                         if (!map[i].fn(ctx, mods, value)) {
303                                 DEBUG(5, ("Add of value %s to modlist failed\n", regval_name(value)));
304                         } else {
305                                 DEBUG(7, ("Mapped value %s\n", regval_name(value)));
306                         }
307                         
308                 }
309         }
310 }
311
312
313 WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli, 
314                                           TALLOC_CTX *mem_ctx,
315                                           ADS_MODLIST *mods,
316                                           const char *printer)
317 {
318         WERROR result;
319         char *printername;
320         struct spoolss_PrinterEnumValues *info;
321         uint32_t count;
322         uint32 i;
323         struct policy_handle pol;
324
325         if ((asprintf(&printername, "%s\\%s", cli->srv_name_slash, printer) == -1)) {
326                 DEBUG(3, ("Insufficient memory\n"));
327                 return WERR_NOMEM;
328         }
329
330         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
331                                                printername,
332                                                SEC_FLAG_MAXIMUM_ALLOWED,
333                                                &pol);
334         if (!W_ERROR_IS_OK(result)) {
335                 DEBUG(3, ("Unable to open printer %s, error is %s.\n",
336                           printername, win_errstr(result)));
337                 SAFE_FREE(printername);
338                 return result;
339         }
340
341         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol,
342                                                   SPOOL_DSDRIVER_KEY,
343                                                   0,
344                                                   &count,
345                                                   &info);
346
347         if (!W_ERROR_IS_OK(result)) {
348                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
349                           printername, win_errstr(result)));
350         } else {
351                 /* Have the data we need now, so start building */
352                 for (i=0; i < count; i++) {
353                         struct regval_blob *v;
354
355                         v = regval_compose(mem_ctx, info[i].value_name,
356                                            info[i].type,
357                                            info[i].data->data,
358                                            info[i].data->length);
359                         if (v == NULL) {
360                                 return WERR_NOMEM;
361                         }
362
363                         map_regval_to_ads(mem_ctx, mods, v);
364                         talloc_free(v);
365                 }
366         }
367
368         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol,
369                                                   SPOOL_DSSPOOLER_KEY,
370                                                   0,
371                                                   &count,
372                                                   &info);
373         if (!W_ERROR_IS_OK(result)) {
374                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
375                           printername, win_errstr(result)));
376         } else {
377                 for (i=0; i < count; i++) {
378                         struct regval_blob *v;
379
380                         v = regval_compose(mem_ctx, info[i].value_name,
381                                            info[i].type,
382                                            info[i].data->data,
383                                            info[i].data->length);
384                         if (v == NULL) {
385                                 return WERR_NOMEM;
386                         }
387
388                         map_regval_to_ads(mem_ctx, mods, v);
389                         talloc_free(v);
390                 }
391         }
392
393         ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
394
395         rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
396         SAFE_FREE(printername);
397
398         return result;
399 }
400
401 #endif