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