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