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