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