r7691: * add .gdbinit to the svn:ignore files
[Samba/gbeck.git] / source / printing / nt_printing.c
blob75473c39f2010102876a7f5dbad52d9ce78e0d0c
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-2003.
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 */
43 #define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_4
45 /* Map generic permissions to printer object specific permissions */
47 GENERIC_MAPPING printer_generic_mapping = {
48 PRINTER_READ,
49 PRINTER_WRITE,
50 PRINTER_EXECUTE,
51 PRINTER_ALL_ACCESS
54 STANDARD_MAPPING printer_std_mapping = {
55 PRINTER_READ,
56 PRINTER_WRITE,
57 PRINTER_EXECUTE,
58 PRINTER_ALL_ACCESS
61 /* Map generic permissions to print server object specific permissions */
63 GENERIC_MAPPING printserver_generic_mapping = {
64 SERVER_READ,
65 SERVER_WRITE,
66 SERVER_EXECUTE,
67 SERVER_ALL_ACCESS
70 STANDARD_MAPPING printserver_std_mapping = {
71 SERVER_READ,
72 SERVER_WRITE,
73 SERVER_EXECUTE,
74 SERVER_ALL_ACCESS
77 /* We need one default form to support our default printer. Msoft adds the
78 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
79 array index). Letter is always first, so (for the current code) additions
80 always put things in the correct order. */
81 static const nt_forms_struct default_forms[] = {
82 {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
83 {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
84 {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
85 {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
86 {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
87 {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
88 {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
89 {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
90 {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
91 {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
92 {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
93 {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
94 {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
95 {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
96 {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
97 {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
98 {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
99 {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
100 {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
101 {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
102 {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
103 {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
104 {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
105 {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
106 {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
107 {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
108 {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
109 {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
110 {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
111 {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
112 {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
113 {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
114 {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
115 {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
116 {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
117 {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
118 {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
119 {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
120 {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
121 {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
122 {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
123 {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
124 {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
125 {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
126 {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
127 {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
128 {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
129 {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
130 {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
131 {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
132 {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
133 {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
134 {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
135 {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
136 {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
137 {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
138 {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
139 {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
140 {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
141 {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
142 {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
143 {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
144 {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
145 {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
146 {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
147 {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
148 {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
149 {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
150 {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
151 {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
152 {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
153 {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
154 {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
155 {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
156 {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
157 {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
158 {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
159 {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
160 {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
161 {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
162 {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
163 {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
164 {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
165 {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
166 {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
167 {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
168 {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
169 {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
170 {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
171 {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
172 {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
173 {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
174 {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
175 {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
176 {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
177 {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
178 {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
179 {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
180 {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
181 {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
182 {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
183 {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
184 {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
185 {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
186 {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
187 {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
188 {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
189 {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
190 {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
191 {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
192 {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
193 {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
194 {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
195 {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
196 {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
197 {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
198 {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
199 {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
202 struct table_node {
203 const char *long_archi;
204 const char *short_archi;
205 int version;
208 #define SPL_ARCH_WIN40 "WIN40"
209 #define SPL_ARCH_W32X86 "W32X86"
210 #define SPL_ARCH_W32MIPS "W32MIPS"
211 #define SPL_ARCH_W32ALPHA "W32ALPHA"
212 #define SPL_ARCH_W32PPC "W32PPC"
213 #define SPL_ARCH_IA64 "IA64"
214 #define SPL_ARCH_X64 "x64"
216 static const struct table_node archi_table[]= {
218 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
219 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
220 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
221 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
222 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
223 {"Windows IA64", SPL_ARCH_IA64, 3 },
224 {"Windows x64", SPL_ARCH_X64, 3 },
225 {NULL, "", -1 }
228 static BOOL upgrade_to_version_3(void)
230 TDB_DATA kbuf, newkey, dbuf;
232 DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
234 for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
235 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
237 dbuf = tdb_fetch(tdb_drivers, kbuf);
239 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
240 DEBUG(0,("upgrade_to_version_3:moving form\n"));
241 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
242 SAFE_FREE(dbuf.dptr);
243 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
244 return False;
246 if (tdb_delete(tdb_drivers, kbuf) != 0) {
247 SAFE_FREE(dbuf.dptr);
248 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
249 return False;
253 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
254 DEBUG(0,("upgrade_to_version_3:moving printer\n"));
255 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
256 SAFE_FREE(dbuf.dptr);
257 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
258 return False;
260 if (tdb_delete(tdb_drivers, kbuf) != 0) {
261 SAFE_FREE(dbuf.dptr);
262 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
263 return False;
267 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
268 DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
269 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
270 SAFE_FREE(dbuf.dptr);
271 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
272 return False;
274 if (tdb_delete(tdb_drivers, kbuf) != 0) {
275 SAFE_FREE(dbuf.dptr);
276 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
277 return False;
281 SAFE_FREE(dbuf.dptr);
284 return True;
287 /*******************************************************************
288 Fix an issue with security descriptors. Printer sec_desc must
289 use more than the generic bits that were previously used
290 in <= 3.0.14a. They must also have a owner and group SID assigned.
291 Otherwise, any printers than have been migrated to a Windows
292 host using printmig.exe will not be accessible.
293 *******************************************************************/
295 static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
296 TDB_DATA data, void *state )
298 prs_struct ps;
299 SEC_DESC_BUF *sd_orig = NULL;
300 SEC_DESC_BUF *sd_new, *sd_store;
301 SEC_DESC *sec, *new_sec;
302 TALLOC_CTX *ctx = state;
303 int result, i;
304 uint32 sd_size, size_new_sec;
305 DOM_SID sid;
307 if (!data.dptr || data.dsize == 0)
308 return 0;
310 if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 )
311 return 0;
313 /* upgrade the security descriptor */
315 ZERO_STRUCT( ps );
317 prs_init( &ps, 0, ctx, UNMARSHALL );
318 prs_give_memory( &ps, data.dptr, data.dsize, True );
320 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
321 /* delete bad entries */
322 DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si. Deleting....\n", key.dptr ));
323 tdb_delete( tdb_printers, key );
324 return 0;
327 sec = sd_orig->sec;
329 /* is this even valid? */
331 if ( !sec->dacl )
332 return 0;
334 /* update access masks */
336 for ( i=0; i<sec->dacl->num_aces; i++ ) {
337 switch ( sec->dacl->ace[i].info.mask ) {
338 case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
339 sec->dacl->ace[i].info.mask = PRINTER_ACE_PRINT;
340 break;
342 case GENERIC_ALL_ACCESS:
343 sec->dacl->ace[i].info.mask = PRINTER_ACE_FULL_CONTROL;
344 break;
346 case READ_CONTROL_ACCESS:
347 sec->dacl->ace[i].info.mask = PRINTER_ACE_MANAGE_DOCUMENTS;
349 default: /* no change */
350 break;
354 /* create a new SEC_DESC with the appropriate owner and group SIDs */
356 string_to_sid(&sid, "S-1-5-32-544" );
357 new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
358 &sid, &sid,
359 NULL, NULL, &size_new_sec );
360 sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
362 if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
363 DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
364 return 0;
367 /* store it back */
369 sd_size = sec_desc_size(sd_store->sec) + sizeof(SEC_DESC_BUF);
370 prs_init(&ps, sd_size, ctx, MARSHALL);
372 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
373 DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
374 return 0;
377 data.dptr = prs_data_p( &ps );
378 data.dsize = sd_size;
380 result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
382 prs_mem_free( &ps );
384 /* 0 to continue and non-zero to stop traversal */
386 return (result == -1);
389 /*******************************************************************
390 *******************************************************************/
392 static BOOL upgrade_to_version_4(void)
394 TALLOC_CTX *ctx;
395 int result;
397 DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
399 if ( !(ctx = talloc_init( "upgrade_to_version_4" )) )
400 return False;
402 result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
404 talloc_destroy( ctx );
406 return ( result != -1 );
409 /****************************************************************************
410 Open the NT printing tdbs. Done once before fork().
411 ****************************************************************************/
413 BOOL nt_printing_init(void)
415 static pid_t local_pid;
416 const char *vstring = "INFO/version";
417 WERROR win_rc;
418 uint32 vers_id;
420 if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
421 return True;
423 if (tdb_drivers)
424 tdb_close(tdb_drivers);
425 tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
426 if (!tdb_drivers) {
427 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
428 lock_path("ntdrivers.tdb"), strerror(errno) ));
429 return False;
432 if (tdb_printers)
433 tdb_close(tdb_printers);
434 tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
435 if (!tdb_printers) {
436 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
437 lock_path("ntprinters.tdb"), strerror(errno) ));
438 return False;
441 if (tdb_forms)
442 tdb_close(tdb_forms);
443 tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
444 if (!tdb_forms) {
445 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
446 lock_path("ntforms.tdb"), strerror(errno) ));
447 return False;
450 local_pid = sys_getpid();
452 /* handle a Samba upgrade */
453 tdb_lock_bystring(tdb_drivers, vstring, 0);
455 /* ---------------- Start Lock Region ---------------- */
457 /* Cope with byte-reversed older versions of the db. */
458 vers_id = tdb_fetch_int32(tdb_drivers, vstring);
460 if ( vers_id != NTDRIVERS_DATABASE_VERSION ) {
462 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
463 /* Written on a bigendian machine with old fetch_int code. Save as le. */
464 /* The only upgrade between V2 and V3 is to save the version in little-endian. */
465 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
466 vers_id = NTDRIVERS_DATABASE_VERSION_3;
469 if (vers_id != NTDRIVERS_DATABASE_VERSION_3 ) {
471 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
472 if (!upgrade_to_version_3())
473 return False;
474 } else
475 tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL);
477 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
480 /* at this point we know that the database is at version 3 so upgrade to v4 */
482 if ( !upgrade_to_version_4() )
483 return False;
484 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
487 /* ---------------- End Lock Region ------------------ */
489 tdb_unlock_bystring(tdb_drivers, vstring);
491 update_c_setprinter(True);
494 * register callback to handle updating printers as new
495 * drivers are installed
498 message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
501 * register callback to handle updating printer data
502 * when a driver is initialized
505 message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
508 * register callback to handle invalidating the printer cache
509 * between smbd processes.
512 message_register( MSG_PRINTER_MOD, receive_printer_mod_msg);
514 /* of course, none of the message callbacks matter if you don't
515 tell messages.c that you interested in receiving PRINT_GENERAL
516 msgs. This is done in claim_connection() */
519 if ( lp_security() == SEC_ADS ) {
520 win_rc = check_published_printers();
521 if (!W_ERROR_IS_OK(win_rc))
522 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
525 return True;
528 /*******************************************************************
529 Function to allow filename parsing "the old way".
530 ********************************************************************/
532 static BOOL driver_unix_convert(char *name,connection_struct *conn,
533 char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst)
535 unix_format(name);
536 unix_clean_name(name);
537 trim_string(name,"/","/");
538 return unix_convert(name, conn, saved_last_component, bad_path, pst);
541 /*******************************************************************
542 tdb traversal function for counting printers.
543 ********************************************************************/
545 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
546 TDB_DATA data, void *context)
548 int *printer_count = (int*)context;
550 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
551 (*printer_count)++;
552 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
555 return 0;
558 /*******************************************************************
559 Update the spooler global c_setprinter. This variable is initialized
560 when the parent smbd starts with the number of existing printers. It
561 is monotonically increased by the current number of printers *after*
562 each add or delete printer RPC. Only Microsoft knows why... JRR020119
563 ********************************************************************/
565 uint32 update_c_setprinter(BOOL initialize)
567 int32 c_setprinter;
568 int32 printer_count = 0;
570 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0);
572 /* Traverse the tdb, counting the printers */
573 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
575 /* If initializing, set c_setprinter to current printers count
576 * otherwise, bump it by the current printer count
578 if (!initialize)
579 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
580 else
581 c_setprinter = printer_count;
583 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
584 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
586 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
588 return (uint32)c_setprinter;
591 /*******************************************************************
592 Get the spooler global c_setprinter, accounting for initialization.
593 ********************************************************************/
595 uint32 get_c_setprinter(void)
597 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
599 if (c_setprinter == (int32)-1)
600 c_setprinter = update_c_setprinter(True);
602 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
604 return (uint32)c_setprinter;
607 /****************************************************************************
608 Get builtin form struct list.
609 ****************************************************************************/
611 int get_builtin_ntforms(nt_forms_struct **list)
613 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
614 return sizeof(default_forms) / sizeof(default_forms[0]);
617 /****************************************************************************
618 get a builtin form struct
619 ****************************************************************************/
621 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
623 int i,count;
624 fstring form_name;
625 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
626 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
627 count = sizeof(default_forms) / sizeof(default_forms[0]);
628 for (i=0;i<count;i++) {
629 if (strequal(form_name,default_forms[i].name)) {
630 DEBUGADD(6,("Found builtin form %s \n", form_name));
631 memcpy(form,&default_forms[i],sizeof(*form));
632 break;
636 return (i !=count);
639 /****************************************************************************
640 get a form struct list
641 ****************************************************************************/
642 int get_ntforms(nt_forms_struct **list)
644 TDB_DATA kbuf, newkey, dbuf;
645 nt_forms_struct *tl;
646 nt_forms_struct form;
647 int ret;
648 int i;
649 int n = 0;
651 for (kbuf = tdb_firstkey(tdb_forms);
652 kbuf.dptr;
653 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
655 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
656 continue;
658 dbuf = tdb_fetch(tdb_forms, kbuf);
659 if (!dbuf.dptr)
660 continue;
662 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
663 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
664 &i, &form.flag, &form.width, &form.length, &form.left,
665 &form.top, &form.right, &form.bottom);
666 SAFE_FREE(dbuf.dptr);
667 if (ret != dbuf.dsize)
668 continue;
670 tl = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
671 if (!tl) {
672 DEBUG(0,("get_ntforms: Realloc fail.\n"));
673 return 0;
675 *list = tl;
676 (*list)[n] = form;
677 n++;
681 return n;
684 /****************************************************************************
685 write a form struct list
686 ****************************************************************************/
687 int write_ntforms(nt_forms_struct **list, int number)
689 pstring buf, key;
690 int len;
691 TDB_DATA kbuf,dbuf;
692 int i;
694 for (i=0;i<number;i++) {
695 /* save index, so list is rebuilt in correct order */
696 len = tdb_pack(buf, sizeof(buf), "dddddddd",
697 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
698 (*list)[i].left, (*list)[i].top, (*list)[i].right,
699 (*list)[i].bottom);
700 if (len > sizeof(buf)) break;
701 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
702 kbuf.dsize = strlen(key)+1;
703 kbuf.dptr = key;
704 dbuf.dsize = len;
705 dbuf.dptr = buf;
706 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
709 return i;
712 /****************************************************************************
713 add a form struct at the end of the list
714 ****************************************************************************/
715 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
717 int n=0;
718 BOOL update;
719 fstring form_name;
720 nt_forms_struct *tl;
723 * NT tries to add forms even when
724 * they are already in the base
725 * only update the values if already present
728 update=False;
730 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
731 for (n=0; n<*count; n++) {
732 if ( strequal((*list)[n].name, form_name) ) {
733 update=True;
734 break;
738 if (update==False) {
739 if((tl=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
740 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
741 return False;
743 *list = tl;
744 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
745 (*count)++;
748 (*list)[n].flag=form->flags;
749 (*list)[n].width=form->size_x;
750 (*list)[n].length=form->size_y;
751 (*list)[n].left=form->left;
752 (*list)[n].top=form->top;
753 (*list)[n].right=form->right;
754 (*list)[n].bottom=form->bottom;
756 DEBUG(6,("add_a_form: Successfully %s form [%s]\n",
757 update ? "updated" : "added", form_name));
759 return True;
762 /****************************************************************************
763 Delete a named form struct.
764 ****************************************************************************/
766 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
768 pstring key;
769 TDB_DATA kbuf;
770 int n=0;
771 fstring form_name;
773 *ret = WERR_OK;
775 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
777 for (n=0; n<*count; n++) {
778 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
779 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
780 break;
784 if (n == *count) {
785 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
786 *ret = WERR_INVALID_PARAM;
787 return False;
790 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
791 kbuf.dsize = strlen(key)+1;
792 kbuf.dptr = key;
793 if (tdb_delete(tdb_forms, kbuf) != 0) {
794 *ret = WERR_NOMEM;
795 return False;
798 return True;
801 /****************************************************************************
802 Update a form struct.
803 ****************************************************************************/
805 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
807 int n=0;
808 fstring form_name;
809 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
811 DEBUG(106, ("[%s]\n", form_name));
812 for (n=0; n<count; n++) {
813 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
814 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
815 break;
818 if (n==count) return;
820 (*list)[n].flag=form->flags;
821 (*list)[n].width=form->size_x;
822 (*list)[n].length=form->size_y;
823 (*list)[n].left=form->left;
824 (*list)[n].top=form->top;
825 (*list)[n].right=form->right;
826 (*list)[n].bottom=form->bottom;
829 /****************************************************************************
830 Get the nt drivers list.
831 Traverse the database and look-up the matching names.
832 ****************************************************************************/
833 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
835 int total=0;
836 const char *short_archi;
837 fstring *fl;
838 pstring key;
839 TDB_DATA kbuf, newkey;
841 short_archi = get_short_archi(architecture);
842 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
844 for (kbuf = tdb_firstkey(tdb_drivers);
845 kbuf.dptr;
846 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
848 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
849 continue;
851 if((fl = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
852 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
853 return -1;
855 else *list = fl;
857 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
858 total++;
861 return(total);
864 /****************************************************************************
865 function to do the mapping between the long architecture name and
866 the short one.
867 ****************************************************************************/
868 const char *get_short_archi(const char *long_archi)
870 int i=-1;
872 DEBUG(107,("Getting architecture dependant directory\n"));
873 do {
874 i++;
875 } while ( (archi_table[i].long_archi!=NULL ) &&
876 StrCaseCmp(long_archi, archi_table[i].long_archi) );
878 if (archi_table[i].long_archi==NULL) {
879 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
880 return NULL;
883 /* this might be client code - but shouldn't this be an fstrcpy etc? */
886 DEBUGADD(108,("index: [%d]\n", i));
887 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
888 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
890 return archi_table[i].short_archi;
893 /****************************************************************************
894 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
895 There are two case to be covered here: PE (Portable Executable) and NE (New
896 Executable) files. Both files support the same INFO structure, but PE files
897 store the signature in unicode, and NE files store it as !unicode.
898 returns -1 on error, 1 on version info found, and 0 on no version info found.
899 ****************************************************************************/
901 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
903 int i;
904 char *buf = NULL;
905 ssize_t byte_count;
907 if ((buf=SMB_MALLOC(PE_HEADER_SIZE)) == NULL) {
908 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
909 fname, PE_HEADER_SIZE));
910 goto error_exit;
913 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
914 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
915 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
916 fname, (unsigned long)byte_count));
917 goto no_version_info;
920 /* Is this really a DOS header? */
921 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
922 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
923 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
924 goto no_version_info;
927 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
928 if (SMB_VFS_LSEEK(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
929 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
930 fname, errno));
931 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
932 goto no_version_info;
935 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
936 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
937 fname, (unsigned long)byte_count));
938 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
939 goto no_version_info;
942 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
943 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
944 unsigned int num_sections;
945 unsigned int section_table_bytes;
947 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
948 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
949 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
950 /* At this point, we assume the file is in error. It still could be somthing
951 * else besides a PE file, but it unlikely at this point.
953 goto error_exit;
956 /* get the section table */
957 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
958 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
959 if (section_table_bytes == 0)
960 goto error_exit;
962 SAFE_FREE(buf);
963 if ((buf=SMB_MALLOC(section_table_bytes)) == NULL) {
964 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
965 fname, section_table_bytes));
966 goto error_exit;
969 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
970 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
971 fname, (unsigned long)byte_count));
972 goto error_exit;
975 /* Iterate the section table looking for the resource section ".rsrc" */
976 for (i = 0; i < num_sections; i++) {
977 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
979 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
980 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
981 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
983 if (section_bytes == 0)
984 goto error_exit;
986 SAFE_FREE(buf);
987 if ((buf=SMB_MALLOC(section_bytes)) == NULL) {
988 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
989 fname, section_bytes));
990 goto error_exit;
993 /* Seek to the start of the .rsrc section info */
994 if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
995 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
996 fname, errno));
997 goto error_exit;
1000 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
1001 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
1002 fname, (unsigned long)byte_count));
1003 goto error_exit;
1006 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
1007 goto error_exit;
1009 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
1010 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
1011 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
1012 /* Align to next long address */
1013 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
1015 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
1016 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
1017 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
1019 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1020 fname, *major, *minor,
1021 (*major>>16)&0xffff, *major&0xffff,
1022 (*minor>>16)&0xffff, *minor&0xffff));
1023 SAFE_FREE(buf);
1024 return 1;
1031 /* Version info not found, fall back to origin date/time */
1032 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
1033 SAFE_FREE(buf);
1034 return 0;
1036 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
1037 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
1038 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
1039 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
1040 /* At this point, we assume the file is in error. It still could be somthing
1041 * else besides a NE file, but it unlikely at this point. */
1042 goto error_exit;
1045 /* Allocate a bit more space to speed up things */
1046 SAFE_FREE(buf);
1047 if ((buf=SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
1048 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
1049 fname, PE_HEADER_SIZE));
1050 goto error_exit;
1053 /* This is a HACK! I got tired of trying to sort through the messy
1054 * 'NE' file format. If anyone wants to clean this up please have at
1055 * it, but this works. 'NE' files will eventually fade away. JRR */
1056 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
1057 /* Cover case that should not occur in a well formed 'NE' .dll file */
1058 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
1060 for(i=0; i<byte_count; i++) {
1061 /* Fast skip past data that can't possibly match */
1062 if (buf[i] != 'V') continue;
1064 /* Potential match data crosses buf boundry, move it to beginning
1065 * of buf, and fill the buf with as much as it will hold. */
1066 if (i>byte_count-VS_VERSION_INFO_SIZE) {
1067 int bc;
1069 memcpy(buf, &buf[i], byte_count-i);
1070 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
1071 (byte_count-i))) < 0) {
1073 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
1074 fname, errno));
1075 goto error_exit;
1078 byte_count = bc + (byte_count - i);
1079 if (byte_count<VS_VERSION_INFO_SIZE) break;
1081 i = 0;
1084 /* Check that the full signature string and the magic number that
1085 * follows exist (not a perfect solution, but the chances that this
1086 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
1087 * twice, as it is simpler to read the code. */
1088 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
1089 /* Compute skip alignment to next long address */
1090 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
1091 sizeof(VS_SIGNATURE)) & 3;
1092 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
1094 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
1095 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
1096 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1097 fname, *major, *minor,
1098 (*major>>16)&0xffff, *major&0xffff,
1099 (*minor>>16)&0xffff, *minor&0xffff));
1100 SAFE_FREE(buf);
1101 return 1;
1106 /* Version info not found, fall back to origin date/time */
1107 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
1108 SAFE_FREE(buf);
1109 return 0;
1111 } else
1112 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1113 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
1114 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
1116 no_version_info:
1117 SAFE_FREE(buf);
1118 return 0;
1120 error_exit:
1121 SAFE_FREE(buf);
1122 return -1;
1125 /****************************************************************************
1126 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
1127 share one or more files. During the MS installation process files are checked
1128 to insure that only a newer version of a shared file is installed over an
1129 older version. There are several possibilities for this comparison. If there
1130 is no previous version, the new one is newer (obviously). If either file is
1131 missing the version info structure, compare the creation date (on Unix use
1132 the modification date). Otherwise chose the numerically larger version number.
1133 ****************************************************************************/
1135 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
1137 BOOL use_version = True;
1138 pstring filepath;
1140 uint32 new_major;
1141 uint32 new_minor;
1142 time_t new_create_time;
1144 uint32 old_major;
1145 uint32 old_minor;
1146 time_t old_create_time;
1148 int access_mode;
1149 int action;
1150 files_struct *fsp = NULL;
1151 SMB_STRUCT_STAT st;
1152 SMB_STRUCT_STAT stat_buf;
1153 BOOL bad_path;
1155 SET_STAT_INVALID(st);
1156 SET_STAT_INVALID(stat_buf);
1157 new_create_time = (time_t)0;
1158 old_create_time = (time_t)0;
1160 /* Get file version info (if available) for previous file (if it exists) */
1161 pstrcpy(filepath, old_file);
1163 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1165 fsp = open_file_shared(conn, filepath, &stat_buf,
1166 SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
1167 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1168 FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
1169 if (!fsp) {
1170 /* Old file not found, so by definition new file is in fact newer */
1171 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
1172 filepath, errno));
1173 return True;
1175 } else {
1176 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
1177 if (ret == -1) goto error_exit;
1179 if (!ret) {
1180 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1181 old_file));
1182 use_version = False;
1183 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1184 old_create_time = st.st_mtime;
1185 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1188 close_file(fsp, True);
1190 /* Get file version info (if available) for new file */
1191 pstrcpy(filepath, new_file);
1192 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1194 fsp = open_file_shared(conn, filepath, &stat_buf,
1195 SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
1196 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1197 FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
1198 if (!fsp) {
1199 /* New file not found, this shouldn't occur if the caller did its job */
1200 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1201 filepath, errno));
1202 goto error_exit;
1204 } else {
1205 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1206 if (ret == -1) goto error_exit;
1208 if (!ret) {
1209 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1210 new_file));
1211 use_version = False;
1212 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1213 new_create_time = st.st_mtime;
1214 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1217 close_file(fsp, True);
1219 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1220 /* Compare versions and choose the larger version number */
1221 if (new_major > old_major ||
1222 (new_major == old_major && new_minor > old_minor)) {
1224 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1225 return True;
1227 else {
1228 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1229 return False;
1232 } else {
1233 /* Compare modification time/dates and choose the newest time/date */
1234 if (new_create_time > old_create_time) {
1235 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1236 return True;
1238 else {
1239 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1240 return False;
1244 error_exit:
1245 if(fsp)
1246 close_file(fsp, True);
1247 return -1;
1250 /****************************************************************************
1251 Determine the correct cVersion associated with an architecture and driver
1252 ****************************************************************************/
1253 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1254 struct current_user *user, WERROR *perr)
1256 int cversion;
1257 int access_mode;
1258 int action;
1259 NTSTATUS nt_status;
1260 pstring driverpath;
1261 DATA_BLOB null_pw;
1262 fstring res_type;
1263 files_struct *fsp = NULL;
1264 BOOL bad_path;
1265 SMB_STRUCT_STAT st;
1266 connection_struct *conn;
1268 SET_STAT_INVALID(st);
1270 *perr = WERR_INVALID_PARAM;
1272 /* If architecture is Windows 95/98/ME, the version is always 0. */
1273 if (strcmp(architecture, "WIN40") == 0) {
1274 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1275 *perr = WERR_OK;
1276 return 0;
1280 * Connect to the print$ share under the same account as the user connected
1281 * to the rpc pipe. Note we must still be root to do this.
1284 /* Null password is ok - we are already an authenticated user... */
1285 null_pw = data_blob(NULL, 0);
1286 fstrcpy(res_type, "A:");
1287 become_root();
1288 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1289 unbecome_root();
1291 if (conn == NULL) {
1292 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1293 *perr = ntstatus_to_werror(nt_status);
1294 return -1;
1297 /* We are temporarily becoming the connection user. */
1298 if (!become_user(conn, user->vuid)) {
1299 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1300 *perr = WERR_ACCESS_DENIED;
1301 return -1;
1304 /* Open the driver file (Portable Executable format) and determine the
1305 * deriver the cversion. */
1306 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1308 driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
1310 if ( !vfs_file_exist( conn, driverpath, &st ) ) {
1311 *perr = WERR_BADFILE;
1312 goto error_exit;
1315 fsp = open_file_shared(conn, driverpath, &st,
1316 SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
1317 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1318 FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action);
1320 if (!fsp) {
1321 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1322 driverpath, errno));
1323 *perr = WERR_ACCESS_DENIED;
1324 goto error_exit;
1326 else {
1327 uint32 major;
1328 uint32 minor;
1329 int ret = get_file_version(fsp, driverpath, &major, &minor);
1330 if (ret == -1) goto error_exit;
1332 if (!ret) {
1333 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1334 goto error_exit;
1338 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1339 * for more details. Version in this case is not just the version of the
1340 * file, but the version in the sense of kernal mode (2) vs. user mode
1341 * (3) drivers. Other bits of the version fields are the version info.
1342 * JRR 010716
1344 cversion = major & 0x0000ffff;
1345 switch (cversion) {
1346 case 2: /* WinNT drivers */
1347 case 3: /* Win2K drivers */
1348 break;
1350 default:
1351 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1352 driverpath, cversion));
1353 goto error_exit;
1356 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1357 driverpath, major, minor));
1360 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1361 driverpath, cversion));
1363 close_file(fsp, True);
1364 close_cnum(conn, user->vuid);
1365 unbecome_user();
1366 *perr = WERR_OK;
1367 return cversion;
1370 error_exit:
1372 if(fsp)
1373 close_file(fsp, True);
1375 close_cnum(conn, user->vuid);
1376 unbecome_user();
1377 return -1;
1380 /****************************************************************************
1381 ****************************************************************************/
1382 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1383 struct current_user *user)
1385 const char *architecture;
1386 fstring new_name;
1387 char *p;
1388 int i;
1389 WERROR err;
1391 /* clean up the driver name.
1392 * we can get .\driver.dll
1393 * or worse c:\windows\system\driver.dll !
1395 /* using an intermediate string to not have overlaping memcpy()'s */
1396 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1397 fstrcpy(new_name, p+1);
1398 fstrcpy(driver->driverpath, new_name);
1401 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1402 fstrcpy(new_name, p+1);
1403 fstrcpy(driver->datafile, new_name);
1406 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1407 fstrcpy(new_name, p+1);
1408 fstrcpy(driver->configfile, new_name);
1411 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1412 fstrcpy(new_name, p+1);
1413 fstrcpy(driver->helpfile, new_name);
1416 if (driver->dependentfiles) {
1417 for (i=0; *driver->dependentfiles[i]; i++) {
1418 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1419 fstrcpy(new_name, p+1);
1420 fstrcpy(driver->dependentfiles[i], new_name);
1425 architecture = get_short_archi(driver->environment);
1427 /* jfm:7/16/2000 the client always sends the cversion=0.
1428 * The server should check which version the driver is by reading
1429 * the PE header of driver->driverpath.
1431 * For Windows 95/98 the version is 0 (so the value sent is correct)
1432 * For Windows NT (the architecture doesn't matter)
1433 * NT 3.1: cversion=0
1434 * NT 3.5/3.51: cversion=1
1435 * NT 4: cversion=2
1436 * NT2K: cversion=3
1438 if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
1439 return err;
1441 return WERR_OK;
1444 /****************************************************************************
1445 ****************************************************************************/
1446 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1448 const char *architecture;
1449 fstring new_name;
1450 char *p;
1451 int i;
1452 WERROR err;
1454 /* clean up the driver name.
1455 * we can get .\driver.dll
1456 * or worse c:\windows\system\driver.dll !
1458 /* using an intermediate string to not have overlaping memcpy()'s */
1459 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1460 fstrcpy(new_name, p+1);
1461 fstrcpy(driver->driverpath, new_name);
1464 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1465 fstrcpy(new_name, p+1);
1466 fstrcpy(driver->datafile, new_name);
1469 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1470 fstrcpy(new_name, p+1);
1471 fstrcpy(driver->configfile, new_name);
1474 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1475 fstrcpy(new_name, p+1);
1476 fstrcpy(driver->helpfile, new_name);
1479 if (driver->dependentfiles) {
1480 for (i=0; *driver->dependentfiles[i]; i++) {
1481 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1482 fstrcpy(new_name, p+1);
1483 fstrcpy(driver->dependentfiles[i], new_name);
1488 architecture = get_short_archi(driver->environment);
1490 /* jfm:7/16/2000 the client always sends the cversion=0.
1491 * The server should check which version the driver is by reading
1492 * the PE header of driver->driverpath.
1494 * For Windows 95/98 the version is 0 (so the value sent is correct)
1495 * For Windows NT (the architecture doesn't matter)
1496 * NT 3.1: cversion=0
1497 * NT 3.5/3.51: cversion=1
1498 * NT 4: cversion=2
1499 * NT2K: cversion=3
1502 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1503 return err;
1505 return WERR_OK;
1508 /****************************************************************************
1509 ****************************************************************************/
1510 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1511 uint32 level, struct current_user *user)
1513 switch (level) {
1514 case 3:
1516 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1517 driver=driver_abstract.info_3;
1518 return clean_up_driver_struct_level_3(driver, user);
1520 case 6:
1522 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1523 driver=driver_abstract.info_6;
1524 return clean_up_driver_struct_level_6(driver, user);
1526 default:
1527 return WERR_INVALID_PARAM;
1531 /****************************************************************************
1532 This function sucks and should be replaced. JRA.
1533 ****************************************************************************/
1535 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1537 dst->cversion = src->version;
1539 fstrcpy( dst->name, src->name);
1540 fstrcpy( dst->environment, src->environment);
1541 fstrcpy( dst->driverpath, src->driverpath);
1542 fstrcpy( dst->datafile, src->datafile);
1543 fstrcpy( dst->configfile, src->configfile);
1544 fstrcpy( dst->helpfile, src->helpfile);
1545 fstrcpy( dst->monitorname, src->monitorname);
1546 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1547 dst->dependentfiles = src->dependentfiles;
1550 #if 0 /* Debugging function */
1552 static char* ffmt(unsigned char *c){
1553 int i;
1554 static char ffmt_str[17];
1556 for (i=0; i<16; i++) {
1557 if ((c[i] < ' ') || (c[i] > '~'))
1558 ffmt_str[i]='.';
1559 else
1560 ffmt_str[i]=c[i];
1562 ffmt_str[16]='\0';
1563 return ffmt_str;
1566 #endif
1568 /****************************************************************************
1569 ****************************************************************************/
1570 WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1571 struct current_user *user, WERROR *perr)
1573 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1574 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1575 const char *architecture;
1576 pstring new_dir;
1577 pstring old_name;
1578 pstring new_name;
1579 DATA_BLOB null_pw;
1580 connection_struct *conn;
1581 NTSTATUS nt_status;
1582 pstring inbuf;
1583 pstring outbuf;
1584 fstring res_type;
1585 BOOL bad_path;
1586 SMB_STRUCT_STAT st;
1587 int ver = 0;
1588 int i;
1589 int err;
1591 memset(inbuf, '\0', sizeof(inbuf));
1592 memset(outbuf, '\0', sizeof(outbuf));
1593 *perr = WERR_OK;
1595 if (level==3)
1596 driver=driver_abstract.info_3;
1597 else if (level==6) {
1598 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1599 driver = &converted_driver;
1600 } else {
1601 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1602 return WERR_UNKNOWN_LEVEL;
1605 architecture = get_short_archi(driver->environment);
1608 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1609 * Note we must be root to do this.
1612 null_pw = data_blob(NULL, 0);
1613 fstrcpy(res_type, "A:");
1614 become_root();
1615 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1616 unbecome_root();
1618 if (conn == NULL) {
1619 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1620 *perr = ntstatus_to_werror(nt_status);
1621 return WERR_NO_SUCH_SHARE;
1625 * Save who we are - we are temporarily becoming the connection user.
1628 if (!become_user(conn, conn->vuid)) {
1629 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1630 return WERR_ACCESS_DENIED;
1634 * make the directories version and version\driver_name
1635 * under the architecture directory.
1637 DEBUG(5,("Creating first directory\n"));
1638 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1639 driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
1640 mkdir_internal(conn, new_dir, bad_path);
1642 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1643 * listed for this driver which has already been moved, skip it (note:
1644 * drivers may list the same file name several times. Then check if the
1645 * file already exists in archi\cversion\, if so, check that the version
1646 * info (or time stamps if version info is unavailable) is newer (or the
1647 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1648 * Otherwise, delete the file.
1650 * If a file is not moved to archi\cversion\ because of an error, all the
1651 * rest of the 'unmoved' driver files are removed from archi\. If one or
1652 * more of the driver's files was already moved to archi\cversion\, it
1653 * potentially leaves the driver in a partially updated state. Version
1654 * trauma will most likely occur if an client attempts to use any printer
1655 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1656 * done is appropriate... later JRR
1659 DEBUG(5,("Moving files now !\n"));
1661 if (driver->driverpath && strlen(driver->driverpath)) {
1662 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1663 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1664 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1665 NTSTATUS status;
1666 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1667 if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1668 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1669 new_name, old_name));
1670 *perr = ntstatus_to_werror(status);
1671 ver = -1;
1676 if (driver->datafile && strlen(driver->datafile)) {
1677 if (!strequal(driver->datafile, driver->driverpath)) {
1678 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1679 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1680 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1681 NTSTATUS status;
1682 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1683 if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1684 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1685 new_name, old_name));
1686 *perr = ntstatus_to_werror(status);
1687 ver = -1;
1693 if (driver->configfile && strlen(driver->configfile)) {
1694 if (!strequal(driver->configfile, driver->driverpath) &&
1695 !strequal(driver->configfile, driver->datafile)) {
1696 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1697 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1698 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1699 NTSTATUS status;
1700 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1701 if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1702 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1703 new_name, old_name));
1704 *perr = ntstatus_to_werror(status);
1705 ver = -1;
1711 if (driver->helpfile && strlen(driver->helpfile)) {
1712 if (!strequal(driver->helpfile, driver->driverpath) &&
1713 !strequal(driver->helpfile, driver->datafile) &&
1714 !strequal(driver->helpfile, driver->configfile)) {
1715 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1716 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1717 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1718 NTSTATUS status;
1719 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1720 if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1721 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1722 new_name, old_name));
1723 *perr = ntstatus_to_werror(status);
1724 ver = -1;
1730 if (driver->dependentfiles) {
1731 for (i=0; *driver->dependentfiles[i]; i++) {
1732 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1733 !strequal(driver->dependentfiles[i], driver->datafile) &&
1734 !strequal(driver->dependentfiles[i], driver->configfile) &&
1735 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1736 int j;
1737 for (j=0; j < i; j++) {
1738 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1739 goto NextDriver;
1743 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1744 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1745 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1746 NTSTATUS status;
1747 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1748 if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) {
1749 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1750 new_name, old_name));
1751 *perr = ntstatus_to_werror(status);
1752 ver = -1;
1756 NextDriver: ;
1760 close_cnum(conn, user->vuid);
1761 unbecome_user();
1763 return ver != -1 ? WERR_OK : WERR_UNKNOWN_PRINTER_DRIVER;
1766 /****************************************************************************
1767 ****************************************************************************/
1768 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1770 int len, buflen;
1771 const char *architecture;
1772 pstring directory;
1773 fstring temp_name;
1774 pstring key;
1775 char *buf;
1776 int i, ret;
1777 TDB_DATA kbuf, dbuf;
1779 architecture = get_short_archi(driver->environment);
1781 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1782 * \\server is added in the rpc server layer.
1783 * It does make sense to NOT store the server's name in the printer TDB.
1786 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1788 /* .inf files do not always list a file for each of the four standard files.
1789 * Don't prepend a path to a null filename, or client claims:
1790 * "The server on which the printer resides does not have a suitable
1791 * <printer driver name> printer driver installed. Click OK if you
1792 * wish to install the driver on your local machine."
1794 if (strlen(driver->driverpath)) {
1795 fstrcpy(temp_name, driver->driverpath);
1796 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1799 if (strlen(driver->datafile)) {
1800 fstrcpy(temp_name, driver->datafile);
1801 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1804 if (strlen(driver->configfile)) {
1805 fstrcpy(temp_name, driver->configfile);
1806 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1809 if (strlen(driver->helpfile)) {
1810 fstrcpy(temp_name, driver->helpfile);
1811 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1814 if (driver->dependentfiles) {
1815 for (i=0; *driver->dependentfiles[i]; i++) {
1816 fstrcpy(temp_name, driver->dependentfiles[i]);
1817 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1821 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1823 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1825 buf = NULL;
1826 len = buflen = 0;
1828 again:
1829 len = 0;
1830 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1831 driver->cversion,
1832 driver->name,
1833 driver->environment,
1834 driver->driverpath,
1835 driver->datafile,
1836 driver->configfile,
1837 driver->helpfile,
1838 driver->monitorname,
1839 driver->defaultdatatype);
1841 if (driver->dependentfiles) {
1842 for (i=0; *driver->dependentfiles[i]; i++) {
1843 len += tdb_pack(buf+len, buflen-len, "f",
1844 driver->dependentfiles[i]);
1848 if (len != buflen) {
1849 char *tb;
1851 tb = (char *)SMB_REALLOC(buf, len);
1852 if (!tb) {
1853 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1854 ret = -1;
1855 goto done;
1857 else buf = tb;
1858 buflen = len;
1859 goto again;
1863 kbuf.dptr = key;
1864 kbuf.dsize = strlen(key)+1;
1865 dbuf.dptr = buf;
1866 dbuf.dsize = len;
1868 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1870 done:
1871 if (ret)
1872 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1874 SAFE_FREE(buf);
1875 return ret;
1878 /****************************************************************************
1879 ****************************************************************************/
1880 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
1882 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
1884 ZERO_STRUCT(info3);
1885 info3.cversion = driver->version;
1886 fstrcpy(info3.name,driver->name);
1887 fstrcpy(info3.environment,driver->environment);
1888 fstrcpy(info3.driverpath,driver->driverpath);
1889 fstrcpy(info3.datafile,driver->datafile);
1890 fstrcpy(info3.configfile,driver->configfile);
1891 fstrcpy(info3.helpfile,driver->helpfile);
1892 fstrcpy(info3.monitorname,driver->monitorname);
1893 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
1894 info3.dependentfiles = driver->dependentfiles;
1896 return add_a_printer_driver_3(&info3);
1900 /****************************************************************************
1901 ****************************************************************************/
1902 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
1904 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
1906 ZERO_STRUCT(info);
1908 fstrcpy(info.name, driver);
1909 fstrcpy(info.defaultdatatype, "RAW");
1911 fstrcpy(info.driverpath, "");
1912 fstrcpy(info.datafile, "");
1913 fstrcpy(info.configfile, "");
1914 fstrcpy(info.helpfile, "");
1916 if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
1917 return WERR_NOMEM;
1919 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
1920 fstrcpy(info.dependentfiles[0], "");
1922 *info_ptr = memdup(&info, sizeof(info));
1924 return WERR_OK;
1927 /****************************************************************************
1928 ****************************************************************************/
1929 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
1931 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
1932 TDB_DATA kbuf, dbuf;
1933 const char *architecture;
1934 int len = 0;
1935 int i;
1936 pstring key;
1938 ZERO_STRUCT(driver);
1940 architecture = get_short_archi(arch);
1942 if ( !architecture )
1943 return WERR_UNKNOWN_PRINTER_DRIVER;
1945 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
1947 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
1948 version = 0;
1950 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
1952 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
1954 kbuf.dptr = key;
1955 kbuf.dsize = strlen(key)+1;
1957 dbuf = tdb_fetch(tdb_drivers, kbuf);
1958 if (!dbuf.dptr)
1959 return WERR_UNKNOWN_PRINTER_DRIVER;
1961 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
1962 &driver.cversion,
1963 driver.name,
1964 driver.environment,
1965 driver.driverpath,
1966 driver.datafile,
1967 driver.configfile,
1968 driver.helpfile,
1969 driver.monitorname,
1970 driver.defaultdatatype);
1972 i=0;
1973 while (len < dbuf.dsize) {
1974 fstring *tddfs;
1976 tddfs = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
1977 if (tddfs == NULL) {
1978 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
1979 break;
1981 else driver.dependentfiles = tddfs;
1983 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
1984 &driver.dependentfiles[i]);
1985 i++;
1988 if (driver.dependentfiles != NULL)
1989 fstrcpy(driver.dependentfiles[i], "");
1991 SAFE_FREE(dbuf.dptr);
1993 if (len != dbuf.dsize) {
1994 SAFE_FREE(driver.dependentfiles);
1996 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
1999 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
2001 return WERR_OK;
2004 /****************************************************************************
2005 Debugging function, dump at level 6 the struct in the logs.
2006 ****************************************************************************/
2008 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
2010 uint32 result;
2011 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
2012 int i;
2014 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
2016 switch (level)
2018 case 3:
2020 if (driver.info_3 == NULL)
2021 result=5;
2022 else {
2023 info3=driver.info_3;
2025 DEBUGADD(20,("version:[%d]\n", info3->cversion));
2026 DEBUGADD(20,("name:[%s]\n", info3->name));
2027 DEBUGADD(20,("environment:[%s]\n", info3->environment));
2028 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
2029 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
2030 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
2031 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
2032 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
2033 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
2035 for (i=0; info3->dependentfiles &&
2036 *info3->dependentfiles[i]; i++) {
2037 DEBUGADD(20,("dependentfile:[%s]\n",
2038 info3->dependentfiles[i]));
2040 result=0;
2042 break;
2044 default:
2045 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
2046 result=1;
2047 break;
2050 return result;
2053 /****************************************************************************
2054 ****************************************************************************/
2055 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
2057 int len = 0;
2059 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
2061 if (!nt_devmode)
2062 return len;
2064 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2065 nt_devmode->devicename,
2066 nt_devmode->formname,
2068 nt_devmode->specversion,
2069 nt_devmode->driverversion,
2070 nt_devmode->size,
2071 nt_devmode->driverextra,
2072 nt_devmode->orientation,
2073 nt_devmode->papersize,
2074 nt_devmode->paperlength,
2075 nt_devmode->paperwidth,
2076 nt_devmode->scale,
2077 nt_devmode->copies,
2078 nt_devmode->defaultsource,
2079 nt_devmode->printquality,
2080 nt_devmode->color,
2081 nt_devmode->duplex,
2082 nt_devmode->yresolution,
2083 nt_devmode->ttoption,
2084 nt_devmode->collate,
2085 nt_devmode->logpixels,
2087 nt_devmode->fields,
2088 nt_devmode->bitsperpel,
2089 nt_devmode->pelswidth,
2090 nt_devmode->pelsheight,
2091 nt_devmode->displayflags,
2092 nt_devmode->displayfrequency,
2093 nt_devmode->icmmethod,
2094 nt_devmode->icmintent,
2095 nt_devmode->mediatype,
2096 nt_devmode->dithertype,
2097 nt_devmode->reserved1,
2098 nt_devmode->reserved2,
2099 nt_devmode->panningwidth,
2100 nt_devmode->panningheight,
2101 nt_devmode->private);
2104 if (nt_devmode->private) {
2105 len += tdb_pack(buf+len, buflen-len, "B",
2106 nt_devmode->driverextra,
2107 nt_devmode->private);
2110 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
2112 return len;
2115 /****************************************************************************
2116 Pack all values in all printer keys
2117 ***************************************************************************/
2119 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
2121 int len = 0;
2122 int i, j;
2123 REGISTRY_VALUE *val;
2124 REGVAL_CTR *val_ctr;
2125 pstring path;
2126 int num_values;
2128 if ( !data )
2129 return 0;
2131 /* loop over all keys */
2133 for ( i=0; i<data->num_keys; i++ ) {
2134 val_ctr = &data->keys[i].values;
2135 num_values = regval_ctr_numvals( val_ctr );
2137 /* loop over all values */
2139 for ( j=0; j<num_values; j++ ) {
2140 /* pathname should be stored as <key>\<value> */
2142 val = regval_ctr_specific_value( val_ctr, j );
2143 pstrcpy( path, data->keys[i].name );
2144 pstrcat( path, "\\" );
2145 pstrcat( path, regval_name(val) );
2147 len += tdb_pack(buf+len, buflen-len, "pPdB",
2148 val,
2149 path,
2150 regval_type(val),
2151 regval_size(val),
2152 regval_data_p(val) );
2157 /* terminator */
2159 len += tdb_pack(buf+len, buflen-len, "p", NULL);
2161 return len;
2165 /****************************************************************************
2166 Delete a printer - this just deletes the printer info file, any open
2167 handles are not affected.
2168 ****************************************************************************/
2170 uint32 del_a_printer(const char *sharename)
2172 pstring key;
2173 TDB_DATA kbuf;
2174 pstring printdb_path;
2176 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
2177 kbuf.dptr=key;
2178 kbuf.dsize=strlen(key)+1;
2179 tdb_delete(tdb_printers, kbuf);
2181 slprintf(key, sizeof(key)-1, "%s%s", SECDESC_PREFIX, sharename);
2182 kbuf.dptr=key;
2183 kbuf.dsize=strlen(key)+1;
2184 tdb_delete(tdb_printers, kbuf);
2186 close_all_print_db();
2188 if (geteuid() == 0) {
2189 pstrcpy(printdb_path, lock_path("printing/"));
2190 pstrcat(printdb_path, sharename);
2191 pstrcat(printdb_path, ".tdb");
2193 unlink(printdb_path);
2196 return 0;
2199 /****************************************************************************
2200 ****************************************************************************/
2201 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2203 pstring key;
2204 char *buf;
2205 int buflen, len;
2206 WERROR ret;
2207 TDB_DATA kbuf, dbuf;
2210 * in addprinter: no servername and the printer is the name
2211 * in setprinter: servername is \\server
2212 * and printer is \\server\\printer
2214 * Samba manages only local printers.
2215 * we currently don't support things like i
2216 * path=\\other_server\printer
2218 * We only store the printername, not \\server\printername
2221 if ( info->servername[0] != '\0' ) {
2222 trim_string(info->printername, info->servername, NULL);
2223 trim_char(info->printername, '\\', '\0');
2224 info->servername[0]='\0';
2228 * JFM: one day I'll forget.
2229 * below that's info->portname because that's the SAMBA sharename
2230 * and I made NT 'thinks' it's the portname
2231 * the info->sharename is the thing you can name when you add a printer
2232 * that's the short-name when you create shared printer for 95/98
2233 * So I've made a limitation in SAMBA: you can only have 1 printer model
2234 * behind a SAMBA share.
2237 buf = NULL;
2238 buflen = 0;
2240 again:
2241 len = 0;
2242 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2243 info->attributes,
2244 info->priority,
2245 info->default_priority,
2246 info->starttime,
2247 info->untiltime,
2248 info->status,
2249 info->cjobs,
2250 info->averageppm,
2251 info->changeid,
2252 info->c_setprinter,
2253 info->setuptime,
2254 info->servername,
2255 info->printername,
2256 info->sharename,
2257 info->portname,
2258 info->drivername,
2259 info->comment,
2260 info->location,
2261 info->sepfile,
2262 info->printprocessor,
2263 info->datatype,
2264 info->parameters);
2266 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2268 len += pack_values( &info->data, buf+len, buflen-len );
2270 if (buflen != len) {
2271 char *tb;
2273 tb = (char *)SMB_REALLOC(buf, len);
2274 if (!tb) {
2275 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2276 ret = WERR_NOMEM;
2277 goto done;
2279 else buf = tb;
2280 buflen = len;
2281 goto again;
2285 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
2287 kbuf.dptr = key;
2288 kbuf.dsize = strlen(key)+1;
2289 dbuf.dptr = buf;
2290 dbuf.dsize = len;
2292 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2294 done:
2295 if (!W_ERROR_IS_OK(ret))
2296 DEBUG(8, ("error updating printer to tdb on disk\n"));
2298 SAFE_FREE(buf);
2300 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2301 info->sharename, info->drivername, info->portname, len));
2303 return ret;
2307 /****************************************************************************
2308 Malloc and return an NT devicemode.
2309 ****************************************************************************/
2311 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2314 char adevice[MAXDEVICENAME];
2315 NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
2317 if (nt_devmode == NULL) {
2318 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2319 return NULL;
2322 ZERO_STRUCTP(nt_devmode);
2324 slprintf(adevice, sizeof(adevice), "%s", default_devicename);
2325 fstrcpy(nt_devmode->devicename, adevice);
2327 fstrcpy(nt_devmode->formname, "Letter");
2329 nt_devmode->specversion = 0x0401;
2330 nt_devmode->driverversion = 0x0400;
2331 nt_devmode->size = 0x00DC;
2332 nt_devmode->driverextra = 0x0000;
2333 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2334 DEFAULTSOURCE | COPIES | SCALE |
2335 PAPERSIZE | ORIENTATION;
2336 nt_devmode->orientation = 1;
2337 nt_devmode->papersize = PAPER_LETTER;
2338 nt_devmode->paperlength = 0;
2339 nt_devmode->paperwidth = 0;
2340 nt_devmode->scale = 0x64;
2341 nt_devmode->copies = 1;
2342 nt_devmode->defaultsource = BIN_FORMSOURCE;
2343 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2344 nt_devmode->color = COLOR_MONOCHROME;
2345 nt_devmode->duplex = DUP_SIMPLEX;
2346 nt_devmode->yresolution = 0;
2347 nt_devmode->ttoption = TT_SUBDEV;
2348 nt_devmode->collate = COLLATE_FALSE;
2349 nt_devmode->icmmethod = 0;
2350 nt_devmode->icmintent = 0;
2351 nt_devmode->mediatype = 0;
2352 nt_devmode->dithertype = 0;
2354 /* non utilisés par un driver d'imprimante */
2355 nt_devmode->logpixels = 0;
2356 nt_devmode->bitsperpel = 0;
2357 nt_devmode->pelswidth = 0;
2358 nt_devmode->pelsheight = 0;
2359 nt_devmode->displayflags = 0;
2360 nt_devmode->displayfrequency = 0;
2361 nt_devmode->reserved1 = 0;
2362 nt_devmode->reserved2 = 0;
2363 nt_devmode->panningwidth = 0;
2364 nt_devmode->panningheight = 0;
2366 nt_devmode->private = NULL;
2367 return nt_devmode;
2370 /****************************************************************************
2371 Deepcopy an NT devicemode.
2372 ****************************************************************************/
2374 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2376 NT_DEVICEMODE *new_nt_devicemode = NULL;
2378 if ( !nt_devicemode )
2379 return NULL;
2381 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2382 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2383 return NULL;
2386 new_nt_devicemode->private = NULL;
2387 if (nt_devicemode->private != NULL) {
2388 if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
2389 SAFE_FREE(new_nt_devicemode);
2390 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2391 return NULL;
2395 return new_nt_devicemode;
2398 /****************************************************************************
2399 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2400 ****************************************************************************/
2402 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2404 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2406 if(nt_devmode == NULL)
2407 return;
2409 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2411 SAFE_FREE(nt_devmode->private);
2412 SAFE_FREE(*devmode_ptr);
2415 /****************************************************************************
2416 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2417 ****************************************************************************/
2418 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2420 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2421 NT_PRINTER_DATA *data;
2422 int i;
2424 if ( !info )
2425 return;
2427 DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
2429 free_nt_devicemode(&info->devmode);
2431 /* clean up all registry keys */
2433 data = &info->data;
2434 for ( i=0; i<data->num_keys; i++ ) {
2435 SAFE_FREE( data->keys[i].name );
2436 regval_ctr_destroy( &data->keys[i].values );
2438 SAFE_FREE( data->keys );
2440 /* finally the top level structure */
2442 SAFE_FREE( *info_ptr );
2446 /****************************************************************************
2447 ****************************************************************************/
2448 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2450 int len = 0;
2451 int extra_len = 0;
2452 NT_DEVICEMODE devmode;
2454 ZERO_STRUCT(devmode);
2456 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2458 if (!*nt_devmode) return len;
2460 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2461 devmode.devicename,
2462 devmode.formname,
2464 &devmode.specversion,
2465 &devmode.driverversion,
2466 &devmode.size,
2467 &devmode.driverextra,
2468 &devmode.orientation,
2469 &devmode.papersize,
2470 &devmode.paperlength,
2471 &devmode.paperwidth,
2472 &devmode.scale,
2473 &devmode.copies,
2474 &devmode.defaultsource,
2475 &devmode.printquality,
2476 &devmode.color,
2477 &devmode.duplex,
2478 &devmode.yresolution,
2479 &devmode.ttoption,
2480 &devmode.collate,
2481 &devmode.logpixels,
2483 &devmode.fields,
2484 &devmode.bitsperpel,
2485 &devmode.pelswidth,
2486 &devmode.pelsheight,
2487 &devmode.displayflags,
2488 &devmode.displayfrequency,
2489 &devmode.icmmethod,
2490 &devmode.icmintent,
2491 &devmode.mediatype,
2492 &devmode.dithertype,
2493 &devmode.reserved1,
2494 &devmode.reserved2,
2495 &devmode.panningwidth,
2496 &devmode.panningheight,
2497 &devmode.private);
2499 if (devmode.private) {
2500 /* the len in tdb_unpack is an int value and
2501 * devmode.driverextra is only a short
2503 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
2504 devmode.driverextra=(uint16)extra_len;
2506 /* check to catch an invalid TDB entry so we don't segfault */
2507 if (devmode.driverextra == 0) {
2508 devmode.private = NULL;
2512 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2514 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2515 if (devmode.private)
2516 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2518 return len;
2521 /****************************************************************************
2522 Allocate and initialize a new slot.
2523 ***************************************************************************/
2525 static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2527 NT_PRINTER_KEY *d;
2528 int key_index;
2530 if ( !data || !name )
2531 return -1;
2533 /* allocate another slot in the NT_PRINTER_KEY array */
2535 d = SMB_REALLOC_ARRAY( data->keys, NT_PRINTER_KEY, data->num_keys+1);
2536 if ( d )
2537 data->keys = d;
2539 key_index = data->num_keys;
2541 /* initialze new key */
2543 data->num_keys++;
2544 data->keys[key_index].name = SMB_STRDUP( name );
2546 regval_ctr_init( &data->keys[key_index].values );
2548 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2550 return key_index;
2553 /****************************************************************************
2554 search for a registry key name in the existing printer data
2555 ***************************************************************************/
2557 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2559 int key_index = -1;
2560 int i;
2562 if ( !data || !name )
2563 return -1;
2565 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2567 /* loop over all existing keys */
2569 for ( i=0; i<data->num_keys; i++ ) {
2570 if ( strequal(data->keys[i].name, name) ) {
2571 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2572 key_index = i;
2573 break;
2578 return key_index;
2581 /****************************************************************************
2582 ***************************************************************************/
2584 uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2586 int i, j;
2587 int key_len;
2588 int num_subkeys = 0;
2589 char *p;
2590 fstring *ptr, *subkeys_ptr = NULL;
2591 fstring subkeyname;
2593 if ( !data )
2594 return 0;
2596 for ( i=0; i<data->num_keys; i++ ) {
2597 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2598 /* match sure it is a subkey and not the key itself */
2600 key_len = strlen( key );
2601 if ( strlen(data->keys[i].name) == key_len )
2602 continue;
2604 /* get subkey path */
2606 p = data->keys[i].name + key_len;
2607 if ( *p == '\\' )
2608 p++;
2609 fstrcpy( subkeyname, p );
2610 if ( (p = strchr( subkeyname, '\\' )) )
2611 *p = '\0';
2613 /* don't add a key more than once */
2615 for ( j=0; j<num_subkeys; j++ ) {
2616 if ( strequal( subkeys_ptr[j], subkeyname ) )
2617 break;
2620 if ( j != num_subkeys )
2621 continue;
2623 /* found a match, so allocate space and copy the name */
2625 if ( !(ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
2626 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2627 num_subkeys+1));
2628 SAFE_FREE( subkeys );
2629 return 0;
2632 subkeys_ptr = ptr;
2633 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2634 num_subkeys++;
2639 /* tag of the end */
2641 if (num_subkeys)
2642 fstrcpy(subkeys_ptr[num_subkeys], "" );
2644 *subkeys = subkeys_ptr;
2646 return num_subkeys;
2649 #ifdef HAVE_ADS
2650 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2651 const char *sz)
2653 smb_ucs2_t conv_str[1024];
2654 size_t str_size;
2656 regval_ctr_delvalue(ctr, val_name);
2657 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2658 STR_TERMINATE | STR_NOALIGN);
2659 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2660 (char *) conv_str, str_size);
2663 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2664 uint32 dword)
2666 regval_ctr_delvalue(ctr, val_name);
2667 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2668 (char *) &dword, sizeof(dword));
2671 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2672 BOOL b)
2674 uint8 bin_bool = (b ? 1 : 0);
2675 regval_ctr_delvalue(ctr, val_name);
2676 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2677 (char *) &bin_bool, sizeof(bin_bool));
2680 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2681 const char *multi_sz)
2683 smb_ucs2_t *conv_strs = NULL;
2684 size_t str_size;
2686 /* a multi-sz has to have a null string terminator, i.e., the last
2687 string must be followed by two nulls */
2688 str_size = strlen(multi_sz) + 2;
2689 conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
2690 if (!conv_strs) {
2691 return;
2694 /* Change to byte units. */
2695 str_size *= sizeof(smb_ucs2_t);
2696 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2697 STR_TERMINATE | STR_NOALIGN);
2699 regval_ctr_delvalue(ctr, val_name);
2700 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2701 (char *) conv_strs, str_size);
2702 safe_free(conv_strs);
2706 /****************************************************************************
2707 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2709 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2710 * @return BOOL indicating success or failure
2711 ***************************************************************************/
2713 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2715 REGVAL_CTR *ctr = NULL;
2716 fstring longname;
2717 fstring dnssuffix;
2718 char *allocated_string = NULL;
2719 const char *ascii_str;
2720 int i;
2722 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2723 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2724 ctr = &info2->data.keys[i].values;
2726 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2727 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2729 /* we make the assumption that the netbios name is the same
2730 as the DNS name sinc ethe former will be what we used to
2731 join the domain */
2733 if ( get_mydnsdomname( dnssuffix ) )
2734 fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
2735 else
2736 fstrcpy( longname, global_myname() );
2738 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2740 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2741 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2742 SAFE_FREE(allocated_string);
2744 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2745 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2746 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2747 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2748 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2749 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2750 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2751 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2752 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2754 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2755 (info2->attributes &
2756 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2758 switch (info2->attributes & 0x3) {
2759 case 0:
2760 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2761 break;
2762 case 1:
2763 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2764 break;
2765 case 2:
2766 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2767 break;
2768 default:
2769 ascii_str = "unknown";
2771 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2773 return True;
2776 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
2777 struct uuid guid)
2779 int i;
2780 REGVAL_CTR *ctr=NULL;
2782 /* find the DsSpooler key */
2783 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2784 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2785 ctr = &info2->data.keys[i].values;
2787 regval_ctr_delvalue(ctr, "objectGUID");
2788 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2789 (char *) &guid, sizeof(struct uuid));
2792 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
2793 NT_PRINTER_INFO_LEVEL *printer)
2795 ADS_STATUS ads_rc;
2796 void *res;
2797 char *prt_dn = NULL, *srv_dn, *srv_cn_0;
2798 char *srv_dn_utf8, **srv_cn_utf8;
2799 TALLOC_CTX *ctx;
2800 ADS_MODLIST mods;
2801 const char *attrs[] = {"objectGUID", NULL};
2802 struct uuid guid;
2803 WERROR win_rc = WERR_OK;
2805 DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
2807 /* figure out where to publish */
2808 ads_find_machine_acct(ads, &res, global_myname());
2810 /* We use ldap_get_dn here as we need the answer
2811 * in utf8 to call ldap_explode_dn(). JRA. */
2813 srv_dn_utf8 = ldap_get_dn(ads->ld, res);
2814 if (!srv_dn_utf8) {
2815 ads_destroy(&ads);
2816 return WERR_SERVER_UNAVAILABLE;
2818 ads_msgfree(ads, res);
2819 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
2820 if (!srv_cn_utf8) {
2821 ldap_memfree(srv_dn_utf8);
2822 ads_destroy(&ads);
2823 return WERR_SERVER_UNAVAILABLE;
2825 /* Now convert to CH_UNIX. */
2826 if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
2827 ldap_memfree(srv_dn_utf8);
2828 ldap_memfree(srv_cn_utf8);
2829 ads_destroy(&ads);
2830 return WERR_SERVER_UNAVAILABLE;
2832 if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
2833 ldap_memfree(srv_dn_utf8);
2834 ldap_memfree(srv_cn_utf8);
2835 ads_destroy(&ads);
2836 SAFE_FREE(srv_dn);
2837 return WERR_SERVER_UNAVAILABLE;
2840 ldap_memfree(srv_dn_utf8);
2841 ldap_memfree(srv_cn_utf8);
2843 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0,
2844 printer->info_2->sharename, srv_dn);
2846 SAFE_FREE(srv_dn);
2847 SAFE_FREE(srv_cn_0);
2849 /* build the ads mods */
2850 ctx = talloc_init("nt_printer_publish_ads");
2851 mods = ads_init_mods(ctx);
2853 get_local_printer_publishing_data(ctx, &mods,
2854 &printer->info_2->data);
2855 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
2856 printer->info_2->sharename);
2858 /* publish it */
2859 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
2860 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
2861 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
2863 if (!ADS_ERR_OK(ads_rc))
2864 DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
2866 talloc_destroy(ctx);
2868 /* retreive the guid and store it locally */
2869 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
2870 ZERO_STRUCT(guid);
2871 ads_pull_guid(ads, res, &guid);
2872 ads_msgfree(ads, res);
2873 store_printer_guid(printer->info_2, guid);
2874 win_rc = mod_a_printer(printer, 2);
2877 SAFE_FREE(prt_dn);
2878 return win_rc;
2881 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
2882 NT_PRINTER_INFO_LEVEL *printer)
2884 ADS_STATUS ads_rc;
2885 void *res;
2886 char *prt_dn = NULL;
2888 DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
2890 /* remove the printer from the directory */
2891 ads_rc = ads_find_printer_on_server(ads, &res,
2892 printer->info_2->sharename, global_myname());
2894 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
2895 prt_dn = ads_get_dn(ads, res);
2896 ads_rc = ads_del_dn(ads, prt_dn);
2897 ads_memfree(ads, prt_dn);
2900 ads_msgfree(ads, res);
2901 return WERR_OK;
2904 /****************************************************************************
2905 * Publish a printer in the directory
2907 * @param snum describing printer service
2908 * @return WERROR indicating status of publishing
2909 ***************************************************************************/
2911 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2913 ADS_STATUS ads_rc;
2914 ADS_STRUCT *ads = NULL;
2915 NT_PRINTER_INFO_LEVEL *printer = NULL;
2916 WERROR win_rc;
2918 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2919 if (!W_ERROR_IS_OK(win_rc))
2920 goto done;
2922 switch (action) {
2923 case SPOOL_DS_PUBLISH:
2924 case SPOOL_DS_UPDATE:
2925 /* set the DsSpooler info and attributes */
2926 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
2927 win_rc = WERR_NOMEM;
2928 goto done;
2931 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
2932 break;
2933 case SPOOL_DS_UNPUBLISH:
2934 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
2935 break;
2936 default:
2937 win_rc = WERR_NOT_SUPPORTED;
2938 goto done;
2941 win_rc = mod_a_printer(printer, 2);
2942 if (!W_ERROR_IS_OK(win_rc)) {
2943 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
2944 goto done;
2947 ads = ads_init(NULL, NULL, NULL);
2948 if (!ads) {
2949 DEBUG(3, ("ads_init() failed\n"));
2950 win_rc = WERR_SERVER_UNAVAILABLE;
2951 goto done;
2953 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2954 SAFE_FREE(ads->auth.password);
2955 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2956 NULL, NULL);
2958 /* ads_connect() will find the DC for us */
2959 ads_rc = ads_connect(ads);
2960 if (!ADS_ERR_OK(ads_rc)) {
2961 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2962 win_rc = WERR_ACCESS_DENIED;
2963 goto done;
2966 switch (action) {
2967 case SPOOL_DS_PUBLISH:
2968 case SPOOL_DS_UPDATE:
2969 win_rc = nt_printer_publish_ads(ads, printer);
2970 break;
2971 case SPOOL_DS_UNPUBLISH:
2972 win_rc = nt_printer_unpublish_ads(ads, printer);
2973 break;
2976 done:
2977 free_a_printer(&printer, 2);
2978 ads_destroy(&ads);
2979 return win_rc;
2982 WERROR check_published_printers(void)
2984 ADS_STATUS ads_rc;
2985 ADS_STRUCT *ads = NULL;
2986 int snum;
2987 int n_services = lp_numservices();
2988 NT_PRINTER_INFO_LEVEL *printer = NULL;
2990 ads = ads_init(NULL, NULL, NULL);
2991 if (!ads) {
2992 DEBUG(3, ("ads_init() failed\n"));
2993 return WERR_SERVER_UNAVAILABLE;
2995 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2996 SAFE_FREE(ads->auth.password);
2997 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2998 NULL, NULL);
3000 /* ads_connect() will find the DC for us */
3001 ads_rc = ads_connect(ads);
3002 if (!ADS_ERR_OK(ads_rc)) {
3003 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
3004 ads_destroy(&ads);
3005 return WERR_ACCESS_DENIED;
3008 for (snum = 0; snum < n_services; snum++) {
3009 if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
3010 continue;
3012 if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
3013 lp_servicename(snum))) &&
3014 (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
3015 nt_printer_publish_ads(ads, printer);
3017 free_a_printer(&printer, 2);
3020 ads_destroy(&ads);
3021 return WERR_OK;
3024 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3025 struct uuid *guid)
3027 NT_PRINTER_INFO_LEVEL *printer = NULL;
3028 REGVAL_CTR *ctr;
3029 REGISTRY_VALUE *guid_val;
3030 WERROR win_rc;
3031 int i;
3033 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
3035 if (!W_ERROR_IS_OK(win_rc) ||
3036 !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
3037 ((i = lookup_printerkey(&printer->info_2->data,
3038 SPOOL_DSSPOOLER_KEY)) < 0) ||
3039 !(ctr = &printer->info_2->data.keys[i].values) ||
3040 !(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
3041 free_a_printer(&printer, 2);
3042 return False;
3045 /* fetching printer guids really ought to be a separate function.. */
3046 if (guid && regval_size(guid_val) == sizeof(struct uuid))
3047 memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
3049 free_a_printer(&printer, 2);
3050 return True;
3052 #else
3053 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
3055 return WERR_OK;
3058 WERROR check_published_printers(void)
3060 return WERR_OK;
3063 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3064 struct uuid *guid)
3066 return False;
3068 #endif /* HAVE_ADS */
3070 /****************************************************************************
3071 ***************************************************************************/
3073 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
3075 NT_PRINTER_DATA *data;
3076 int i;
3077 int removed_keys = 0;
3078 int empty_slot;
3080 data = &p2->data;
3081 empty_slot = data->num_keys;
3083 if ( !key )
3084 return WERR_INVALID_PARAM;
3086 /* remove all keys */
3088 if ( !strlen(key) ) {
3089 for ( i=0; i<data->num_keys; i++ ) {
3090 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
3091 data->keys[i].name));
3093 SAFE_FREE( data->keys[i].name );
3094 regval_ctr_destroy( &data->keys[i].values );
3097 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
3098 p2->printername ));
3100 SAFE_FREE( data->keys );
3101 ZERO_STRUCTP( data );
3103 return WERR_OK;
3106 /* remove a specific key (and all subkeys) */
3108 for ( i=0; i<data->num_keys; i++ ) {
3109 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
3110 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
3111 data->keys[i].name));
3113 SAFE_FREE( data->keys[i].name );
3114 regval_ctr_destroy( &data->keys[i].values );
3116 /* mark the slot as empty */
3118 ZERO_STRUCTP( &data->keys[i] );
3122 /* find the first empty slot */
3124 for ( i=0; i<data->num_keys; i++ ) {
3125 if ( !data->keys[i].name ) {
3126 empty_slot = i;
3127 removed_keys++;
3128 break;
3132 if ( i == data->num_keys )
3133 /* nothing was removed */
3134 return WERR_INVALID_PARAM;
3136 /* move everything down */
3138 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
3139 if ( data->keys[i].name ) {
3140 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
3141 ZERO_STRUCTP( &data->keys[i] );
3142 empty_slot++;
3143 removed_keys++;
3147 /* update count */
3149 data->num_keys -= removed_keys;
3151 /* sanity check to see if anything is left */
3153 if ( !data->num_keys ) {
3154 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
3156 SAFE_FREE( data->keys );
3157 ZERO_STRUCTP( data );
3160 return WERR_OK;
3163 /****************************************************************************
3164 ***************************************************************************/
3166 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3168 WERROR result = WERR_OK;
3169 int key_index;
3171 /* we must have names on non-zero length */
3173 if ( !key || !*key|| !value || !*value )
3174 return WERR_INVALID_NAME;
3176 /* find the printer key first */
3178 key_index = lookup_printerkey( &p2->data, key );
3179 if ( key_index == -1 )
3180 return WERR_OK;
3182 /* make sure the value exists so we can return the correct error code */
3184 if ( !regval_ctr_getvalue( &p2->data.keys[key_index].values, value ) )
3185 return WERR_BADFILE;
3187 regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
3189 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
3190 key, value ));
3192 return result;
3195 /****************************************************************************
3196 ***************************************************************************/
3198 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
3199 uint32 type, uint8 *data, int real_len )
3201 WERROR result = WERR_OK;
3202 int key_index;
3204 /* we must have names on non-zero length */
3206 if ( !key || !*key|| !value || !*value )
3207 return WERR_INVALID_NAME;
3209 /* find the printer key first */
3211 key_index = lookup_printerkey( &p2->data, key );
3212 if ( key_index == -1 )
3213 key_index = add_new_printer_key( &p2->data, key );
3215 if ( key_index == -1 )
3216 return WERR_NOMEM;
3218 regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
3219 type, (const char *)data, real_len );
3221 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
3222 key, value, type, real_len ));
3224 return result;
3227 /****************************************************************************
3228 ***************************************************************************/
3230 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3232 int key_index;
3234 if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
3235 return NULL;
3237 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
3238 key, value ));
3240 return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
3243 /****************************************************************************
3244 Unpack a list of registry values frem the TDB
3245 ***************************************************************************/
3247 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
3249 int len = 0;
3250 uint32 type;
3251 pstring string, valuename, keyname;
3252 char *str;
3253 int size;
3254 uint8 *data_p;
3255 REGISTRY_VALUE *regval_p;
3256 int key_index;
3258 /* add the "PrinterDriverData" key first for performance reasons */
3260 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
3262 /* loop and unpack the rest of the registry values */
3264 while ( True ) {
3266 /* check to see if there are any more registry values */
3268 regval_p = NULL;
3269 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
3270 if ( !regval_p )
3271 break;
3273 /* unpack the next regval */
3275 len += tdb_unpack(buf+len, buflen-len, "fdB",
3276 string,
3277 &type,
3278 &size,
3279 &data_p);
3282 * break of the keyname from the value name.
3283 * Valuenames can have embedded '\'s so be careful.
3284 * only support one level of keys. See the
3285 * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
3286 * -- jerry
3289 str = strchr_m( string, '\\');
3291 /* Put in "PrinterDriverData" is no key specified */
3293 if ( !str ) {
3294 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3295 pstrcpy( valuename, string );
3297 else {
3298 *str = '\0';
3299 pstrcpy( keyname, string );
3300 pstrcpy( valuename, str+1 );
3303 /* see if we need a new key */
3305 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3306 key_index = add_new_printer_key( printer_data, keyname );
3308 if ( key_index == -1 ) {
3309 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3310 keyname));
3311 break;
3314 /* add the new value */
3316 regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3318 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3320 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3323 return len;
3326 /****************************************************************************
3327 ***************************************************************************/
3329 static void map_to_os2_driver(fstring drivername)
3331 static BOOL initialised=False;
3332 static fstring last_from,last_to;
3333 char *mapfile = lp_os2_driver_map();
3334 char **lines = NULL;
3335 int numlines = 0;
3336 int i;
3338 if (!strlen(drivername))
3339 return;
3341 if (!*mapfile)
3342 return;
3344 if (!initialised) {
3345 *last_from = *last_to = 0;
3346 initialised = True;
3349 if (strequal(drivername,last_from)) {
3350 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3351 fstrcpy(drivername,last_to);
3352 return;
3355 lines = file_lines_load(mapfile, &numlines);
3356 if (numlines == 0) {
3357 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3358 return;
3361 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3363 for( i = 0; i < numlines; i++) {
3364 char *nt_name = lines[i];
3365 char *os2_name = strchr(nt_name,'=');
3367 if (!os2_name)
3368 continue;
3370 *os2_name++ = 0;
3372 while (isspace(*nt_name))
3373 nt_name++;
3375 if (!*nt_name || strchr("#;",*nt_name))
3376 continue;
3379 int l = strlen(nt_name);
3380 while (l && isspace(nt_name[l-1])) {
3381 nt_name[l-1] = 0;
3382 l--;
3386 while (isspace(*os2_name))
3387 os2_name++;
3390 int l = strlen(os2_name);
3391 while (l && isspace(os2_name[l-1])) {
3392 os2_name[l-1] = 0;
3393 l--;
3397 if (strequal(nt_name,drivername)) {
3398 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3399 fstrcpy(last_from,drivername);
3400 fstrcpy(last_to,os2_name);
3401 fstrcpy(drivername,os2_name);
3402 file_lines_free(lines);
3403 return;
3407 file_lines_free(lines);
3410 /****************************************************************************
3411 Get a default printer info 2 struct.
3412 ****************************************************************************/
3413 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char* sharename)
3415 int snum;
3416 NT_PRINTER_INFO_LEVEL_2 info;
3418 ZERO_STRUCT(info);
3420 snum = lp_servicenumber(sharename);
3422 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername);
3423 slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
3424 servername, sharename);
3425 fstrcpy(info.sharename, sharename);
3426 fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
3428 /* by setting the driver name to an empty string, a local NT admin
3429 can now run the **local** APW to install a local printer driver
3430 for a Samba shared printer in 2.2. Without this, drivers **must** be
3431 installed on the Samba server for NT clients --jerry */
3432 #if 0 /* JERRY --do not uncomment-- */
3433 if (!*info.drivername)
3434 fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3435 #endif
3438 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
3440 pstrcpy(info.comment, "");
3441 fstrcpy(info.printprocessor, "winprint");
3442 fstrcpy(info.datatype, "RAW");
3444 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3446 info.starttime = 0; /* Minutes since 12:00am GMT */
3447 info.untiltime = 0; /* Minutes since 12:00am GMT */
3448 info.priority = 1;
3449 info.default_priority = 1;
3450 info.setuptime = (uint32)time(NULL);
3453 * I changed this as I think it is better to have a generic
3454 * DEVMODE than to crash Win2k explorer.exe --jerry
3455 * See the HP Deskjet 990c Win2k drivers for an example.
3457 * However the default devmode appears to cause problems
3458 * with the HP CLJ 8500 PCL driver. Hence the addition of
3459 * the "default devmode" parameter --jerry 22/01/2002
3462 if (lp_default_devmode(snum)) {
3463 if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
3464 goto fail;
3466 else {
3467 info.devmode = NULL;
3470 /* This will get the current RPC talloc context, but we should be
3471 passing this as a parameter... fixme... JRA ! */
3473 if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
3474 goto fail;
3476 *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
3477 if (! *info_ptr) {
3478 DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
3479 goto fail;
3482 return WERR_OK;
3484 fail:
3485 if (info.devmode)
3486 free_nt_devicemode(&info.devmode);
3487 return WERR_ACCESS_DENIED;
3490 /****************************************************************************
3491 ****************************************************************************/
3492 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *servername, const char *sharename)
3494 pstring key;
3495 NT_PRINTER_INFO_LEVEL_2 info;
3496 int len = 0;
3497 int snum = lp_servicenumber(sharename);
3498 TDB_DATA kbuf, dbuf;
3499 fstring printername;
3500 char adevice[MAXDEVICENAME];
3502 ZERO_STRUCT(info);
3504 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
3506 kbuf.dptr = key;
3507 kbuf.dsize = strlen(key)+1;
3509 dbuf = tdb_fetch(tdb_printers, kbuf);
3510 if (!dbuf.dptr)
3511 return get_a_printer_2_default(info_ptr, servername, sharename);
3513 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3514 &info.attributes,
3515 &info.priority,
3516 &info.default_priority,
3517 &info.starttime,
3518 &info.untiltime,
3519 &info.status,
3520 &info.cjobs,
3521 &info.averageppm,
3522 &info.changeid,
3523 &info.c_setprinter,
3524 &info.setuptime,
3525 info.servername,
3526 info.printername,
3527 info.sharename,
3528 info.portname,
3529 info.drivername,
3530 info.comment,
3531 info.location,
3532 info.sepfile,
3533 info.printprocessor,
3534 info.datatype,
3535 info.parameters);
3537 /* Samba has to have shared raw drivers. */
3538 info.attributes |= PRINTER_ATTRIBUTE_SAMBA;
3539 info.attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
3541 /* Restore the stripped strings. */
3542 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", servername);
3544 if ( lp_force_printername(snum) )
3545 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
3546 else
3547 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info.printername);
3549 fstrcpy(info.printername, printername);
3551 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3554 * Some client drivers freak out if there is a NULL devmode
3555 * (probably the driver is not checking before accessing
3556 * the devmode pointer) --jerry
3558 * See comments in get_a_printer_2_default()
3561 if (lp_default_devmode(snum) && !info.devmode) {
3562 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3563 printername));
3564 info.devmode = construct_nt_devicemode(printername);
3567 slprintf( adevice, sizeof(adevice), "%s", info.printername );
3568 if (info.devmode) {
3569 fstrcpy(info.devmode->devicename, adevice);
3572 len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
3574 /* This will get the current RPC talloc context, but we should be
3575 passing this as a parameter... fixme... JRA ! */
3577 nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
3579 /* Fix for OS/2 drivers. */
3581 if (get_remote_arch() == RA_OS2)
3582 map_to_os2_driver(info.drivername);
3584 SAFE_FREE(dbuf.dptr);
3585 *info_ptr=memdup(&info, sizeof(info));
3587 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3588 sharename, info.printername, info.drivername));
3590 return WERR_OK;
3593 /****************************************************************************
3594 Debugging function, dump at level 6 the struct in the logs.
3595 ****************************************************************************/
3596 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3598 uint32 result;
3599 NT_PRINTER_INFO_LEVEL_2 *info2;
3601 DEBUG(106,("Dumping printer at level [%d]\n", level));
3603 switch (level) {
3604 case 2:
3606 if (printer->info_2 == NULL)
3607 result=5;
3608 else
3610 info2=printer->info_2;
3612 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3613 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3614 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3615 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3616 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3617 DEBUGADD(106,("status:[%d]\n", info2->status));
3618 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3619 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3620 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3621 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3622 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3624 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3625 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3626 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3627 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3628 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3629 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3630 DEBUGADD(106,("location:[%s]\n", info2->location));
3631 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3632 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3633 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3634 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3635 result=0;
3637 break;
3639 default:
3640 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3641 result=1;
3642 break;
3645 return result;
3648 /****************************************************************************
3649 Update the changeid time.
3650 This is SO NASTY as some drivers need this to change, others need it
3651 static. This value will change every second, and I must hope that this
3652 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3653 UTAH ! JRA.
3654 ****************************************************************************/
3656 static uint32 rev_changeid(void)
3658 struct timeval tv;
3660 get_process_uptime(&tv);
3662 #if 1 /* JERRY */
3663 /* Return changeid as msec since spooler restart */
3664 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3665 #else
3667 * This setting seems to work well but is too untested
3668 * to replace the above calculation. Left in for experiementation
3669 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3671 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3672 #endif
3675 /********************************************************************
3676 Send a message to all smbds about the printer that just changed
3677 ********************************************************************/
3679 static BOOL send_printer_mod_msg( char* printername )
3681 int len = strlen(printername);
3683 if (!len)
3684 return False;
3686 DEBUG(10,("send_printer_mod_msg: Sending message about printer change [%s]\n",
3687 printername));
3689 /* spam everyone that we just changed this printer */
3691 message_send_all( conn_tdb_ctx(), MSG_PRINTER_MOD, printername, len+1, False, NULL );
3693 return True;
3697 * The function below are the high level ones.
3698 * only those ones must be called from the spoolss code.
3699 * JFM.
3702 /****************************************************************************
3703 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3704 ****************************************************************************/
3706 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3708 WERROR result;
3710 dump_a_printer(printer, level);
3713 * invalidate cache for all open handles to this printer.
3714 * cache for a given handle will be updated on the next
3715 * get_a_printer()
3718 invalidate_printer_hnd_cache( printer->info_2->sharename );
3719 send_printer_mod_msg( printer->info_2->sharename );
3721 switch (level) {
3722 case 2:
3725 * Update the changestamp. Emperical tests show that the
3726 * ChangeID is always updated,but c_setprinter is
3727 * global spooler variable (not per printer).
3730 /* ChangeID **must** be increasing over the lifetime
3731 of client's spoolss service in order for the
3732 client's cache to show updates */
3734 printer->info_2->changeid = rev_changeid();
3737 * Because one day someone will ask:
3738 * NT->NT An admin connection to a remote
3739 * printer show changes imeediately in
3740 * the properities dialog
3742 * A non-admin connection will only show the
3743 * changes after viewing the properites page
3744 * 2 times. Seems to be related to a
3745 * race condition in the client between the spooler
3746 * updating the local cache and the Explorer.exe GUI
3747 * actually displaying the properties.
3749 * This is fixed in Win2k. admin/non-admin
3750 * connections both display changes immediately.
3752 * 14/12/01 --jerry
3755 result=update_a_printer_2(printer->info_2);
3757 break;
3759 default:
3760 result=WERR_UNKNOWN_LEVEL;
3761 break;
3764 return result;
3767 /****************************************************************************
3768 Initialize printer devmode & data with previously saved driver init values.
3769 ****************************************************************************/
3771 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3773 int len = 0;
3774 pstring key;
3775 TDB_DATA kbuf, dbuf;
3776 NT_PRINTER_INFO_LEVEL_2 info;
3779 ZERO_STRUCT(info);
3782 * Delete any printer data 'values' already set. When called for driver
3783 * replace, there will generally be some, but during an add printer, there
3784 * should not be any (if there are delete them).
3787 delete_all_printer_data( info_ptr, "" );
3789 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3791 kbuf.dptr = key;
3792 kbuf.dsize = strlen(key)+1;
3794 dbuf = tdb_fetch(tdb_drivers, kbuf);
3795 if (!dbuf.dptr) {
3797 * When changing to a driver that has no init info in the tdb, remove
3798 * the previous drivers init info and leave the new on blank.
3800 free_nt_devicemode(&info_ptr->devmode);
3801 return False;
3805 * Get the saved DEVMODE..
3808 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3811 * The saved DEVMODE contains the devicename from the printer used during
3812 * the initialization save. Change it to reflect the new printer.
3815 if ( info.devmode ) {
3816 ZERO_STRUCT(info.devmode->devicename);
3817 fstrcpy(info.devmode->devicename, info_ptr->printername);
3821 * NT/2k does not change out the entire DeviceMode of a printer
3822 * when changing the driver. Only the driverextra, private, &
3823 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3825 * Later examination revealed that Windows NT/2k does reset the
3826 * the printer's device mode, bit **only** when you change a
3827 * property of the device mode such as the page orientation.
3828 * --jerry
3832 /* Bind the saved DEVMODE to the new the printer */
3834 free_nt_devicemode(&info_ptr->devmode);
3835 info_ptr->devmode = info.devmode;
3837 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3838 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3840 /* Add the printer data 'values' to the new printer */
3842 len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3845 SAFE_FREE(dbuf.dptr);
3847 return True;
3850 /****************************************************************************
3851 Initialize printer devmode & data with previously saved driver init values.
3852 When a printer is created using AddPrinter, the drivername bound to the
3853 printer is used to lookup previously saved driver initialization info, which
3854 is bound to the new printer.
3855 ****************************************************************************/
3857 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3859 BOOL result = False;
3861 switch (level) {
3862 case 2:
3863 result = set_driver_init_2(printer->info_2);
3864 break;
3866 default:
3867 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
3868 level));
3869 break;
3872 return result;
3875 /****************************************************************************
3876 Delete driver init data stored for a specified driver
3877 ****************************************************************************/
3879 BOOL del_driver_init(char *drivername)
3881 pstring key;
3882 TDB_DATA kbuf;
3884 if (!drivername || !*drivername) {
3885 DEBUG(3,("del_driver_init: No drivername specified!\n"));
3886 return False;
3889 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
3891 kbuf.dptr = key;
3892 kbuf.dsize = strlen(key)+1;
3894 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
3896 return (tdb_delete(tdb_drivers, kbuf) == 0);
3899 /****************************************************************************
3900 Pack up the DEVMODE and values for a printer into a 'driver init' entry
3901 in the tdb. Note: this is different from the driver entry and the printer
3902 entry. There should be a single driver init entry for each driver regardless
3903 of whether it was installed from NT or 2K. Technically, they should be
3904 different, but they work out to the same struct.
3905 ****************************************************************************/
3907 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
3909 pstring key;
3910 char *buf;
3911 int buflen, len, ret;
3912 TDB_DATA kbuf, dbuf;
3914 buf = NULL;
3915 buflen = 0;
3917 again:
3918 len = 0;
3919 len += pack_devicemode(info->devmode, buf+len, buflen-len);
3921 len += pack_values( &info->data, buf+len, buflen-len );
3923 if (buflen < len) {
3924 char *tb;
3926 tb = (char *)SMB_REALLOC(buf, len);
3927 if (!tb) {
3928 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
3929 ret = -1;
3930 goto done;
3932 else
3933 buf = tb;
3934 buflen = len;
3935 goto again;
3938 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
3940 kbuf.dptr = key;
3941 kbuf.dsize = strlen(key)+1;
3942 dbuf.dptr = buf;
3943 dbuf.dsize = len;
3945 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
3947 done:
3948 if (ret == -1)
3949 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
3951 SAFE_FREE(buf);
3953 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
3954 info->sharename, info->drivername));
3956 return ret;
3959 /****************************************************************************
3960 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
3961 ****************************************************************************/
3963 static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3965 uint32 result;
3967 dump_a_printer(printer, level);
3969 switch (level) {
3970 case 2:
3971 result = update_driver_init_2(printer->info_2);
3972 break;
3973 default:
3974 result = 1;
3975 break;
3978 return result;
3981 /****************************************************************************
3982 Convert the printer data value, a REG_BINARY array, into an initialization
3983 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
3984 got to keep the endians happy :).
3985 ****************************************************************************/
3987 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
3989 BOOL result = False;
3990 prs_struct ps;
3991 DEVICEMODE devmode;
3993 ZERO_STRUCT(devmode);
3995 prs_init(&ps, 0, ctx, UNMARSHALL);
3996 ps.data_p = (char *)data;
3997 ps.buffer_size = data_len;
3999 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
4000 result = convert_devicemode("", &devmode, &nt_devmode);
4001 else
4002 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
4004 return result;
4007 /****************************************************************************
4008 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
4010 1. Use the driver's config DLL to this UNC printername and:
4011 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
4012 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
4013 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
4015 The last step triggers saving the "driver initialization" information for
4016 this printer into the tdb. Later, new printers that use this driver will
4017 have this initialization information bound to them. This simulates the
4018 driver initialization, as if it had run on the Samba server (as it would
4019 have done on NT).
4021 The Win32 client side code requirement sucks! But until we can run arbitrary
4022 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
4024 It would have been easier to use SetPrinter because all the UNMARSHALLING of
4025 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
4026 about it and you will realize why. JRR 010720
4027 ****************************************************************************/
4029 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
4031 WERROR status = WERR_OK;
4032 TALLOC_CTX *ctx = NULL;
4033 NT_DEVICEMODE *nt_devmode = NULL;
4034 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
4037 * When the DEVMODE is already set on the printer, don't try to unpack it.
4039 DEBUG(8,("save_driver_init_2: Enter...\n"));
4041 if ( !printer->info_2->devmode && data_len ) {
4043 * Set devmode on printer info, so entire printer initialization can be
4044 * saved to tdb.
4047 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
4048 return WERR_NOMEM;
4050 if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
4051 status = WERR_NOMEM;
4052 goto done;
4055 ZERO_STRUCTP(nt_devmode);
4058 * The DEVMODE is held in the 'data' component of the param in raw binary.
4059 * Convert it to to a devmode structure
4061 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
4062 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
4063 status = WERR_INVALID_PARAM;
4064 goto done;
4067 printer->info_2->devmode = nt_devmode;
4071 * Pack up and add (or update) the DEVMODE and any current printer data to
4072 * a 'driver init' element in the tdb
4076 if ( update_driver_init(printer, 2) != 0 ) {
4077 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
4078 status = WERR_NOMEM;
4079 goto done;
4083 * If driver initialization info was successfully saved, set the current
4084 * printer to match it. This allows initialization of the current printer
4085 * as well as the driver.
4087 status = mod_a_printer(printer, 2);
4088 if (!W_ERROR_IS_OK(status)) {
4089 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
4090 printer->info_2->printername));
4093 done:
4094 talloc_destroy(ctx);
4095 free_nt_devicemode( &nt_devmode );
4097 printer->info_2->devmode = tmp_devmode;
4099 return status;
4102 /****************************************************************************
4103 Update the driver init info (DEVMODE and specifics) for a printer
4104 ****************************************************************************/
4106 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
4108 WERROR status = WERR_OK;
4110 switch (level) {
4111 case 2:
4112 status = save_driver_init_2( printer, data, data_len );
4113 break;
4114 default:
4115 status = WERR_UNKNOWN_LEVEL;
4116 break;
4119 return status;
4122 /****************************************************************************
4123 Deep copy a NT_PRINTER_DATA
4124 ****************************************************************************/
4126 static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src )
4128 int i, j, num_vals, new_key_index;
4129 REGVAL_CTR *src_key, *dst_key;
4131 if ( !dst || !src )
4132 return NT_STATUS_NO_MEMORY;
4134 for ( i=0; i<src->num_keys; i++ ) {
4136 /* create a new instance of the printerkey in the destination
4137 printer_data object */
4139 new_key_index = add_new_printer_key( dst, src->keys[i].name );
4140 dst_key = &dst->keys[new_key_index].values;
4142 src_key = &src->keys[i].values;
4143 num_vals = regval_ctr_numvals( src_key );
4145 /* dup the printer entire printer key */
4147 for ( j=0; j<num_vals; j++ ) {
4148 regval_ctr_copyvalue( dst_key, regval_ctr_specific_value(src_key, j) );
4152 return NT_STATUS_OK;
4155 /****************************************************************************
4156 Deep copy a NT_PRINTER_INFO_LEVEL_2 structure using malloc()'d memeory
4157 Caller must free.
4158 ****************************************************************************/
4160 NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 *printer )
4162 NT_PRINTER_INFO_LEVEL_2 *copy;
4164 if ( !printer )
4165 return NULL;
4167 if ( !(copy = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL_2)) )
4168 return NULL;
4170 memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
4172 /* malloc()'d members copied here */
4174 copy->devmode = dup_nt_devicemode( printer->devmode );
4176 ZERO_STRUCT( copy->data );
4177 copy_printer_data( &copy->data, &printer->data );
4179 /* this is talloc()'d; very ugly that we have a structure that
4180 is half malloc()'d and half talloc()'d but that is the way
4181 that the PRINTER_INFO stuff is written right now. --jerry */
4183 copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf );
4185 return copy;
4188 /****************************************************************************
4189 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
4191 Previously the code had a memory allocation problem because it always
4192 used the TALLOC_CTX from the Printer_entry*. This context lasts
4193 as a long as the original handle is open. So if the client made a lot
4194 of getprinter[data]() calls, the memory usage would climb. Now we use
4195 a short lived TALLOC_CTX for printer_info_2 objects returned. We
4196 still use the Printer_entry->ctx for maintaining the cache copy though
4197 since that object must live as long as the handle by definition.
4198 --jerry
4200 ****************************************************************************/
4202 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
4203 const char *sharename)
4205 WERROR result;
4206 NT_PRINTER_INFO_LEVEL *printer = NULL;
4207 fstring servername;
4209 *pp_printer = NULL;
4211 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
4213 switch (level) {
4214 case 2:
4215 if ((printer = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL)) == NULL) {
4216 DEBUG(0,("get_a_printer: malloc fail.\n"));
4217 return WERR_NOMEM;
4219 ZERO_STRUCTP(printer);
4221 if ( print_hnd )
4222 fstrcpy( servername, print_hnd->servername );
4223 else {
4224 fstrcpy( servername, "%L" );
4225 standard_sub_basic( "", servername, sizeof(servername)-1 );
4229 * check for cache first. A Printer handle cannot changed
4230 * to another printer object so we only check that the printer
4231 * is actually for a printer and that the printer_info pointer
4232 * is valid
4234 if ( print_hnd
4235 && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)
4236 && print_hnd->printer_info )
4238 /* get_talloc_ctx() works here because we need a short
4239 lived talloc context */
4241 if ( !(printer->info_2 = dup_printer_2(get_talloc_ctx(), print_hnd->printer_info->info_2)) )
4243 DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
4245 SAFE_FREE(printer);
4246 return WERR_NOMEM;
4249 DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n"));
4251 *pp_printer = printer;
4252 result = WERR_OK;
4254 break;
4257 /* no cache for this handle; see if we can match one from another handle.
4258 Make sure to use a short lived talloc ctx */
4260 if ( print_hnd )
4261 result = find_printer_in_print_hnd_cache(get_talloc_ctx(), &printer->info_2, servername, sharename);
4263 /* fail to disk if we don't have it with any open handle */
4265 if ( !print_hnd || !W_ERROR_IS_OK(result) )
4266 result = get_a_printer_2(&printer->info_2, servername, sharename );
4268 /* we have a new printer now. Save it with this handle */
4270 if ( W_ERROR_IS_OK(result) ) {
4271 dump_a_printer(printer, level);
4273 /* save a copy in cache */
4274 if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
4275 if ( !print_hnd->printer_info )
4276 print_hnd->printer_info = SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL);
4278 if ( print_hnd->printer_info ) {
4279 /* make sure to use the handle's talloc ctx here since
4280 the printer_2 object must last until the handle is closed */
4282 print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2);
4284 /* don't fail the lookup just because the cache update failed */
4285 if ( !print_hnd->printer_info->info_2 )
4286 DEBUG(0,("get_a_printer: unable to copy new printer info!\n"));
4289 *pp_printer = printer;
4291 else
4292 SAFE_FREE(printer);
4294 break;
4296 default:
4297 result=WERR_UNKNOWN_LEVEL;
4298 break;
4301 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result)));
4303 return result;
4306 /****************************************************************************
4307 Deletes a NT_PRINTER_INFO_LEVEL struct.
4308 ****************************************************************************/
4310 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
4312 uint32 result;
4313 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
4315 DEBUG(104,("freeing a printer at level [%d]\n", level));
4317 if (printer == NULL)
4318 return 0;
4320 switch (level) {
4321 case 2:
4322 if (printer->info_2 != NULL) {
4323 free_nt_printer_info_level_2(&printer->info_2);
4324 result=0;
4325 } else
4326 result=4;
4327 break;
4329 default:
4330 result=1;
4331 break;
4334 SAFE_FREE(*pp_printer);
4335 return result;
4338 /****************************************************************************
4339 ****************************************************************************/
4340 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4342 uint32 result;
4343 DEBUG(104,("adding a printer at level [%d]\n", level));
4344 dump_a_printer_driver(driver, level);
4346 switch (level) {
4347 case 3:
4348 result=add_a_printer_driver_3(driver.info_3);
4349 break;
4351 case 6:
4352 result=add_a_printer_driver_6(driver.info_6);
4353 break;
4355 default:
4356 result=1;
4357 break;
4360 return result;
4362 /****************************************************************************
4363 ****************************************************************************/
4365 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4366 fstring drivername, const char *architecture, uint32 version)
4368 WERROR result;
4370 switch (level) {
4371 case 3:
4372 /* Sometime we just want any version of the driver */
4374 if ( version == DRIVER_ANY_VERSION ) {
4375 /* look for Win2k first and then for NT4 */
4376 result = get_a_printer_driver_3(&driver->info_3, drivername,
4377 architecture, 3);
4379 if ( !W_ERROR_IS_OK(result) ) {
4380 result = get_a_printer_driver_3( &driver->info_3,
4381 drivername, architecture, 2 );
4383 } else {
4384 result = get_a_printer_driver_3(&driver->info_3, drivername,
4385 architecture, version);
4387 break;
4389 default:
4390 result=W_ERROR(1);
4391 break;
4394 if (W_ERROR_IS_OK(result))
4395 dump_a_printer_driver(*driver, level);
4397 return result;
4400 /****************************************************************************
4401 ****************************************************************************/
4402 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4404 uint32 result;
4406 switch (level) {
4407 case 3:
4409 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4410 if (driver.info_3 != NULL)
4412 info3=driver.info_3;
4413 SAFE_FREE(info3->dependentfiles);
4414 ZERO_STRUCTP(info3);
4415 SAFE_FREE(info3);
4416 result=0;
4417 } else {
4418 result=4;
4420 break;
4422 case 6:
4424 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4425 if (driver.info_6 != NULL) {
4426 info6=driver.info_6;
4427 SAFE_FREE(info6->dependentfiles);
4428 SAFE_FREE(info6->previousnames);
4429 ZERO_STRUCTP(info6);
4430 SAFE_FREE(info6);
4431 result=0;
4432 } else {
4433 result=4;
4435 break;
4437 default:
4438 result=1;
4439 break;
4441 return result;
4445 /****************************************************************************
4446 Determine whether or not a particular driver is currently assigned
4447 to a printer
4448 ****************************************************************************/
4450 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4452 int snum;
4453 int n_services = lp_numservices();
4454 NT_PRINTER_INFO_LEVEL *printer = NULL;
4455 BOOL in_use = False;
4457 if ( !info_3 )
4458 return False;
4460 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4462 /* loop through the printers.tdb and check for the drivername */
4464 for (snum=0; snum<n_services && !in_use; snum++) {
4465 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4466 continue;
4468 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4469 continue;
4471 if ( strequal(info_3->name, printer->info_2->drivername) )
4472 in_use = True;
4474 free_a_printer( &printer, 2 );
4477 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4479 if ( in_use ) {
4480 NT_PRINTER_DRIVER_INFO_LEVEL d;
4481 WERROR werr;
4483 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
4485 /* we can still remove the driver if there is one of
4486 "Windows NT x86" version 2 or 3 left */
4488 if ( !strequal( "Windows NT x86", info_3->environment ) ) {
4489 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );
4491 else {
4492 switch ( info_3->cversion ) {
4493 case 2:
4494 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
4495 break;
4496 case 3:
4497 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
4498 break;
4499 default:
4500 DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n",
4501 info_3->cversion));
4502 werr = WERR_UNKNOWN_PRINTER_DRIVER;
4503 break;
4507 /* now check the error code */
4509 if ( W_ERROR_IS_OK(werr) ) {
4510 /* it's ok to remove the driver, we have other architctures left */
4511 in_use = False;
4512 free_a_printer_driver( d, 3 );
4516 /* report that the driver is not in use by default */
4518 return in_use;
4522 /**********************************************************************
4523 Check to see if a ogiven file is in use by *info
4524 *********************************************************************/
4526 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4528 int i = 0;
4530 if ( !info )
4531 return False;
4533 if ( strequal(file, info->driverpath) )
4534 return True;
4536 if ( strequal(file, info->datafile) )
4537 return True;
4539 if ( strequal(file, info->configfile) )
4540 return True;
4542 if ( strequal(file, info->helpfile) )
4543 return True;
4545 /* see of there are any dependent files to examine */
4547 if ( !info->dependentfiles )
4548 return False;
4550 while ( *info->dependentfiles[i] ) {
4551 if ( strequal(file, info->dependentfiles[i]) )
4552 return True;
4553 i++;
4556 return False;
4560 /**********************************************************************
4561 Utility function to remove the dependent file pointed to by the
4562 input parameter from the list
4563 *********************************************************************/
4565 static void trim_dependent_file( fstring files[], int idx )
4568 /* bump everything down a slot */
4570 while( *files[idx+1] ) {
4571 fstrcpy( files[idx], files[idx+1] );
4572 idx++;
4575 *files[idx] = '\0';
4577 return;
4580 /**********************************************************************
4581 Check if any of the files used by src are also used by drv
4582 *********************************************************************/
4584 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4585 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4587 BOOL in_use = False;
4588 int i = 0;
4590 if ( !src || !drv )
4591 return False;
4593 /* check each file. Remove it from the src structure if it overlaps */
4595 if ( drv_file_in_use(src->driverpath, drv) ) {
4596 in_use = True;
4597 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4598 fstrcpy( src->driverpath, "" );
4601 if ( drv_file_in_use(src->datafile, drv) ) {
4602 in_use = True;
4603 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4604 fstrcpy( src->datafile, "" );
4607 if ( drv_file_in_use(src->configfile, drv) ) {
4608 in_use = True;
4609 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4610 fstrcpy( src->configfile, "" );
4613 if ( drv_file_in_use(src->helpfile, drv) ) {
4614 in_use = True;
4615 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4616 fstrcpy( src->helpfile, "" );
4619 /* are there any dependentfiles to examine? */
4621 if ( !src->dependentfiles )
4622 return in_use;
4624 while ( *src->dependentfiles[i] ) {
4625 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4626 in_use = True;
4627 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4628 trim_dependent_file( src->dependentfiles, i );
4629 } else
4630 i++;
4633 return in_use;
4636 /****************************************************************************
4637 Determine whether or not a particular driver files are currently being
4638 used by any other driver.
4640 Return value is True if any files were in use by other drivers
4641 and False otherwise.
4643 Upon return, *info has been modified to only contain the driver files
4644 which are not in use
4645 ****************************************************************************/
4647 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4649 int i;
4650 int ndrivers;
4651 uint32 version;
4652 fstring *list = NULL;
4653 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4655 if ( !info )
4656 return False;
4658 version = info->cversion;
4660 /* loop over all driver versions */
4662 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4664 /* get the list of drivers */
4666 list = NULL;
4667 ndrivers = get_ntdrivers(&list, info->environment, version);
4669 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4670 ndrivers, info->environment, version));
4672 /* check each driver for overlap in files */
4674 for (i=0; i<ndrivers; i++) {
4675 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4677 ZERO_STRUCT(driver);
4679 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4680 SAFE_FREE(list);
4681 return True;
4684 /* check if d2 uses any files from d1 */
4685 /* only if this is a different driver than the one being deleted */
4687 if ( !strequal(info->name, driver.info_3->name) ) {
4688 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4689 free_a_printer_driver(driver, 3);
4690 SAFE_FREE( list );
4691 return True;
4695 free_a_printer_driver(driver, 3);
4698 SAFE_FREE(list);
4700 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4702 driver.info_3 = info;
4704 if ( DEBUGLEVEL >= 20 )
4705 dump_a_printer_driver( driver, 3 );
4707 return False;
4710 /****************************************************************************
4711 Actually delete the driver files. Make sure that
4712 printer_driver_files_in_use() return False before calling
4713 this.
4714 ****************************************************************************/
4716 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4718 int i = 0;
4719 char *s;
4720 connection_struct *conn;
4721 DATA_BLOB null_pw;
4722 NTSTATUS nt_status;
4723 fstring res_type;
4724 BOOL bad_path;
4725 SMB_STRUCT_STAT st;
4727 if ( !info_3 )
4728 return False;
4730 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4733 * Connect to the print$ share under the same account as the
4734 * user connected to the rpc pipe. Note we must be root to
4735 * do this.
4738 null_pw = data_blob( NULL, 0 );
4739 fstrcpy(res_type, "A:");
4740 become_root();
4741 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4742 unbecome_root();
4744 if ( !conn ) {
4745 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4746 return False;
4749 /* Save who we are - we are temporarily becoming the connection user. */
4751 if ( !become_user(conn, conn->vuid) ) {
4752 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4753 return False;
4756 /* now delete the files; must strip the '\print$' string from
4757 fron of path */
4759 if ( *info_3->driverpath ) {
4760 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4761 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4762 DEBUG(10,("deleting driverfile [%s]\n", s));
4763 unlink_internals(conn, 0, s);
4767 if ( *info_3->configfile ) {
4768 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4769 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4770 DEBUG(10,("deleting configfile [%s]\n", s));
4771 unlink_internals(conn, 0, s);
4775 if ( *info_3->datafile ) {
4776 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4777 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4778 DEBUG(10,("deleting datafile [%s]\n", s));
4779 unlink_internals(conn, 0, s);
4783 if ( *info_3->helpfile ) {
4784 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4785 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4786 DEBUG(10,("deleting helpfile [%s]\n", s));
4787 unlink_internals(conn, 0, s);
4791 /* check if we are done removing files */
4793 if ( info_3->dependentfiles ) {
4794 while ( *info_3->dependentfiles[i] ) {
4795 char *file;
4797 /* bypass the "\print$" portion of the path */
4799 if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4800 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4801 DEBUG(10,("deleting dependent file [%s]\n", file));
4802 unlink_internals(conn, 0, file );
4805 i++;
4809 unbecome_user();
4811 return True;
4814 /****************************************************************************
4815 Remove a printer driver from the TDB. This assumes that the the driver was
4816 previously looked up.
4817 ***************************************************************************/
4819 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4820 uint32 version, BOOL delete_files )
4822 pstring key;
4823 const char *arch;
4824 TDB_DATA kbuf, dbuf;
4825 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4827 /* delete the tdb data first */
4829 arch = get_short_archi(info_3->environment);
4830 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4831 arch, version, info_3->name);
4833 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4834 key, delete_files ? "TRUE" : "FALSE" ));
4836 ctr.info_3 = info_3;
4837 dump_a_printer_driver( ctr, 3 );
4839 kbuf.dptr=key;
4840 kbuf.dsize=strlen(key)+1;
4842 /* check if the driver actually exists for this environment */
4844 dbuf = tdb_fetch( tdb_drivers, kbuf );
4845 if ( !dbuf.dptr ) {
4846 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4847 return WERR_UNKNOWN_PRINTER_DRIVER;
4850 SAFE_FREE( dbuf.dptr );
4852 /* ok... the driver exists so the delete should return success */
4854 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4855 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4856 return WERR_ACCESS_DENIED;
4860 * now delete any associated files if delete_files == True
4861 * even if this part failes, we return succes because the
4862 * driver doesn not exist any more
4865 if ( delete_files )
4866 delete_driver_files( info_3, user );
4869 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4871 return WERR_OK;
4874 /****************************************************************************
4875 Store a security desc for a printer.
4876 ****************************************************************************/
4878 WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
4880 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4881 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4882 prs_struct ps;
4883 TALLOC_CTX *mem_ctx = NULL;
4884 fstring key;
4885 WERROR status;
4887 mem_ctx = talloc_init("nt_printing_setsec");
4888 if (mem_ctx == NULL)
4889 return WERR_NOMEM;
4891 /* The old owner and group sids of the security descriptor are not
4892 present when new ACEs are added or removed by changing printer
4893 permissions through NT. If they are NULL in the new security
4894 descriptor then copy them over from the old one. */
4896 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4897 DOM_SID *owner_sid, *group_sid;
4898 SEC_ACL *dacl, *sacl;
4899 SEC_DESC *psd = NULL;
4900 size_t size;
4902 nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
4904 /* Pick out correct owner and group sids */
4906 owner_sid = secdesc_ctr->sec->owner_sid ?
4907 secdesc_ctr->sec->owner_sid :
4908 old_secdesc_ctr->sec->owner_sid;
4910 group_sid = secdesc_ctr->sec->grp_sid ?
4911 secdesc_ctr->sec->grp_sid :
4912 old_secdesc_ctr->sec->grp_sid;
4914 dacl = secdesc_ctr->sec->dacl ?
4915 secdesc_ctr->sec->dacl :
4916 old_secdesc_ctr->sec->dacl;
4918 sacl = secdesc_ctr->sec->sacl ?
4919 secdesc_ctr->sec->sacl :
4920 old_secdesc_ctr->sec->sacl;
4922 /* Make a deep copy of the security descriptor */
4924 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type,
4925 owner_sid, group_sid,
4926 sacl,
4927 dacl,
4928 &size);
4930 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4933 if (!new_secdesc_ctr) {
4934 new_secdesc_ctr = secdesc_ctr;
4937 /* Store the security descriptor in a tdb */
4939 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4940 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4942 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4943 &ps, 1)) {
4944 status = WERR_BADFUNC;
4945 goto out;
4948 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4950 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4951 status = WERR_OK;
4952 } else {
4953 DEBUG(1,("Failed to store secdesc for %s\n", printername));
4954 status = WERR_BADFUNC;
4957 /* Free malloc'ed memory */
4959 out:
4961 prs_mem_free(&ps);
4962 if (mem_ctx)
4963 talloc_destroy(mem_ctx);
4964 return status;
4967 /****************************************************************************
4968 Construct a default security descriptor buffer for a printer.
4969 ****************************************************************************/
4971 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
4973 SEC_ACE ace[5]; /* max number of ace entries */
4974 int i = 0;
4975 SEC_ACCESS sa;
4976 SEC_ACL *psa = NULL;
4977 SEC_DESC_BUF *sdb = NULL;
4978 SEC_DESC *psd = NULL;
4979 DOM_SID adm_sid;
4980 size_t sd_size;
4982 /* Create an ACE where Everyone is allowed to print */
4984 init_sec_access(&sa, PRINTER_ACE_PRINT);
4985 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
4986 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4988 /* Add the domain admins group if we are a DC */
4990 if ( IS_DC ) {
4991 DOM_SID domadmins_sid;
4993 sid_copy(&domadmins_sid, get_global_sam_sid());
4994 sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
4996 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4997 init_sec_ace(&ace[i++], &domadmins_sid,
4998 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
4999 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5000 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5001 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5003 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
5004 sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
5006 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5007 init_sec_ace(&ace[i++], &adm_sid,
5008 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5009 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5010 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5011 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5014 /* add BUILTIN\Administrators as FULL CONTROL */
5016 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5017 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5018 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5019 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5020 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5021 SEC_ACE_TYPE_ACCESS_ALLOWED,
5022 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5024 /* Make the security descriptor owned by the BUILTIN\Administrators */
5026 /* The ACL revision number in rpc_secdesc.h differs from the one
5027 created by NT when setting ACE entries in printer
5028 descriptors. NT4 complains about the property being edited by a
5029 NT5 machine. */
5031 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
5032 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
5033 &global_sid_Builtin_Administrators,
5034 &global_sid_Builtin_Administrators,
5035 NULL, psa, &sd_size);
5038 if (!psd) {
5039 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
5040 return NULL;
5043 sdb = make_sec_desc_buf(ctx, sd_size, psd);
5045 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
5046 (unsigned int)sd_size));
5048 return sdb;
5051 /****************************************************************************
5052 Get a security desc for a printer.
5053 ****************************************************************************/
5055 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
5057 prs_struct ps;
5058 fstring key;
5059 char *temp;
5061 if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
5062 printername = temp + 1;
5065 /* Fetch security descriptor from tdb */
5067 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
5069 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
5070 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
5072 DEBUG(4,("using default secdesc for %s\n", printername));
5074 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
5075 return False;
5078 /* Save default security descriptor for later */
5080 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
5081 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
5083 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
5084 tdb_prs_store(tdb_printers, key, &ps);
5086 prs_mem_free(&ps);
5088 return True;
5091 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
5092 this security descriptor has been created when winbindd was
5093 down. Take ownership of security descriptor. */
5095 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
5096 DOM_SID owner_sid;
5098 /* Change sd owner to workgroup administrator */
5100 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
5101 SEC_DESC_BUF *new_secdesc_ctr = NULL;
5102 SEC_DESC *psd = NULL;
5103 size_t size;
5105 /* Create new sd */
5107 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
5109 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type,
5110 &owner_sid,
5111 (*secdesc_ctr)->sec->grp_sid,
5112 (*secdesc_ctr)->sec->sacl,
5113 (*secdesc_ctr)->sec->dacl,
5114 &size);
5116 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
5118 /* Swap with other one */
5120 *secdesc_ctr = new_secdesc_ctr;
5122 /* Set it */
5124 nt_printing_setsec(printername, *secdesc_ctr);
5128 if (DEBUGLEVEL >= 10) {
5129 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
5130 int i;
5132 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
5133 printername, the_acl->num_aces));
5135 for (i = 0; i < the_acl->num_aces; i++) {
5136 fstring sid_str;
5138 sid_to_string(sid_str, &the_acl->ace[i].trustee);
5140 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
5141 the_acl->ace[i].type, the_acl->ace[i].flags,
5142 the_acl->ace[i].info.mask));
5146 prs_mem_free(&ps);
5147 return True;
5150 /* error code:
5151 0: everything OK
5152 1: level not implemented
5153 2: file doesn't exist
5154 3: can't allocate memory
5155 4: can't free memory
5156 5: non existant struct
5160 A printer and a printer driver are 2 different things.
5161 NT manages them separatelly, Samba does the same.
5162 Why ? Simply because it's easier and it makes sense !
5164 Now explanation: You have 3 printers behind your samba server,
5165 2 of them are the same make and model (laser A and B). But laser B
5166 has an 3000 sheet feeder and laser A doesn't such an option.
5167 Your third printer is an old dot-matrix model for the accounting :-).
5169 If the /usr/local/samba/lib directory (default dir), you will have
5170 5 files to describe all of this.
5172 3 files for the printers (1 by printer):
5173 NTprinter_laser A
5174 NTprinter_laser B
5175 NTprinter_accounting
5176 2 files for the drivers (1 for the laser and 1 for the dot matrix)
5177 NTdriver_printer model X
5178 NTdriver_printer model Y
5180 jfm: I should use this comment for the text file to explain
5181 same thing for the forms BTW.
5182 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
5186 /* Convert generic access rights to printer object specific access rights.
5187 It turns out that NT4 security descriptors use generic access rights and
5188 NT5 the object specific ones. */
5190 void map_printer_permissions(SEC_DESC *sd)
5192 int i;
5194 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
5195 se_map_generic(&sd->dacl->ace[i].info.mask,
5196 &printer_generic_mapping);
5200 /****************************************************************************
5201 Check a user has permissions to perform the given operation. We use the
5202 permission constants defined in include/rpc_spoolss.h to check the various
5203 actions we perform when checking printer access.
5205 PRINTER_ACCESS_ADMINISTER:
5206 print_queue_pause, print_queue_resume, update_printer_sec,
5207 update_printer, spoolss_addprinterex_level_2,
5208 _spoolss_setprinterdata
5210 PRINTER_ACCESS_USE:
5211 print_job_start
5213 JOB_ACCESS_ADMINISTER:
5214 print_job_delete, print_job_pause, print_job_resume,
5215 print_queue_purge
5217 Try access control in the following order (for performance reasons):
5218 1) root ans SE_PRINT_OPERATOR can do anything (easy check)
5219 2) check security descriptor (bit comparisons in memory)
5220 3) "printer admins" (may result in numerous calls to winbind)
5222 ****************************************************************************/
5223 BOOL print_access_check(struct current_user *user, int snum, int access_type)
5225 SEC_DESC_BUF *secdesc = NULL;
5226 uint32 access_granted;
5227 NTSTATUS status;
5228 BOOL result;
5229 const char *pname;
5230 TALLOC_CTX *mem_ctx = NULL;
5231 SE_PRIV se_printop = SE_PRINT_OPERATOR;
5233 /* If user is NULL then use the current_user structure */
5235 if (!user)
5236 user = &current_user;
5238 /* Always allow root or SE_PRINT_OPERATROR to do anything */
5240 if ( user->uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
5241 return True;
5244 /* Get printer name */
5246 pname = PRINTERNAME(snum);
5248 if (!pname || !*pname) {
5249 errno = EACCES;
5250 return False;
5253 /* Get printer security descriptor */
5255 if(!(mem_ctx = talloc_init("print_access_check"))) {
5256 errno = ENOMEM;
5257 return False;
5260 nt_printing_getsec(mem_ctx, pname, &secdesc);
5262 if (access_type == JOB_ACCESS_ADMINISTER) {
5263 SEC_DESC_BUF *parent_secdesc = secdesc;
5265 /* Create a child security descriptor to check permissions
5266 against. This is because print jobs are child objects
5267 objects of a printer. */
5269 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
5271 /* Now this is the bit that really confuses me. The access
5272 type needs to be changed from JOB_ACCESS_ADMINISTER to
5273 PRINTER_ACCESS_ADMINISTER for this to work. Something
5274 to do with the child (job) object becoming like a
5275 printer?? -tpot */
5277 access_type = PRINTER_ACCESS_ADMINISTER;
5280 /* Check access */
5282 map_printer_permissions(secdesc->sec);
5284 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
5285 &access_granted, &status);
5287 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
5289 /* see if we need to try the printer admin list */
5291 if ( access_granted == 0 ) {
5292 if ( user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups) )
5293 return True;
5296 talloc_destroy(mem_ctx);
5298 if (!result)
5299 errno = EACCES;
5301 return result;
5304 /****************************************************************************
5305 Check the time parameters allow a print operation.
5306 *****************************************************************************/
5308 BOOL print_time_access_check(int snum)
5310 NT_PRINTER_INFO_LEVEL *printer = NULL;
5311 BOOL ok = False;
5312 time_t now = time(NULL);
5313 struct tm *t;
5314 uint32 mins;
5316 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
5317 return False;
5319 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
5320 ok = True;
5322 t = gmtime(&now);
5323 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
5325 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
5326 ok = True;
5328 free_a_printer(&printer, 2);
5330 if (!ok)
5331 errno = EACCES;
5333 return ok;
5336 /****************************************************************************
5337 Fill in the servername sent in the _spoolss_open_printer_ex() call
5338 ****************************************************************************/
5339 char* get_server_name( Printer_entry *printer )
5341 return printer->servername;