251dfb0a81548394f3b09be39a75d18251c6cd2d
[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/ndr_spoolss_c.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                 ads_msgfree(ads, *res);
51                 *res = NULL;
52                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
53         }
54         srv_dn = ldap_get_dn(ads->ldap.ld, *res);
55         if (srv_dn == NULL) {
56                 ads_msgfree(ads, *res);
57                 *res = NULL;
58                 return ADS_ERROR(LDAP_NO_MEMORY);
59         }
60         srv_cn = ldap_explode_dn(srv_dn, 1);
61         if (srv_cn == NULL) {
62                 ldap_memfree(srv_dn);
63                 ads_msgfree(ads, *res);
64                 *res = NULL;
65                 return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
66         }
67         ads_msgfree(ads, *res);
68         *res = NULL;
69
70         if (asprintf(&s, "(cn=%s-%s)", srv_cn[0], printer) == -1) {
71                 ldap_memfree(srv_dn);
72                 return ADS_ERROR(LDAP_NO_MEMORY);
73         }
74         status = ads_search(ads, res, s, attrs);
75
76         ldap_memfree(srv_dn);
77         ldap_value_free(srv_cn);
78         SAFE_FREE(s);
79         return status;  
80 }
81
82  ADS_STATUS ads_find_printers(ADS_STRUCT *ads, LDAPMessage **res)
83 {
84         const char *ldap_expr;
85         const char *attrs[] = { "objectClass", "printerName", "location", "driverName",
86                                 "serverName", "description", NULL };
87
88         /* For the moment only display all printers */
89
90         ldap_expr = "(&(!(showInAdvancedViewOnly=TRUE))(uncName=*)"
91                 "(objectCategory=printQueue))";
92
93         return ads_search(ads, res, ldap_expr, attrs);
94 }
95
96 /*
97   modify a printer entry in the directory
98 */
99 ADS_STATUS ads_mod_printer_entry(ADS_STRUCT *ads, char *prt_dn,
100                                  TALLOC_CTX *ctx, const ADS_MODLIST *mods)
101 {
102         return ads_gen_mod(ads, prt_dn, *mods);
103 }
104
105 /*
106   add a printer to the directory
107 */
108 ADS_STATUS ads_add_printer_entry(ADS_STRUCT *ads, char *prt_dn,
109                                         TALLOC_CTX *ctx, ADS_MODLIST *mods)
110 {
111         ads_mod_str(ctx, mods, "objectClass", "printQueue");
112         return ads_gen_add(ads, prt_dn, *mods);
113 }
114
115 /*
116   map a REG_SZ to an ldap mod
117 */
118 static bool map_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
119                    struct regval_blob *value)
120 {
121         char *str_value = NULL;
122         size_t converted_size;
123         ADS_STATUS status;
124
125         if (regval_type(value) != REG_SZ)
126                 return false;
127
128         if (regval_size(value) && *((smb_ucs2_t *) regval_data_p(value))) {
129                 if (!pull_ucs2_talloc(ctx, &str_value,
130                                       (const smb_ucs2_t *) regval_data_p(value),
131                                       &converted_size))
132                 {
133                         return false;
134                 }
135                 status = ads_mod_str(ctx, mods, regval_name(value), str_value);
136                 return ADS_ERR_OK(status);
137         }
138         return true;
139                 
140 }
141
142 /*
143   map a REG_DWORD to an ldap mod
144 */
145 static bool map_dword(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
146                       struct regval_blob *value)
147 {
148         char *str_value = NULL;
149         ADS_STATUS status;
150
151         if (regval_type(value) != REG_DWORD)
152                 return False;
153         str_value = talloc_asprintf(ctx, "%d", *((uint32 *) regval_data_p(value)));
154         if (!str_value) {
155                 return False;
156         }
157         status = ads_mod_str(ctx, mods, regval_name(value), str_value);
158         return ADS_ERR_OK(status);
159 }
160
161 /*
162   map a boolean REG_BINARY to an ldap mod
163 */
164 static bool map_bool(TALLOC_CTX *ctx, ADS_MODLIST *mods,
165                      struct regval_blob *value)
166 {
167         char *str_value;
168         ADS_STATUS status;
169
170         if ((regval_type(value) != REG_BINARY) || (regval_size(value) != 1))
171                 return False;
172         str_value =  talloc_asprintf(ctx, "%s", 
173                                      *(regval_data_p(value)) ? "TRUE" : "FALSE");
174         if (!str_value) {
175                 return False;
176         }
177         status = ads_mod_str(ctx, mods, regval_name(value), str_value);
178         return ADS_ERR_OK(status);
179 }
180
181 /*
182   map a REG_MULTI_SZ to an ldap mod
183 */
184 static bool map_multi_sz(TALLOC_CTX *ctx, ADS_MODLIST *mods,
185                          struct regval_blob *value)
186 {
187         char **str_values = NULL;
188         size_t converted_size;
189         smb_ucs2_t *cur_str = (smb_ucs2_t *) regval_data_p(value);
190         uint32 size = 0, num_vals = 0, i=0;
191         ADS_STATUS status;
192
193         if (regval_type(value) != REG_MULTI_SZ)
194                 return False;
195
196         while(cur_str && *cur_str && (size < regval_size(value))) {
197                 size += 2 * (strlen_w(cur_str) + 1);
198                 cur_str += strlen_w(cur_str) + 1;
199                 num_vals++;
200         };
201
202         if (num_vals) {
203                 str_values = TALLOC_ARRAY(ctx, char *, num_vals + 1);
204                 if (!str_values) {
205                         return False;
206                 }
207                 memset(str_values, '\0', 
208                        (num_vals + 1) * sizeof(char *));
209
210                 cur_str = (smb_ucs2_t *) regval_data_p(value);
211                 for (i=0; i < num_vals; i++) {
212                         cur_str += pull_ucs2_talloc(ctx, &str_values[i],
213                                                     cur_str, &converted_size) ?
214                             converted_size : (size_t)-1;
215                 }
216
217                 status = ads_mod_strlist(ctx, mods, regval_name(value),
218                                          (const char **) str_values);
219                 return ADS_ERR_OK(status);
220         } 
221         return True;
222 }
223
224 struct valmap_to_ads {
225         const char *valname;
226         bool (*fn)(TALLOC_CTX *, ADS_MODLIST *, struct regval_blob *);
227 };
228
229 /*
230   map a REG_SZ to an ldap mod
231 */
232 static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
233                               struct regval_blob *value)
234 {
235         const struct valmap_to_ads map[] = {
236                 {SPOOL_REG_ASSETNUMBER, map_sz},
237                 {SPOOL_REG_BYTESPERMINUTE, map_dword},
238                 {SPOOL_REG_DEFAULTPRIORITY, map_dword},
239                 {SPOOL_REG_DESCRIPTION, map_sz},
240                 {SPOOL_REG_DRIVERNAME, map_sz},
241                 {SPOOL_REG_DRIVERVERSION, map_dword},
242                 {SPOOL_REG_FLAGS, map_dword},
243                 {SPOOL_REG_LOCATION, map_sz},
244                 {SPOOL_REG_OPERATINGSYSTEM, map_sz},
245                 {SPOOL_REG_OPERATINGSYSTEMHOTFIX, map_sz},
246                 {SPOOL_REG_OPERATINGSYSTEMSERVICEPACK, map_sz},
247                 {SPOOL_REG_OPERATINGSYSTEMVERSION, map_sz},
248                 {SPOOL_REG_PORTNAME, map_multi_sz},
249                 {SPOOL_REG_PRINTATTRIBUTES, map_dword},
250                 {SPOOL_REG_PRINTBINNAMES, map_multi_sz},
251                 {SPOOL_REG_PRINTCOLLATE, map_bool},
252                 {SPOOL_REG_PRINTCOLOR, map_bool},
253                 {SPOOL_REG_PRINTDUPLEXSUPPORTED, map_bool},
254                 {SPOOL_REG_PRINTENDTIME, map_dword},
255                 {SPOOL_REG_PRINTFORMNAME, map_sz},
256                 {SPOOL_REG_PRINTKEEPPRINTEDJOBS, map_bool},
257                 {SPOOL_REG_PRINTLANGUAGE, map_multi_sz},
258                 {SPOOL_REG_PRINTMACADDRESS, map_sz},
259                 {SPOOL_REG_PRINTMAXCOPIES, map_sz},
260                 {SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED, map_dword},
261                 {SPOOL_REG_PRINTMAXXEXTENT, map_dword},
262                 {SPOOL_REG_PRINTMAXYEXTENT, map_dword},
263                 {SPOOL_REG_PRINTMEDIAREADY, map_multi_sz},
264                 {SPOOL_REG_PRINTMEDIASUPPORTED, map_multi_sz},
265                 {SPOOL_REG_PRINTMEMORY, map_dword},
266                 {SPOOL_REG_PRINTMINXEXTENT, map_dword},
267                 {SPOOL_REG_PRINTMINYEXTENT, map_dword},
268                 {SPOOL_REG_PRINTNETWORKADDRESS, map_sz},
269                 {SPOOL_REG_PRINTNOTIFY, map_sz},
270                 {SPOOL_REG_PRINTNUMBERUP, map_dword},
271                 {SPOOL_REG_PRINTORIENTATIONSSUPPORTED, map_multi_sz},
272                 {SPOOL_REG_PRINTOWNER, map_sz},
273                 {SPOOL_REG_PRINTPAGESPERMINUTE, map_dword},
274                 {SPOOL_REG_PRINTRATE, map_dword},
275                 {SPOOL_REG_PRINTRATEUNIT, map_sz},
276                 {SPOOL_REG_PRINTSEPARATORFILE, map_sz},
277                 {SPOOL_REG_PRINTSHARENAME, map_sz},
278                 {SPOOL_REG_PRINTSPOOLING, map_sz},
279                 {SPOOL_REG_PRINTSTAPLINGSUPPORTED, map_bool},
280                 {SPOOL_REG_PRINTSTARTTIME, map_dword},
281                 {SPOOL_REG_PRINTSTATUS, map_sz},
282                 {SPOOL_REG_PRIORITY, map_dword},
283                 {SPOOL_REG_SERVERNAME, map_sz},
284                 {SPOOL_REG_SHORTSERVERNAME, map_sz},
285                 {SPOOL_REG_UNCNAME, map_sz},
286                 {SPOOL_REG_URL, map_sz},
287                 {SPOOL_REG_VERSIONNUMBER, map_dword},
288                 {NULL, NULL}
289         };
290         int i;
291
292         for (i=0; map[i].valname; i++) {
293                 if (StrCaseCmp(map[i].valname, regval_name(value)) == 0) {
294                         if (!map[i].fn(ctx, mods, value)) {
295                                 DEBUG(5, ("Add of value %s to modlist failed\n", regval_name(value)));
296                         } else {
297                                 DEBUG(7, ("Mapped value %s\n", regval_name(value)));
298                         }
299                         
300                 }
301         }
302 }
303
304
305 WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli, 
306                                           TALLOC_CTX *mem_ctx,
307                                           ADS_MODLIST *mods,
308                                           const char *printer)
309 {
310         struct dcerpc_binding_handle *b = cli->binding_handle;
311         WERROR result;
312         char *printername;
313         struct spoolss_PrinterEnumValues *info;
314         uint32_t count;
315         uint32 i;
316         struct policy_handle pol;
317         WERROR werr;
318
319         if ((asprintf(&printername, "%s\\%s", cli->srv_name_slash, printer) == -1)) {
320                 DEBUG(3, ("Insufficient memory\n"));
321                 return WERR_NOMEM;
322         }
323
324         result = rpccli_spoolss_openprinter_ex(cli, mem_ctx,
325                                                printername,
326                                                SEC_FLAG_MAXIMUM_ALLOWED,
327                                                &pol);
328         if (!W_ERROR_IS_OK(result)) {
329                 DEBUG(3, ("Unable to open printer %s, error is %s.\n",
330                           printername, win_errstr(result)));
331                 SAFE_FREE(printername);
332                 return result;
333         }
334
335         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol,
336                                                   SPOOL_DSDRIVER_KEY,
337                                                   0,
338                                                   &count,
339                                                   &info);
340
341         if (!W_ERROR_IS_OK(result)) {
342                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
343                           printername, win_errstr(result)));
344         } else {
345                 /* Have the data we need now, so start building */
346                 for (i=0; i < count; i++) {
347                         struct regval_blob *v;
348
349                         v = regval_compose(mem_ctx, info[i].value_name,
350                                            info[i].type,
351                                            info[i].data->data,
352                                            info[i].data->length);
353                         if (v == NULL) {
354                                 return WERR_NOMEM;
355                         }
356
357                         map_regval_to_ads(mem_ctx, mods, v);
358                         talloc_free(v);
359                 }
360         }
361
362         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol,
363                                                   SPOOL_DSSPOOLER_KEY,
364                                                   0,
365                                                   &count,
366                                                   &info);
367         if (!W_ERROR_IS_OK(result)) {
368                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
369                           printername, win_errstr(result)));
370         } else {
371                 for (i=0; i < count; i++) {
372                         struct regval_blob *v;
373
374                         v = regval_compose(mem_ctx, info[i].value_name,
375                                            info[i].type,
376                                            info[i].data->data,
377                                            info[i].data->length);
378                         if (v == NULL) {
379                                 return WERR_NOMEM;
380                         }
381
382                         map_regval_to_ads(mem_ctx, mods, v);
383                         talloc_free(v);
384                 }
385         }
386
387         ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
388
389         dcerpc_spoolss_ClosePrinter(b, mem_ctx, &pol, &werr);
390         SAFE_FREE(printername);
391
392         return result;
393 }
394
395 #endif