r9742: merging reg_objects and NT_PRINTER_DATA changes from SAMBA_3_0
[Samba.git] / source / printing / nt_printing.c
blob3b659f4c75bd0d37f5f3feedc0955f4cc64d95b8
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 extern struct current_user current_user;
27 static TDB_CONTEXT *tdb_forms; /* used for forms files */
28 static TDB_CONTEXT *tdb_drivers; /* used for driver files */
29 static TDB_CONTEXT *tdb_printers; /* used for printers files */
31 #define FORMS_PREFIX "FORMS/"
32 #define DRIVERS_PREFIX "DRIVERS/"
33 #define DRIVER_INIT_PREFIX "DRIVER_INIT/"
34 #define PRINTERS_PREFIX "PRINTERS/"
35 #define SECDESC_PREFIX "SECDESC/"
36 #define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
38 #define NTDRIVERS_DATABASE_VERSION_1 1
39 #define NTDRIVERS_DATABASE_VERSION_2 2
40 #define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */
41 #define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */
42 #define NTDRIVERS_DATABASE_VERSION_5 5 /* normalize keys in ntprinters.tdb */
44 /* Map generic permissions to printer object specific permissions */
46 GENERIC_MAPPING printer_generic_mapping = {
47 PRINTER_READ,
48 PRINTER_WRITE,
49 PRINTER_EXECUTE,
50 PRINTER_ALL_ACCESS
53 STANDARD_MAPPING printer_std_mapping = {
54 PRINTER_READ,
55 PRINTER_WRITE,
56 PRINTER_EXECUTE,
57 PRINTER_ALL_ACCESS
60 /* Map generic permissions to print server object specific permissions */
62 GENERIC_MAPPING printserver_generic_mapping = {
63 SERVER_READ,
64 SERVER_WRITE,
65 SERVER_EXECUTE,
66 SERVER_ALL_ACCESS
69 STANDARD_MAPPING printserver_std_mapping = {
70 SERVER_READ,
71 SERVER_WRITE,
72 SERVER_EXECUTE,
73 SERVER_ALL_ACCESS
76 /* We need one default form to support our default printer. Msoft adds the
77 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
78 array index). Letter is always first, so (for the current code) additions
79 always put things in the correct order. */
80 static const nt_forms_struct default_forms[] = {
81 {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
82 {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
83 {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
84 {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
85 {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
86 {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
87 {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
88 {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
89 {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
90 {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
91 {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
92 {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
93 {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
94 {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
95 {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
96 {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
97 {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
98 {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
99 {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
100 {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
101 {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
102 {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
103 {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
104 {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
105 {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
106 {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
107 {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
108 {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
109 {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
110 {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
111 {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
112 {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
113 {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
114 {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
115 {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
116 {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
117 {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
118 {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
119 {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
120 {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
121 {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
122 {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
123 {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
124 {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
125 {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
126 {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
127 {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
128 {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
129 {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
130 {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
131 {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
132 {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
133 {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
134 {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
135 {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
136 {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
137 {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
138 {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
139 {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
140 {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
141 {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
142 {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
143 {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
144 {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
145 {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
146 {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
147 {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
148 {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
149 {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
150 {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
151 {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
152 {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
153 {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
154 {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
155 {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
156 {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
157 {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
158 {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
159 {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
160 {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
161 {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
162 {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
163 {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
164 {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
165 {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
166 {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
167 {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
168 {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
169 {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
170 {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
171 {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
172 {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
173 {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
174 {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
175 {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
176 {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
177 {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
178 {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
179 {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
180 {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
181 {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
182 {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
183 {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
184 {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
185 {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
186 {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
187 {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
188 {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
189 {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
190 {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
191 {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
192 {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
193 {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
194 {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
195 {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
196 {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
197 {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
198 {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
201 struct table_node {
202 const char *long_archi;
203 const char *short_archi;
204 int version;
207 #define SPL_ARCH_WIN40 "WIN40"
208 #define SPL_ARCH_W32X86 "W32X86"
209 #define SPL_ARCH_W32MIPS "W32MIPS"
210 #define SPL_ARCH_W32ALPHA "W32ALPHA"
211 #define SPL_ARCH_W32PPC "W32PPC"
212 #define SPL_ARCH_IA64 "IA64"
213 #define SPL_ARCH_X64 "x64"
215 static const struct table_node archi_table[]= {
217 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
218 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
219 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
220 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
221 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
222 {"Windows IA64", SPL_ARCH_IA64, 3 },
223 {"Windows x64", SPL_ARCH_X64, 3 },
224 {NULL, "", -1 }
228 /****************************************************************************
229 generate a new TDB_DATA key for storing a printer
230 ****************************************************************************/
232 static TDB_DATA make_printer_tdbkey( const char *sharename )
234 fstring share;
235 static pstring keystr;
236 TDB_DATA key;
238 fstrcpy( share, sharename );
239 strlower_m( share );
241 pstr_sprintf( keystr, "%s%s", PRINTERS_PREFIX, share );
243 key.dptr = keystr;
244 key.dsize = strlen(keystr)+1;
246 return key;
249 /****************************************************************************
250 generate a new TDB_DATA key for storing a printer security descriptor
251 ****************************************************************************/
253 static char* make_printers_secdesc_tdbkey( const char* sharename )
255 fstring share;
256 static pstring keystr;
258 fstrcpy( share, sharename );
259 strlower_m( share );
261 pstr_sprintf( keystr, "%s%s", SECDESC_PREFIX, share );
263 return keystr;
266 /****************************************************************************
267 ****************************************************************************/
269 static BOOL upgrade_to_version_3(void)
271 TDB_DATA kbuf, newkey, dbuf;
273 DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
275 for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
276 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
278 dbuf = tdb_fetch(tdb_drivers, kbuf);
280 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
281 DEBUG(0,("upgrade_to_version_3:moving form\n"));
282 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
283 SAFE_FREE(dbuf.dptr);
284 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
285 return False;
287 if (tdb_delete(tdb_drivers, kbuf) != 0) {
288 SAFE_FREE(dbuf.dptr);
289 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
290 return False;
294 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
295 DEBUG(0,("upgrade_to_version_3:moving printer\n"));
296 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
297 SAFE_FREE(dbuf.dptr);
298 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
299 return False;
301 if (tdb_delete(tdb_drivers, kbuf) != 0) {
302 SAFE_FREE(dbuf.dptr);
303 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
304 return False;
308 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
309 DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
310 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
311 SAFE_FREE(dbuf.dptr);
312 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
313 return False;
315 if (tdb_delete(tdb_drivers, kbuf) != 0) {
316 SAFE_FREE(dbuf.dptr);
317 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
318 return False;
322 SAFE_FREE(dbuf.dptr);
325 return True;
328 /*******************************************************************
329 Fix an issue with security descriptors. Printer sec_desc must
330 use more than the generic bits that were previously used
331 in <= 3.0.14a. They must also have a owner and group SID assigned.
332 Otherwise, any printers than have been migrated to a Windows
333 host using printmig.exe will not be accessible.
334 *******************************************************************/
336 static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
337 TDB_DATA data, void *state )
339 prs_struct ps;
340 SEC_DESC_BUF *sd_orig = NULL;
341 SEC_DESC_BUF *sd_new, *sd_store;
342 SEC_DESC *sec, *new_sec;
343 TALLOC_CTX *ctx = state;
344 int result, i;
345 uint32 sd_size, size_new_sec;
346 DOM_SID sid;
348 if (!data.dptr || data.dsize == 0)
349 return 0;
351 if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 )
352 return 0;
354 /* upgrade the security descriptor */
356 ZERO_STRUCT( ps );
358 prs_init( &ps, 0, ctx, UNMARSHALL );
359 prs_give_memory( &ps, data.dptr, data.dsize, True );
361 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
362 /* delete bad entries */
363 DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si. Deleting....\n", key.dptr ));
364 tdb_delete( tdb_printers, key );
365 return 0;
368 sec = sd_orig->sec;
370 /* is this even valid? */
372 if ( !sec->dacl )
373 return 0;
375 /* update access masks */
377 for ( i=0; i<sec->dacl->num_aces; i++ ) {
378 switch ( sec->dacl->ace[i].info.mask ) {
379 case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
380 sec->dacl->ace[i].info.mask = PRINTER_ACE_PRINT;
381 break;
383 case GENERIC_ALL_ACCESS:
384 sec->dacl->ace[i].info.mask = PRINTER_ACE_FULL_CONTROL;
385 break;
387 case READ_CONTROL_ACCESS:
388 sec->dacl->ace[i].info.mask = PRINTER_ACE_MANAGE_DOCUMENTS;
390 default: /* no change */
391 break;
395 /* create a new SEC_DESC with the appropriate owner and group SIDs */
397 string_to_sid(&sid, "S-1-5-32-544" );
398 new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
399 &sid, &sid,
400 NULL, NULL, &size_new_sec );
401 sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
403 if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
404 DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
405 return 0;
408 /* store it back */
410 sd_size = sec_desc_size(sd_store->sec) + sizeof(SEC_DESC_BUF);
411 prs_init(&ps, sd_size, ctx, MARSHALL);
413 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
414 DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
415 return 0;
418 data.dptr = prs_data_p( &ps );
419 data.dsize = sd_size;
421 result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
423 prs_mem_free( &ps );
425 /* 0 to continue and non-zero to stop traversal */
427 return (result == -1);
430 /*******************************************************************
431 *******************************************************************/
433 static BOOL upgrade_to_version_4(void)
435 TALLOC_CTX *ctx;
436 int result;
438 DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
440 if ( !(ctx = talloc_init( "upgrade_to_version_4" )) )
441 return False;
443 result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
445 talloc_destroy( ctx );
447 return ( result != -1 );
450 /*******************************************************************
451 Fix an issue with security descriptors. Printer sec_desc must
452 use more than the generic bits that were previously used
453 in <= 3.0.14a. They must also have a owner and group SID assigned.
454 Otherwise, any printers than have been migrated to a Windows
455 host using printmig.exe will not be accessible.
456 *******************************************************************/
458 static int normalize_printers_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
459 TDB_DATA data, void *state )
461 TDB_DATA new_key;
463 if (!data.dptr || data.dsize == 0)
464 return 0;
466 /* upgrade printer records and security descriptors */
468 if ( strncmp( key.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX) ) == 0 ) {
469 new_key = make_printer_tdbkey( key.dptr+strlen(PRINTERS_PREFIX) );
471 else if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) == 0 ) {
472 new_key.dptr = make_printers_secdesc_tdbkey( key.dptr+strlen(SECDESC_PREFIX) );
473 new_key.dsize = strlen( new_key.dptr ) + 1;
475 else {
476 /* ignore this record */
477 return 0;
480 /* delete the original record and store under the normalized key */
482 if ( tdb_delete( the_tdb, key ) != 0 ) {
483 DEBUG(0,("normalize_printers_fn: tdb_delete for [%s] failed!\n",
484 key.dptr));
485 return 1;
488 if ( tdb_store( the_tdb, new_key, data, TDB_REPLACE) != 0 ) {
489 DEBUG(0,("normalize_printers_fn: failed to store new record for [%s]!\n",
490 key.dptr));
491 return 1;
494 return 0;
497 /*******************************************************************
498 *******************************************************************/
500 static BOOL upgrade_to_version_5(void)
502 TALLOC_CTX *ctx;
503 int result;
505 DEBUG(0,("upgrade_to_version_5: normalizing printer keys\n"));
507 if ( !(ctx = talloc_init( "upgrade_to_version_5" )) )
508 return False;
510 result = tdb_traverse( tdb_printers, normalize_printers_fn, NULL );
512 talloc_destroy( ctx );
514 return ( result != -1 );
517 /****************************************************************************
518 Open the NT printing tdbs. Done once before fork().
519 ****************************************************************************/
521 BOOL nt_printing_init(void)
523 const char *vstring = "INFO/version";
524 WERROR win_rc;
525 int32 vers_id;
527 if ( tdb_drivers && tdb_printers && tdb_forms )
528 return True;
530 if (tdb_drivers)
531 tdb_close(tdb_drivers);
532 tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
533 if (!tdb_drivers) {
534 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
535 lock_path("ntdrivers.tdb"), strerror(errno) ));
536 return False;
539 if (tdb_printers)
540 tdb_close(tdb_printers);
541 tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
542 if (!tdb_printers) {
543 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
544 lock_path("ntprinters.tdb"), strerror(errno) ));
545 return False;
548 if (tdb_forms)
549 tdb_close(tdb_forms);
550 tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
551 if (!tdb_forms) {
552 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
553 lock_path("ntforms.tdb"), strerror(errno) ));
554 return False;
557 /* handle a Samba upgrade */
559 vers_id = tdb_fetch_int32(tdb_drivers, vstring);
560 if (vers_id == -1) {
561 DEBUG(10, ("Fresh database\n"));
562 tdb_store_int32( tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5 );
563 vers_id = NTDRIVERS_DATABASE_VERSION_5;
566 if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
568 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
569 if (!upgrade_to_version_3())
570 return False;
571 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
572 vers_id = NTDRIVERS_DATABASE_VERSION_3;
575 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
576 /* Written on a bigendian machine with old fetch_int code. Save as le. */
577 /* The only upgrade between V2 and V3 is to save the version in little-endian. */
578 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
579 vers_id = NTDRIVERS_DATABASE_VERSION_3;
582 if (vers_id == NTDRIVERS_DATABASE_VERSION_3 ) {
583 if ( !upgrade_to_version_4() )
584 return False;
585 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_4);
586 vers_id = NTDRIVERS_DATABASE_VERSION_4;
589 if (vers_id == NTDRIVERS_DATABASE_VERSION_4 ) {
590 if ( !upgrade_to_version_5() )
591 return False;
592 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5);
593 vers_id = NTDRIVERS_DATABASE_VERSION_5;
597 if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
598 DEBUG(0,("nt_printing_init: Unknown printer database version [%d]\n", vers_id));
599 return False;
603 update_c_setprinter(True);
606 * register callback to handle updating printers as new
607 * drivers are installed
610 message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
613 * register callback to handle updating printer data
614 * when a driver is initialized
617 message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
619 /* of course, none of the message callbacks matter if you don't
620 tell messages.c that you interested in receiving PRINT_GENERAL
621 msgs. This is done in claim_connection() */
624 if ( lp_security() == SEC_ADS ) {
625 win_rc = check_published_printers();
626 if (!W_ERROR_IS_OK(win_rc))
627 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
630 return True;
633 /*******************************************************************
634 Function to allow filename parsing "the old way".
635 ********************************************************************/
637 static BOOL driver_unix_convert(char *name,connection_struct *conn,
638 char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst)
640 unix_format(name);
641 unix_clean_name(name);
642 trim_string(name,"/","/");
643 return unix_convert(name, conn, saved_last_component, bad_path, pst);
646 /*******************************************************************
647 tdb traversal function for counting printers.
648 ********************************************************************/
650 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
651 TDB_DATA data, void *context)
653 int *printer_count = (int*)context;
655 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
656 (*printer_count)++;
657 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
660 return 0;
663 /*******************************************************************
664 Update the spooler global c_setprinter. This variable is initialized
665 when the parent smbd starts with the number of existing printers. It
666 is monotonically increased by the current number of printers *after*
667 each add or delete printer RPC. Only Microsoft knows why... JRR020119
668 ********************************************************************/
670 uint32 update_c_setprinter(BOOL initialize)
672 int32 c_setprinter;
673 int32 printer_count = 0;
675 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0);
677 /* Traverse the tdb, counting the printers */
678 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
680 /* If initializing, set c_setprinter to current printers count
681 * otherwise, bump it by the current printer count
683 if (!initialize)
684 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
685 else
686 c_setprinter = printer_count;
688 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
689 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
691 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
693 return (uint32)c_setprinter;
696 /*******************************************************************
697 Get the spooler global c_setprinter, accounting for initialization.
698 ********************************************************************/
700 uint32 get_c_setprinter(void)
702 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
704 if (c_setprinter == (int32)-1)
705 c_setprinter = update_c_setprinter(True);
707 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
709 return (uint32)c_setprinter;
712 /****************************************************************************
713 Get builtin form struct list.
714 ****************************************************************************/
716 int get_builtin_ntforms(nt_forms_struct **list)
718 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
719 return sizeof(default_forms) / sizeof(default_forms[0]);
722 /****************************************************************************
723 get a builtin form struct
724 ****************************************************************************/
726 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
728 int i,count;
729 fstring form_name;
730 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
731 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
732 count = sizeof(default_forms) / sizeof(default_forms[0]);
733 for (i=0;i<count;i++) {
734 if (strequal(form_name,default_forms[i].name)) {
735 DEBUGADD(6,("Found builtin form %s \n", form_name));
736 memcpy(form,&default_forms[i],sizeof(*form));
737 break;
741 return (i !=count);
744 /****************************************************************************
745 get a form struct list
746 ****************************************************************************/
747 int get_ntforms(nt_forms_struct **list)
749 TDB_DATA kbuf, newkey, dbuf;
750 nt_forms_struct *tl;
751 nt_forms_struct form;
752 int ret;
753 int i;
754 int n = 0;
756 for (kbuf = tdb_firstkey(tdb_forms);
757 kbuf.dptr;
758 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
760 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
761 continue;
763 dbuf = tdb_fetch(tdb_forms, kbuf);
764 if (!dbuf.dptr)
765 continue;
767 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
768 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
769 &i, &form.flag, &form.width, &form.length, &form.left,
770 &form.top, &form.right, &form.bottom);
771 SAFE_FREE(dbuf.dptr);
772 if (ret != dbuf.dsize)
773 continue;
775 tl = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
776 if (!tl) {
777 DEBUG(0,("get_ntforms: Realloc fail.\n"));
778 return 0;
780 *list = tl;
781 (*list)[n] = form;
782 n++;
786 return n;
789 /****************************************************************************
790 write a form struct list
791 ****************************************************************************/
792 int write_ntforms(nt_forms_struct **list, int number)
794 pstring buf, key;
795 int len;
796 TDB_DATA kbuf,dbuf;
797 int i;
799 for (i=0;i<number;i++) {
800 /* save index, so list is rebuilt in correct order */
801 len = tdb_pack(buf, sizeof(buf), "dddddddd",
802 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
803 (*list)[i].left, (*list)[i].top, (*list)[i].right,
804 (*list)[i].bottom);
805 if (len > sizeof(buf)) break;
806 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
807 kbuf.dsize = strlen(key)+1;
808 kbuf.dptr = key;
809 dbuf.dsize = len;
810 dbuf.dptr = buf;
811 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
814 return i;
817 /****************************************************************************
818 add a form struct at the end of the list
819 ****************************************************************************/
820 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
822 int n=0;
823 BOOL update;
824 fstring form_name;
825 nt_forms_struct *tl;
828 * NT tries to add forms even when
829 * they are already in the base
830 * only update the values if already present
833 update=False;
835 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
836 for (n=0; n<*count; n++) {
837 if ( strequal((*list)[n].name, form_name) ) {
838 update=True;
839 break;
843 if (update==False) {
844 if((tl=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
845 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
846 return False;
848 *list = tl;
849 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
850 (*count)++;
853 (*list)[n].flag=form->flags;
854 (*list)[n].width=form->size_x;
855 (*list)[n].length=form->size_y;
856 (*list)[n].left=form->left;
857 (*list)[n].top=form->top;
858 (*list)[n].right=form->right;
859 (*list)[n].bottom=form->bottom;
861 DEBUG(6,("add_a_form: Successfully %s form [%s]\n",
862 update ? "updated" : "added", form_name));
864 return True;
867 /****************************************************************************
868 Delete a named form struct.
869 ****************************************************************************/
871 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
873 pstring key;
874 TDB_DATA kbuf;
875 int n=0;
876 fstring form_name;
878 *ret = WERR_OK;
880 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
882 for (n=0; n<*count; n++) {
883 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
884 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
885 break;
889 if (n == *count) {
890 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
891 *ret = WERR_INVALID_PARAM;
892 return False;
895 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
896 kbuf.dsize = strlen(key)+1;
897 kbuf.dptr = key;
898 if (tdb_delete(tdb_forms, kbuf) != 0) {
899 *ret = WERR_NOMEM;
900 return False;
903 return True;
906 /****************************************************************************
907 Update a form struct.
908 ****************************************************************************/
910 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
912 int n=0;
913 fstring form_name;
914 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
916 DEBUG(106, ("[%s]\n", form_name));
917 for (n=0; n<count; n++) {
918 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
919 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
920 break;
923 if (n==count) return;
925 (*list)[n].flag=form->flags;
926 (*list)[n].width=form->size_x;
927 (*list)[n].length=form->size_y;
928 (*list)[n].left=form->left;
929 (*list)[n].top=form->top;
930 (*list)[n].right=form->right;
931 (*list)[n].bottom=form->bottom;
934 /****************************************************************************
935 Get the nt drivers list.
936 Traverse the database and look-up the matching names.
937 ****************************************************************************/
938 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
940 int total=0;
941 const char *short_archi;
942 fstring *fl;
943 pstring key;
944 TDB_DATA kbuf, newkey;
946 short_archi = get_short_archi(architecture);
947 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
949 for (kbuf = tdb_firstkey(tdb_drivers);
950 kbuf.dptr;
951 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
953 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
954 continue;
956 if((fl = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
957 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
958 return -1;
960 else *list = fl;
962 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
963 total++;
966 return(total);
969 /****************************************************************************
970 function to do the mapping between the long architecture name and
971 the short one.
972 ****************************************************************************/
973 const char *get_short_archi(const char *long_archi)
975 int i=-1;
977 DEBUG(107,("Getting architecture dependant directory\n"));
978 do {
979 i++;
980 } while ( (archi_table[i].long_archi!=NULL ) &&
981 StrCaseCmp(long_archi, archi_table[i].long_archi) );
983 if (archi_table[i].long_archi==NULL) {
984 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
985 return NULL;
988 /* this might be client code - but shouldn't this be an fstrcpy etc? */
991 DEBUGADD(108,("index: [%d]\n", i));
992 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
993 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
995 return archi_table[i].short_archi;
998 /****************************************************************************
999 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
1000 There are two case to be covered here: PE (Portable Executable) and NE (New
1001 Executable) files. Both files support the same INFO structure, but PE files
1002 store the signature in unicode, and NE files store it as !unicode.
1003 returns -1 on error, 1 on version info found, and 0 on no version info found.
1004 ****************************************************************************/
1006 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
1008 int i;
1009 char *buf = NULL;
1010 ssize_t byte_count;
1012 if ((buf=SMB_MALLOC(PE_HEADER_SIZE)) == NULL) {
1013 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
1014 fname, PE_HEADER_SIZE));
1015 goto error_exit;
1018 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
1019 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
1020 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
1021 fname, (unsigned long)byte_count));
1022 goto no_version_info;
1025 /* Is this really a DOS header? */
1026 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
1027 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
1028 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
1029 goto no_version_info;
1032 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
1033 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
1034 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
1035 fname, errno));
1036 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1037 goto no_version_info;
1040 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
1041 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
1042 fname, (unsigned long)byte_count));
1043 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1044 goto no_version_info;
1047 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
1048 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
1049 unsigned int num_sections;
1050 unsigned int section_table_bytes;
1052 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
1053 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
1054 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
1055 /* At this point, we assume the file is in error. It still could be somthing
1056 * else besides a PE file, but it unlikely at this point.
1058 goto error_exit;
1061 /* get the section table */
1062 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
1063 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
1064 if (section_table_bytes == 0)
1065 goto error_exit;
1067 SAFE_FREE(buf);
1068 if ((buf=SMB_MALLOC(section_table_bytes)) == NULL) {
1069 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
1070 fname, section_table_bytes));
1071 goto error_exit;
1074 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
1075 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
1076 fname, (unsigned long)byte_count));
1077 goto error_exit;
1080 /* Iterate the section table looking for the resource section ".rsrc" */
1081 for (i = 0; i < num_sections; i++) {
1082 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
1084 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
1085 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
1086 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
1088 if (section_bytes == 0)
1089 goto error_exit;
1091 SAFE_FREE(buf);
1092 if ((buf=SMB_MALLOC(section_bytes)) == NULL) {
1093 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
1094 fname, section_bytes));
1095 goto error_exit;
1098 /* Seek to the start of the .rsrc section info */
1099 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
1100 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
1101 fname, errno));
1102 goto error_exit;
1105 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
1106 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
1107 fname, (unsigned long)byte_count));
1108 goto error_exit;
1111 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
1112 goto error_exit;
1114 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
1115 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
1116 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
1117 /* Align to next long address */
1118 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
1120 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
1121 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
1122 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
1124 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1125 fname, *major, *minor,
1126 (*major>>16)&0xffff, *major&0xffff,
1127 (*minor>>16)&0xffff, *minor&0xffff));
1128 SAFE_FREE(buf);
1129 return 1;
1136 /* Version info not found, fall back to origin date/time */
1137 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
1138 SAFE_FREE(buf);
1139 return 0;
1141 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
1142 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
1143 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
1144 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
1145 /* At this point, we assume the file is in error. It still could be somthing
1146 * else besides a NE file, but it unlikely at this point. */
1147 goto error_exit;
1150 /* Allocate a bit more space to speed up things */
1151 SAFE_FREE(buf);
1152 if ((buf=SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
1153 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
1154 fname, PE_HEADER_SIZE));
1155 goto error_exit;
1158 /* This is a HACK! I got tired of trying to sort through the messy
1159 * 'NE' file format. If anyone wants to clean this up please have at
1160 * it, but this works. 'NE' files will eventually fade away. JRR */
1161 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
1162 /* Cover case that should not occur in a well formed 'NE' .dll file */
1163 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
1165 for(i=0; i<byte_count; i++) {
1166 /* Fast skip past data that can't possibly match */
1167 if (buf[i] != 'V') continue;
1169 /* Potential match data crosses buf boundry, move it to beginning
1170 * of buf, and fill the buf with as much as it will hold. */
1171 if (i>byte_count-VS_VERSION_INFO_SIZE) {
1172 int bc;
1174 memcpy(buf, &buf[i], byte_count-i);
1175 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
1176 (byte_count-i))) < 0) {
1178 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
1179 fname, errno));
1180 goto error_exit;
1183 byte_count = bc + (byte_count - i);
1184 if (byte_count<VS_VERSION_INFO_SIZE) break;
1186 i = 0;
1189 /* Check that the full signature string and the magic number that
1190 * follows exist (not a perfect solution, but the chances that this
1191 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
1192 * twice, as it is simpler to read the code. */
1193 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
1194 /* Compute skip alignment to next long address */
1195 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fh->fd, 0, SEEK_CUR) - (byte_count - i) +
1196 sizeof(VS_SIGNATURE)) & 3;
1197 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
1199 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
1200 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
1201 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1202 fname, *major, *minor,
1203 (*major>>16)&0xffff, *major&0xffff,
1204 (*minor>>16)&0xffff, *minor&0xffff));
1205 SAFE_FREE(buf);
1206 return 1;
1211 /* Version info not found, fall back to origin date/time */
1212 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
1213 SAFE_FREE(buf);
1214 return 0;
1216 } else
1217 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1218 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
1219 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
1221 no_version_info:
1222 SAFE_FREE(buf);
1223 return 0;
1225 error_exit:
1226 SAFE_FREE(buf);
1227 return -1;
1230 /****************************************************************************
1231 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
1232 share one or more files. During the MS installation process files are checked
1233 to insure that only a newer version of a shared file is installed over an
1234 older version. There are several possibilities for this comparison. If there
1235 is no previous version, the new one is newer (obviously). If either file is
1236 missing the version info structure, compare the creation date (on Unix use
1237 the modification date). Otherwise chose the numerically larger version number.
1238 ****************************************************************************/
1240 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
1242 BOOL use_version = True;
1243 pstring filepath;
1245 uint32 new_major;
1246 uint32 new_minor;
1247 time_t new_create_time;
1249 uint32 old_major;
1250 uint32 old_minor;
1251 time_t old_create_time;
1253 files_struct *fsp = NULL;
1254 SMB_STRUCT_STAT st;
1255 SMB_STRUCT_STAT stat_buf;
1256 BOOL bad_path;
1258 SET_STAT_INVALID(st);
1259 SET_STAT_INVALID(stat_buf);
1260 new_create_time = (time_t)0;
1261 old_create_time = (time_t)0;
1263 /* Get file version info (if available) for previous file (if it exists) */
1264 pstrcpy(filepath, old_file);
1266 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1268 fsp = open_file_ntcreate(conn, filepath, &stat_buf,
1269 FILE_GENERIC_READ,
1270 FILE_SHARE_READ|FILE_SHARE_WRITE,
1271 FILE_OPEN,
1273 FILE_ATTRIBUTE_NORMAL,
1274 INTERNAL_OPEN_ONLY,
1275 NULL);
1277 if (!fsp) {
1278 /* Old file not found, so by definition new file is in fact newer */
1279 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
1280 filepath, errno));
1281 return True;
1283 } else {
1284 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
1285 if (ret == -1) {
1286 goto error_exit;
1289 if (!ret) {
1290 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1291 old_file));
1292 use_version = False;
1293 if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
1294 old_create_time = st.st_mtime;
1295 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1298 close_file(fsp, True);
1300 /* Get file version info (if available) for new file */
1301 pstrcpy(filepath, new_file);
1302 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1304 fsp = open_file_ntcreate(conn, filepath, &stat_buf,
1305 FILE_GENERIC_READ,
1306 FILE_SHARE_READ|FILE_SHARE_WRITE,
1307 FILE_OPEN,
1309 FILE_ATTRIBUTE_NORMAL,
1310 INTERNAL_OPEN_ONLY,
1311 NULL);
1313 if (!fsp) {
1314 /* New file not found, this shouldn't occur if the caller did its job */
1315 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1316 filepath, errno));
1317 goto error_exit;
1319 } else {
1320 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1321 if (ret == -1) {
1322 goto error_exit;
1325 if (!ret) {
1326 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1327 new_file));
1328 use_version = False;
1329 if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
1330 new_create_time = st.st_mtime;
1331 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1334 close_file(fsp, True);
1336 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1337 /* Compare versions and choose the larger version number */
1338 if (new_major > old_major ||
1339 (new_major == old_major && new_minor > old_minor)) {
1341 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1342 return True;
1344 else {
1345 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1346 return False;
1349 } else {
1350 /* Compare modification time/dates and choose the newest time/date */
1351 if (new_create_time > old_create_time) {
1352 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1353 return True;
1355 else {
1356 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1357 return False;
1361 error_exit:
1362 if(fsp)
1363 close_file(fsp, True);
1364 return -1;
1367 /****************************************************************************
1368 Determine the correct cVersion associated with an architecture and driver
1369 ****************************************************************************/
1370 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1371 struct current_user *user, WERROR *perr)
1373 int cversion;
1374 NTSTATUS nt_status;
1375 pstring driverpath;
1376 DATA_BLOB null_pw;
1377 fstring res_type;
1378 files_struct *fsp = NULL;
1379 BOOL bad_path;
1380 SMB_STRUCT_STAT st;
1381 connection_struct *conn;
1383 SET_STAT_INVALID(st);
1385 *perr = WERR_INVALID_PARAM;
1387 /* If architecture is Windows 95/98/ME, the version is always 0. */
1388 if (strcmp(architecture, "WIN40") == 0) {
1389 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1390 *perr = WERR_OK;
1391 return 0;
1395 * Connect to the print$ share under the same account as the user connected
1396 * to the rpc pipe. Note we must still be root to do this.
1399 /* Null password is ok - we are already an authenticated user... */
1400 null_pw = data_blob(NULL, 0);
1401 fstrcpy(res_type, "A:");
1402 become_root();
1403 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1404 unbecome_root();
1406 if (conn == NULL) {
1407 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1408 *perr = ntstatus_to_werror(nt_status);
1409 return -1;
1412 /* We are temporarily becoming the connection user. */
1413 if (!become_user(conn, user->vuid)) {
1414 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1415 *perr = WERR_ACCESS_DENIED;
1416 return -1;
1419 /* Open the driver file (Portable Executable format) and determine the
1420 * deriver the cversion. */
1421 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1423 driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
1425 if ( !vfs_file_exist( conn, driverpath, &st ) ) {
1426 *perr = WERR_BADFILE;
1427 goto error_exit;
1430 fsp = open_file_ntcreate(conn, driverpath, &st,
1431 FILE_GENERIC_READ,
1432 FILE_SHARE_READ|FILE_SHARE_WRITE,
1433 FILE_OPEN,
1435 FILE_ATTRIBUTE_NORMAL,
1436 INTERNAL_OPEN_ONLY,
1437 NULL);
1439 if (!fsp) {
1440 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1441 driverpath, errno));
1442 *perr = WERR_ACCESS_DENIED;
1443 goto error_exit;
1444 } else {
1445 uint32 major;
1446 uint32 minor;
1447 int ret = get_file_version(fsp, driverpath, &major, &minor);
1448 if (ret == -1) goto error_exit;
1450 if (!ret) {
1451 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1452 goto error_exit;
1456 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1457 * for more details. Version in this case is not just the version of the
1458 * file, but the version in the sense of kernal mode (2) vs. user mode
1459 * (3) drivers. Other bits of the version fields are the version info.
1460 * JRR 010716
1462 cversion = major & 0x0000ffff;
1463 switch (cversion) {
1464 case 2: /* WinNT drivers */
1465 case 3: /* Win2K drivers */
1466 break;
1468 default:
1469 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1470 driverpath, cversion));
1471 goto error_exit;
1474 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1475 driverpath, major, minor));
1478 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1479 driverpath, cversion));
1481 close_file(fsp, True);
1482 close_cnum(conn, user->vuid);
1483 unbecome_user();
1484 *perr = WERR_OK;
1485 return cversion;
1488 error_exit:
1490 if(fsp)
1491 close_file(fsp, True);
1493 close_cnum(conn, user->vuid);
1494 unbecome_user();
1495 return -1;
1498 /****************************************************************************
1499 ****************************************************************************/
1500 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1501 struct current_user *user)
1503 const char *architecture;
1504 fstring new_name;
1505 char *p;
1506 int i;
1507 WERROR err;
1509 /* clean up the driver name.
1510 * we can get .\driver.dll
1511 * or worse c:\windows\system\driver.dll !
1513 /* using an intermediate string to not have overlaping memcpy()'s */
1514 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1515 fstrcpy(new_name, p+1);
1516 fstrcpy(driver->driverpath, new_name);
1519 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1520 fstrcpy(new_name, p+1);
1521 fstrcpy(driver->datafile, new_name);
1524 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1525 fstrcpy(new_name, p+1);
1526 fstrcpy(driver->configfile, new_name);
1529 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1530 fstrcpy(new_name, p+1);
1531 fstrcpy(driver->helpfile, new_name);
1534 if (driver->dependentfiles) {
1535 for (i=0; *driver->dependentfiles[i]; i++) {
1536 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1537 fstrcpy(new_name, p+1);
1538 fstrcpy(driver->dependentfiles[i], new_name);
1543 architecture = get_short_archi(driver->environment);
1545 /* jfm:7/16/2000 the client always sends the cversion=0.
1546 * The server should check which version the driver is by reading
1547 * the PE header of driver->driverpath.
1549 * For Windows 95/98 the version is 0 (so the value sent is correct)
1550 * For Windows NT (the architecture doesn't matter)
1551 * NT 3.1: cversion=0
1552 * NT 3.5/3.51: cversion=1
1553 * NT 4: cversion=2
1554 * NT2K: cversion=3
1556 if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
1557 return err;
1559 return WERR_OK;
1562 /****************************************************************************
1563 ****************************************************************************/
1564 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1566 const char *architecture;
1567 fstring new_name;
1568 char *p;
1569 int i;
1570 WERROR err;
1572 /* clean up the driver name.
1573 * we can get .\driver.dll
1574 * or worse c:\windows\system\driver.dll !
1576 /* using an intermediate string to not have overlaping memcpy()'s */
1577 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1578 fstrcpy(new_name, p+1);
1579 fstrcpy(driver->driverpath, new_name);
1582 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1583 fstrcpy(new_name, p+1);
1584 fstrcpy(driver->datafile, new_name);
1587 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1588 fstrcpy(new_name, p+1);
1589 fstrcpy(driver->configfile, new_name);
1592 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1593 fstrcpy(new_name, p+1);
1594 fstrcpy(driver->helpfile, new_name);
1597 if (driver->dependentfiles) {
1598 for (i=0; *driver->dependentfiles[i]; i++) {
1599 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1600 fstrcpy(new_name, p+1);
1601 fstrcpy(driver->dependentfiles[i], new_name);
1606 architecture = get_short_archi(driver->environment);
1608 /* jfm:7/16/2000 the client always sends the cversion=0.
1609 * The server should check which version the driver is by reading
1610 * the PE header of driver->driverpath.
1612 * For Windows 95/98 the version is 0 (so the value sent is correct)
1613 * For Windows NT (the architecture doesn't matter)
1614 * NT 3.1: cversion=0
1615 * NT 3.5/3.51: cversion=1
1616 * NT 4: cversion=2
1617 * NT2K: cversion=3
1620 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1621 return err;
1623 return WERR_OK;
1626 /****************************************************************************
1627 ****************************************************************************/
1628 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1629 uint32 level, struct current_user *user)
1631 switch (level) {
1632 case 3:
1634 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1635 driver=driver_abstract.info_3;
1636 return clean_up_driver_struct_level_3(driver, user);
1638 case 6:
1640 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1641 driver=driver_abstract.info_6;
1642 return clean_up_driver_struct_level_6(driver, user);
1644 default:
1645 return WERR_INVALID_PARAM;
1649 /****************************************************************************
1650 This function sucks and should be replaced. JRA.
1651 ****************************************************************************/
1653 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1655 dst->cversion = src->version;
1657 fstrcpy( dst->name, src->name);
1658 fstrcpy( dst->environment, src->environment);
1659 fstrcpy( dst->driverpath, src->driverpath);
1660 fstrcpy( dst->datafile, src->datafile);
1661 fstrcpy( dst->configfile, src->configfile);
1662 fstrcpy( dst->helpfile, src->helpfile);
1663 fstrcpy( dst->monitorname, src->monitorname);
1664 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1665 dst->dependentfiles = src->dependentfiles;
1668 #if 0 /* Debugging function */
1670 static char* ffmt(unsigned char *c){
1671 int i;
1672 static char ffmt_str[17];
1674 for (i=0; i<16; i++) {
1675 if ((c[i] < ' ') || (c[i] > '~'))
1676 ffmt_str[i]='.';
1677 else
1678 ffmt_str[i]=c[i];
1680 ffmt_str[16]='\0';
1681 return ffmt_str;
1684 #endif
1686 /****************************************************************************
1687 ****************************************************************************/
1688 WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1689 struct current_user *user, WERROR *perr)
1691 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1692 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1693 const char *architecture;
1694 pstring new_dir;
1695 pstring old_name;
1696 pstring new_name;
1697 DATA_BLOB null_pw;
1698 connection_struct *conn;
1699 NTSTATUS nt_status;
1700 pstring inbuf;
1701 pstring outbuf;
1702 fstring res_type;
1703 BOOL bad_path;
1704 SMB_STRUCT_STAT st;
1705 int ver = 0;
1706 int i;
1707 int err;
1709 memset(inbuf, '\0', sizeof(inbuf));
1710 memset(outbuf, '\0', sizeof(outbuf));
1711 *perr = WERR_OK;
1713 if (level==3)
1714 driver=driver_abstract.info_3;
1715 else if (level==6) {
1716 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1717 driver = &converted_driver;
1718 } else {
1719 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1720 return WERR_UNKNOWN_LEVEL;
1723 architecture = get_short_archi(driver->environment);
1726 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1727 * Note we must be root to do this.
1730 null_pw = data_blob(NULL, 0);
1731 fstrcpy(res_type, "A:");
1732 become_root();
1733 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1734 unbecome_root();
1736 if (conn == NULL) {
1737 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1738 *perr = ntstatus_to_werror(nt_status);
1739 return WERR_NO_SUCH_SHARE;
1743 * Save who we are - we are temporarily becoming the connection user.
1746 if (!become_user(conn, conn->vuid)) {
1747 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1748 return WERR_ACCESS_DENIED;
1752 * make the directories version and version\driver_name
1753 * under the architecture directory.
1755 DEBUG(5,("Creating first directory\n"));
1756 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1757 driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
1758 mkdir_internal(conn, new_dir, bad_path);
1760 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1761 * listed for this driver which has already been moved, skip it (note:
1762 * drivers may list the same file name several times. Then check if the
1763 * file already exists in archi\cversion\, if so, check that the version
1764 * info (or time stamps if version info is unavailable) is newer (or the
1765 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1766 * Otherwise, delete the file.
1768 * If a file is not moved to archi\cversion\ because of an error, all the
1769 * rest of the 'unmoved' driver files are removed from archi\. If one or
1770 * more of the driver's files was already moved to archi\cversion\, it
1771 * potentially leaves the driver in a partially updated state. Version
1772 * trauma will most likely occur if an client attempts to use any printer
1773 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1774 * done is appropriate... later JRR
1777 DEBUG(5,("Moving files now !\n"));
1779 if (driver->driverpath && strlen(driver->driverpath)) {
1780 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1781 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1782 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1783 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1784 if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1785 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1786 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1787 new_name, old_name));
1788 *perr = WERR_ACCESS_DENIED;
1789 ver = -1;
1794 if (driver->datafile && strlen(driver->datafile)) {
1795 if (!strequal(driver->datafile, driver->driverpath)) {
1796 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1797 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1798 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1799 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1800 if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1801 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1802 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1803 new_name, old_name));
1804 *perr = WERR_ACCESS_DENIED;
1805 ver = -1;
1811 if (driver->configfile && strlen(driver->configfile)) {
1812 if (!strequal(driver->configfile, driver->driverpath) &&
1813 !strequal(driver->configfile, driver->datafile)) {
1814 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1815 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1816 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1817 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1818 if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1819 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1820 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1821 new_name, old_name));
1822 *perr = WERR_ACCESS_DENIED;
1823 ver = -1;
1829 if (driver->helpfile && strlen(driver->helpfile)) {
1830 if (!strequal(driver->helpfile, driver->driverpath) &&
1831 !strequal(driver->helpfile, driver->datafile) &&
1832 !strequal(driver->helpfile, driver->configfile)) {
1833 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1834 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1835 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1836 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1837 if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1838 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1839 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1840 new_name, old_name));
1841 *perr = WERR_ACCESS_DENIED;
1842 ver = -1;
1848 if (driver->dependentfiles) {
1849 for (i=0; *driver->dependentfiles[i]; i++) {
1850 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1851 !strequal(driver->dependentfiles[i], driver->datafile) &&
1852 !strequal(driver->dependentfiles[i], driver->configfile) &&
1853 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1854 int j;
1855 for (j=0; j < i; j++) {
1856 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1857 goto NextDriver;
1861 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1862 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1863 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1864 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1865 if ( !copy_file(new_name, old_name, conn,
1866 OPENX_FILE_EXISTS_TRUNCATE|
1867 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1868 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1869 new_name, old_name));
1870 *perr = WERR_ACCESS_DENIED;
1871 ver = -1;
1875 NextDriver: ;
1879 close_cnum(conn, user->vuid);
1880 unbecome_user();
1882 return ver != -1 ? WERR_OK : WERR_UNKNOWN_PRINTER_DRIVER;
1885 /****************************************************************************
1886 ****************************************************************************/
1887 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1889 int len, buflen;
1890 const char *architecture;
1891 pstring directory;
1892 fstring temp_name;
1893 pstring key;
1894 char *buf;
1895 int i, ret;
1896 TDB_DATA kbuf, dbuf;
1898 architecture = get_short_archi(driver->environment);
1900 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1901 * \\server is added in the rpc server layer.
1902 * It does make sense to NOT store the server's name in the printer TDB.
1905 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1907 /* .inf files do not always list a file for each of the four standard files.
1908 * Don't prepend a path to a null filename, or client claims:
1909 * "The server on which the printer resides does not have a suitable
1910 * <printer driver name> printer driver installed. Click OK if you
1911 * wish to install the driver on your local machine."
1913 if (strlen(driver->driverpath)) {
1914 fstrcpy(temp_name, driver->driverpath);
1915 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1918 if (strlen(driver->datafile)) {
1919 fstrcpy(temp_name, driver->datafile);
1920 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1923 if (strlen(driver->configfile)) {
1924 fstrcpy(temp_name, driver->configfile);
1925 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1928 if (strlen(driver->helpfile)) {
1929 fstrcpy(temp_name, driver->helpfile);
1930 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1933 if (driver->dependentfiles) {
1934 for (i=0; *driver->dependentfiles[i]; i++) {
1935 fstrcpy(temp_name, driver->dependentfiles[i]);
1936 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1940 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1942 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1944 buf = NULL;
1945 len = buflen = 0;
1947 again:
1948 len = 0;
1949 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1950 driver->cversion,
1951 driver->name,
1952 driver->environment,
1953 driver->driverpath,
1954 driver->datafile,
1955 driver->configfile,
1956 driver->helpfile,
1957 driver->monitorname,
1958 driver->defaultdatatype);
1960 if (driver->dependentfiles) {
1961 for (i=0; *driver->dependentfiles[i]; i++) {
1962 len += tdb_pack(buf+len, buflen-len, "f",
1963 driver->dependentfiles[i]);
1967 if (len != buflen) {
1968 char *tb;
1970 tb = (char *)SMB_REALLOC(buf, len);
1971 if (!tb) {
1972 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1973 ret = -1;
1974 goto done;
1976 else buf = tb;
1977 buflen = len;
1978 goto again;
1982 kbuf.dptr = key;
1983 kbuf.dsize = strlen(key)+1;
1984 dbuf.dptr = buf;
1985 dbuf.dsize = len;
1987 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1989 done:
1990 if (ret)
1991 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1993 SAFE_FREE(buf);
1994 return ret;
1997 /****************************************************************************
1998 ****************************************************************************/
1999 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
2001 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
2003 ZERO_STRUCT(info3);
2004 info3.cversion = driver->version;
2005 fstrcpy(info3.name,driver->name);
2006 fstrcpy(info3.environment,driver->environment);
2007 fstrcpy(info3.driverpath,driver->driverpath);
2008 fstrcpy(info3.datafile,driver->datafile);
2009 fstrcpy(info3.configfile,driver->configfile);
2010 fstrcpy(info3.helpfile,driver->helpfile);
2011 fstrcpy(info3.monitorname,driver->monitorname);
2012 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
2013 info3.dependentfiles = driver->dependentfiles;
2015 return add_a_printer_driver_3(&info3);
2019 /****************************************************************************
2020 ****************************************************************************/
2021 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
2023 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
2025 ZERO_STRUCT(info);
2027 fstrcpy(info.name, driver);
2028 fstrcpy(info.defaultdatatype, "RAW");
2030 fstrcpy(info.driverpath, "");
2031 fstrcpy(info.datafile, "");
2032 fstrcpy(info.configfile, "");
2033 fstrcpy(info.helpfile, "");
2035 if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
2036 return WERR_NOMEM;
2038 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
2039 fstrcpy(info.dependentfiles[0], "");
2041 *info_ptr = memdup(&info, sizeof(info));
2043 return WERR_OK;
2046 /****************************************************************************
2047 ****************************************************************************/
2048 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
2050 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
2051 TDB_DATA kbuf, dbuf;
2052 const char *architecture;
2053 int len = 0;
2054 int i;
2055 pstring key;
2057 ZERO_STRUCT(driver);
2059 architecture = get_short_archi(arch);
2061 if ( !architecture )
2062 return WERR_UNKNOWN_PRINTER_DRIVER;
2064 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
2066 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
2067 version = 0;
2069 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
2071 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
2073 kbuf.dptr = key;
2074 kbuf.dsize = strlen(key)+1;
2076 dbuf = tdb_fetch(tdb_drivers, kbuf);
2077 if (!dbuf.dptr)
2078 return WERR_UNKNOWN_PRINTER_DRIVER;
2080 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
2081 &driver.cversion,
2082 driver.name,
2083 driver.environment,
2084 driver.driverpath,
2085 driver.datafile,
2086 driver.configfile,
2087 driver.helpfile,
2088 driver.monitorname,
2089 driver.defaultdatatype);
2091 i=0;
2092 while (len < dbuf.dsize) {
2093 fstring *tddfs;
2095 tddfs = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
2096 if ( !tddfs ) {
2097 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
2098 break;
2100 else
2101 driver.dependentfiles = tddfs;
2103 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
2104 &driver.dependentfiles[i]);
2105 i++;
2108 if ( driver.dependentfiles )
2109 fstrcpy( driver.dependentfiles[i], "" );
2111 SAFE_FREE(dbuf.dptr);
2113 if (len != dbuf.dsize) {
2114 SAFE_FREE(driver.dependentfiles);
2116 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
2119 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
2121 return WERR_OK;
2124 /****************************************************************************
2125 Debugging function, dump at level 6 the struct in the logs.
2126 ****************************************************************************/
2128 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
2130 uint32 result;
2131 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
2132 int i;
2134 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
2136 switch (level)
2138 case 3:
2140 if (driver.info_3 == NULL)
2141 result=5;
2142 else {
2143 info3=driver.info_3;
2145 DEBUGADD(20,("version:[%d]\n", info3->cversion));
2146 DEBUGADD(20,("name:[%s]\n", info3->name));
2147 DEBUGADD(20,("environment:[%s]\n", info3->environment));
2148 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
2149 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
2150 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
2151 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
2152 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
2153 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
2155 for (i=0; info3->dependentfiles &&
2156 *info3->dependentfiles[i]; i++) {
2157 DEBUGADD(20,("dependentfile:[%s]\n",
2158 info3->dependentfiles[i]));
2160 result=0;
2162 break;
2164 default:
2165 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
2166 result=1;
2167 break;
2170 return result;
2173 /****************************************************************************
2174 ****************************************************************************/
2175 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
2177 int len = 0;
2179 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
2181 if (!nt_devmode)
2182 return len;
2184 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2185 nt_devmode->devicename,
2186 nt_devmode->formname,
2188 nt_devmode->specversion,
2189 nt_devmode->driverversion,
2190 nt_devmode->size,
2191 nt_devmode->driverextra,
2192 nt_devmode->orientation,
2193 nt_devmode->papersize,
2194 nt_devmode->paperlength,
2195 nt_devmode->paperwidth,
2196 nt_devmode->scale,
2197 nt_devmode->copies,
2198 nt_devmode->defaultsource,
2199 nt_devmode->printquality,
2200 nt_devmode->color,
2201 nt_devmode->duplex,
2202 nt_devmode->yresolution,
2203 nt_devmode->ttoption,
2204 nt_devmode->collate,
2205 nt_devmode->logpixels,
2207 nt_devmode->fields,
2208 nt_devmode->bitsperpel,
2209 nt_devmode->pelswidth,
2210 nt_devmode->pelsheight,
2211 nt_devmode->displayflags,
2212 nt_devmode->displayfrequency,
2213 nt_devmode->icmmethod,
2214 nt_devmode->icmintent,
2215 nt_devmode->mediatype,
2216 nt_devmode->dithertype,
2217 nt_devmode->reserved1,
2218 nt_devmode->reserved2,
2219 nt_devmode->panningwidth,
2220 nt_devmode->panningheight,
2221 nt_devmode->nt_dev_private);
2224 if (nt_devmode->nt_dev_private) {
2225 len += tdb_pack(buf+len, buflen-len, "B",
2226 nt_devmode->driverextra,
2227 nt_devmode->nt_dev_private);
2230 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
2232 return len;
2235 /****************************************************************************
2236 Pack all values in all printer keys
2237 ***************************************************************************/
2239 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
2241 int len = 0;
2242 int i, j;
2243 REGISTRY_VALUE *val;
2244 REGVAL_CTR *val_ctr;
2245 pstring path;
2246 int num_values;
2248 if ( !data )
2249 return 0;
2251 /* loop over all keys */
2253 for ( i=0; i<data->num_keys; i++ ) {
2254 val_ctr = data->keys[i].values;
2255 num_values = regval_ctr_numvals( val_ctr );
2257 /* pack the keyname followed by a empty value */
2259 len += tdb_pack(buf+len, buflen-len, "pPdB",
2260 &data->keys[i].name,
2261 data->keys[i].name,
2262 REG_NONE,
2264 NULL);
2266 /* now loop over all values */
2268 for ( j=0; j<num_values; j++ ) {
2269 /* pathname should be stored as <key>\<value> */
2271 val = regval_ctr_specific_value( val_ctr, j );
2272 pstrcpy( path, data->keys[i].name );
2273 pstrcat( path, "\\" );
2274 pstrcat( path, regval_name(val) );
2276 len += tdb_pack(buf+len, buflen-len, "pPdB",
2277 val,
2278 path,
2279 regval_type(val),
2280 regval_size(val),
2281 regval_data_p(val) );
2283 DEBUG(8,("specific: [%s], len: %d\n", regval_name(val), regval_size(val)));
2288 /* terminator */
2290 len += tdb_pack(buf+len, buflen-len, "p", NULL);
2292 return len;
2296 /****************************************************************************
2297 Delete a printer - this just deletes the printer info file, any open
2298 handles are not affected.
2299 ****************************************************************************/
2301 uint32 del_a_printer(const char *sharename)
2303 pstring key;
2304 TDB_DATA kbuf;
2305 pstring printdb_path;
2307 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
2308 kbuf.dptr=key;
2309 kbuf.dsize=strlen(key)+1;
2310 tdb_delete(tdb_printers, kbuf);
2312 slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, sharename);
2313 kbuf.dptr=key;
2314 kbuf.dsize=strlen(key)+1;
2315 tdb_delete(tdb_printers, kbuf);
2317 close_all_print_db();
2319 if (geteuid() == 0) {
2320 pstrcpy(printdb_path, lock_path("printing/"));
2321 pstrcat(printdb_path, sharename);
2322 pstrcat(printdb_path, ".tdb");
2324 unlink(printdb_path);
2327 return 0;
2330 /****************************************************************************
2331 ****************************************************************************/
2332 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2334 char *buf;
2335 int buflen, len;
2336 WERROR ret;
2337 TDB_DATA kbuf, dbuf;
2340 * in addprinter: no servername and the printer is the name
2341 * in setprinter: servername is \\server
2342 * and printer is \\server\\printer
2344 * Samba manages only local printers.
2345 * we currently don't support things like i
2346 * path=\\other_server\printer
2348 * We only store the printername, not \\server\printername
2351 if ( info->servername[0] != '\0' ) {
2352 trim_string(info->printername, info->servername, NULL);
2353 trim_char(info->printername, '\\', '\0');
2354 info->servername[0]='\0';
2358 * JFM: one day I'll forget.
2359 * below that's info->portname because that's the SAMBA sharename
2360 * and I made NT 'thinks' it's the portname
2361 * the info->sharename is the thing you can name when you add a printer
2362 * that's the short-name when you create shared printer for 95/98
2363 * So I've made a limitation in SAMBA: you can only have 1 printer model
2364 * behind a SAMBA share.
2367 buf = NULL;
2368 buflen = 0;
2370 again:
2371 len = 0;
2372 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2373 info->attributes,
2374 info->priority,
2375 info->default_priority,
2376 info->starttime,
2377 info->untiltime,
2378 info->status,
2379 info->cjobs,
2380 info->averageppm,
2381 info->changeid,
2382 info->c_setprinter,
2383 info->setuptime,
2384 info->servername,
2385 info->printername,
2386 info->sharename,
2387 info->portname,
2388 info->drivername,
2389 info->comment,
2390 info->location,
2391 info->sepfile,
2392 info->printprocessor,
2393 info->datatype,
2394 info->parameters);
2396 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2398 len += pack_values( info->data, buf+len, buflen-len );
2400 if (buflen != len) {
2401 char *tb;
2403 tb = (char *)SMB_REALLOC(buf, len);
2404 if (!tb) {
2405 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2406 ret = WERR_NOMEM;
2407 goto done;
2409 else buf = tb;
2410 buflen = len;
2411 goto again;
2415 kbuf = make_printer_tdbkey( info->sharename );
2417 dbuf.dptr = buf;
2418 dbuf.dsize = len;
2420 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2422 done:
2423 if (!W_ERROR_IS_OK(ret))
2424 DEBUG(8, ("error updating printer to tdb on disk\n"));
2426 SAFE_FREE(buf);
2428 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2429 info->sharename, info->drivername, info->portname, len));
2431 return ret;
2435 /****************************************************************************
2436 Malloc and return an NT devicemode.
2437 ****************************************************************************/
2439 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2442 char adevice[MAXDEVICENAME];
2443 NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
2445 if (nt_devmode == NULL) {
2446 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2447 return NULL;
2450 ZERO_STRUCTP(nt_devmode);
2452 slprintf(adevice, sizeof(adevice), "%s", default_devicename);
2453 fstrcpy(nt_devmode->devicename, adevice);
2455 fstrcpy(nt_devmode->formname, "Letter");
2457 nt_devmode->specversion = 0x0401;
2458 nt_devmode->driverversion = 0x0400;
2459 nt_devmode->size = 0x00DC;
2460 nt_devmode->driverextra = 0x0000;
2461 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2462 DEFAULTSOURCE | COPIES | SCALE |
2463 PAPERSIZE | ORIENTATION;
2464 nt_devmode->orientation = 1;
2465 nt_devmode->papersize = PAPER_LETTER;
2466 nt_devmode->paperlength = 0;
2467 nt_devmode->paperwidth = 0;
2468 nt_devmode->scale = 0x64;
2469 nt_devmode->copies = 1;
2470 nt_devmode->defaultsource = BIN_FORMSOURCE;
2471 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2472 nt_devmode->color = COLOR_MONOCHROME;
2473 nt_devmode->duplex = DUP_SIMPLEX;
2474 nt_devmode->yresolution = 0;
2475 nt_devmode->ttoption = TT_SUBDEV;
2476 nt_devmode->collate = COLLATE_FALSE;
2477 nt_devmode->icmmethod = 0;
2478 nt_devmode->icmintent = 0;
2479 nt_devmode->mediatype = 0;
2480 nt_devmode->dithertype = 0;
2482 /* non utilisés par un driver d'imprimante */
2483 nt_devmode->logpixels = 0;
2484 nt_devmode->bitsperpel = 0;
2485 nt_devmode->pelswidth = 0;
2486 nt_devmode->pelsheight = 0;
2487 nt_devmode->displayflags = 0;
2488 nt_devmode->displayfrequency = 0;
2489 nt_devmode->reserved1 = 0;
2490 nt_devmode->reserved2 = 0;
2491 nt_devmode->panningwidth = 0;
2492 nt_devmode->panningheight = 0;
2494 nt_devmode->nt_dev_private = NULL;
2495 return nt_devmode;
2498 /****************************************************************************
2499 Deepcopy an NT devicemode.
2500 ****************************************************************************/
2502 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2504 NT_DEVICEMODE *new_nt_devicemode = NULL;
2506 if ( !nt_devicemode )
2507 return NULL;
2509 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2510 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2511 return NULL;
2514 new_nt_devicemode->nt_dev_private = NULL;
2515 if (nt_devicemode->nt_dev_private != NULL) {
2516 if ((new_nt_devicemode->nt_dev_private = memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
2517 SAFE_FREE(new_nt_devicemode);
2518 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2519 return NULL;
2523 return new_nt_devicemode;
2526 /****************************************************************************
2527 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2528 ****************************************************************************/
2530 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2532 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2534 if(nt_devmode == NULL)
2535 return;
2537 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2539 SAFE_FREE(nt_devmode->nt_dev_private);
2540 SAFE_FREE(*devmode_ptr);
2543 /****************************************************************************
2544 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2545 ****************************************************************************/
2547 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2549 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2551 if ( !info )
2552 return;
2554 free_nt_devicemode(&info->devmode);
2556 TALLOC_FREE( *info_ptr );
2560 /****************************************************************************
2561 ****************************************************************************/
2562 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2564 int len = 0;
2565 int extra_len = 0;
2566 NT_DEVICEMODE devmode;
2568 ZERO_STRUCT(devmode);
2570 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2572 if (!*nt_devmode) return len;
2574 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2575 devmode.devicename,
2576 devmode.formname,
2578 &devmode.specversion,
2579 &devmode.driverversion,
2580 &devmode.size,
2581 &devmode.driverextra,
2582 &devmode.orientation,
2583 &devmode.papersize,
2584 &devmode.paperlength,
2585 &devmode.paperwidth,
2586 &devmode.scale,
2587 &devmode.copies,
2588 &devmode.defaultsource,
2589 &devmode.printquality,
2590 &devmode.color,
2591 &devmode.duplex,
2592 &devmode.yresolution,
2593 &devmode.ttoption,
2594 &devmode.collate,
2595 &devmode.logpixels,
2597 &devmode.fields,
2598 &devmode.bitsperpel,
2599 &devmode.pelswidth,
2600 &devmode.pelsheight,
2601 &devmode.displayflags,
2602 &devmode.displayfrequency,
2603 &devmode.icmmethod,
2604 &devmode.icmintent,
2605 &devmode.mediatype,
2606 &devmode.dithertype,
2607 &devmode.reserved1,
2608 &devmode.reserved2,
2609 &devmode.panningwidth,
2610 &devmode.panningheight,
2611 &devmode.nt_dev_private);
2613 if (devmode.nt_dev_private) {
2614 /* the len in tdb_unpack is an int value and
2615 * devmode.driverextra is only a short
2617 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_private);
2618 devmode.driverextra=(uint16)extra_len;
2620 /* check to catch an invalid TDB entry so we don't segfault */
2621 if (devmode.driverextra == 0) {
2622 devmode.nt_dev_private = NULL;
2626 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2628 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2629 if (devmode.nt_dev_private)
2630 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2632 return len;
2635 /****************************************************************************
2636 Allocate and initialize a new slot.
2637 ***************************************************************************/
2639 int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2641 NT_PRINTER_KEY *d;
2642 int key_index;
2644 if ( !name || !data )
2645 return -1;
2647 /* allocate another slot in the NT_PRINTER_KEY array */
2649 if ( !(d = TALLOC_REALLOC_ARRAY( data, data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) {
2650 DEBUG(0,("add_new_printer_key: Realloc() failed!\n"));
2651 return -1;
2654 data->keys = d;
2656 key_index = data->num_keys;
2658 /* initialze new key */
2660 data->keys[key_index].name = talloc_strdup( data, name );
2662 if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) )
2663 return -1;
2665 data->num_keys++;
2667 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2669 return key_index;
2672 /****************************************************************************
2673 search for a registry key name in the existing printer data
2674 ***************************************************************************/
2676 int delete_printer_key( NT_PRINTER_DATA *data, const char *name )
2678 int i;
2680 for ( i=0; i<data->num_keys; i++ ) {
2681 if ( strequal( data->keys[i].name, name ) ) {
2683 /* cleanup memory */
2685 TALLOC_FREE( data->keys[i].name );
2686 TALLOC_FREE( data->keys[i].values );
2688 /* if not the end of the array, move remaining elements down one slot */
2690 data->num_keys--;
2691 if ( data->num_keys && (i < data->num_keys) )
2692 memmove( &data->keys[i], &data->keys[i+1], sizeof(NT_PRINTER_KEY)*(data->num_keys-i) );
2694 break;
2699 return data->num_keys;
2702 /****************************************************************************
2703 search for a registry key name in the existing printer data
2704 ***************************************************************************/
2706 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2708 int key_index = -1;
2709 int i;
2711 if ( !data || !name )
2712 return -1;
2714 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2716 /* loop over all existing keys */
2718 for ( i=0; i<data->num_keys; i++ ) {
2719 if ( strequal(data->keys[i].name, name) ) {
2720 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2721 key_index = i;
2722 break;
2727 return key_index;
2730 /****************************************************************************
2731 ***************************************************************************/
2733 int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2735 int i, j;
2736 int key_len;
2737 int num_subkeys = 0;
2738 char *p;
2739 fstring *ptr, *subkeys_ptr = NULL;
2740 fstring subkeyname;
2742 if ( !data )
2743 return 0;
2745 if ( !key )
2746 return -1;
2748 /* special case of asking for the top level printer data registry key names */
2750 if ( strlen(key) == 0 ) {
2751 for ( i=0; i<data->num_keys; i++ ) {
2753 /* found a match, so allocate space and copy the name */
2755 if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
2756 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2757 num_subkeys+1));
2758 SAFE_FREE( subkeys );
2759 return -1;
2762 subkeys_ptr = ptr;
2763 fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name );
2764 num_subkeys++;
2767 goto done;
2770 /* asking for the subkeys of some key */
2771 /* subkey paths are stored in the key name using '\' as the delimiter */
2773 for ( i=0; i<data->num_keys; i++ ) {
2774 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2776 /* if we found the exact key, then break */
2777 key_len = strlen( key );
2778 if ( strlen(data->keys[i].name) == key_len )
2779 break;
2781 /* get subkey path */
2783 p = data->keys[i].name + key_len;
2784 if ( *p == '\\' )
2785 p++;
2786 fstrcpy( subkeyname, p );
2787 if ( (p = strchr( subkeyname, '\\' )) )
2788 *p = '\0';
2790 /* don't add a key more than once */
2792 for ( j=0; j<num_subkeys; j++ ) {
2793 if ( strequal( subkeys_ptr[j], subkeyname ) )
2794 break;
2797 if ( j != num_subkeys )
2798 continue;
2800 /* found a match, so allocate space and copy the name */
2802 if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
2803 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2804 num_subkeys+1));
2805 SAFE_FREE( subkeys );
2806 return 0;
2809 subkeys_ptr = ptr;
2810 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2811 num_subkeys++;
2816 /* return error if the key was not found */
2818 if ( i == data->num_keys )
2819 return -1;
2821 done:
2822 /* tag off the end */
2824 if (num_subkeys)
2825 fstrcpy(subkeys_ptr[num_subkeys], "" );
2827 *subkeys = subkeys_ptr;
2829 return num_subkeys;
2832 #ifdef HAVE_ADS
2833 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2834 const char *sz)
2836 smb_ucs2_t conv_str[1024];
2837 size_t str_size;
2839 regval_ctr_delvalue(ctr, val_name);
2840 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2841 STR_TERMINATE | STR_NOALIGN);
2842 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2843 (char *) conv_str, str_size);
2846 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2847 uint32 dword)
2849 regval_ctr_delvalue(ctr, val_name);
2850 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2851 (char *) &dword, sizeof(dword));
2854 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2855 BOOL b)
2857 uint8 bin_bool = (b ? 1 : 0);
2858 regval_ctr_delvalue(ctr, val_name);
2859 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2860 (char *) &bin_bool, sizeof(bin_bool));
2863 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2864 const char *multi_sz)
2866 smb_ucs2_t *conv_strs = NULL;
2867 size_t str_size;
2869 /* a multi-sz has to have a null string terminator, i.e., the last
2870 string must be followed by two nulls */
2871 str_size = strlen(multi_sz) + 2;
2872 conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
2873 if (!conv_strs) {
2874 return;
2877 /* Change to byte units. */
2878 str_size *= sizeof(smb_ucs2_t);
2879 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2880 STR_TERMINATE | STR_NOALIGN);
2882 regval_ctr_delvalue(ctr, val_name);
2883 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2884 (char *) conv_strs, str_size);
2885 safe_free(conv_strs);
2889 /****************************************************************************
2890 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2892 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2893 * @return BOOL indicating success or failure
2894 ***************************************************************************/
2896 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2898 REGVAL_CTR *ctr = NULL;
2899 fstring longname;
2900 fstring dnssuffix;
2901 char *allocated_string = NULL;
2902 const char *ascii_str;
2903 int i;
2905 if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2906 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
2907 ctr = info2->data->keys[i].values;
2909 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2910 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2912 /* we make the assumption that the netbios name is the same
2913 as the DNS name sinc ethe former will be what we used to
2914 join the domain */
2916 if ( get_mydnsdomname( dnssuffix ) )
2917 fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
2918 else
2919 fstrcpy( longname, global_myname() );
2921 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2923 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2924 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2925 SAFE_FREE(allocated_string);
2927 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2928 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2929 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2930 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2931 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2932 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2933 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2934 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2935 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2937 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2938 (info2->attributes &
2939 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2941 switch (info2->attributes & 0x3) {
2942 case 0:
2943 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2944 break;
2945 case 1:
2946 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2947 break;
2948 case 2:
2949 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2950 break;
2951 default:
2952 ascii_str = "unknown";
2954 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2956 return True;
2959 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
2960 struct uuid guid)
2962 int i;
2963 REGVAL_CTR *ctr=NULL;
2965 /* find the DsSpooler key */
2966 if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2967 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
2968 ctr = info2->data->keys[i].values;
2970 regval_ctr_delvalue(ctr, "objectGUID");
2971 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2972 (char *) &guid, sizeof(struct uuid));
2975 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
2976 NT_PRINTER_INFO_LEVEL *printer)
2978 ADS_STATUS ads_rc;
2979 void *res;
2980 char *prt_dn = NULL, *srv_dn, *srv_cn_0;
2981 char *srv_dn_utf8, **srv_cn_utf8;
2982 TALLOC_CTX *ctx;
2983 ADS_MODLIST mods;
2984 const char *attrs[] = {"objectGUID", NULL};
2985 struct uuid guid;
2986 WERROR win_rc = WERR_OK;
2988 DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
2990 /* figure out where to publish */
2991 ads_find_machine_acct(ads, &res, global_myname());
2993 /* We use ldap_get_dn here as we need the answer
2994 * in utf8 to call ldap_explode_dn(). JRA. */
2996 srv_dn_utf8 = ldap_get_dn(ads->ld, res);
2997 if (!srv_dn_utf8) {
2998 ads_destroy(&ads);
2999 return WERR_SERVER_UNAVAILABLE;
3001 ads_msgfree(ads, res);
3002 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
3003 if (!srv_cn_utf8) {
3004 ldap_memfree(srv_dn_utf8);
3005 ads_destroy(&ads);
3006 return WERR_SERVER_UNAVAILABLE;
3008 /* Now convert to CH_UNIX. */
3009 if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
3010 ldap_memfree(srv_dn_utf8);
3011 ldap_memfree(srv_cn_utf8);
3012 ads_destroy(&ads);
3013 return WERR_SERVER_UNAVAILABLE;
3015 if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
3016 ldap_memfree(srv_dn_utf8);
3017 ldap_memfree(srv_cn_utf8);
3018 ads_destroy(&ads);
3019 SAFE_FREE(srv_dn);
3020 return WERR_SERVER_UNAVAILABLE;
3023 ldap_memfree(srv_dn_utf8);
3024 ldap_memfree(srv_cn_utf8);
3026 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0,
3027 printer->info_2->sharename, srv_dn);
3029 SAFE_FREE(srv_dn);
3030 SAFE_FREE(srv_cn_0);
3032 /* build the ads mods */
3033 ctx = talloc_init("nt_printer_publish_ads");
3034 mods = ads_init_mods(ctx);
3036 get_local_printer_publishing_data(ctx, &mods, printer->info_2->data);
3037 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
3038 printer->info_2->sharename);
3040 /* publish it */
3041 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
3042 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
3043 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
3045 if (!ADS_ERR_OK(ads_rc))
3046 DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
3048 talloc_destroy(ctx);
3050 /* retreive the guid and store it locally */
3051 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
3052 ZERO_STRUCT(guid);
3053 ads_pull_guid(ads, res, &guid);
3054 ads_msgfree(ads, res);
3055 store_printer_guid(printer->info_2, guid);
3056 win_rc = mod_a_printer(printer, 2);
3059 SAFE_FREE(prt_dn);
3060 return win_rc;
3063 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
3064 NT_PRINTER_INFO_LEVEL *printer)
3066 ADS_STATUS ads_rc;
3067 void *res;
3068 char *prt_dn = NULL;
3070 DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
3072 /* remove the printer from the directory */
3073 ads_rc = ads_find_printer_on_server(ads, &res,
3074 printer->info_2->sharename, global_myname());
3076 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
3077 prt_dn = ads_get_dn(ads, res);
3078 ads_rc = ads_del_dn(ads, prt_dn);
3079 ads_memfree(ads, prt_dn);
3082 ads_msgfree(ads, res);
3083 return WERR_OK;
3086 /****************************************************************************
3087 * Publish a printer in the directory
3089 * @param snum describing printer service
3090 * @return WERROR indicating status of publishing
3091 ***************************************************************************/
3093 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
3095 ADS_STATUS ads_rc;
3096 ADS_STRUCT *ads = NULL;
3097 NT_PRINTER_INFO_LEVEL *printer = NULL;
3098 WERROR win_rc;
3100 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
3101 if (!W_ERROR_IS_OK(win_rc))
3102 goto done;
3104 switch (action) {
3105 case SPOOL_DS_PUBLISH:
3106 case SPOOL_DS_UPDATE:
3107 /* set the DsSpooler info and attributes */
3108 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
3109 win_rc = WERR_NOMEM;
3110 goto done;
3113 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
3114 break;
3115 case SPOOL_DS_UNPUBLISH:
3116 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
3117 break;
3118 default:
3119 win_rc = WERR_NOT_SUPPORTED;
3120 goto done;
3123 win_rc = mod_a_printer(printer, 2);
3124 if (!W_ERROR_IS_OK(win_rc)) {
3125 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
3126 goto done;
3129 ads = ads_init(NULL, NULL, NULL);
3130 if (!ads) {
3131 DEBUG(3, ("ads_init() failed\n"));
3132 win_rc = WERR_SERVER_UNAVAILABLE;
3133 goto done;
3135 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
3136 SAFE_FREE(ads->auth.password);
3137 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
3138 NULL, NULL);
3140 /* ads_connect() will find the DC for us */
3141 ads_rc = ads_connect(ads);
3142 if (!ADS_ERR_OK(ads_rc)) {
3143 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
3144 win_rc = WERR_ACCESS_DENIED;
3145 goto done;
3148 switch (action) {
3149 case SPOOL_DS_PUBLISH:
3150 case SPOOL_DS_UPDATE:
3151 win_rc = nt_printer_publish_ads(ads, printer);
3152 break;
3153 case SPOOL_DS_UNPUBLISH:
3154 win_rc = nt_printer_unpublish_ads(ads, printer);
3155 break;
3158 done:
3159 free_a_printer(&printer, 2);
3160 ads_destroy(&ads);
3161 return win_rc;
3164 WERROR check_published_printers(void)
3166 ADS_STATUS ads_rc;
3167 ADS_STRUCT *ads = NULL;
3168 int snum;
3169 int n_services = lp_numservices();
3170 NT_PRINTER_INFO_LEVEL *printer = NULL;
3172 ads = ads_init(NULL, NULL, NULL);
3173 if (!ads) {
3174 DEBUG(3, ("ads_init() failed\n"));
3175 return WERR_SERVER_UNAVAILABLE;
3177 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
3178 SAFE_FREE(ads->auth.password);
3179 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
3180 NULL, NULL);
3182 /* ads_connect() will find the DC for us */
3183 ads_rc = ads_connect(ads);
3184 if (!ADS_ERR_OK(ads_rc)) {
3185 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
3186 ads_destroy(&ads);
3187 return WERR_ACCESS_DENIED;
3190 for (snum = 0; snum < n_services; snum++) {
3191 if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
3192 continue;
3194 if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
3195 lp_servicename(snum))) &&
3196 (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
3197 nt_printer_publish_ads(ads, printer);
3199 free_a_printer(&printer, 2);
3202 ads_destroy(&ads);
3203 return WERR_OK;
3206 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3207 struct uuid *guid)
3209 NT_PRINTER_INFO_LEVEL *printer = NULL;
3210 REGVAL_CTR *ctr;
3211 REGISTRY_VALUE *guid_val;
3212 WERROR win_rc;
3213 int i;
3215 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
3217 if (!W_ERROR_IS_OK(win_rc) ||
3218 !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
3219 ((i = lookup_printerkey(printer->info_2->data, SPOOL_DSSPOOLER_KEY)) < 0) ||
3220 !(ctr = printer->info_2->data->keys[i].values) ||
3221 !(guid_val = regval_ctr_getvalue(ctr, "objectGUID")))
3223 free_a_printer(&printer, 2);
3224 return False;
3227 /* fetching printer guids really ought to be a separate function.. */
3228 if (guid && regval_size(guid_val) == sizeof(struct uuid))
3229 memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
3231 free_a_printer(&printer, 2);
3232 return True;
3234 #else
3235 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
3237 return WERR_OK;
3240 WERROR check_published_printers(void)
3242 return WERR_OK;
3245 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3246 struct uuid *guid)
3248 return False;
3250 #endif /* HAVE_ADS */
3252 /****************************************************************************
3253 ***************************************************************************/
3255 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
3257 NT_PRINTER_DATA *data;
3258 int i;
3259 int removed_keys = 0;
3260 int empty_slot;
3262 data = p2->data;
3263 empty_slot = data->num_keys;
3265 if ( !key )
3266 return WERR_INVALID_PARAM;
3268 /* remove all keys */
3270 if ( !strlen(key) ) {
3272 TALLOC_FREE( data );
3274 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
3275 p2->printername ));
3277 return WERR_OK;
3280 /* remove a specific key (and all subkeys) */
3282 for ( i=0; i<data->num_keys; i++ ) {
3283 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
3284 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
3285 data->keys[i].name));
3287 TALLOC_FREE( data->keys[i].name );
3288 TALLOC_FREE( data->keys[i].values );
3290 /* mark the slot as empty */
3292 ZERO_STRUCTP( &data->keys[i] );
3296 /* find the first empty slot */
3298 for ( i=0; i<data->num_keys; i++ ) {
3299 if ( !data->keys[i].name ) {
3300 empty_slot = i;
3301 removed_keys++;
3302 break;
3306 if ( i == data->num_keys )
3307 /* nothing was removed */
3308 return WERR_INVALID_PARAM;
3310 /* move everything down */
3312 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
3313 if ( data->keys[i].name ) {
3314 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
3315 ZERO_STRUCTP( &data->keys[i] );
3316 empty_slot++;
3317 removed_keys++;
3321 /* update count */
3323 data->num_keys -= removed_keys;
3325 /* sanity check to see if anything is left */
3327 if ( !data->num_keys ) {
3328 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
3330 SAFE_FREE( data->keys );
3331 ZERO_STRUCTP( data );
3334 return WERR_OK;
3337 /****************************************************************************
3338 ***************************************************************************/
3340 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3342 WERROR result = WERR_OK;
3343 int key_index;
3345 /* we must have names on non-zero length */
3347 if ( !key || !*key|| !value || !*value )
3348 return WERR_INVALID_NAME;
3350 /* find the printer key first */
3352 key_index = lookup_printerkey( p2->data, key );
3353 if ( key_index == -1 )
3354 return WERR_OK;
3356 /* make sure the value exists so we can return the correct error code */
3358 if ( !regval_ctr_getvalue( p2->data->keys[key_index].values, value ) )
3359 return WERR_BADFILE;
3361 regval_ctr_delvalue( p2->data->keys[key_index].values, value );
3363 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
3364 key, value ));
3366 return result;
3369 /****************************************************************************
3370 ***************************************************************************/
3372 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
3373 uint32 type, uint8 *data, int real_len )
3375 WERROR result = WERR_OK;
3376 int key_index;
3378 /* we must have names on non-zero length */
3380 if ( !key || !*key|| !value || !*value )
3381 return WERR_INVALID_NAME;
3383 /* find the printer key first */
3385 key_index = lookup_printerkey( p2->data, key );
3386 if ( key_index == -1 )
3387 key_index = add_new_printer_key( p2->data, key );
3389 if ( key_index == -1 )
3390 return WERR_NOMEM;
3392 regval_ctr_addvalue( p2->data->keys[key_index].values, value,
3393 type, (const char *)data, real_len );
3395 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
3396 key, value, type, real_len ));
3398 return result;
3401 /****************************************************************************
3402 ***************************************************************************/
3404 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3406 int key_index;
3408 if ( (key_index = lookup_printerkey( p2->data, key )) == -1 )
3409 return NULL;
3411 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
3412 key, value ));
3414 return regval_ctr_getvalue( p2->data->keys[key_index].values, value );
3417 /****************************************************************************
3418 Unpack a list of registry values frem the TDB
3419 ***************************************************************************/
3421 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
3423 int len = 0;
3424 uint32 type;
3425 pstring string, valuename, keyname;
3426 char *str;
3427 int size;
3428 uint8 *data_p;
3429 REGISTRY_VALUE *regval_p;
3430 int key_index;
3432 /* add the "PrinterDriverData" key first for performance reasons */
3434 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
3436 /* loop and unpack the rest of the registry values */
3438 while ( True ) {
3440 /* check to see if there are any more registry values */
3442 regval_p = NULL;
3443 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
3444 if ( !regval_p )
3445 break;
3447 /* unpack the next regval */
3449 len += tdb_unpack(buf+len, buflen-len, "fdB",
3450 string,
3451 &type,
3452 &size,
3453 &data_p);
3455 /* lookup for subkey names which have a type of REG_NONE */
3456 /* there's no data with this entry */
3458 if ( type == REG_NONE ) {
3459 if ( (key_index=lookup_printerkey( printer_data, string)) == -1 )
3460 add_new_printer_key( printer_data, string );
3461 continue;
3465 * break of the keyname from the value name.
3466 * Valuenames can have embedded '\'s so be careful.
3467 * only support one level of keys. See the
3468 * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
3469 * -- jerry
3472 str = strchr_m( string, '\\');
3474 /* Put in "PrinterDriverData" is no key specified */
3476 if ( !str ) {
3477 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3478 pstrcpy( valuename, string );
3480 else {
3481 *str = '\0';
3482 pstrcpy( keyname, string );
3483 pstrcpy( valuename, str+1 );
3486 /* see if we need a new key */
3488 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3489 key_index = add_new_printer_key( printer_data, keyname );
3491 if ( key_index == -1 ) {
3492 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3493 keyname));
3494 break;
3497 /* add the new value */
3499 regval_ctr_addvalue( printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3501 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3503 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3506 return len;
3509 /****************************************************************************
3510 ***************************************************************************/
3512 static void map_to_os2_driver(fstring drivername)
3514 static BOOL initialised=False;
3515 static fstring last_from,last_to;
3516 char *mapfile = lp_os2_driver_map();
3517 char **lines = NULL;
3518 int numlines = 0;
3519 int i;
3521 if (!strlen(drivername))
3522 return;
3524 if (!*mapfile)
3525 return;
3527 if (!initialised) {
3528 *last_from = *last_to = 0;
3529 initialised = True;
3532 if (strequal(drivername,last_from)) {
3533 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3534 fstrcpy(drivername,last_to);
3535 return;
3538 lines = file_lines_load(mapfile, &numlines);
3539 if (numlines == 0) {
3540 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3541 return;
3544 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3546 for( i = 0; i < numlines; i++) {
3547 char *nt_name = lines[i];
3548 char *os2_name = strchr(nt_name,'=');
3550 if (!os2_name)
3551 continue;
3553 *os2_name++ = 0;
3555 while (isspace(*nt_name))
3556 nt_name++;
3558 if (!*nt_name || strchr("#;",*nt_name))
3559 continue;
3562 int l = strlen(nt_name);
3563 while (l && isspace(nt_name[l-1])) {
3564 nt_name[l-1] = 0;
3565 l--;
3569 while (isspace(*os2_name))
3570 os2_name++;
3573 int l = strlen(os2_name);
3574 while (l && isspace(os2_name[l-1])) {
3575 os2_name[l-1] = 0;
3576 l--;
3580 if (strequal(nt_name,drivername)) {
3581 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3582 fstrcpy(last_from,drivername);
3583 fstrcpy(last_to,os2_name);
3584 fstrcpy(drivername,os2_name);
3585 file_lines_free(lines);
3586 return;
3590 file_lines_free(lines);
3593 /****************************************************************************
3594 Get a default printer info 2 struct.
3595 ****************************************************************************/
3596 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char* sharename)
3598 int snum;
3600 snum = lp_servicenumber(sharename);
3602 slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
3603 slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
3604 servername, sharename);
3605 fstrcpy(info->sharename, sharename);
3606 fstrcpy(info->portname, SAMBA_PRINTER_PORT_NAME);
3608 /* by setting the driver name to an empty string, a local NT admin
3609 can now run the **local** APW to install a local printer driver
3610 for a Samba shared printer in 2.2. Without this, drivers **must** be
3611 installed on the Samba server for NT clients --jerry */
3612 #if 0 /* JERRY --do not uncomment-- */
3613 if (!*info->drivername)
3614 fstrcpy(info->drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3615 #endif
3618 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info->drivername));
3620 pstrcpy(info->comment, "");
3621 fstrcpy(info->printprocessor, "winprint");
3622 fstrcpy(info->datatype, "RAW");
3624 info->attributes = PRINTER_ATTRIBUTE_SAMBA;
3626 info->starttime = 0; /* Minutes since 12:00am GMT */
3627 info->untiltime = 0; /* Minutes since 12:00am GMT */
3628 info->priority = 1;
3629 info->default_priority = 1;
3630 info->setuptime = (uint32)time(NULL);
3633 * I changed this as I think it is better to have a generic
3634 * DEVMODE than to crash Win2k explorer.exe --jerry
3635 * See the HP Deskjet 990c Win2k drivers for an example.
3637 * However the default devmode appears to cause problems
3638 * with the HP CLJ 8500 PCL driver. Hence the addition of
3639 * the "default devmode" parameter --jerry 22/01/2002
3642 if (lp_default_devmode(snum)) {
3643 if ((info->devmode = construct_nt_devicemode(info->printername)) == NULL)
3644 goto fail;
3646 else {
3647 info->devmode = NULL;
3650 if (!nt_printing_getsec(info, sharename, &info->secdesc_buf))
3651 goto fail;
3653 return WERR_OK;
3655 fail:
3656 if (info->devmode)
3657 free_nt_devicemode(&info->devmode);
3659 return WERR_ACCESS_DENIED;
3662 /****************************************************************************
3663 ****************************************************************************/
3664 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char *sharename)
3666 int len = 0;
3667 int snum = lp_servicenumber(sharename);
3668 TDB_DATA kbuf, dbuf;
3669 fstring printername;
3670 char adevice[MAXDEVICENAME];
3672 kbuf = make_printer_tdbkey( sharename );
3674 dbuf = tdb_fetch(tdb_printers, kbuf);
3675 if (!dbuf.dptr)
3676 return get_a_printer_2_default(info, servername, sharename);
3678 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3679 &info->attributes,
3680 &info->priority,
3681 &info->default_priority,
3682 &info->starttime,
3683 &info->untiltime,
3684 &info->status,
3685 &info->cjobs,
3686 &info->averageppm,
3687 &info->changeid,
3688 &info->c_setprinter,
3689 &info->setuptime,
3690 info->servername,
3691 info->printername,
3692 info->sharename,
3693 info->portname,
3694 info->drivername,
3695 info->comment,
3696 info->location,
3697 info->sepfile,
3698 info->printprocessor,
3699 info->datatype,
3700 info->parameters);
3702 /* Samba has to have shared raw drivers. */
3703 info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
3704 info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
3706 /* Restore the stripped strings. */
3707 slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
3709 if ( lp_force_printername(snum) )
3710 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
3711 else
3712 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info->printername);
3714 fstrcpy(info->printername, printername);
3716 len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len);
3719 * Some client drivers freak out if there is a NULL devmode
3720 * (probably the driver is not checking before accessing
3721 * the devmode pointer) --jerry
3723 * See comments in get_a_printer_2_default()
3726 if (lp_default_devmode(snum) && !info->devmode) {
3727 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3728 printername));
3729 info->devmode = construct_nt_devicemode(printername);
3732 slprintf( adevice, sizeof(adevice), "%s", info->printername );
3733 if (info->devmode) {
3734 fstrcpy(info->devmode->devicename, adevice);
3737 if ( !(info->data = TALLOC_ZERO_P( info, NT_PRINTER_DATA )) ) {
3738 DEBUG(0,("unpack_values: talloc() failed!\n"));
3739 return WERR_NOMEM;
3741 len += unpack_values( info->data, dbuf.dptr+len, dbuf.dsize-len );
3743 /* This will get the current RPC talloc context, but we should be
3744 passing this as a parameter... fixme... JRA ! */
3746 nt_printing_getsec(info, sharename, &info->secdesc_buf);
3748 /* Fix for OS/2 drivers. */
3750 if (get_remote_arch() == RA_OS2)
3751 map_to_os2_driver(info->drivername);
3753 SAFE_FREE(dbuf.dptr);
3755 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3756 sharename, info->printername, info->drivername));
3758 return WERR_OK;
3761 /****************************************************************************
3762 Debugging function, dump at level 6 the struct in the logs.
3763 ****************************************************************************/
3764 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3766 uint32 result;
3767 NT_PRINTER_INFO_LEVEL_2 *info2;
3769 DEBUG(106,("Dumping printer at level [%d]\n", level));
3771 switch (level) {
3772 case 2:
3774 if (printer->info_2 == NULL)
3775 result=5;
3776 else
3778 info2=printer->info_2;
3780 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3781 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3782 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3783 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3784 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3785 DEBUGADD(106,("status:[%d]\n", info2->status));
3786 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3787 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3788 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3789 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3790 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3792 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3793 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3794 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3795 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3796 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3797 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3798 DEBUGADD(106,("location:[%s]\n", info2->location));
3799 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3800 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3801 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3802 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3803 result=0;
3805 break;
3807 default:
3808 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3809 result=1;
3810 break;
3813 return result;
3816 /****************************************************************************
3817 Update the changeid time.
3818 This is SO NASTY as some drivers need this to change, others need it
3819 static. This value will change every second, and I must hope that this
3820 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3821 UTAH ! JRA.
3822 ****************************************************************************/
3824 static uint32 rev_changeid(void)
3826 struct timeval tv;
3828 get_process_uptime(&tv);
3830 #if 1 /* JERRY */
3831 /* Return changeid as msec since spooler restart */
3832 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3833 #else
3835 * This setting seems to work well but is too untested
3836 * to replace the above calculation. Left in for experiementation
3837 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3839 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3840 #endif
3845 * The function below are the high level ones.
3846 * only those ones must be called from the spoolss code.
3847 * JFM.
3850 /****************************************************************************
3851 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3852 ****************************************************************************/
3854 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3856 WERROR result;
3858 dump_a_printer(printer, level);
3860 switch (level) {
3861 case 2:
3864 * Update the changestamp. Emperical tests show that the
3865 * ChangeID is always updated,but c_setprinter is
3866 * global spooler variable (not per printer).
3869 /* ChangeID **must** be increasing over the lifetime
3870 of client's spoolss service in order for the
3871 client's cache to show updates */
3873 printer->info_2->changeid = rev_changeid();
3876 * Because one day someone will ask:
3877 * NT->NT An admin connection to a remote
3878 * printer show changes imeediately in
3879 * the properities dialog
3881 * A non-admin connection will only show the
3882 * changes after viewing the properites page
3883 * 2 times. Seems to be related to a
3884 * race condition in the client between the spooler
3885 * updating the local cache and the Explorer.exe GUI
3886 * actually displaying the properties.
3888 * This is fixed in Win2k. admin/non-admin
3889 * connections both display changes immediately.
3891 * 14/12/01 --jerry
3894 result=update_a_printer_2(printer->info_2);
3896 break;
3898 default:
3899 result=WERR_UNKNOWN_LEVEL;
3900 break;
3903 return result;
3906 /****************************************************************************
3907 Initialize printer devmode & data with previously saved driver init values.
3908 ****************************************************************************/
3910 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3912 int len = 0;
3913 pstring key;
3914 TDB_DATA kbuf, dbuf;
3915 NT_PRINTER_INFO_LEVEL_2 info;
3918 ZERO_STRUCT(info);
3921 * Delete any printer data 'values' already set. When called for driver
3922 * replace, there will generally be some, but during an add printer, there
3923 * should not be any (if there are delete them).
3926 if ( info_ptr->data )
3927 delete_all_printer_data( info_ptr, "" );
3929 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3931 kbuf.dptr = key;
3932 kbuf.dsize = strlen(key)+1;
3934 dbuf = tdb_fetch(tdb_drivers, kbuf);
3935 if (!dbuf.dptr) {
3937 * When changing to a driver that has no init info in the tdb, remove
3938 * the previous drivers init info and leave the new on blank.
3940 free_nt_devicemode(&info_ptr->devmode);
3941 return False;
3945 * Get the saved DEVMODE..
3948 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3951 * The saved DEVMODE contains the devicename from the printer used during
3952 * the initialization save. Change it to reflect the new printer.
3955 if ( info.devmode ) {
3956 ZERO_STRUCT(info.devmode->devicename);
3957 fstrcpy(info.devmode->devicename, info_ptr->printername);
3961 * NT/2k does not change out the entire DeviceMode of a printer
3962 * when changing the driver. Only the driverextra, private, &
3963 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3965 * Later examination revealed that Windows NT/2k does reset the
3966 * the printer's device mode, bit **only** when you change a
3967 * property of the device mode such as the page orientation.
3968 * --jerry
3972 /* Bind the saved DEVMODE to the new the printer */
3974 free_nt_devicemode(&info_ptr->devmode);
3975 info_ptr->devmode = info.devmode;
3977 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3978 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3980 /* Add the printer data 'values' to the new printer */
3982 if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) {
3983 DEBUG(0,("set_driver_init_2: talloc() failed!\n"));
3984 return False;
3987 len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3990 SAFE_FREE(dbuf.dptr);
3992 return True;
3995 /****************************************************************************
3996 Initialize printer devmode & data with previously saved driver init values.
3997 When a printer is created using AddPrinter, the drivername bound to the
3998 printer is used to lookup previously saved driver initialization info, which
3999 is bound to the new printer.
4000 ****************************************************************************/
4002 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
4004 BOOL result = False;
4006 switch (level) {
4007 case 2:
4008 result = set_driver_init_2(printer->info_2);
4009 break;
4011 default:
4012 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
4013 level));
4014 break;
4017 return result;
4020 /****************************************************************************
4021 Delete driver init data stored for a specified driver
4022 ****************************************************************************/
4024 BOOL del_driver_init(char *drivername)
4026 pstring key;
4027 TDB_DATA kbuf;
4029 if (!drivername || !*drivername) {
4030 DEBUG(3,("del_driver_init: No drivername specified!\n"));
4031 return False;
4034 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
4036 kbuf.dptr = key;
4037 kbuf.dsize = strlen(key)+1;
4039 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
4041 return (tdb_delete(tdb_drivers, kbuf) == 0);
4044 /****************************************************************************
4045 Pack up the DEVMODE and values for a printer into a 'driver init' entry
4046 in the tdb. Note: this is different from the driver entry and the printer
4047 entry. There should be a single driver init entry for each driver regardless
4048 of whether it was installed from NT or 2K. Technically, they should be
4049 different, but they work out to the same struct.
4050 ****************************************************************************/
4052 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
4054 pstring key;
4055 char *buf;
4056 int buflen, len, ret;
4057 TDB_DATA kbuf, dbuf;
4059 buf = NULL;
4060 buflen = 0;
4062 again:
4063 len = 0;
4064 len += pack_devicemode(info->devmode, buf+len, buflen-len);
4066 len += pack_values( info->data, buf+len, buflen-len );
4068 if (buflen < len) {
4069 char *tb;
4071 tb = (char *)SMB_REALLOC(buf, len);
4072 if (!tb) {
4073 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
4074 ret = -1;
4075 goto done;
4077 else
4078 buf = tb;
4079 buflen = len;
4080 goto again;
4083 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
4085 kbuf.dptr = key;
4086 kbuf.dsize = strlen(key)+1;
4087 dbuf.dptr = buf;
4088 dbuf.dsize = len;
4090 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
4092 done:
4093 if (ret == -1)
4094 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
4096 SAFE_FREE(buf);
4098 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
4099 info->sharename, info->drivername));
4101 return ret;
4104 /****************************************************************************
4105 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
4106 ****************************************************************************/
4108 static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
4110 uint32 result;
4112 dump_a_printer(printer, level);
4114 switch (level) {
4115 case 2:
4116 result = update_driver_init_2(printer->info_2);
4117 break;
4118 default:
4119 result = 1;
4120 break;
4123 return result;
4126 /****************************************************************************
4127 Convert the printer data value, a REG_BINARY array, into an initialization
4128 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
4129 got to keep the endians happy :).
4130 ****************************************************************************/
4132 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
4134 BOOL result = False;
4135 prs_struct ps;
4136 DEVICEMODE devmode;
4138 ZERO_STRUCT(devmode);
4140 prs_init(&ps, 0, ctx, UNMARSHALL);
4141 ps.data_p = (char *)data;
4142 ps.buffer_size = data_len;
4144 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
4145 result = convert_devicemode("", &devmode, &nt_devmode);
4146 else
4147 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
4149 return result;
4152 /****************************************************************************
4153 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
4155 1. Use the driver's config DLL to this UNC printername and:
4156 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
4157 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
4158 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
4160 The last step triggers saving the "driver initialization" information for
4161 this printer into the tdb. Later, new printers that use this driver will
4162 have this initialization information bound to them. This simulates the
4163 driver initialization, as if it had run on the Samba server (as it would
4164 have done on NT).
4166 The Win32 client side code requirement sucks! But until we can run arbitrary
4167 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
4169 It would have been easier to use SetPrinter because all the UNMARSHALLING of
4170 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
4171 about it and you will realize why. JRR 010720
4172 ****************************************************************************/
4174 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
4176 WERROR status = WERR_OK;
4177 TALLOC_CTX *ctx = NULL;
4178 NT_DEVICEMODE *nt_devmode = NULL;
4179 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
4182 * When the DEVMODE is already set on the printer, don't try to unpack it.
4184 DEBUG(8,("save_driver_init_2: Enter...\n"));
4186 if ( !printer->info_2->devmode && data_len ) {
4188 * Set devmode on printer info, so entire printer initialization can be
4189 * saved to tdb.
4192 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
4193 return WERR_NOMEM;
4195 if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
4196 status = WERR_NOMEM;
4197 goto done;
4200 ZERO_STRUCTP(nt_devmode);
4203 * The DEVMODE is held in the 'data' component of the param in raw binary.
4204 * Convert it to to a devmode structure
4206 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
4207 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
4208 status = WERR_INVALID_PARAM;
4209 goto done;
4212 printer->info_2->devmode = nt_devmode;
4216 * Pack up and add (or update) the DEVMODE and any current printer data to
4217 * a 'driver init' element in the tdb
4221 if ( update_driver_init(printer, 2) != 0 ) {
4222 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
4223 status = WERR_NOMEM;
4224 goto done;
4228 * If driver initialization info was successfully saved, set the current
4229 * printer to match it. This allows initialization of the current printer
4230 * as well as the driver.
4232 status = mod_a_printer(printer, 2);
4233 if (!W_ERROR_IS_OK(status)) {
4234 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
4235 printer->info_2->printername));
4238 done:
4239 talloc_destroy(ctx);
4240 free_nt_devicemode( &nt_devmode );
4242 printer->info_2->devmode = tmp_devmode;
4244 return status;
4247 /****************************************************************************
4248 Update the driver init info (DEVMODE and specifics) for a printer
4249 ****************************************************************************/
4251 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
4253 WERROR status = WERR_OK;
4255 switch (level) {
4256 case 2:
4257 status = save_driver_init_2( printer, data, data_len );
4258 break;
4259 default:
4260 status = WERR_UNKNOWN_LEVEL;
4261 break;
4264 return status;
4267 /****************************************************************************
4268 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
4270 Previously the code had a memory allocation problem because it always
4271 used the TALLOC_CTX from the Printer_entry*. This context lasts
4272 as a long as the original handle is open. So if the client made a lot
4273 of getprinter[data]() calls, the memory usage would climb. Now we use
4274 a short lived TALLOC_CTX for printer_info_2 objects returned. We
4275 still use the Printer_entry->ctx for maintaining the cache copy though
4276 since that object must live as long as the handle by definition.
4277 --jerry
4279 ****************************************************************************/
4281 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
4282 const char *sharename)
4284 WERROR result;
4285 fstring servername;
4287 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
4289 if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
4290 DEBUG(0,("get_a_printer: talloc() fail.\n"));
4291 return WERR_NOMEM;
4294 switch (level) {
4295 case 2:
4296 if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
4297 DEBUG(0,("get_a_printer: talloc() fail.\n"));
4298 TALLOC_FREE( *pp_printer );
4299 return WERR_NOMEM;
4302 if ( print_hnd )
4303 fstrcpy( servername, print_hnd->servername );
4304 else {
4305 fstrcpy( servername, "%L" );
4306 standard_sub_basic( "", servername, sizeof(servername)-1 );
4309 result = get_a_printer_2( (*pp_printer)->info_2, servername, sharename );
4312 /* we have a new printer now. Save it with this handle */
4314 if ( !W_ERROR_IS_OK(result) ) {
4315 TALLOC_FREE( *pp_printer );
4316 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n",
4317 sharename, (unsigned int)level, dos_errstr(result)));
4318 return result;
4321 dump_a_printer( *pp_printer, level);
4323 break;
4325 default:
4326 TALLOC_FREE( *pp_printer );
4327 return WERR_UNKNOWN_LEVEL;
4330 return WERR_OK;
4333 /****************************************************************************
4334 Deletes a NT_PRINTER_INFO_LEVEL struct.
4335 ****************************************************************************/
4337 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
4339 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
4341 if ( !printer )
4342 return 0;
4344 switch (level) {
4345 case 2:
4346 if ( printer->info_2 )
4347 free_nt_printer_info_level_2(&printer->info_2);
4348 break;
4350 default:
4351 DEBUG(0,("free_a_printer: unknown level! [%d]\n", level ));
4352 return 1;
4355 TALLOC_FREE(*pp_printer);
4357 return 0;
4360 /****************************************************************************
4361 ****************************************************************************/
4362 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4364 uint32 result;
4365 DEBUG(104,("adding a printer at level [%d]\n", level));
4366 dump_a_printer_driver(driver, level);
4368 switch (level) {
4369 case 3:
4370 result=add_a_printer_driver_3(driver.info_3);
4371 break;
4373 case 6:
4374 result=add_a_printer_driver_6(driver.info_6);
4375 break;
4377 default:
4378 result=1;
4379 break;
4382 return result;
4384 /****************************************************************************
4385 ****************************************************************************/
4387 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4388 fstring drivername, const char *architecture, uint32 version)
4390 WERROR result;
4392 switch (level) {
4393 case 3:
4394 /* Sometime we just want any version of the driver */
4396 if ( version == DRIVER_ANY_VERSION ) {
4397 /* look for Win2k first and then for NT4 */
4398 result = get_a_printer_driver_3(&driver->info_3, drivername,
4399 architecture, 3);
4401 if ( !W_ERROR_IS_OK(result) ) {
4402 result = get_a_printer_driver_3( &driver->info_3,
4403 drivername, architecture, 2 );
4405 } else {
4406 result = get_a_printer_driver_3(&driver->info_3, drivername,
4407 architecture, version);
4409 break;
4411 default:
4412 result=W_ERROR(1);
4413 break;
4416 if (W_ERROR_IS_OK(result))
4417 dump_a_printer_driver(*driver, level);
4419 return result;
4422 /****************************************************************************
4423 ****************************************************************************/
4424 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4426 uint32 result;
4428 switch (level) {
4429 case 3:
4431 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4432 if (driver.info_3 != NULL)
4434 info3=driver.info_3;
4435 SAFE_FREE(info3->dependentfiles);
4436 ZERO_STRUCTP(info3);
4437 SAFE_FREE(info3);
4438 result=0;
4439 } else {
4440 result=4;
4442 break;
4444 case 6:
4446 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4447 if (driver.info_6 != NULL) {
4448 info6=driver.info_6;
4449 SAFE_FREE(info6->dependentfiles);
4450 SAFE_FREE(info6->previousnames);
4451 ZERO_STRUCTP(info6);
4452 SAFE_FREE(info6);
4453 result=0;
4454 } else {
4455 result=4;
4457 break;
4459 default:
4460 result=1;
4461 break;
4463 return result;
4467 /****************************************************************************
4468 Determine whether or not a particular driver is currently assigned
4469 to a printer
4470 ****************************************************************************/
4472 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4474 int snum;
4475 int n_services = lp_numservices();
4476 NT_PRINTER_INFO_LEVEL *printer = NULL;
4477 BOOL in_use = False;
4479 if ( !info_3 )
4480 return False;
4482 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4484 /* loop through the printers.tdb and check for the drivername */
4486 for (snum=0; snum<n_services && !in_use; snum++) {
4487 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4488 continue;
4490 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4491 continue;
4493 if ( strequal(info_3->name, printer->info_2->drivername) )
4494 in_use = True;
4496 free_a_printer( &printer, 2 );
4499 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4501 if ( in_use ) {
4502 NT_PRINTER_DRIVER_INFO_LEVEL d;
4503 WERROR werr;
4505 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
4507 /* we can still remove the driver if there is one of
4508 "Windows NT x86" version 2 or 3 left */
4510 if ( !strequal( "Windows NT x86", info_3->environment ) ) {
4511 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );
4513 else {
4514 switch ( info_3->cversion ) {
4515 case 2:
4516 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
4517 break;
4518 case 3:
4519 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
4520 break;
4521 default:
4522 DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n",
4523 info_3->cversion));
4524 werr = WERR_UNKNOWN_PRINTER_DRIVER;
4525 break;
4529 /* now check the error code */
4531 if ( W_ERROR_IS_OK(werr) ) {
4532 /* it's ok to remove the driver, we have other architctures left */
4533 in_use = False;
4534 free_a_printer_driver( d, 3 );
4538 /* report that the driver is not in use by default */
4540 return in_use;
4544 /**********************************************************************
4545 Check to see if a ogiven file is in use by *info
4546 *********************************************************************/
4548 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4550 int i = 0;
4552 if ( !info )
4553 return False;
4555 if ( strequal(file, info->driverpath) )
4556 return True;
4558 if ( strequal(file, info->datafile) )
4559 return True;
4561 if ( strequal(file, info->configfile) )
4562 return True;
4564 if ( strequal(file, info->helpfile) )
4565 return True;
4567 /* see of there are any dependent files to examine */
4569 if ( !info->dependentfiles )
4570 return False;
4572 while ( *info->dependentfiles[i] ) {
4573 if ( strequal(file, info->dependentfiles[i]) )
4574 return True;
4575 i++;
4578 return False;
4582 /**********************************************************************
4583 Utility function to remove the dependent file pointed to by the
4584 input parameter from the list
4585 *********************************************************************/
4587 static void trim_dependent_file( fstring files[], int idx )
4590 /* bump everything down a slot */
4592 while( *files[idx+1] ) {
4593 fstrcpy( files[idx], files[idx+1] );
4594 idx++;
4597 *files[idx] = '\0';
4599 return;
4602 /**********************************************************************
4603 Check if any of the files used by src are also used by drv
4604 *********************************************************************/
4606 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4607 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4609 BOOL in_use = False;
4610 int i = 0;
4612 if ( !src || !drv )
4613 return False;
4615 /* check each file. Remove it from the src structure if it overlaps */
4617 if ( drv_file_in_use(src->driverpath, drv) ) {
4618 in_use = True;
4619 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4620 fstrcpy( src->driverpath, "" );
4623 if ( drv_file_in_use(src->datafile, drv) ) {
4624 in_use = True;
4625 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4626 fstrcpy( src->datafile, "" );
4629 if ( drv_file_in_use(src->configfile, drv) ) {
4630 in_use = True;
4631 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4632 fstrcpy( src->configfile, "" );
4635 if ( drv_file_in_use(src->helpfile, drv) ) {
4636 in_use = True;
4637 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4638 fstrcpy( src->helpfile, "" );
4641 /* are there any dependentfiles to examine? */
4643 if ( !src->dependentfiles )
4644 return in_use;
4646 while ( *src->dependentfiles[i] ) {
4647 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4648 in_use = True;
4649 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4650 trim_dependent_file( src->dependentfiles, i );
4651 } else
4652 i++;
4655 return in_use;
4658 /****************************************************************************
4659 Determine whether or not a particular driver files are currently being
4660 used by any other driver.
4662 Return value is True if any files were in use by other drivers
4663 and False otherwise.
4665 Upon return, *info has been modified to only contain the driver files
4666 which are not in use
4667 ****************************************************************************/
4669 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4671 int i;
4672 int ndrivers;
4673 uint32 version;
4674 fstring *list = NULL;
4675 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4677 if ( !info )
4678 return False;
4680 version = info->cversion;
4682 /* loop over all driver versions */
4684 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4686 /* get the list of drivers */
4688 list = NULL;
4689 ndrivers = get_ntdrivers(&list, info->environment, version);
4691 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4692 ndrivers, info->environment, version));
4694 /* check each driver for overlap in files */
4696 for (i=0; i<ndrivers; i++) {
4697 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4699 ZERO_STRUCT(driver);
4701 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4702 SAFE_FREE(list);
4703 return True;
4706 /* check if d2 uses any files from d1 */
4707 /* only if this is a different driver than the one being deleted */
4709 if ( !strequal(info->name, driver.info_3->name) ) {
4710 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4711 free_a_printer_driver(driver, 3);
4712 SAFE_FREE( list );
4713 return True;
4717 free_a_printer_driver(driver, 3);
4720 SAFE_FREE(list);
4722 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4724 driver.info_3 = info;
4726 if ( DEBUGLEVEL >= 20 )
4727 dump_a_printer_driver( driver, 3 );
4729 return False;
4732 /****************************************************************************
4733 Actually delete the driver files. Make sure that
4734 printer_driver_files_in_use() return False before calling
4735 this.
4736 ****************************************************************************/
4738 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4740 int i = 0;
4741 char *s;
4742 pstring file;
4743 connection_struct *conn;
4744 DATA_BLOB null_pw;
4745 NTSTATUS nt_status;
4746 fstring res_type;
4747 BOOL bad_path;
4748 SMB_STRUCT_STAT st;
4750 if ( !info_3 )
4751 return False;
4753 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4756 * Connect to the print$ share under the same account as the
4757 * user connected to the rpc pipe. Note we must be root to
4758 * do this.
4761 null_pw = data_blob( NULL, 0 );
4762 fstrcpy(res_type, "A:");
4763 become_root();
4764 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4765 unbecome_root();
4767 if ( !conn ) {
4768 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4769 return False;
4772 /* Save who we are - we are temporarily becoming the connection user. */
4774 if ( !become_user(conn, conn->vuid) ) {
4775 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4776 return False;
4779 /* now delete the files; must strip the '\print$' string from
4780 fron of path */
4782 if ( *info_3->driverpath ) {
4783 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4784 pstrcpy( file, s );
4785 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4786 DEBUG(10,("deleting driverfile [%s]\n", s));
4787 unlink_internals(conn, 0, file);
4791 if ( *info_3->configfile ) {
4792 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4793 pstrcpy( file, s );
4794 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4795 DEBUG(10,("deleting configfile [%s]\n", s));
4796 unlink_internals(conn, 0, file);
4800 if ( *info_3->datafile ) {
4801 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4802 pstrcpy( file, s );
4803 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4804 DEBUG(10,("deleting datafile [%s]\n", s));
4805 unlink_internals(conn, 0, file);
4809 if ( *info_3->helpfile ) {
4810 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4811 pstrcpy( file, s );
4812 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4813 DEBUG(10,("deleting helpfile [%s]\n", s));
4814 unlink_internals(conn, 0, file);
4818 /* check if we are done removing files */
4820 if ( info_3->dependentfiles ) {
4821 while ( info_3->dependentfiles[i][0] ) {
4822 char *p;
4824 /* bypass the "\print$" portion of the path */
4826 if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4827 pstrcpy( file, p );
4828 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4829 DEBUG(10,("deleting dependent file [%s]\n", file));
4830 unlink_internals(conn, 0, file );
4833 i++;
4837 unbecome_user();
4839 return True;
4842 /****************************************************************************
4843 Remove a printer driver from the TDB. This assumes that the the driver was
4844 previously looked up.
4845 ***************************************************************************/
4847 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4848 uint32 version, BOOL delete_files )
4850 pstring key;
4851 const char *arch;
4852 TDB_DATA kbuf, dbuf;
4853 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4855 /* delete the tdb data first */
4857 arch = get_short_archi(info_3->environment);
4858 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4859 arch, version, info_3->name);
4861 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4862 key, delete_files ? "TRUE" : "FALSE" ));
4864 ctr.info_3 = info_3;
4865 dump_a_printer_driver( ctr, 3 );
4867 kbuf.dptr=key;
4868 kbuf.dsize=strlen(key)+1;
4870 /* check if the driver actually exists for this environment */
4872 dbuf = tdb_fetch( tdb_drivers, kbuf );
4873 if ( !dbuf.dptr ) {
4874 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4875 return WERR_UNKNOWN_PRINTER_DRIVER;
4878 SAFE_FREE( dbuf.dptr );
4880 /* ok... the driver exists so the delete should return success */
4882 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4883 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4884 return WERR_ACCESS_DENIED;
4888 * now delete any associated files if delete_files == True
4889 * even if this part failes, we return succes because the
4890 * driver doesn not exist any more
4893 if ( delete_files )
4894 delete_driver_files( info_3, user );
4897 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4899 return WERR_OK;
4902 /****************************************************************************
4903 Store a security desc for a printer.
4904 ****************************************************************************/
4906 WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
4908 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4909 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4910 prs_struct ps;
4911 TALLOC_CTX *mem_ctx = NULL;
4912 char *key;
4913 WERROR status;
4915 mem_ctx = talloc_init("nt_printing_setsec");
4916 if (mem_ctx == NULL)
4917 return WERR_NOMEM;
4919 /* The old owner and group sids of the security descriptor are not
4920 present when new ACEs are added or removed by changing printer
4921 permissions through NT. If they are NULL in the new security
4922 descriptor then copy them over from the old one. */
4924 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4925 DOM_SID *owner_sid, *group_sid;
4926 SEC_ACL *dacl, *sacl;
4927 SEC_DESC *psd = NULL;
4928 size_t size;
4930 nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr);
4932 /* Pick out correct owner and group sids */
4934 owner_sid = secdesc_ctr->sec->owner_sid ?
4935 secdesc_ctr->sec->owner_sid :
4936 old_secdesc_ctr->sec->owner_sid;
4938 group_sid = secdesc_ctr->sec->grp_sid ?
4939 secdesc_ctr->sec->grp_sid :
4940 old_secdesc_ctr->sec->grp_sid;
4942 dacl = secdesc_ctr->sec->dacl ?
4943 secdesc_ctr->sec->dacl :
4944 old_secdesc_ctr->sec->dacl;
4946 sacl = secdesc_ctr->sec->sacl ?
4947 secdesc_ctr->sec->sacl :
4948 old_secdesc_ctr->sec->sacl;
4950 /* Make a deep copy of the security descriptor */
4952 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type,
4953 owner_sid, group_sid,
4954 sacl,
4955 dacl,
4956 &size);
4958 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4961 if (!new_secdesc_ctr) {
4962 new_secdesc_ctr = secdesc_ctr;
4965 /* Store the security descriptor in a tdb */
4967 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4968 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4970 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4971 &ps, 1)) {
4972 status = WERR_BADFUNC;
4973 goto out;
4976 key = make_printers_secdesc_tdbkey( sharename );
4978 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4979 status = WERR_OK;
4980 } else {
4981 DEBUG(1,("Failed to store secdesc for %s\n", sharename));
4982 status = WERR_BADFUNC;
4985 /* Free malloc'ed memory */
4987 out:
4989 prs_mem_free(&ps);
4990 if (mem_ctx)
4991 talloc_destroy(mem_ctx);
4992 return status;
4995 /****************************************************************************
4996 Construct a default security descriptor buffer for a printer.
4997 ****************************************************************************/
4999 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
5001 SEC_ACE ace[5]; /* max number of ace entries */
5002 int i = 0;
5003 SEC_ACCESS sa;
5004 SEC_ACL *psa = NULL;
5005 SEC_DESC_BUF *sdb = NULL;
5006 SEC_DESC *psd = NULL;
5007 DOM_SID adm_sid;
5008 size_t sd_size;
5010 /* Create an ACE where Everyone is allowed to print */
5012 init_sec_access(&sa, PRINTER_ACE_PRINT);
5013 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
5014 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5016 /* Add the domain admins group if we are a DC */
5018 if ( IS_DC ) {
5019 DOM_SID domadmins_sid;
5021 sid_copy(&domadmins_sid, get_global_sam_sid());
5022 sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
5024 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5025 init_sec_ace(&ace[i++], &domadmins_sid,
5026 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5027 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5028 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5029 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5031 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
5032 sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
5034 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5035 init_sec_ace(&ace[i++], &adm_sid,
5036 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5037 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5038 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5039 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5042 /* add BUILTIN\Administrators as FULL CONTROL */
5044 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5045 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5046 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5047 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5048 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5049 SEC_ACE_TYPE_ACCESS_ALLOWED,
5050 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5052 /* Make the security descriptor owned by the BUILTIN\Administrators */
5054 /* The ACL revision number in rpc_secdesc.h differs from the one
5055 created by NT when setting ACE entries in printer
5056 descriptors. NT4 complains about the property being edited by a
5057 NT5 machine. */
5059 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
5060 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
5061 &global_sid_Builtin_Administrators,
5062 &global_sid_Builtin_Administrators,
5063 NULL, psa, &sd_size);
5066 if (!psd) {
5067 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
5068 return NULL;
5071 sdb = make_sec_desc_buf(ctx, sd_size, psd);
5073 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
5074 (unsigned int)sd_size));
5076 return sdb;
5079 /****************************************************************************
5080 Get a security desc for a printer.
5081 ****************************************************************************/
5083 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
5085 prs_struct ps;
5086 char *key;
5087 char *temp;
5089 if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) {
5090 sharename = temp + 1;
5093 /* Fetch security descriptor from tdb */
5095 key = make_printers_secdesc_tdbkey( sharename );
5097 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
5098 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
5100 DEBUG(4,("using default secdesc for %s\n", sharename));
5102 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
5103 return False;
5106 /* Save default security descriptor for later */
5108 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
5109 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
5111 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
5112 tdb_prs_store(tdb_printers, key, &ps);
5114 prs_mem_free(&ps);
5116 return True;
5119 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
5120 this security descriptor has been created when winbindd was
5121 down. Take ownership of security descriptor. */
5123 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
5124 DOM_SID owner_sid;
5126 /* Change sd owner to workgroup administrator */
5128 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
5129 SEC_DESC_BUF *new_secdesc_ctr = NULL;
5130 SEC_DESC *psd = NULL;
5131 size_t size;
5133 /* Create new sd */
5135 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
5137 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type,
5138 &owner_sid,
5139 (*secdesc_ctr)->sec->grp_sid,
5140 (*secdesc_ctr)->sec->sacl,
5141 (*secdesc_ctr)->sec->dacl,
5142 &size);
5144 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
5146 /* Swap with other one */
5148 *secdesc_ctr = new_secdesc_ctr;
5150 /* Set it */
5152 nt_printing_setsec(sharename, *secdesc_ctr);
5156 if (DEBUGLEVEL >= 10) {
5157 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
5158 int i;
5160 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
5161 sharename, the_acl->num_aces));
5163 for (i = 0; i < the_acl->num_aces; i++) {
5164 fstring sid_str;
5166 sid_to_string(sid_str, &the_acl->ace[i].trustee);
5168 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
5169 the_acl->ace[i].type, the_acl->ace[i].flags,
5170 the_acl->ace[i].info.mask));
5174 prs_mem_free(&ps);
5175 return True;
5178 /* error code:
5179 0: everything OK
5180 1: level not implemented
5181 2: file doesn't exist
5182 3: can't allocate memory
5183 4: can't free memory
5184 5: non existant struct
5188 A printer and a printer driver are 2 different things.
5189 NT manages them separatelly, Samba does the same.
5190 Why ? Simply because it's easier and it makes sense !
5192 Now explanation: You have 3 printers behind your samba server,
5193 2 of them are the same make and model (laser A and B). But laser B
5194 has an 3000 sheet feeder and laser A doesn't such an option.
5195 Your third printer is an old dot-matrix model for the accounting :-).
5197 If the /usr/local/samba/lib directory (default dir), you will have
5198 5 files to describe all of this.
5200 3 files for the printers (1 by printer):
5201 NTprinter_laser A
5202 NTprinter_laser B
5203 NTprinter_accounting
5204 2 files for the drivers (1 for the laser and 1 for the dot matrix)
5205 NTdriver_printer model X
5206 NTdriver_printer model Y
5208 jfm: I should use this comment for the text file to explain
5209 same thing for the forms BTW.
5210 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
5214 /* Convert generic access rights to printer object specific access rights.
5215 It turns out that NT4 security descriptors use generic access rights and
5216 NT5 the object specific ones. */
5218 void map_printer_permissions(SEC_DESC *sd)
5220 int i;
5222 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
5223 se_map_generic(&sd->dacl->ace[i].info.mask,
5224 &printer_generic_mapping);
5228 /****************************************************************************
5229 Check a user has permissions to perform the given operation. We use the
5230 permission constants defined in include/rpc_spoolss.h to check the various
5231 actions we perform when checking printer access.
5233 PRINTER_ACCESS_ADMINISTER:
5234 print_queue_pause, print_queue_resume, update_printer_sec,
5235 update_printer, spoolss_addprinterex_level_2,
5236 _spoolss_setprinterdata
5238 PRINTER_ACCESS_USE:
5239 print_job_start
5241 JOB_ACCESS_ADMINISTER:
5242 print_job_delete, print_job_pause, print_job_resume,
5243 print_queue_purge
5245 Try access control in the following order (for performance reasons):
5246 1) root ans SE_PRINT_OPERATOR can do anything (easy check)
5247 2) check security descriptor (bit comparisons in memory)
5248 3) "printer admins" (may result in numerous calls to winbind)
5250 ****************************************************************************/
5251 BOOL print_access_check(struct current_user *user, int snum, int access_type)
5253 SEC_DESC_BUF *secdesc = NULL;
5254 uint32 access_granted;
5255 NTSTATUS status;
5256 BOOL result;
5257 const char *pname;
5258 TALLOC_CTX *mem_ctx = NULL;
5259 SE_PRIV se_printop = SE_PRINT_OPERATOR;
5261 /* If user is NULL then use the current_user structure */
5263 if (!user)
5264 user = &current_user;
5266 /* Always allow root or SE_PRINT_OPERATROR to do anything */
5268 if ( user->uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
5269 return True;
5272 /* Get printer name */
5274 pname = PRINTERNAME(snum);
5276 if (!pname || !*pname) {
5277 errno = EACCES;
5278 return False;
5281 /* Get printer security descriptor */
5283 if(!(mem_ctx = talloc_init("print_access_check"))) {
5284 errno = ENOMEM;
5285 return False;
5288 nt_printing_getsec(mem_ctx, pname, &secdesc);
5290 if (access_type == JOB_ACCESS_ADMINISTER) {
5291 SEC_DESC_BUF *parent_secdesc = secdesc;
5293 /* Create a child security descriptor to check permissions
5294 against. This is because print jobs are child objects
5295 objects of a printer. */
5297 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
5299 /* Now this is the bit that really confuses me. The access
5300 type needs to be changed from JOB_ACCESS_ADMINISTER to
5301 PRINTER_ACCESS_ADMINISTER for this to work. Something
5302 to do with the child (job) object becoming like a
5303 printer?? -tpot */
5305 access_type = PRINTER_ACCESS_ADMINISTER;
5308 /* Check access */
5310 map_printer_permissions(secdesc->sec);
5312 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
5313 &access_granted, &status);
5315 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
5317 /* see if we need to try the printer admin list */
5319 if ( access_granted == 0 ) {
5320 if ( user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups) )
5321 return True;
5324 talloc_destroy(mem_ctx);
5326 if (!result)
5327 errno = EACCES;
5329 return result;
5332 /****************************************************************************
5333 Check the time parameters allow a print operation.
5334 *****************************************************************************/
5336 BOOL print_time_access_check(int snum)
5338 NT_PRINTER_INFO_LEVEL *printer = NULL;
5339 BOOL ok = False;
5340 time_t now = time(NULL);
5341 struct tm *t;
5342 uint32 mins;
5344 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
5345 return False;
5347 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
5348 ok = True;
5350 t = gmtime(&now);
5351 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
5353 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
5354 ok = True;
5356 free_a_printer(&printer, 2);
5358 if (!ok)
5359 errno = EACCES;
5361 return ok;
5364 /****************************************************************************
5365 Fill in the servername sent in the _spoolss_open_printer_ex() call
5366 ****************************************************************************/
5368 char* get_server_name( Printer_entry *printer )
5370 return printer->servername;