s3-rpcclient: use srv_name_slash instead of formating servername again and again.
[vlendec/samba-autobuild/.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_open_printer_ex(cli, mem_ctx, printername, 
324                                              "", MAXIMUM_ALLOWED_ACCESS, 
325                                              cli->srv_name_slash, cli->auth->user_name,
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                 return result;
331         }
332         
333         if ( !(dsdriver_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) 
334                 return WERR_NOMEM;
335
336         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSDRIVER_KEY, dsdriver_ctr);
337
338         if (!W_ERROR_IS_OK(result)) {
339                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
340                           printername, win_errstr(result)));
341         } else {
342                 uint32 num_values = regval_ctr_numvals( dsdriver_ctr );
343
344                 /* Have the data we need now, so start building */
345                 for (i=0; i < num_values; i++) {
346                         map_regval_to_ads(mem_ctx, mods, dsdriver_ctr->values[i]);
347                 }
348         }
349         
350         if ( !(dsspooler_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) )
351                 return WERR_NOMEM;
352
353         result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSSPOOLER_KEY, dsspooler_ctr);
354
355         if (!W_ERROR_IS_OK(result)) {
356                 DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n",
357                           printername, win_errstr(result)));
358         } else {
359                 uint32 num_values = regval_ctr_numvals( dsspooler_ctr );
360
361                 for (i=0; i<num_values; i++) {
362                         map_regval_to_ads(mem_ctx, mods, dsspooler_ctr->values[i]);
363                 }
364         }
365         
366         ads_mod_str(mem_ctx, mods, SPOOL_REG_PRINTERNAME, printer);
367
368         TALLOC_FREE( dsdriver_ctr );
369         TALLOC_FREE( dsspooler_ctr );
370
371         rpccli_spoolss_ClosePrinter(cli, mem_ctx, &pol, NULL);
372
373         return result;
374 }
375
376 bool get_local_printer_publishing_data(TALLOC_CTX *mem_ctx,
377                                        ADS_MODLIST *mods,
378                                        NT_PRINTER_DATA *data)
379 {
380         uint32 key,val;
381
382         for (key=0; key < data->num_keys; key++) {
383                 REGVAL_CTR *ctr = data->keys[key].values;
384                 for (val=0; val < ctr->num_values; val++)
385                         map_regval_to_ads(mem_ctx, mods, ctr->values[val]);
386         }
387         return True;
388 }
389
390 #endif