r20544: Change copy_file() to return NTSTATUS. This is in preparation of turning
[Samba/bb.git] / source3 / printing / nt_printing.c
blob5fa5db54e4bf7b7d5f47a4f2559e6ab2f68eada3
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 extern struct current_user current_user;
27 static TDB_CONTEXT *tdb_forms; /* used for forms files */
28 static TDB_CONTEXT *tdb_drivers; /* used for driver files */
29 static TDB_CONTEXT *tdb_printers; /* used for printers files */
31 #define FORMS_PREFIX "FORMS/"
32 #define DRIVERS_PREFIX "DRIVERS/"
33 #define DRIVER_INIT_PREFIX "DRIVER_INIT/"
34 #define PRINTERS_PREFIX "PRINTERS/"
35 #define SECDESC_PREFIX "SECDESC/"
36 #define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
38 #define NTDRIVERS_DATABASE_VERSION_1 1
39 #define NTDRIVERS_DATABASE_VERSION_2 2
40 #define NTDRIVERS_DATABASE_VERSION_3 3 /* little endian version of v2 */
41 #define NTDRIVERS_DATABASE_VERSION_4 4 /* fix generic bits in security descriptors */
42 #define NTDRIVERS_DATABASE_VERSION_5 5 /* normalize keys in ntprinters.tdb */
44 /* Map generic permissions to printer object specific permissions */
46 GENERIC_MAPPING printer_generic_mapping = {
47 PRINTER_READ,
48 PRINTER_WRITE,
49 PRINTER_EXECUTE,
50 PRINTER_ALL_ACCESS
53 STANDARD_MAPPING printer_std_mapping = {
54 PRINTER_READ,
55 PRINTER_WRITE,
56 PRINTER_EXECUTE,
57 PRINTER_ALL_ACCESS
60 /* Map generic permissions to print server object specific permissions */
62 GENERIC_MAPPING printserver_generic_mapping = {
63 SERVER_READ,
64 SERVER_WRITE,
65 SERVER_EXECUTE,
66 SERVER_ALL_ACCESS
69 STANDARD_MAPPING printserver_std_mapping = {
70 SERVER_READ,
71 SERVER_WRITE,
72 SERVER_EXECUTE,
73 SERVER_ALL_ACCESS
76 /* We need one default form to support our default printer. Msoft adds the
77 forms it wants and in the ORDER it wants them (note: DEVMODE papersize is an
78 array index). Letter is always first, so (for the current code) additions
79 always put things in the correct order. */
80 static const nt_forms_struct default_forms[] = {
81 {"Letter",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
82 {"Letter Small",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
83 {"Tabloid",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
84 {"Ledger",0x1,0x696b8,0x44368,0x0,0x0,0x696b8,0x44368},
85 {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
86 {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
87 {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
88 {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
89 {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
90 {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
91 {"A5",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
92 {"B4 (JIS)",0x1,0x3ebe8,0x58de0,0x0,0x0,0x3ebe8,0x58de0},
93 {"B5 (JIS)",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
94 {"Folio",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
95 {"Quarto",0x1,0x347d8,0x43238,0x0,0x0,0x347d8,0x43238},
96 {"10x14",0x1,0x3e030,0x56d10,0x0,0x0,0x3e030,0x56d10},
97 {"11x17",0x1,0x44368,0x696b8,0x0,0x0,0x44368,0x696b8},
98 {"Note",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
99 {"Envelope #9",0x1,0x18079,0x37091,0x0,0x0,0x18079,0x37091},
100 {"Envelope #10",0x1,0x19947,0x3ae94,0x0,0x0,0x19947,0x3ae94},
101 {"Envelope #11",0x1,0x1be7c,0x40565,0x0,0x0,0x1be7c,0x40565},
102 {"Envelope #12",0x1,0x1d74a,0x44368,0x0,0x0,0x1d74a,0x44368},
103 {"Envelope #14",0x1,0x1f018,0x47504,0x0,0x0,0x1f018,0x47504},
104 {"C size sheet",0x1,0x696b8,0x886d0,0x0,0x0,0x696b8,0x886d0},
105 {"D size sheet",0x1,0x886d0,0xd2d70,0x0,0x0,0x886d0,0xd2d70},
106 {"E size sheet",0x1,0xd2d70,0x110da0,0x0,0x0,0xd2d70,0x110da0},
107 {"Envelope DL",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
108 {"Envelope C5",0x1,0x278d0,0x37e88,0x0,0x0,0x278d0,0x37e88},
109 {"Envelope C3",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
110 {"Envelope C4",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
111 {"Envelope C6",0x1,0x1bd50,0x278d0,0x0,0x0,0x1bd50,0x278d0},
112 {"Envelope C65",0x1,0x1bd50,0x37e88,0x0,0x0,0x1bd50,0x37e88},
113 {"Envelope B4",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
114 {"Envelope B5",0x1,0x2af80,0x3d090,0x0,0x0,0x2af80,0x3d090},
115 {"Envelope B6",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
116 {"Envelope",0x1,0x1adb0,0x38270,0x0,0x0,0x1adb0,0x38270},
117 {"Envelope Monarch",0x1,0x18079,0x2e824,0x0,0x0,0x18079,0x2e824},
118 {"6 3/4 Envelope",0x1,0x167ab,0x284ec,0x0,0x0,0x167ab,0x284ec},
119 {"US Std Fanfold",0x1,0x5c3e1,0x44368,0x0,0x0,0x5c3e1,0x44368},
120 {"German Std Fanfold",0x1,0x34b5c,0x4a6a0,0x0,0x0,0x34b5c,0x4a6a0},
121 {"German Legal Fanfold",0x1,0x34b5c,0x509d8,0x0,0x0,0x34b5c,0x509d8},
122 {"B4 (ISO)",0x1,0x3d090,0x562e8,0x0,0x0,0x3d090,0x562e8},
123 {"Japanese Postcard",0x1,0x186a0,0x24220,0x0,0x0,0x186a0,0x24220},
124 {"9x11",0x1,0x37cf8,0x44368,0x0,0x0,0x37cf8,0x44368},
125 {"10x11",0x1,0x3e030,0x44368,0x0,0x0,0x3e030,0x44368},
126 {"15x11",0x1,0x5d048,0x44368,0x0,0x0,0x5d048,0x44368},
127 {"Envelope Invite",0x1,0x35b60,0x35b60,0x0,0x0,0x35b60,0x35b60},
128 {"Reserved48",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
129 {"Reserved49",0x1,0x1,0x1,0x0,0x0,0x1,0x1},
130 {"Letter Extra",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
131 {"Legal Extra",0x1,0x3ae94,0x5d048,0x0,0x0,0x3ae94,0x5d048},
132 {"Tabloid Extra",0x1,0x4a6a0,0x6f9f0,0x0,0x0,0x4a6a0,0x6f9f0},
133 {"A4 Extra",0x1,0x397c2,0x4eb16,0x0,0x0,0x397c2,0x4eb16},
134 {"Letter Transverse",0x1,0x34b5c,0x44368,0x0,0x0,0x34b5c,0x44368},
135 {"A4 Transverse",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
136 {"Letter Extra Transverse",0x1,0x3ae94,0x4a6a0,0x0,0x0,0x3ae94,0x4a6a0},
137 {"Super A",0x1,0x376b8,0x56ea0,0x0,0x0,0x376b8,0x56ea0},
138 {"Super B",0x1,0x4a768,0x76e58,0x0,0x0,0x4a768,0x76e58},
139 {"Letter Plus",0x1,0x34b5c,0x4eb16,0x0,0x0,0x34b5c,0x4eb16},
140 {"A4 Plus",0x1,0x33450,0x50910,0x0,0x0,0x33450,0x50910},
141 {"A5 Transverse",0x1,0x24220,0x33450,0x0,0x0,0x24220,0x33450},
142 {"B5 (JIS) Transverse",0x1,0x2c6f0,0x3ebe8,0x0,0x0,0x2c6f0,0x3ebe8},
143 {"A3 Extra",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
144 {"A5 Extra",0x1,0x2a7b0,0x395f8,0x0,0x0,0x2a7b0,0x395f8},
145 {"B5 (ISO) Extra",0x1,0x31128,0x43620,0x0,0x0,0x31128,0x43620},
146 {"A2",0x1,0x668a0,0x91050,0x0,0x0,0x668a0,0x91050},
147 {"A3 Transverse",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
148 {"A3 Extra Transverse",0x1,0x4e9d0,0x6ca48,0x0,0x0,0x4e9d0,0x6ca48},
149 {"Japanese Double Postcard",0x1,0x30d40,0x24220,0x0,0x0,0x30d40,0x24220},
150 {"A6",0x1,0x19a28,0x24220,0x0,0x0,0x19a28,0x24220},
151 {"Japanese Envelope Kaku #2",0x1,0x3a980,0x510e0,0x0,0x0,0x3a980,0x510e0},
152 {"Japanese Envelope Kaku #3",0x1,0x34bc0,0x43a08,0x0,0x0,0x34bc0,0x43a08},
153 {"Japanese Envelope Chou #3",0x1,0x1d4c0,0x395f8,0x0,0x0,0x1d4c0,0x395f8},
154 {"Japanese Envelope Chou #4",0x1,0x15f90,0x320c8,0x0,0x0,0x15f90,0x320c8},
155 {"Letter Rotated",0x1,0x44368,0x34b5c,0x0,0x0,0x44368,0x34b5c},
156 {"A3 Rotated",0x1,0x668a0,0x48828,0x0,0x0,0x668a0,0x48828},
157 {"A4 Rotated",0x1,0x48828,0x33450,0x0,0x0,0x48828,0x33450},
158 {"A5 Rotated",0x1,0x33450,0x24220,0x0,0x0,0x33450,0x24220},
159 {"B4 (JIS) Rotated",0x1,0x58de0,0x3ebe8,0x0,0x0,0x58de0,0x3ebe8},
160 {"B5 (JIS) Rotated",0x1,0x3ebe8,0x2c6f0,0x0,0x0,0x3ebe8,0x2c6f0},
161 {"Japanese Postcard Rotated",0x1,0x24220,0x186a0,0x0,0x0,0x24220,0x186a0},
162 {"Double Japan Postcard Rotated",0x1,0x24220,0x30d40,0x0,0x0,0x24220,0x30d40},
163 {"A6 Rotated",0x1,0x24220,0x19a28,0x0,0x0,0x24220,0x19a28},
164 {"Japan Envelope Kaku #2 Rotated",0x1,0x510e0,0x3a980,0x0,0x0,0x510e0,0x3a980},
165 {"Japan Envelope Kaku #3 Rotated",0x1,0x43a08,0x34bc0,0x0,0x0,0x43a08, 0x34bc0},
166 {"Japan Envelope Chou #3 Rotated",0x1,0x395f8,0x1d4c0,0x0,0x0,0x395f8,0x1d4c0},
167 {"Japan Envelope Chou #4 Rotated",0x1,0x320c8,0x15f90,0x0,0x0,0x320c8,0x15f90},
168 {"B6 (JIS)",0x1,0x1f400,0x2c6f0,0x0,0x0,0x1f400,0x2c6f0},
169 {"B6 (JIS) Rotated",0x1,0x2c6f0,0x1f400,0x0,0x0,0x2c6f0,0x1f400},
170 {"12x11",0x1,0x4a724,0x443e1,0x0,0x0,0x4a724,0x443e1},
171 {"Japan Envelope You #4",0x1,0x19a28,0x395f8,0x0,0x0,0x19a28,0x395f8},
172 {"Japan Envelope You #4 Rotated",0x1,0x395f8,0x19a28,0x0,0x0,0x395f8,0x19a28},
173 {"PRC 16K",0x1,0x2de60,0x3f7a0,0x0,0x0,0x2de60,0x3f7a0},
174 {"PRC 32K",0x1,0x1fbd0,0x2cec0,0x0,0x0,0x1fbd0,0x2cec0},
175 {"PRC 32K(Big)",0x1,0x222e0,0x318f8,0x0,0x0,0x222e0,0x318f8},
176 {"PRC Envelope #1",0x1,0x18e70,0x28488,0x0,0x0,0x18e70,0x28488},
177 {"PRC Envelope #2",0x1,0x18e70,0x2af80,0x0,0x0,0x18e70,0x2af80},
178 {"PRC Envelope #3",0x1,0x1e848,0x2af80,0x0,0x0,0x1e848,0x2af80},
179 {"PRC Envelope #4",0x1,0x1adb0,0x32c80,0x0,0x0,0x1adb0,0x32c80},
180 {"PRC Envelope #5",0x1,0x1adb0,0x35b60,0x0,0x0,0x1adb0,0x35b60},
181 {"PRC Envelope #6",0x1,0x1d4c0,0x38270,0x0,0x0,0x1d4c0,0x38270},
182 {"PRC Envelope #7",0x1,0x27100,0x38270,0x0,0x0,0x27100,0x38270},
183 {"PRC Envelope #8",0x1,0x1d4c0,0x4b708,0x0,0x0,0x1d4c0,0x4b708},
184 {"PRC Envelope #9",0x1,0x37e88,0x4f1a0,0x0,0x0,0x37e88,0x4f1a0},
185 {"PRC Envelope #10",0x1,0x4f1a0,0x6fd10,0x0,0x0,0x4f1a0,0x6fd10},
186 {"PRC 16K Rotated",0x1,0x3f7a0,0x2de60,0x0,0x0,0x3f7a0,0x2de60},
187 {"PRC 32K Rotated",0x1,0x2cec0,0x1fbd0,0x0,0x0,0x2cec0,0x1fbd0},
188 {"PRC 32K(Big) Rotated",0x1,0x318f8,0x222e0,0x0,0x0,0x318f8,0x222e0},
189 {"PRC Envelope #1 Rotated",0x1,0x28488,0x18e70,0x0,0x0,0x28488,0x18e70},
190 {"PRC Envelope #2 Rotated",0x1,0x2af80,0x18e70,0x0,0x0,0x2af80,0x18e70},
191 {"PRC Envelope #3 Rotated",0x1,0x2af80,0x1e848,0x0,0x0,0x2af80,0x1e848},
192 {"PRC Envelope #4 Rotated",0x1,0x32c80,0x1adb0,0x0,0x0,0x32c80,0x1adb0},
193 {"PRC Envelope #5 Rotated",0x1,0x35b60,0x1adb0,0x0,0x0,0x35b60,0x1adb0},
194 {"PRC Envelope #6 Rotated",0x1,0x38270,0x1d4c0,0x0,0x0,0x38270,0x1d4c0},
195 {"PRC Envelope #7 Rotated",0x1,0x38270,0x27100,0x0,0x0,0x38270,0x27100},
196 {"PRC Envelope #8 Rotated",0x1,0x4b708,0x1d4c0,0x0,0x0,0x4b708,0x1d4c0},
197 {"PRC Envelope #9 Rotated",0x1,0x4f1a0,0x37e88,0x0,0x0,0x4f1a0,0x37e88},
198 {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
201 struct table_node {
202 const char *long_archi;
203 const char *short_archi;
204 int version;
207 #define SPL_ARCH_WIN40 "WIN40"
208 #define SPL_ARCH_W32X86 "W32X86"
209 #define SPL_ARCH_W32MIPS "W32MIPS"
210 #define SPL_ARCH_W32ALPHA "W32ALPHA"
211 #define SPL_ARCH_W32PPC "W32PPC"
212 #define SPL_ARCH_IA64 "IA64"
213 #define SPL_ARCH_X64 "x64"
215 static const struct table_node archi_table[]= {
217 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
218 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
219 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
220 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
221 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
222 {"Windows IA64", SPL_ARCH_IA64, 3 },
223 {"Windows x64", SPL_ARCH_X64, 3 },
224 {NULL, "", -1 }
228 /****************************************************************************
229 generate a new TDB_DATA key for storing a printer
230 ****************************************************************************/
232 static TDB_DATA make_printer_tdbkey( const char *sharename )
234 fstring share;
235 static pstring keystr;
236 TDB_DATA key;
238 fstrcpy( share, sharename );
239 strlower_m( share );
241 pstr_sprintf( keystr, "%s%s", PRINTERS_PREFIX, share );
243 key.dptr = keystr;
244 key.dsize = strlen(keystr)+1;
246 return key;
249 /****************************************************************************
250 generate a new TDB_DATA key for storing a printer security descriptor
251 ****************************************************************************/
253 static char *make_printers_secdesc_tdbkey( const char* sharename )
255 fstring share;
256 static pstring keystr;
258 fstrcpy( share, sharename );
259 strlower_m( share );
261 pstr_sprintf( keystr, "%s%s", SECDESC_PREFIX, share );
263 return keystr;
266 /****************************************************************************
267 ****************************************************************************/
269 static BOOL upgrade_to_version_3(void)
271 TDB_DATA kbuf, newkey, dbuf;
273 DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
275 for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
276 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
278 dbuf = tdb_fetch(tdb_drivers, kbuf);
280 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
281 DEBUG(0,("upgrade_to_version_3:moving form\n"));
282 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
283 SAFE_FREE(dbuf.dptr);
284 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
285 return False;
287 if (tdb_delete(tdb_drivers, kbuf) != 0) {
288 SAFE_FREE(dbuf.dptr);
289 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
290 return False;
294 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
295 DEBUG(0,("upgrade_to_version_3:moving printer\n"));
296 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
297 SAFE_FREE(dbuf.dptr);
298 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
299 return False;
301 if (tdb_delete(tdb_drivers, kbuf) != 0) {
302 SAFE_FREE(dbuf.dptr);
303 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
304 return False;
308 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
309 DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
310 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
311 SAFE_FREE(dbuf.dptr);
312 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
313 return False;
315 if (tdb_delete(tdb_drivers, kbuf) != 0) {
316 SAFE_FREE(dbuf.dptr);
317 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
318 return False;
322 SAFE_FREE(dbuf.dptr);
325 return True;
328 /*******************************************************************
329 Fix an issue with security descriptors. Printer sec_desc must
330 use more than the generic bits that were previously used
331 in <= 3.0.14a. They must also have a owner and group SID assigned.
332 Otherwise, any printers than have been migrated to a Windows
333 host using printmig.exe will not be accessible.
334 *******************************************************************/
336 static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
337 TDB_DATA data, void *state )
339 prs_struct ps;
340 SEC_DESC_BUF *sd_orig = NULL;
341 SEC_DESC_BUF *sd_new, *sd_store;
342 SEC_DESC *sec, *new_sec;
343 TALLOC_CTX *ctx = state;
344 int result, i;
345 uint32 sd_size;
346 size_t size_new_sec;
347 DOM_SID sid;
349 if (!data.dptr || data.dsize == 0) {
350 return 0;
353 if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) != 0 ) {
354 return 0;
357 /* upgrade the security descriptor */
359 ZERO_STRUCT( ps );
361 prs_init( &ps, 0, ctx, UNMARSHALL );
362 prs_give_memory( &ps, data.dptr, data.dsize, False );
364 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_orig, &ps, 1 ) ) {
365 /* delete bad entries */
366 DEBUG(0,("sec_desc_upg_fn: Failed to parse original sec_desc for %si. Deleting....\n", key.dptr ));
367 tdb_delete( tdb_printers, key );
368 prs_mem_free( &ps );
369 return 0;
372 if (!sd_orig) {
373 prs_mem_free( &ps );
374 return 0;
376 sec = sd_orig->sd;
378 /* is this even valid? */
380 if ( !sec->dacl ) {
381 prs_mem_free( &ps );
382 return 0;
385 /* update access masks */
387 for ( i=0; i<sec->dacl->num_aces; i++ ) {
388 switch ( sec->dacl->aces[i].access_mask ) {
389 case (GENERIC_READ_ACCESS | GENERIC_WRITE_ACCESS | GENERIC_EXECUTE_ACCESS):
390 sec->dacl->aces[i].access_mask = PRINTER_ACE_PRINT;
391 break;
393 case GENERIC_ALL_ACCESS:
394 sec->dacl->aces[i].access_mask = PRINTER_ACE_FULL_CONTROL;
395 break;
397 case READ_CONTROL_ACCESS:
398 sec->dacl->aces[i].access_mask = PRINTER_ACE_MANAGE_DOCUMENTS;
400 default: /* no change */
401 break;
405 /* create a new SEC_DESC with the appropriate owner and group SIDs */
407 string_to_sid(&sid, "S-1-5-32-544" );
408 new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
409 &sid, &sid,
410 NULL, NULL, &size_new_sec );
411 if (!new_sec) {
412 prs_mem_free( &ps );
413 return 0;
415 sd_new = make_sec_desc_buf( ctx, size_new_sec, new_sec );
416 if (!sd_new) {
417 prs_mem_free( &ps );
418 return 0;
421 if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
422 DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
423 prs_mem_free( &ps );
424 return 0;
427 prs_mem_free( &ps );
429 /* store it back */
431 sd_size = sec_desc_size(sd_store->sd) + sizeof(SEC_DESC_BUF);
432 prs_init(&ps, sd_size, ctx, MARSHALL);
434 if ( !sec_io_desc_buf( "sec_desc_upg_fn", &sd_store, &ps, 1 ) ) {
435 DEBUG(0,("sec_desc_upg_fn: Failed to parse new sec_desc for %s\n", key.dptr ));
436 prs_mem_free( &ps );
437 return 0;
440 data.dptr = prs_data_p( &ps );
441 data.dsize = sd_size;
443 result = tdb_store( tdb_printers, key, data, TDB_REPLACE );
445 prs_mem_free( &ps );
447 /* 0 to continue and non-zero to stop traversal */
449 return (result == -1);
452 /*******************************************************************
453 *******************************************************************/
455 static BOOL upgrade_to_version_4(void)
457 TALLOC_CTX *ctx;
458 int result;
460 DEBUG(0,("upgrade_to_version_4: upgrading printer security descriptors\n"));
462 if ( !(ctx = talloc_init( "upgrade_to_version_4" )) )
463 return False;
465 result = tdb_traverse( tdb_printers, sec_desc_upg_fn, ctx );
467 talloc_destroy( ctx );
469 return ( result != -1 );
472 /*******************************************************************
473 Fix an issue with security descriptors. Printer sec_desc must
474 use more than the generic bits that were previously used
475 in <= 3.0.14a. They must also have a owner and group SID assigned.
476 Otherwise, any printers than have been migrated to a Windows
477 host using printmig.exe will not be accessible.
478 *******************************************************************/
480 static int normalize_printers_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
481 TDB_DATA data, void *state )
483 TDB_DATA new_key;
485 if (!data.dptr || data.dsize == 0)
486 return 0;
488 /* upgrade printer records and security descriptors */
490 if ( strncmp( key.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX) ) == 0 ) {
491 new_key = make_printer_tdbkey( key.dptr+strlen(PRINTERS_PREFIX) );
493 else if ( strncmp( key.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX) ) == 0 ) {
494 new_key.dptr = make_printers_secdesc_tdbkey( key.dptr+strlen(SECDESC_PREFIX) );
495 new_key.dsize = strlen( new_key.dptr ) + 1;
497 else {
498 /* ignore this record */
499 return 0;
502 /* delete the original record and store under the normalized key */
504 if ( tdb_delete( the_tdb, key ) != 0 ) {
505 DEBUG(0,("normalize_printers_fn: tdb_delete for [%s] failed!\n",
506 key.dptr));
507 return 1;
510 if ( tdb_store( the_tdb, new_key, data, TDB_REPLACE) != 0 ) {
511 DEBUG(0,("normalize_printers_fn: failed to store new record for [%s]!\n",
512 key.dptr));
513 return 1;
516 return 0;
519 /*******************************************************************
520 *******************************************************************/
522 static BOOL upgrade_to_version_5(void)
524 TALLOC_CTX *ctx;
525 int result;
527 DEBUG(0,("upgrade_to_version_5: normalizing printer keys\n"));
529 if ( !(ctx = talloc_init( "upgrade_to_version_5" )) )
530 return False;
532 result = tdb_traverse( tdb_printers, normalize_printers_fn, NULL );
534 talloc_destroy( ctx );
536 return ( result != -1 );
539 /****************************************************************************
540 Open the NT printing tdbs. Done once before fork().
541 ****************************************************************************/
543 BOOL nt_printing_init(void)
545 const char *vstring = "INFO/version";
546 WERROR win_rc;
547 int32 vers_id;
549 if ( tdb_drivers && tdb_printers && tdb_forms )
550 return True;
552 if (tdb_drivers)
553 tdb_close(tdb_drivers);
554 tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
555 if (!tdb_drivers) {
556 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
557 lock_path("ntdrivers.tdb"), strerror(errno) ));
558 return False;
561 if (tdb_printers)
562 tdb_close(tdb_printers);
563 tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
564 if (!tdb_printers) {
565 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
566 lock_path("ntprinters.tdb"), strerror(errno) ));
567 return False;
570 if (tdb_forms)
571 tdb_close(tdb_forms);
572 tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
573 if (!tdb_forms) {
574 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
575 lock_path("ntforms.tdb"), strerror(errno) ));
576 return False;
579 /* handle a Samba upgrade */
581 vers_id = tdb_fetch_int32(tdb_drivers, vstring);
582 if (vers_id == -1) {
583 DEBUG(10, ("Fresh database\n"));
584 tdb_store_int32( tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5 );
585 vers_id = NTDRIVERS_DATABASE_VERSION_5;
588 if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
590 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
591 if (!upgrade_to_version_3())
592 return False;
593 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
594 vers_id = NTDRIVERS_DATABASE_VERSION_3;
597 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
598 /* Written on a bigendian machine with old fetch_int code. Save as le. */
599 /* The only upgrade between V2 and V3 is to save the version in little-endian. */
600 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_3);
601 vers_id = NTDRIVERS_DATABASE_VERSION_3;
604 if (vers_id == NTDRIVERS_DATABASE_VERSION_3 ) {
605 if ( !upgrade_to_version_4() )
606 return False;
607 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_4);
608 vers_id = NTDRIVERS_DATABASE_VERSION_4;
611 if (vers_id == NTDRIVERS_DATABASE_VERSION_4 ) {
612 if ( !upgrade_to_version_5() )
613 return False;
614 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION_5);
615 vers_id = NTDRIVERS_DATABASE_VERSION_5;
619 if ( vers_id != NTDRIVERS_DATABASE_VERSION_5 ) {
620 DEBUG(0,("nt_printing_init: Unknown printer database version [%d]\n", vers_id));
621 return False;
625 update_c_setprinter(True);
628 * register callback to handle updating printers as new
629 * drivers are installed
632 message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
635 * register callback to handle updating printer data
636 * when a driver is initialized
639 message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
641 /* of course, none of the message callbacks matter if you don't
642 tell messages.c that you interested in receiving PRINT_GENERAL
643 msgs. This is done in claim_connection() */
646 if ( lp_security() == SEC_ADS ) {
647 win_rc = check_published_printers();
648 if (!W_ERROR_IS_OK(win_rc))
649 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", dos_errstr(win_rc)));
652 return True;
655 /*******************************************************************
656 Function to allow filename parsing "the old way".
657 ********************************************************************/
659 static BOOL driver_unix_convert(char *name,connection_struct *conn,
660 char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst)
662 unix_format(name);
663 unix_clean_name(name);
664 trim_string(name,"/","/");
665 return unix_convert(name, conn, saved_last_component, bad_path, pst);
668 /*******************************************************************
669 tdb traversal function for counting printers.
670 ********************************************************************/
672 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
673 TDB_DATA data, void *context)
675 int *printer_count = (int*)context;
677 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
678 (*printer_count)++;
679 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
682 return 0;
685 /*******************************************************************
686 Update the spooler global c_setprinter. This variable is initialized
687 when the parent smbd starts with the number of existing printers. It
688 is monotonically increased by the current number of printers *after*
689 each add or delete printer RPC. Only Microsoft knows why... JRR020119
690 ********************************************************************/
692 uint32 update_c_setprinter(BOOL initialize)
694 int32 c_setprinter;
695 int32 printer_count = 0;
697 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
699 /* Traverse the tdb, counting the printers */
700 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
702 /* If initializing, set c_setprinter to current printers count
703 * otherwise, bump it by the current printer count
705 if (!initialize)
706 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
707 else
708 c_setprinter = printer_count;
710 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
711 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
713 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
715 return (uint32)c_setprinter;
718 /*******************************************************************
719 Get the spooler global c_setprinter, accounting for initialization.
720 ********************************************************************/
722 uint32 get_c_setprinter(void)
724 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
726 if (c_setprinter == (int32)-1)
727 c_setprinter = update_c_setprinter(True);
729 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
731 return (uint32)c_setprinter;
734 /****************************************************************************
735 Get builtin form struct list.
736 ****************************************************************************/
738 int get_builtin_ntforms(nt_forms_struct **list)
740 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
741 if (!*list) {
742 return 0;
744 return sizeof(default_forms) / sizeof(default_forms[0]);
747 /****************************************************************************
748 get a builtin form struct
749 ****************************************************************************/
751 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
753 int i,count;
754 fstring form_name;
755 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
756 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
757 count = sizeof(default_forms) / sizeof(default_forms[0]);
758 for (i=0;i<count;i++) {
759 if (strequal(form_name,default_forms[i].name)) {
760 DEBUGADD(6,("Found builtin form %s \n", form_name));
761 memcpy(form,&default_forms[i],sizeof(*form));
762 break;
766 return (i !=count);
769 /****************************************************************************
770 get a form struct list.
771 ****************************************************************************/
773 int get_ntforms(nt_forms_struct **list)
775 TDB_DATA kbuf, newkey, dbuf;
776 nt_forms_struct form;
777 int ret;
778 int i;
779 int n = 0;
781 *list = NULL;
783 for (kbuf = tdb_firstkey(tdb_forms);
784 kbuf.dptr;
785 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
787 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
788 continue;
790 dbuf = tdb_fetch(tdb_forms, kbuf);
791 if (!dbuf.dptr)
792 continue;
794 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
795 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
796 &i, &form.flag, &form.width, &form.length, &form.left,
797 &form.top, &form.right, &form.bottom);
798 SAFE_FREE(dbuf.dptr);
799 if (ret != dbuf.dsize)
800 continue;
802 *list = SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1);
803 if (!*list) {
804 DEBUG(0,("get_ntforms: Realloc fail.\n"));
805 return 0;
807 (*list)[n] = form;
808 n++;
812 return n;
815 /****************************************************************************
816 write a form struct list
817 ****************************************************************************/
818 int write_ntforms(nt_forms_struct **list, int number)
820 pstring buf, key;
821 int len;
822 TDB_DATA kbuf,dbuf;
823 int i;
825 for (i=0;i<number;i++) {
826 /* save index, so list is rebuilt in correct order */
827 len = tdb_pack(buf, sizeof(buf), "dddddddd",
828 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
829 (*list)[i].left, (*list)[i].top, (*list)[i].right,
830 (*list)[i].bottom);
831 if (len > sizeof(buf)) break;
832 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
833 kbuf.dsize = strlen(key)+1;
834 kbuf.dptr = key;
835 dbuf.dsize = len;
836 dbuf.dptr = buf;
837 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
840 return i;
843 /****************************************************************************
844 add a form struct at the end of the list
845 ****************************************************************************/
846 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
848 int n=0;
849 BOOL update;
850 fstring form_name;
853 * NT tries to add forms even when
854 * they are already in the base
855 * only update the values if already present
858 update=False;
860 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
861 for (n=0; n<*count; n++) {
862 if ( strequal((*list)[n].name, form_name) ) {
863 update=True;
864 break;
868 if (update==False) {
869 if((*list=SMB_REALLOC_ARRAY(*list, nt_forms_struct, n+1)) == NULL) {
870 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
871 return False;
873 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
874 (*count)++;
877 (*list)[n].flag=form->flags;
878 (*list)[n].width=form->size_x;
879 (*list)[n].length=form->size_y;
880 (*list)[n].left=form->left;
881 (*list)[n].top=form->top;
882 (*list)[n].right=form->right;
883 (*list)[n].bottom=form->bottom;
885 DEBUG(6,("add_a_form: Successfully %s form [%s]\n",
886 update ? "updated" : "added", form_name));
888 return True;
891 /****************************************************************************
892 Delete a named form struct.
893 ****************************************************************************/
895 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
897 pstring key;
898 TDB_DATA kbuf;
899 int n=0;
900 fstring form_name;
902 *ret = WERR_OK;
904 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
906 for (n=0; n<*count; n++) {
907 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
908 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
909 break;
913 if (n == *count) {
914 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
915 *ret = WERR_INVALID_PARAM;
916 return False;
919 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
920 kbuf.dsize = strlen(key)+1;
921 kbuf.dptr = key;
922 if (tdb_delete(tdb_forms, kbuf) != 0) {
923 *ret = WERR_NOMEM;
924 return False;
927 return True;
930 /****************************************************************************
931 Update a form struct.
932 ****************************************************************************/
934 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
936 int n=0;
937 fstring form_name;
938 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
940 DEBUG(106, ("[%s]\n", form_name));
941 for (n=0; n<count; n++) {
942 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
943 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
944 break;
947 if (n==count) return;
949 (*list)[n].flag=form->flags;
950 (*list)[n].width=form->size_x;
951 (*list)[n].length=form->size_y;
952 (*list)[n].left=form->left;
953 (*list)[n].top=form->top;
954 (*list)[n].right=form->right;
955 (*list)[n].bottom=form->bottom;
958 /****************************************************************************
959 Get the nt drivers list.
960 Traverse the database and look-up the matching names.
961 ****************************************************************************/
962 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
964 int total=0;
965 const char *short_archi;
966 pstring key;
967 TDB_DATA kbuf, newkey;
969 short_archi = get_short_archi(architecture);
970 if (!short_archi) {
971 return 0;
974 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
976 for (kbuf = tdb_firstkey(tdb_drivers);
977 kbuf.dptr;
978 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
980 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
981 continue;
983 if((*list = SMB_REALLOC_ARRAY(*list, fstring, total+1)) == NULL) {
984 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
985 return -1;
988 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
989 total++;
992 return(total);
995 /****************************************************************************
996 Function to do the mapping between the long architecture name and
997 the short one.
998 ****************************************************************************/
1000 const char *get_short_archi(const char *long_archi)
1002 int i=-1;
1004 DEBUG(107,("Getting architecture dependant directory\n"));
1005 do {
1006 i++;
1007 } while ( (archi_table[i].long_archi!=NULL ) &&
1008 StrCaseCmp(long_archi, archi_table[i].long_archi) );
1010 if (archi_table[i].long_archi==NULL) {
1011 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
1012 return NULL;
1015 /* this might be client code - but shouldn't this be an fstrcpy etc? */
1017 DEBUGADD(108,("index: [%d]\n", i));
1018 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
1019 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
1021 return archi_table[i].short_archi;
1024 /****************************************************************************
1025 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
1026 There are two case to be covered here: PE (Portable Executable) and NE (New
1027 Executable) files. Both files support the same INFO structure, but PE files
1028 store the signature in unicode, and NE files store it as !unicode.
1029 returns -1 on error, 1 on version info found, and 0 on no version info found.
1030 ****************************************************************************/
1032 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
1034 int i;
1035 char *buf = NULL;
1036 ssize_t byte_count;
1038 if ((buf=(char *)SMB_MALLOC(PE_HEADER_SIZE)) == NULL) {
1039 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
1040 fname, PE_HEADER_SIZE));
1041 goto error_exit;
1044 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
1045 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
1046 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
1047 fname, (unsigned long)byte_count));
1048 goto no_version_info;
1051 /* Is this really a DOS header? */
1052 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
1053 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
1054 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
1055 goto no_version_info;
1058 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
1059 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
1060 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
1061 fname, errno));
1062 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1063 goto no_version_info;
1066 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
1067 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
1068 fname, (unsigned long)byte_count));
1069 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1070 goto no_version_info;
1073 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
1074 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
1075 unsigned int num_sections;
1076 unsigned int section_table_bytes;
1078 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
1079 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
1080 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
1081 /* At this point, we assume the file is in error. It still could be somthing
1082 * else besides a PE file, but it unlikely at this point.
1084 goto error_exit;
1087 /* get the section table */
1088 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
1089 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
1090 if (section_table_bytes == 0)
1091 goto error_exit;
1093 SAFE_FREE(buf);
1094 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
1095 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
1096 fname, section_table_bytes));
1097 goto error_exit;
1100 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
1101 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
1102 fname, (unsigned long)byte_count));
1103 goto error_exit;
1106 /* Iterate the section table looking for the resource section ".rsrc" */
1107 for (i = 0; i < num_sections; i++) {
1108 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
1110 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
1111 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
1112 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
1114 if (section_bytes == 0)
1115 goto error_exit;
1117 SAFE_FREE(buf);
1118 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
1119 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
1120 fname, section_bytes));
1121 goto error_exit;
1124 /* Seek to the start of the .rsrc section info */
1125 if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
1126 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
1127 fname, errno));
1128 goto error_exit;
1131 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
1132 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
1133 fname, (unsigned long)byte_count));
1134 goto error_exit;
1137 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
1138 goto error_exit;
1140 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
1141 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
1142 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
1143 /* Align to next long address */
1144 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
1146 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
1147 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
1148 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
1150 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1151 fname, *major, *minor,
1152 (*major>>16)&0xffff, *major&0xffff,
1153 (*minor>>16)&0xffff, *minor&0xffff));
1154 SAFE_FREE(buf);
1155 return 1;
1162 /* Version info not found, fall back to origin date/time */
1163 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
1164 SAFE_FREE(buf);
1165 return 0;
1167 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
1168 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
1169 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
1170 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
1171 /* At this point, we assume the file is in error. It still could be somthing
1172 * else besides a NE file, but it unlikely at this point. */
1173 goto error_exit;
1176 /* Allocate a bit more space to speed up things */
1177 SAFE_FREE(buf);
1178 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
1179 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
1180 fname, PE_HEADER_SIZE));
1181 goto error_exit;
1184 /* This is a HACK! I got tired of trying to sort through the messy
1185 * 'NE' file format. If anyone wants to clean this up please have at
1186 * it, but this works. 'NE' files will eventually fade away. JRR */
1187 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
1188 /* Cover case that should not occur in a well formed 'NE' .dll file */
1189 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
1191 for(i=0; i<byte_count; i++) {
1192 /* Fast skip past data that can't possibly match */
1193 if (buf[i] != 'V') continue;
1195 /* Potential match data crosses buf boundry, move it to beginning
1196 * of buf, and fill the buf with as much as it will hold. */
1197 if (i>byte_count-VS_VERSION_INFO_SIZE) {
1198 int bc;
1200 memcpy(buf, &buf[i], byte_count-i);
1201 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
1202 (byte_count-i))) < 0) {
1204 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
1205 fname, errno));
1206 goto error_exit;
1209 byte_count = bc + (byte_count - i);
1210 if (byte_count<VS_VERSION_INFO_SIZE) break;
1212 i = 0;
1215 /* Check that the full signature string and the magic number that
1216 * follows exist (not a perfect solution, but the chances that this
1217 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
1218 * twice, as it is simpler to read the code. */
1219 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
1220 /* Compute skip alignment to next long address */
1221 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fh->fd, 0, SEEK_CUR) - (byte_count - i) +
1222 sizeof(VS_SIGNATURE)) & 3;
1223 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
1225 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
1226 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
1227 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
1228 fname, *major, *minor,
1229 (*major>>16)&0xffff, *major&0xffff,
1230 (*minor>>16)&0xffff, *minor&0xffff));
1231 SAFE_FREE(buf);
1232 return 1;
1237 /* Version info not found, fall back to origin date/time */
1238 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
1239 SAFE_FREE(buf);
1240 return 0;
1242 } else
1243 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
1244 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
1245 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
1247 no_version_info:
1248 SAFE_FREE(buf);
1249 return 0;
1251 error_exit:
1252 SAFE_FREE(buf);
1253 return -1;
1256 /****************************************************************************
1257 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
1258 share one or more files. During the MS installation process files are checked
1259 to insure that only a newer version of a shared file is installed over an
1260 older version. There are several possibilities for this comparison. If there
1261 is no previous version, the new one is newer (obviously). If either file is
1262 missing the version info structure, compare the creation date (on Unix use
1263 the modification date). Otherwise chose the numerically larger version number.
1264 ****************************************************************************/
1266 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
1268 BOOL use_version = True;
1269 pstring filepath;
1271 uint32 new_major;
1272 uint32 new_minor;
1273 time_t new_create_time;
1275 uint32 old_major;
1276 uint32 old_minor;
1277 time_t old_create_time;
1279 files_struct *fsp = NULL;
1280 SMB_STRUCT_STAT st;
1281 SMB_STRUCT_STAT stat_buf;
1282 BOOL bad_path;
1284 NTSTATUS status;
1286 SET_STAT_INVALID(st);
1287 SET_STAT_INVALID(stat_buf);
1288 new_create_time = (time_t)0;
1289 old_create_time = (time_t)0;
1291 /* Get file version info (if available) for previous file (if it exists) */
1292 pstrcpy(filepath, old_file);
1294 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1296 status = open_file_ntcreate(conn, filepath, &stat_buf,
1297 FILE_GENERIC_READ,
1298 FILE_SHARE_READ|FILE_SHARE_WRITE,
1299 FILE_OPEN,
1301 FILE_ATTRIBUTE_NORMAL,
1302 INTERNAL_OPEN_ONLY,
1303 NULL, &fsp);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 /* Old file not found, so by definition new file is in fact newer */
1307 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
1308 filepath, errno));
1309 return True;
1311 } else {
1312 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
1313 if (ret == -1) {
1314 goto error_exit;
1317 if (!ret) {
1318 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1319 old_file));
1320 use_version = False;
1321 if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
1322 old_create_time = st.st_mtime;
1323 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1326 close_file(fsp, NORMAL_CLOSE);
1328 /* Get file version info (if available) for new file */
1329 pstrcpy(filepath, new_file);
1330 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1332 status = open_file_ntcreate(conn, filepath, &stat_buf,
1333 FILE_GENERIC_READ,
1334 FILE_SHARE_READ|FILE_SHARE_WRITE,
1335 FILE_OPEN,
1337 FILE_ATTRIBUTE_NORMAL,
1338 INTERNAL_OPEN_ONLY,
1339 NULL, &fsp);
1341 if (!NT_STATUS_IS_OK(status)) {
1342 /* New file not found, this shouldn't occur if the caller did its job */
1343 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1344 filepath, errno));
1345 goto error_exit;
1347 } else {
1348 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1349 if (ret == -1) {
1350 goto error_exit;
1353 if (!ret) {
1354 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1355 new_file));
1356 use_version = False;
1357 if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit;
1358 new_create_time = st.st_mtime;
1359 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1362 close_file(fsp, NORMAL_CLOSE);
1364 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1365 /* Compare versions and choose the larger version number */
1366 if (new_major > old_major ||
1367 (new_major == old_major && new_minor > old_minor)) {
1369 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1370 return True;
1372 else {
1373 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1374 return False;
1377 } else {
1378 /* Compare modification time/dates and choose the newest time/date */
1379 if (new_create_time > old_create_time) {
1380 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1381 return True;
1383 else {
1384 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1385 return False;
1389 error_exit:
1390 if(fsp)
1391 close_file(fsp, NORMAL_CLOSE);
1392 return -1;
1395 /****************************************************************************
1396 Determine the correct cVersion associated with an architecture and driver
1397 ****************************************************************************/
1398 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1399 struct current_user *user, WERROR *perr)
1401 int cversion;
1402 NTSTATUS nt_status;
1403 pstring driverpath;
1404 DATA_BLOB null_pw;
1405 fstring res_type;
1406 files_struct *fsp = NULL;
1407 BOOL bad_path;
1408 SMB_STRUCT_STAT st;
1409 connection_struct *conn;
1410 NTSTATUS status;
1412 SET_STAT_INVALID(st);
1414 *perr = WERR_INVALID_PARAM;
1416 /* If architecture is Windows 95/98/ME, the version is always 0. */
1417 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
1418 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1419 *perr = WERR_OK;
1420 return 0;
1423 /* If architecture is Windows x64, the version is always 3. */
1424 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
1425 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
1426 *perr = WERR_OK;
1427 return 3;
1431 * Connect to the print$ share under the same account as the user connected
1432 * to the rpc pipe. Note we must still be root to do this.
1435 /* Null password is ok - we are already an authenticated user... */
1436 null_pw = data_blob(NULL, 0);
1437 fstrcpy(res_type, "A:");
1438 become_root();
1439 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1440 unbecome_root();
1442 if (conn == NULL) {
1443 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1444 *perr = ntstatus_to_werror(nt_status);
1445 return -1;
1448 /* We are temporarily becoming the connection user. */
1449 if (!become_user(conn, user->vuid)) {
1450 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1451 *perr = WERR_ACCESS_DENIED;
1452 return -1;
1455 /* Open the driver file (Portable Executable format) and determine the
1456 * deriver the cversion. */
1457 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1459 driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
1461 if ( !vfs_file_exist( conn, driverpath, &st ) ) {
1462 *perr = WERR_BADFILE;
1463 goto error_exit;
1466 status = open_file_ntcreate(conn, driverpath, &st,
1467 FILE_GENERIC_READ,
1468 FILE_SHARE_READ|FILE_SHARE_WRITE,
1469 FILE_OPEN,
1471 FILE_ATTRIBUTE_NORMAL,
1472 INTERNAL_OPEN_ONLY,
1473 NULL, &fsp);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1477 driverpath, errno));
1478 *perr = WERR_ACCESS_DENIED;
1479 goto error_exit;
1480 } else {
1481 uint32 major;
1482 uint32 minor;
1483 int ret = get_file_version(fsp, driverpath, &major, &minor);
1484 if (ret == -1) goto error_exit;
1486 if (!ret) {
1487 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1488 goto error_exit;
1492 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1493 * for more details. Version in this case is not just the version of the
1494 * file, but the version in the sense of kernal mode (2) vs. user mode
1495 * (3) drivers. Other bits of the version fields are the version info.
1496 * JRR 010716
1498 cversion = major & 0x0000ffff;
1499 switch (cversion) {
1500 case 2: /* WinNT drivers */
1501 case 3: /* Win2K drivers */
1502 break;
1504 default:
1505 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1506 driverpath, cversion));
1507 goto error_exit;
1510 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1511 driverpath, major, minor));
1514 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1515 driverpath, cversion));
1517 close_file(fsp, NORMAL_CLOSE);
1518 close_cnum(conn, user->vuid);
1519 unbecome_user();
1520 *perr = WERR_OK;
1521 return cversion;
1524 error_exit:
1526 if(fsp)
1527 close_file(fsp, NORMAL_CLOSE);
1529 close_cnum(conn, user->vuid);
1530 unbecome_user();
1531 return -1;
1534 /****************************************************************************
1535 ****************************************************************************/
1536 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1537 struct current_user *user)
1539 const char *architecture;
1540 fstring new_name;
1541 char *p;
1542 int i;
1543 WERROR err;
1545 /* clean up the driver name.
1546 * we can get .\driver.dll
1547 * or worse c:\windows\system\driver.dll !
1549 /* using an intermediate string to not have overlaping memcpy()'s */
1550 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1551 fstrcpy(new_name, p+1);
1552 fstrcpy(driver->driverpath, new_name);
1555 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1556 fstrcpy(new_name, p+1);
1557 fstrcpy(driver->datafile, new_name);
1560 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1561 fstrcpy(new_name, p+1);
1562 fstrcpy(driver->configfile, new_name);
1565 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1566 fstrcpy(new_name, p+1);
1567 fstrcpy(driver->helpfile, new_name);
1570 if (driver->dependentfiles) {
1571 for (i=0; *driver->dependentfiles[i]; i++) {
1572 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1573 fstrcpy(new_name, p+1);
1574 fstrcpy(driver->dependentfiles[i], new_name);
1579 architecture = get_short_archi(driver->environment);
1580 if (!architecture) {
1581 return WERR_UNKNOWN_PRINTER_DRIVER;
1584 /* jfm:7/16/2000 the client always sends the cversion=0.
1585 * The server should check which version the driver is by reading
1586 * the PE header of driver->driverpath.
1588 * For Windows 95/98 the version is 0 (so the value sent is correct)
1589 * For Windows NT (the architecture doesn't matter)
1590 * NT 3.1: cversion=0
1591 * NT 3.5/3.51: cversion=1
1592 * NT 4: cversion=2
1593 * NT2K: cversion=3
1595 if ((driver->cversion = get_correct_cversion( architecture, driver->driverpath, user, &err)) == -1)
1596 return err;
1598 return WERR_OK;
1601 /****************************************************************************
1602 ****************************************************************************/
1603 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1605 const char *architecture;
1606 fstring new_name;
1607 char *p;
1608 int i;
1609 WERROR err;
1611 /* clean up the driver name.
1612 * we can get .\driver.dll
1613 * or worse c:\windows\system\driver.dll !
1615 /* using an intermediate string to not have overlaping memcpy()'s */
1616 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1617 fstrcpy(new_name, p+1);
1618 fstrcpy(driver->driverpath, new_name);
1621 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1622 fstrcpy(new_name, p+1);
1623 fstrcpy(driver->datafile, new_name);
1626 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1627 fstrcpy(new_name, p+1);
1628 fstrcpy(driver->configfile, new_name);
1631 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1632 fstrcpy(new_name, p+1);
1633 fstrcpy(driver->helpfile, new_name);
1636 if (driver->dependentfiles) {
1637 for (i=0; *driver->dependentfiles[i]; i++) {
1638 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1639 fstrcpy(new_name, p+1);
1640 fstrcpy(driver->dependentfiles[i], new_name);
1645 architecture = get_short_archi(driver->environment);
1646 if (!architecture) {
1647 return WERR_UNKNOWN_PRINTER_DRIVER;
1650 /* jfm:7/16/2000 the client always sends the cversion=0.
1651 * The server should check which version the driver is by reading
1652 * the PE header of driver->driverpath.
1654 * For Windows 95/98 the version is 0 (so the value sent is correct)
1655 * For Windows NT (the architecture doesn't matter)
1656 * NT 3.1: cversion=0
1657 * NT 3.5/3.51: cversion=1
1658 * NT 4: cversion=2
1659 * NT2K: cversion=3
1662 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1663 return err;
1665 return WERR_OK;
1668 /****************************************************************************
1669 ****************************************************************************/
1670 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1671 uint32 level, struct current_user *user)
1673 switch (level) {
1674 case 3:
1676 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1677 driver=driver_abstract.info_3;
1678 return clean_up_driver_struct_level_3(driver, user);
1680 case 6:
1682 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1683 driver=driver_abstract.info_6;
1684 return clean_up_driver_struct_level_6(driver, user);
1686 default:
1687 return WERR_INVALID_PARAM;
1691 /****************************************************************************
1692 This function sucks and should be replaced. JRA.
1693 ****************************************************************************/
1695 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1697 dst->cversion = src->version;
1699 fstrcpy( dst->name, src->name);
1700 fstrcpy( dst->environment, src->environment);
1701 fstrcpy( dst->driverpath, src->driverpath);
1702 fstrcpy( dst->datafile, src->datafile);
1703 fstrcpy( dst->configfile, src->configfile);
1704 fstrcpy( dst->helpfile, src->helpfile);
1705 fstrcpy( dst->monitorname, src->monitorname);
1706 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1707 dst->dependentfiles = src->dependentfiles;
1710 #if 0 /* Debugging function */
1712 static char* ffmt(unsigned char *c){
1713 int i;
1714 static char ffmt_str[17];
1716 for (i=0; i<16; i++) {
1717 if ((c[i] < ' ') || (c[i] > '~'))
1718 ffmt_str[i]='.';
1719 else
1720 ffmt_str[i]=c[i];
1722 ffmt_str[16]='\0';
1723 return ffmt_str;
1726 #endif
1728 /****************************************************************************
1729 ****************************************************************************/
1730 WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1731 struct current_user *user, WERROR *perr)
1733 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1734 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1735 const char *architecture;
1736 pstring new_dir;
1737 pstring old_name;
1738 pstring new_name;
1739 DATA_BLOB null_pw;
1740 connection_struct *conn;
1741 NTSTATUS nt_status;
1742 pstring inbuf;
1743 pstring outbuf;
1744 fstring res_type;
1745 BOOL bad_path;
1746 SMB_STRUCT_STAT st;
1747 int ver = 0;
1748 int i;
1750 memset(inbuf, '\0', sizeof(inbuf));
1751 memset(outbuf, '\0', sizeof(outbuf));
1752 *perr = WERR_OK;
1754 if (level==3)
1755 driver=driver_abstract.info_3;
1756 else if (level==6) {
1757 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1758 driver = &converted_driver;
1759 } else {
1760 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1761 return WERR_UNKNOWN_LEVEL;
1764 architecture = get_short_archi(driver->environment);
1765 if (!architecture) {
1766 return WERR_UNKNOWN_PRINTER_DRIVER;
1770 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1771 * Note we must be root to do this.
1774 null_pw = data_blob(NULL, 0);
1775 fstrcpy(res_type, "A:");
1776 become_root();
1777 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1778 unbecome_root();
1780 if (conn == NULL) {
1781 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1782 *perr = ntstatus_to_werror(nt_status);
1783 return WERR_NO_SUCH_SHARE;
1787 * Save who we are - we are temporarily becoming the connection user.
1790 if (!become_user(conn, conn->vuid)) {
1791 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1792 return WERR_ACCESS_DENIED;
1796 * make the directories version and version\driver_name
1797 * under the architecture directory.
1799 DEBUG(5,("Creating first directory\n"));
1800 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1801 driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
1802 create_directory(conn, new_dir);
1804 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1805 * listed for this driver which has already been moved, skip it (note:
1806 * drivers may list the same file name several times. Then check if the
1807 * file already exists in archi\cversion\, if so, check that the version
1808 * info (or time stamps if version info is unavailable) is newer (or the
1809 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1810 * Otherwise, delete the file.
1812 * If a file is not moved to archi\cversion\ because of an error, all the
1813 * rest of the 'unmoved' driver files are removed from archi\. If one or
1814 * more of the driver's files was already moved to archi\cversion\, it
1815 * potentially leaves the driver in a partially updated state. Version
1816 * trauma will most likely occur if an client attempts to use any printer
1817 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1818 * done is appropriate... later JRR
1821 DEBUG(5,("Moving files now !\n"));
1823 if (driver->driverpath && strlen(driver->driverpath)) {
1824 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1825 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1826 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1827 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1828 if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1829 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
1830 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1831 new_name, old_name));
1832 *perr = WERR_ACCESS_DENIED;
1833 ver = -1;
1838 if (driver->datafile && strlen(driver->datafile)) {
1839 if (!strequal(driver->datafile, driver->driverpath)) {
1840 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1841 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1842 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1843 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1844 if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1845 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
1846 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1847 new_name, old_name));
1848 *perr = WERR_ACCESS_DENIED;
1849 ver = -1;
1855 if (driver->configfile && strlen(driver->configfile)) {
1856 if (!strequal(driver->configfile, driver->driverpath) &&
1857 !strequal(driver->configfile, driver->datafile)) {
1858 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1859 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1860 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1861 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1862 if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1863 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
1864 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1865 new_name, old_name));
1866 *perr = WERR_ACCESS_DENIED;
1867 ver = -1;
1873 if (driver->helpfile && strlen(driver->helpfile)) {
1874 if (!strequal(driver->helpfile, driver->driverpath) &&
1875 !strequal(driver->helpfile, driver->datafile) &&
1876 !strequal(driver->helpfile, driver->configfile)) {
1877 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1878 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1879 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1880 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1881 if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE|
1882 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
1883 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1884 new_name, old_name));
1885 *perr = WERR_ACCESS_DENIED;
1886 ver = -1;
1892 if (driver->dependentfiles) {
1893 for (i=0; *driver->dependentfiles[i]; i++) {
1894 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1895 !strequal(driver->dependentfiles[i], driver->datafile) &&
1896 !strequal(driver->dependentfiles[i], driver->configfile) &&
1897 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1898 int j;
1899 for (j=0; j < i; j++) {
1900 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1901 goto NextDriver;
1905 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1906 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1907 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1908 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1909 if ( !NT_STATUS_IS_OK(copy_file(new_name, old_name, conn,
1910 OPENX_FILE_EXISTS_TRUNCATE|
1911 OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
1912 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1913 new_name, old_name));
1914 *perr = WERR_ACCESS_DENIED;
1915 ver = -1;
1919 NextDriver: ;
1923 close_cnum(conn, user->vuid);
1924 unbecome_user();
1926 return ver != -1 ? WERR_OK : WERR_UNKNOWN_PRINTER_DRIVER;
1929 /****************************************************************************
1930 ****************************************************************************/
1931 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1933 int len, buflen;
1934 const char *architecture;
1935 pstring directory;
1936 fstring temp_name;
1937 pstring key;
1938 char *buf;
1939 int i, ret;
1940 TDB_DATA kbuf, dbuf;
1942 architecture = get_short_archi(driver->environment);
1943 if (!architecture) {
1944 return (uint32)-1;
1947 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1948 * \\server is added in the rpc server layer.
1949 * It does make sense to NOT store the server's name in the printer TDB.
1952 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1954 /* .inf files do not always list a file for each of the four standard files.
1955 * Don't prepend a path to a null filename, or client claims:
1956 * "The server on which the printer resides does not have a suitable
1957 * <printer driver name> printer driver installed. Click OK if you
1958 * wish to install the driver on your local machine."
1960 if (strlen(driver->driverpath)) {
1961 fstrcpy(temp_name, driver->driverpath);
1962 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1965 if (strlen(driver->datafile)) {
1966 fstrcpy(temp_name, driver->datafile);
1967 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1970 if (strlen(driver->configfile)) {
1971 fstrcpy(temp_name, driver->configfile);
1972 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1975 if (strlen(driver->helpfile)) {
1976 fstrcpy(temp_name, driver->helpfile);
1977 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1980 if (driver->dependentfiles) {
1981 for (i=0; *driver->dependentfiles[i]; i++) {
1982 fstrcpy(temp_name, driver->dependentfiles[i]);
1983 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1987 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1989 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1991 buf = NULL;
1992 len = buflen = 0;
1994 again:
1995 len = 0;
1996 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1997 driver->cversion,
1998 driver->name,
1999 driver->environment,
2000 driver->driverpath,
2001 driver->datafile,
2002 driver->configfile,
2003 driver->helpfile,
2004 driver->monitorname,
2005 driver->defaultdatatype);
2007 if (driver->dependentfiles) {
2008 for (i=0; *driver->dependentfiles[i]; i++) {
2009 len += tdb_pack(buf+len, buflen-len, "f",
2010 driver->dependentfiles[i]);
2014 if (len != buflen) {
2015 buf = (char *)SMB_REALLOC(buf, len);
2016 if (!buf) {
2017 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
2018 ret = -1;
2019 goto done;
2021 buflen = len;
2022 goto again;
2026 kbuf.dptr = key;
2027 kbuf.dsize = strlen(key)+1;
2028 dbuf.dptr = buf;
2029 dbuf.dsize = len;
2031 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
2033 done:
2034 if (ret)
2035 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
2037 SAFE_FREE(buf);
2038 return ret;
2041 /****************************************************************************
2042 ****************************************************************************/
2043 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
2045 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
2047 ZERO_STRUCT(info3);
2048 info3.cversion = driver->version;
2049 fstrcpy(info3.name,driver->name);
2050 fstrcpy(info3.environment,driver->environment);
2051 fstrcpy(info3.driverpath,driver->driverpath);
2052 fstrcpy(info3.datafile,driver->datafile);
2053 fstrcpy(info3.configfile,driver->configfile);
2054 fstrcpy(info3.helpfile,driver->helpfile);
2055 fstrcpy(info3.monitorname,driver->monitorname);
2056 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
2057 info3.dependentfiles = driver->dependentfiles;
2059 return add_a_printer_driver_3(&info3);
2063 /****************************************************************************
2064 ****************************************************************************/
2065 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
2067 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
2069 ZERO_STRUCT(info);
2071 fstrcpy(info.name, driver);
2072 fstrcpy(info.defaultdatatype, "RAW");
2074 fstrcpy(info.driverpath, "");
2075 fstrcpy(info.datafile, "");
2076 fstrcpy(info.configfile, "");
2077 fstrcpy(info.helpfile, "");
2079 if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
2080 return WERR_NOMEM;
2082 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
2083 fstrcpy(info.dependentfiles[0], "");
2085 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&info, sizeof(info));
2086 if (!*info_ptr) {
2087 SAFE_FREE(info.dependentfiles);
2088 return WERR_NOMEM;
2091 return WERR_OK;
2094 /****************************************************************************
2095 ****************************************************************************/
2096 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
2098 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
2099 TDB_DATA kbuf, dbuf;
2100 const char *architecture;
2101 int len = 0;
2102 int i;
2103 pstring key;
2105 ZERO_STRUCT(driver);
2107 architecture = get_short_archi(arch);
2108 if ( !architecture ) {
2109 return WERR_UNKNOWN_PRINTER_DRIVER;
2112 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
2114 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
2115 version = 0;
2117 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
2119 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
2121 kbuf.dptr = key;
2122 kbuf.dsize = strlen(key)+1;
2124 dbuf = tdb_fetch(tdb_drivers, kbuf);
2125 if (!dbuf.dptr)
2126 return WERR_UNKNOWN_PRINTER_DRIVER;
2128 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
2129 &driver.cversion,
2130 driver.name,
2131 driver.environment,
2132 driver.driverpath,
2133 driver.datafile,
2134 driver.configfile,
2135 driver.helpfile,
2136 driver.monitorname,
2137 driver.defaultdatatype);
2139 i=0;
2140 while (len < dbuf.dsize) {
2141 driver.dependentfiles = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
2142 if ( !driver.dependentfiles ) {
2143 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
2144 break;
2147 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
2148 &driver.dependentfiles[i]);
2149 i++;
2152 if ( driver.dependentfiles )
2153 fstrcpy( driver.dependentfiles[i], "" );
2155 SAFE_FREE(dbuf.dptr);
2157 if (len != dbuf.dsize) {
2158 SAFE_FREE(driver.dependentfiles);
2160 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
2163 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
2164 if (!*info_ptr) {
2165 SAFE_FREE(driver.dependentfiles);
2166 return WERR_NOMEM;
2169 return WERR_OK;
2172 /****************************************************************************
2173 Debugging function, dump at level 6 the struct in the logs.
2174 ****************************************************************************/
2176 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
2178 uint32 result;
2179 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
2180 int i;
2182 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
2184 switch (level)
2186 case 3:
2188 if (driver.info_3 == NULL)
2189 result=5;
2190 else {
2191 info3=driver.info_3;
2193 DEBUGADD(20,("version:[%d]\n", info3->cversion));
2194 DEBUGADD(20,("name:[%s]\n", info3->name));
2195 DEBUGADD(20,("environment:[%s]\n", info3->environment));
2196 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
2197 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
2198 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
2199 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
2200 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
2201 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
2203 for (i=0; info3->dependentfiles &&
2204 *info3->dependentfiles[i]; i++) {
2205 DEBUGADD(20,("dependentfile:[%s]\n",
2206 info3->dependentfiles[i]));
2208 result=0;
2210 break;
2212 default:
2213 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
2214 result=1;
2215 break;
2218 return result;
2221 /****************************************************************************
2222 ****************************************************************************/
2223 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
2225 int len = 0;
2227 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
2229 if (!nt_devmode)
2230 return len;
2232 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2233 nt_devmode->devicename,
2234 nt_devmode->formname,
2236 nt_devmode->specversion,
2237 nt_devmode->driverversion,
2238 nt_devmode->size,
2239 nt_devmode->driverextra,
2240 nt_devmode->orientation,
2241 nt_devmode->papersize,
2242 nt_devmode->paperlength,
2243 nt_devmode->paperwidth,
2244 nt_devmode->scale,
2245 nt_devmode->copies,
2246 nt_devmode->defaultsource,
2247 nt_devmode->printquality,
2248 nt_devmode->color,
2249 nt_devmode->duplex,
2250 nt_devmode->yresolution,
2251 nt_devmode->ttoption,
2252 nt_devmode->collate,
2253 nt_devmode->logpixels,
2255 nt_devmode->fields,
2256 nt_devmode->bitsperpel,
2257 nt_devmode->pelswidth,
2258 nt_devmode->pelsheight,
2259 nt_devmode->displayflags,
2260 nt_devmode->displayfrequency,
2261 nt_devmode->icmmethod,
2262 nt_devmode->icmintent,
2263 nt_devmode->mediatype,
2264 nt_devmode->dithertype,
2265 nt_devmode->reserved1,
2266 nt_devmode->reserved2,
2267 nt_devmode->panningwidth,
2268 nt_devmode->panningheight,
2269 nt_devmode->nt_dev_private);
2272 if (nt_devmode->nt_dev_private) {
2273 len += tdb_pack(buf+len, buflen-len, "B",
2274 nt_devmode->driverextra,
2275 nt_devmode->nt_dev_private);
2278 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
2280 return len;
2283 /****************************************************************************
2284 Pack all values in all printer keys
2285 ***************************************************************************/
2287 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
2289 int len = 0;
2290 int i, j;
2291 REGISTRY_VALUE *val;
2292 REGVAL_CTR *val_ctr;
2293 pstring path;
2294 int num_values;
2296 if ( !data )
2297 return 0;
2299 /* loop over all keys */
2301 for ( i=0; i<data->num_keys; i++ ) {
2302 val_ctr = data->keys[i].values;
2303 num_values = regval_ctr_numvals( val_ctr );
2305 /* pack the keyname followed by a empty value */
2307 len += tdb_pack(buf+len, buflen-len, "pPdB",
2308 &data->keys[i].name,
2309 data->keys[i].name,
2310 REG_NONE,
2312 NULL);
2314 /* now loop over all values */
2316 for ( j=0; j<num_values; j++ ) {
2317 /* pathname should be stored as <key>\<value> */
2319 val = regval_ctr_specific_value( val_ctr, j );
2320 pstrcpy( path, data->keys[i].name );
2321 pstrcat( path, "\\" );
2322 pstrcat( path, regval_name(val) );
2324 len += tdb_pack(buf+len, buflen-len, "pPdB",
2325 val,
2326 path,
2327 regval_type(val),
2328 regval_size(val),
2329 regval_data_p(val) );
2331 DEBUG(8,("specific: [%s], len: %d\n", regval_name(val), regval_size(val)));
2336 /* terminator */
2338 len += tdb_pack(buf+len, buflen-len, "p", NULL);
2340 return len;
2344 /****************************************************************************
2345 Delete a printer - this just deletes the printer info file, any open
2346 handles are not affected.
2347 ****************************************************************************/
2349 uint32 del_a_printer(const char *sharename)
2351 TDB_DATA kbuf;
2352 pstring printdb_path;
2354 kbuf = make_printer_tdbkey( sharename );
2355 tdb_delete(tdb_printers, kbuf);
2357 kbuf.dptr = make_printers_secdesc_tdbkey( sharename );
2358 kbuf.dsize = strlen(kbuf.dptr) + 1;
2359 tdb_delete(tdb_printers, kbuf);
2361 close_all_print_db();
2363 if (geteuid() == 0) {
2364 pstrcpy(printdb_path, lock_path("printing/"));
2365 pstrcat(printdb_path, sharename);
2366 pstrcat(printdb_path, ".tdb");
2368 unlink(printdb_path);
2371 return 0;
2374 /****************************************************************************
2375 ****************************************************************************/
2376 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2378 char *buf;
2379 int buflen, len;
2380 WERROR ret;
2381 TDB_DATA kbuf, dbuf;
2384 * in addprinter: no servername and the printer is the name
2385 * in setprinter: servername is \\server
2386 * and printer is \\server\\printer
2388 * Samba manages only local printers.
2389 * we currently don't support things like i
2390 * path=\\other_server\printer
2392 * We only store the printername, not \\server\printername
2395 if ( info->servername[0] != '\0' ) {
2396 trim_string(info->printername, info->servername, NULL);
2397 trim_char(info->printername, '\\', '\0');
2398 info->servername[0]='\0';
2402 * JFM: one day I'll forget.
2403 * below that's info->portname because that's the SAMBA sharename
2404 * and I made NT 'thinks' it's the portname
2405 * the info->sharename is the thing you can name when you add a printer
2406 * that's the short-name when you create shared printer for 95/98
2407 * So I've made a limitation in SAMBA: you can only have 1 printer model
2408 * behind a SAMBA share.
2411 buf = NULL;
2412 buflen = 0;
2414 again:
2415 len = 0;
2416 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2417 info->attributes,
2418 info->priority,
2419 info->default_priority,
2420 info->starttime,
2421 info->untiltime,
2422 info->status,
2423 info->cjobs,
2424 info->averageppm,
2425 info->changeid,
2426 info->c_setprinter,
2427 info->setuptime,
2428 info->servername,
2429 info->printername,
2430 info->sharename,
2431 info->portname,
2432 info->drivername,
2433 info->comment,
2434 info->location,
2435 info->sepfile,
2436 info->printprocessor,
2437 info->datatype,
2438 info->parameters);
2440 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2442 len += pack_values( info->data, buf+len, buflen-len );
2444 if (buflen != len) {
2445 buf = (char *)SMB_REALLOC(buf, len);
2446 if (!buf) {
2447 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2448 ret = WERR_NOMEM;
2449 goto done;
2451 buflen = len;
2452 goto again;
2456 kbuf = make_printer_tdbkey( info->sharename );
2458 dbuf.dptr = buf;
2459 dbuf.dsize = len;
2461 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2463 done:
2464 if (!W_ERROR_IS_OK(ret))
2465 DEBUG(8, ("error updating printer to tdb on disk\n"));
2467 SAFE_FREE(buf);
2469 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2470 info->sharename, info->drivername, info->portname, len));
2472 return ret;
2476 /****************************************************************************
2477 Malloc and return an NT devicemode.
2478 ****************************************************************************/
2480 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2483 char adevice[MAXDEVICENAME];
2484 NT_DEVICEMODE *nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE);
2486 if (nt_devmode == NULL) {
2487 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2488 return NULL;
2491 ZERO_STRUCTP(nt_devmode);
2493 slprintf(adevice, sizeof(adevice), "%s", default_devicename);
2494 fstrcpy(nt_devmode->devicename, adevice);
2496 fstrcpy(nt_devmode->formname, "Letter");
2498 nt_devmode->specversion = 0x0401;
2499 nt_devmode->driverversion = 0x0400;
2500 nt_devmode->size = 0x00DC;
2501 nt_devmode->driverextra = 0x0000;
2502 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2503 DEFAULTSOURCE | COPIES | SCALE |
2504 PAPERSIZE | ORIENTATION;
2505 nt_devmode->orientation = 1;
2506 nt_devmode->papersize = PAPER_LETTER;
2507 nt_devmode->paperlength = 0;
2508 nt_devmode->paperwidth = 0;
2509 nt_devmode->scale = 0x64;
2510 nt_devmode->copies = 1;
2511 nt_devmode->defaultsource = BIN_FORMSOURCE;
2512 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2513 nt_devmode->color = COLOR_MONOCHROME;
2514 nt_devmode->duplex = DUP_SIMPLEX;
2515 nt_devmode->yresolution = 0;
2516 nt_devmode->ttoption = TT_SUBDEV;
2517 nt_devmode->collate = COLLATE_FALSE;
2518 nt_devmode->icmmethod = 0;
2519 nt_devmode->icmintent = 0;
2520 nt_devmode->mediatype = 0;
2521 nt_devmode->dithertype = 0;
2523 /* non utilisés par un driver d'imprimante */
2524 nt_devmode->logpixels = 0;
2525 nt_devmode->bitsperpel = 0;
2526 nt_devmode->pelswidth = 0;
2527 nt_devmode->pelsheight = 0;
2528 nt_devmode->displayflags = 0;
2529 nt_devmode->displayfrequency = 0;
2530 nt_devmode->reserved1 = 0;
2531 nt_devmode->reserved2 = 0;
2532 nt_devmode->panningwidth = 0;
2533 nt_devmode->panningheight = 0;
2535 nt_devmode->nt_dev_private = NULL;
2536 return nt_devmode;
2539 /****************************************************************************
2540 Deepcopy an NT devicemode.
2541 ****************************************************************************/
2543 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2545 NT_DEVICEMODE *new_nt_devicemode = NULL;
2547 if ( !nt_devicemode )
2548 return NULL;
2550 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2551 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2552 return NULL;
2555 new_nt_devicemode->nt_dev_private = NULL;
2556 if (nt_devicemode->nt_dev_private != NULL) {
2557 if ((new_nt_devicemode->nt_dev_private = (uint8 *)memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
2558 SAFE_FREE(new_nt_devicemode);
2559 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2560 return NULL;
2564 return new_nt_devicemode;
2567 /****************************************************************************
2568 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2569 ****************************************************************************/
2571 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2573 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2575 if(nt_devmode == NULL)
2576 return;
2578 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2580 SAFE_FREE(nt_devmode->nt_dev_private);
2581 SAFE_FREE(*devmode_ptr);
2584 /****************************************************************************
2585 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2586 ****************************************************************************/
2588 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2590 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2592 if ( !info )
2593 return;
2595 free_nt_devicemode(&info->devmode);
2597 TALLOC_FREE( *info_ptr );
2601 /****************************************************************************
2602 ****************************************************************************/
2603 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2605 int len = 0;
2606 int extra_len = 0;
2607 NT_DEVICEMODE devmode;
2609 ZERO_STRUCT(devmode);
2611 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2613 if (!*nt_devmode) return len;
2615 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2616 devmode.devicename,
2617 devmode.formname,
2619 &devmode.specversion,
2620 &devmode.driverversion,
2621 &devmode.size,
2622 &devmode.driverextra,
2623 &devmode.orientation,
2624 &devmode.papersize,
2625 &devmode.paperlength,
2626 &devmode.paperwidth,
2627 &devmode.scale,
2628 &devmode.copies,
2629 &devmode.defaultsource,
2630 &devmode.printquality,
2631 &devmode.color,
2632 &devmode.duplex,
2633 &devmode.yresolution,
2634 &devmode.ttoption,
2635 &devmode.collate,
2636 &devmode.logpixels,
2638 &devmode.fields,
2639 &devmode.bitsperpel,
2640 &devmode.pelswidth,
2641 &devmode.pelsheight,
2642 &devmode.displayflags,
2643 &devmode.displayfrequency,
2644 &devmode.icmmethod,
2645 &devmode.icmintent,
2646 &devmode.mediatype,
2647 &devmode.dithertype,
2648 &devmode.reserved1,
2649 &devmode.reserved2,
2650 &devmode.panningwidth,
2651 &devmode.panningheight,
2652 &devmode.nt_dev_private);
2654 if (devmode.nt_dev_private) {
2655 /* the len in tdb_unpack is an int value and
2656 * devmode.driverextra is only a short
2658 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.nt_dev_private);
2659 devmode.driverextra=(uint16)extra_len;
2661 /* check to catch an invalid TDB entry so we don't segfault */
2662 if (devmode.driverextra == 0) {
2663 devmode.nt_dev_private = NULL;
2667 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2668 if (!*nt_devmode) {
2669 SAFE_FREE(devmode.nt_dev_private);
2670 return -1;
2673 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2674 if (devmode.nt_dev_private)
2675 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2677 return len;
2680 /****************************************************************************
2681 Allocate and initialize a new slot.
2682 ***************************************************************************/
2684 int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2686 NT_PRINTER_KEY *d;
2687 int key_index;
2689 if ( !name || !data )
2690 return -1;
2692 /* allocate another slot in the NT_PRINTER_KEY array */
2694 if ( !(d = TALLOC_REALLOC_ARRAY( data, data->keys, NT_PRINTER_KEY, data->num_keys+1)) ) {
2695 DEBUG(0,("add_new_printer_key: Realloc() failed!\n"));
2696 return -1;
2699 data->keys = d;
2701 key_index = data->num_keys;
2703 /* initialze new key */
2705 data->keys[key_index].name = talloc_strdup( data, name );
2707 if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) )
2708 return -1;
2710 data->num_keys++;
2712 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2714 return key_index;
2717 /****************************************************************************
2718 search for a registry key name in the existing printer data
2719 ***************************************************************************/
2721 int delete_printer_key( NT_PRINTER_DATA *data, const char *name )
2723 int i;
2725 for ( i=0; i<data->num_keys; i++ ) {
2726 if ( strequal( data->keys[i].name, name ) ) {
2728 /* cleanup memory */
2730 TALLOC_FREE( data->keys[i].name );
2731 TALLOC_FREE( data->keys[i].values );
2733 /* if not the end of the array, move remaining elements down one slot */
2735 data->num_keys--;
2736 if ( data->num_keys && (i < data->num_keys) )
2737 memmove( &data->keys[i], &data->keys[i+1], sizeof(NT_PRINTER_KEY)*(data->num_keys-i) );
2739 break;
2744 return data->num_keys;
2747 /****************************************************************************
2748 search for a registry key name in the existing printer data
2749 ***************************************************************************/
2751 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2753 int key_index = -1;
2754 int i;
2756 if ( !data || !name )
2757 return -1;
2759 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2761 /* loop over all existing keys */
2763 for ( i=0; i<data->num_keys; i++ ) {
2764 if ( strequal(data->keys[i].name, name) ) {
2765 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2766 key_index = i;
2767 break;
2772 return key_index;
2775 /****************************************************************************
2776 ***************************************************************************/
2778 int get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2780 int i, j;
2781 int key_len;
2782 int num_subkeys = 0;
2783 char *p;
2784 fstring *subkeys_ptr = NULL;
2785 fstring subkeyname;
2787 *subkeys = NULL;
2789 if ( !data )
2790 return 0;
2792 if ( !key )
2793 return -1;
2795 /* special case of asking for the top level printer data registry key names */
2797 if ( strlen(key) == 0 ) {
2798 for ( i=0; i<data->num_keys; i++ ) {
2800 /* found a match, so allocate space and copy the name */
2802 if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
2803 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2804 num_subkeys+1));
2805 return -1;
2808 fstrcpy( subkeys_ptr[num_subkeys], data->keys[i].name );
2809 num_subkeys++;
2812 goto done;
2815 /* asking for the subkeys of some key */
2816 /* subkey paths are stored in the key name using '\' as the delimiter */
2818 for ( i=0; i<data->num_keys; i++ ) {
2819 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2821 /* if we found the exact key, then break */
2822 key_len = strlen( key );
2823 if ( strlen(data->keys[i].name) == key_len )
2824 break;
2826 /* get subkey path */
2828 p = data->keys[i].name + key_len;
2829 if ( *p == '\\' )
2830 p++;
2831 fstrcpy( subkeyname, p );
2832 if ( (p = strchr( subkeyname, '\\' )) )
2833 *p = '\0';
2835 /* don't add a key more than once */
2837 for ( j=0; j<num_subkeys; j++ ) {
2838 if ( strequal( subkeys_ptr[j], subkeyname ) )
2839 break;
2842 if ( j != num_subkeys )
2843 continue;
2845 /* found a match, so allocate space and copy the name */
2847 if ( !(subkeys_ptr = SMB_REALLOC_ARRAY( subkeys_ptr, fstring, num_subkeys+2)) ) {
2848 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2849 num_subkeys+1));
2850 return 0;
2853 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2854 num_subkeys++;
2859 /* return error if the key was not found */
2861 if ( i == data->num_keys ) {
2862 SAFE_FREE(subkeys_ptr);
2863 return -1;
2866 done:
2867 /* tag off the end */
2869 if (num_subkeys)
2870 fstrcpy(subkeys_ptr[num_subkeys], "" );
2872 *subkeys = subkeys_ptr;
2874 return num_subkeys;
2877 #ifdef HAVE_ADS
2878 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2879 const char *sz)
2881 smb_ucs2_t conv_str[1024];
2882 size_t str_size;
2884 regval_ctr_delvalue(ctr, val_name);
2885 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2886 STR_TERMINATE | STR_NOALIGN);
2887 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2888 (char *) conv_str, str_size);
2891 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2892 uint32 dword)
2894 regval_ctr_delvalue(ctr, val_name);
2895 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2896 (char *) &dword, sizeof(dword));
2899 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2900 BOOL b)
2902 uint8 bin_bool = (b ? 1 : 0);
2903 regval_ctr_delvalue(ctr, val_name);
2904 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2905 (char *) &bin_bool, sizeof(bin_bool));
2908 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2909 const char *multi_sz)
2911 smb_ucs2_t *conv_strs = NULL;
2912 size_t str_size;
2914 /* a multi-sz has to have a null string terminator, i.e., the last
2915 string must be followed by two nulls */
2916 str_size = strlen(multi_sz) + 2;
2917 conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
2918 if (!conv_strs) {
2919 return;
2922 /* Change to byte units. */
2923 str_size *= sizeof(smb_ucs2_t);
2924 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2925 STR_TERMINATE | STR_NOALIGN);
2927 regval_ctr_delvalue(ctr, val_name);
2928 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2929 (char *) conv_strs, str_size);
2930 safe_free(conv_strs);
2934 /****************************************************************************
2935 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2937 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2938 * @return BOOL indicating success or failure
2939 ***************************************************************************/
2941 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2943 REGVAL_CTR *ctr = NULL;
2944 fstring longname;
2945 fstring dnssuffix;
2946 char *allocated_string = NULL;
2947 const char *ascii_str;
2948 int i;
2950 if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2951 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
2952 ctr = info2->data->keys[i].values;
2954 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2955 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2957 /* we make the assumption that the netbios name is the same
2958 as the DNS name sinc ethe former will be what we used to
2959 join the domain */
2961 if ( get_mydnsdomname( dnssuffix ) )
2962 fstr_sprintf( longname, "%s.%s", global_myname(), dnssuffix );
2963 else
2964 fstrcpy( longname, global_myname() );
2966 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2968 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2969 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2970 SAFE_FREE(allocated_string);
2972 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2973 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2974 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2975 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2976 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2977 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2978 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2979 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2980 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2982 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2983 (info2->attributes &
2984 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2986 switch (info2->attributes & 0x3) {
2987 case 0:
2988 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2989 break;
2990 case 1:
2991 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2992 break;
2993 case 2:
2994 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2995 break;
2996 default:
2997 ascii_str = "unknown";
2999 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
3001 return True;
3004 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
3005 struct GUID guid)
3007 int i;
3008 REGVAL_CTR *ctr=NULL;
3010 /* find the DsSpooler key */
3011 if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
3012 i = add_new_printer_key(info2->data, SPOOL_DSSPOOLER_KEY);
3013 ctr = info2->data->keys[i].values;
3015 regval_ctr_delvalue(ctr, "objectGUID");
3016 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
3017 (char *) &guid, sizeof(struct GUID));
3020 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
3021 NT_PRINTER_INFO_LEVEL *printer)
3023 ADS_STATUS ads_rc;
3024 LDAPMessage *res;
3025 char *prt_dn = NULL, *srv_dn, *srv_cn_0;
3026 char *srv_dn_utf8, **srv_cn_utf8;
3027 TALLOC_CTX *ctx;
3028 ADS_MODLIST mods;
3029 const char *attrs[] = {"objectGUID", NULL};
3030 struct GUID guid;
3031 WERROR win_rc = WERR_OK;
3033 DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
3035 /* figure out where to publish */
3036 ads_find_machine_acct(ads, &res, global_myname());
3038 /* We use ldap_get_dn here as we need the answer
3039 * in utf8 to call ldap_explode_dn(). JRA. */
3041 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ld, (LDAPMessage *)res);
3042 if (!srv_dn_utf8) {
3043 ads_destroy(&ads);
3044 return WERR_SERVER_UNAVAILABLE;
3046 ads_msgfree(ads, res);
3047 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
3048 if (!srv_cn_utf8) {
3049 ldap_memfree(srv_dn_utf8);
3050 ads_destroy(&ads);
3051 return WERR_SERVER_UNAVAILABLE;
3053 /* Now convert to CH_UNIX. */
3054 if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
3055 ldap_memfree(srv_dn_utf8);
3056 ldap_memfree(srv_cn_utf8);
3057 ads_destroy(&ads);
3058 return WERR_SERVER_UNAVAILABLE;
3060 if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
3061 ldap_memfree(srv_dn_utf8);
3062 ldap_memfree(srv_cn_utf8);
3063 ads_destroy(&ads);
3064 SAFE_FREE(srv_dn);
3065 return WERR_SERVER_UNAVAILABLE;
3068 ldap_memfree(srv_dn_utf8);
3069 ldap_memfree(srv_cn_utf8);
3071 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0,
3072 printer->info_2->sharename, srv_dn);
3074 SAFE_FREE(srv_dn);
3075 SAFE_FREE(srv_cn_0);
3077 /* build the ads mods */
3078 ctx = talloc_init("nt_printer_publish_ads");
3079 if (ctx == NULL) {
3080 SAFE_FREE(prt_dn);
3081 return WERR_NOMEM;
3084 mods = ads_init_mods(ctx);
3086 if (mods == NULL) {
3087 SAFE_FREE(prt_dn);
3088 talloc_destroy(ctx);
3089 return WERR_NOMEM;
3092 get_local_printer_publishing_data(ctx, &mods, printer->info_2->data);
3093 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
3094 printer->info_2->sharename);
3096 /* publish it */
3097 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
3098 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT)
3099 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
3101 if (!ADS_ERR_OK(ads_rc))
3102 DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
3104 talloc_destroy(ctx);
3106 /* retreive the guid and store it locally */
3107 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
3108 ZERO_STRUCT(guid);
3109 ads_pull_guid(ads, res, &guid);
3110 ads_msgfree(ads, res);
3111 store_printer_guid(printer->info_2, guid);
3112 win_rc = mod_a_printer(printer, 2);
3115 SAFE_FREE(prt_dn);
3116 return win_rc;
3119 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
3120 NT_PRINTER_INFO_LEVEL *printer)
3122 ADS_STATUS ads_rc;
3123 LDAPMessage *res;
3124 char *prt_dn = NULL;
3126 DEBUG(5, ("unpublishing printer %s\n", printer->info_2->printername));
3128 /* remove the printer from the directory */
3129 ads_rc = ads_find_printer_on_server(ads, &res,
3130 printer->info_2->sharename, global_myname());
3132 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
3133 prt_dn = ads_get_dn(ads, res);
3134 if (!prt_dn) {
3135 ads_msgfree(ads, res);
3136 return WERR_NOMEM;
3138 ads_rc = ads_del_dn(ads, prt_dn);
3139 ads_memfree(ads, prt_dn);
3142 ads_msgfree(ads, res);
3143 return WERR_OK;
3146 /****************************************************************************
3147 * Publish a printer in the directory
3149 * @param snum describing printer service
3150 * @return WERROR indicating status of publishing
3151 ***************************************************************************/
3153 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
3155 ADS_STATUS ads_rc;
3156 ADS_STRUCT *ads = NULL;
3157 NT_PRINTER_INFO_LEVEL *printer = NULL;
3158 WERROR win_rc;
3160 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
3161 if (!W_ERROR_IS_OK(win_rc))
3162 goto done;
3164 switch (action) {
3165 case SPOOL_DS_PUBLISH:
3166 case SPOOL_DS_UPDATE:
3167 /* set the DsSpooler info and attributes */
3168 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2))) {
3169 win_rc = WERR_NOMEM;
3170 goto done;
3173 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
3174 break;
3175 case SPOOL_DS_UNPUBLISH:
3176 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
3177 break;
3178 default:
3179 win_rc = WERR_NOT_SUPPORTED;
3180 goto done;
3183 win_rc = mod_a_printer(printer, 2);
3184 if (!W_ERROR_IS_OK(win_rc)) {
3185 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
3186 goto done;
3189 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
3190 if (!ads) {
3191 DEBUG(3, ("ads_init() failed\n"));
3192 win_rc = WERR_SERVER_UNAVAILABLE;
3193 goto done;
3195 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
3196 SAFE_FREE(ads->auth.password);
3197 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
3198 NULL, NULL);
3200 /* ads_connect() will find the DC for us */
3201 ads_rc = ads_connect(ads);
3202 if (!ADS_ERR_OK(ads_rc)) {
3203 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
3204 win_rc = WERR_ACCESS_DENIED;
3205 goto done;
3208 switch (action) {
3209 case SPOOL_DS_PUBLISH:
3210 case SPOOL_DS_UPDATE:
3211 win_rc = nt_printer_publish_ads(ads, printer);
3212 break;
3213 case SPOOL_DS_UNPUBLISH:
3214 win_rc = nt_printer_unpublish_ads(ads, printer);
3215 break;
3218 done:
3219 free_a_printer(&printer, 2);
3220 ads_destroy(&ads);
3221 return win_rc;
3224 WERROR check_published_printers(void)
3226 ADS_STATUS ads_rc;
3227 ADS_STRUCT *ads = NULL;
3228 int snum;
3229 int n_services = lp_numservices();
3230 NT_PRINTER_INFO_LEVEL *printer = NULL;
3232 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
3233 if (!ads) {
3234 DEBUG(3, ("ads_init() failed\n"));
3235 return WERR_SERVER_UNAVAILABLE;
3237 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
3238 SAFE_FREE(ads->auth.password);
3239 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
3240 NULL, NULL);
3242 /* ads_connect() will find the DC for us */
3243 ads_rc = ads_connect(ads);
3244 if (!ADS_ERR_OK(ads_rc)) {
3245 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
3246 ads_destroy(&ads);
3247 return WERR_ACCESS_DENIED;
3250 for (snum = 0; snum < n_services; snum++) {
3251 if (!(lp_snum_ok(snum) && lp_print_ok(snum)))
3252 continue;
3254 if (W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2,
3255 lp_servicename(snum))) &&
3256 (printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
3257 nt_printer_publish_ads(ads, printer);
3259 free_a_printer(&printer, 2);
3262 ads_destroy(&ads);
3263 return WERR_OK;
3266 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3267 struct GUID *guid)
3269 NT_PRINTER_INFO_LEVEL *printer = NULL;
3270 REGVAL_CTR *ctr;
3271 REGISTRY_VALUE *guid_val;
3272 WERROR win_rc;
3273 int i;
3275 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
3277 if (!W_ERROR_IS_OK(win_rc) ||
3278 !(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
3279 ((i = lookup_printerkey(printer->info_2->data, SPOOL_DSSPOOLER_KEY)) < 0) ||
3280 !(ctr = printer->info_2->data->keys[i].values) ||
3281 !(guid_val = regval_ctr_getvalue(ctr, "objectGUID")))
3283 free_a_printer(&printer, 2);
3284 return False;
3287 /* fetching printer guids really ought to be a separate function.. */
3288 if (guid && regval_size(guid_val) == sizeof(struct GUID))
3289 memcpy(guid, regval_data_p(guid_val), sizeof(struct GUID));
3291 free_a_printer(&printer, 2);
3292 return True;
3294 #else
3295 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
3297 return WERR_OK;
3300 WERROR check_published_printers(void)
3302 return WERR_OK;
3305 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
3306 struct GUID *guid)
3308 return False;
3310 #endif /* HAVE_ADS */
3312 /****************************************************************************
3313 ***************************************************************************/
3315 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
3317 NT_PRINTER_DATA *data;
3318 int i;
3319 int removed_keys = 0;
3320 int empty_slot;
3322 data = p2->data;
3323 empty_slot = data->num_keys;
3325 if ( !key )
3326 return WERR_INVALID_PARAM;
3328 /* remove all keys */
3330 if ( !strlen(key) ) {
3332 TALLOC_FREE( data );
3334 p2->data = NULL;
3336 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
3337 p2->printername ));
3339 return WERR_OK;
3342 /* remove a specific key (and all subkeys) */
3344 for ( i=0; i<data->num_keys; i++ ) {
3345 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
3346 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
3347 data->keys[i].name));
3349 TALLOC_FREE( data->keys[i].name );
3350 TALLOC_FREE( data->keys[i].values );
3352 /* mark the slot as empty */
3354 ZERO_STRUCTP( &data->keys[i] );
3358 /* find the first empty slot */
3360 for ( i=0; i<data->num_keys; i++ ) {
3361 if ( !data->keys[i].name ) {
3362 empty_slot = i;
3363 removed_keys++;
3364 break;
3368 if ( i == data->num_keys )
3369 /* nothing was removed */
3370 return WERR_INVALID_PARAM;
3372 /* move everything down */
3374 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
3375 if ( data->keys[i].name ) {
3376 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
3377 ZERO_STRUCTP( &data->keys[i] );
3378 empty_slot++;
3379 removed_keys++;
3383 /* update count */
3385 data->num_keys -= removed_keys;
3387 /* sanity check to see if anything is left */
3389 if ( !data->num_keys ) {
3390 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
3392 SAFE_FREE( data->keys );
3393 ZERO_STRUCTP( data );
3396 return WERR_OK;
3399 /****************************************************************************
3400 ***************************************************************************/
3402 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3404 WERROR result = WERR_OK;
3405 int key_index;
3407 /* we must have names on non-zero length */
3409 if ( !key || !*key|| !value || !*value )
3410 return WERR_INVALID_NAME;
3412 /* find the printer key first */
3414 key_index = lookup_printerkey( p2->data, key );
3415 if ( key_index == -1 )
3416 return WERR_OK;
3418 /* make sure the value exists so we can return the correct error code */
3420 if ( !regval_ctr_getvalue( p2->data->keys[key_index].values, value ) )
3421 return WERR_BADFILE;
3423 regval_ctr_delvalue( p2->data->keys[key_index].values, value );
3425 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
3426 key, value ));
3428 return result;
3431 /****************************************************************************
3432 ***************************************************************************/
3434 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
3435 uint32 type, uint8 *data, int real_len )
3437 WERROR result = WERR_OK;
3438 int key_index;
3440 /* we must have names on non-zero length */
3442 if ( !key || !*key|| !value || !*value )
3443 return WERR_INVALID_NAME;
3445 /* find the printer key first */
3447 key_index = lookup_printerkey( p2->data, key );
3448 if ( key_index == -1 )
3449 key_index = add_new_printer_key( p2->data, key );
3451 if ( key_index == -1 )
3452 return WERR_NOMEM;
3454 regval_ctr_addvalue( p2->data->keys[key_index].values, value,
3455 type, (const char *)data, real_len );
3457 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
3458 key, value, type, real_len ));
3460 return result;
3463 /****************************************************************************
3464 ***************************************************************************/
3466 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3468 int key_index;
3470 if ( (key_index = lookup_printerkey( p2->data, key )) == -1 )
3471 return NULL;
3473 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
3474 key, value ));
3476 return regval_ctr_getvalue( p2->data->keys[key_index].values, value );
3479 /****************************************************************************
3480 Unpack a list of registry values frem the TDB
3481 ***************************************************************************/
3483 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
3485 int len = 0;
3486 uint32 type;
3487 pstring string, valuename, keyname;
3488 char *str;
3489 int size;
3490 uint8 *data_p;
3491 REGISTRY_VALUE *regval_p;
3492 int key_index;
3494 /* add the "PrinterDriverData" key first for performance reasons */
3496 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
3498 /* loop and unpack the rest of the registry values */
3500 while ( True ) {
3502 /* check to see if there are any more registry values */
3504 regval_p = NULL;
3505 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
3506 if ( !regval_p )
3507 break;
3509 /* unpack the next regval */
3511 len += tdb_unpack(buf+len, buflen-len, "fdB",
3512 string,
3513 &type,
3514 &size,
3515 &data_p);
3517 /* lookup for subkey names which have a type of REG_NONE */
3518 /* there's no data with this entry */
3520 if ( type == REG_NONE ) {
3521 if ( (key_index=lookup_printerkey( printer_data, string)) == -1 )
3522 add_new_printer_key( printer_data, string );
3523 continue;
3527 * break of the keyname from the value name.
3528 * Valuenames can have embedded '\'s so be careful.
3529 * only support one level of keys. See the
3530 * "Konica Fiery S300 50C-K v1.1. enu" 2k driver.
3531 * -- jerry
3534 str = strchr_m( string, '\\');
3536 /* Put in "PrinterDriverData" is no key specified */
3538 if ( !str ) {
3539 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3540 pstrcpy( valuename, string );
3542 else {
3543 *str = '\0';
3544 pstrcpy( keyname, string );
3545 pstrcpy( valuename, str+1 );
3548 /* see if we need a new key */
3550 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3551 key_index = add_new_printer_key( printer_data, keyname );
3553 if ( key_index == -1 ) {
3554 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3555 keyname));
3556 break;
3559 /* add the new value */
3561 regval_ctr_addvalue( printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3563 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3565 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3568 return len;
3571 /****************************************************************************
3572 ***************************************************************************/
3574 static void map_to_os2_driver(fstring drivername)
3576 static BOOL initialised=False;
3577 static fstring last_from,last_to;
3578 char *mapfile = lp_os2_driver_map();
3579 char **lines = NULL;
3580 int numlines = 0;
3581 int i;
3583 if (!strlen(drivername))
3584 return;
3586 if (!*mapfile)
3587 return;
3589 if (!initialised) {
3590 *last_from = *last_to = 0;
3591 initialised = True;
3594 if (strequal(drivername,last_from)) {
3595 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3596 fstrcpy(drivername,last_to);
3597 return;
3600 lines = file_lines_load(mapfile, &numlines,0);
3601 if (numlines == 0 || lines == NULL) {
3602 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3603 SAFE_FREE(lines);
3604 return;
3607 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3609 for( i = 0; i < numlines; i++) {
3610 char *nt_name = lines[i];
3611 char *os2_name = strchr(nt_name,'=');
3613 if (!os2_name)
3614 continue;
3616 *os2_name++ = 0;
3618 while (isspace(*nt_name))
3619 nt_name++;
3621 if (!*nt_name || strchr("#;",*nt_name))
3622 continue;
3625 int l = strlen(nt_name);
3626 while (l && isspace(nt_name[l-1])) {
3627 nt_name[l-1] = 0;
3628 l--;
3632 while (isspace(*os2_name))
3633 os2_name++;
3636 int l = strlen(os2_name);
3637 while (l && isspace(os2_name[l-1])) {
3638 os2_name[l-1] = 0;
3639 l--;
3643 if (strequal(nt_name,drivername)) {
3644 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3645 fstrcpy(last_from,drivername);
3646 fstrcpy(last_to,os2_name);
3647 fstrcpy(drivername,os2_name);
3648 file_lines_free(lines);
3649 return;
3653 file_lines_free(lines);
3656 /****************************************************************************
3657 Get a default printer info 2 struct.
3658 ****************************************************************************/
3659 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char* sharename)
3661 int snum;
3663 snum = lp_servicenumber(sharename);
3665 slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
3666 slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
3667 servername, sharename);
3668 fstrcpy(info->sharename, sharename);
3669 fstrcpy(info->portname, SAMBA_PRINTER_PORT_NAME);
3671 /* by setting the driver name to an empty string, a local NT admin
3672 can now run the **local** APW to install a local printer driver
3673 for a Samba shared printer in 2.2. Without this, drivers **must** be
3674 installed on the Samba server for NT clients --jerry */
3675 #if 0 /* JERRY --do not uncomment-- */
3676 if (!*info->drivername)
3677 fstrcpy(info->drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3678 #endif
3681 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info->drivername));
3683 pstrcpy(info->comment, "");
3684 fstrcpy(info->printprocessor, "winprint");
3685 fstrcpy(info->datatype, "RAW");
3687 info->attributes = PRINTER_ATTRIBUTE_SAMBA;
3689 info->starttime = 0; /* Minutes since 12:00am GMT */
3690 info->untiltime = 0; /* Minutes since 12:00am GMT */
3691 info->priority = 1;
3692 info->default_priority = 1;
3693 info->setuptime = (uint32)time(NULL);
3696 * I changed this as I think it is better to have a generic
3697 * DEVMODE than to crash Win2k explorer.exe --jerry
3698 * See the HP Deskjet 990c Win2k drivers for an example.
3700 * However the default devmode appears to cause problems
3701 * with the HP CLJ 8500 PCL driver. Hence the addition of
3702 * the "default devmode" parameter --jerry 22/01/2002
3705 if (lp_default_devmode(snum)) {
3706 if ((info->devmode = construct_nt_devicemode(info->printername)) == NULL) {
3707 goto fail;
3709 } else {
3710 info->devmode = NULL;
3713 if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
3714 goto fail;
3717 return WERR_OK;
3719 fail:
3720 if (info->devmode)
3721 free_nt_devicemode(&info->devmode);
3723 return WERR_ACCESS_DENIED;
3726 /****************************************************************************
3727 ****************************************************************************/
3728 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info, const char *servername, const char *sharename)
3730 int len = 0;
3731 int snum = lp_servicenumber(sharename);
3732 TDB_DATA kbuf, dbuf;
3733 fstring printername;
3734 char adevice[MAXDEVICENAME];
3736 kbuf = make_printer_tdbkey( sharename );
3738 dbuf = tdb_fetch(tdb_printers, kbuf);
3739 if (!dbuf.dptr) {
3740 return get_a_printer_2_default(info, servername, sharename);
3743 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3744 &info->attributes,
3745 &info->priority,
3746 &info->default_priority,
3747 &info->starttime,
3748 &info->untiltime,
3749 &info->status,
3750 &info->cjobs,
3751 &info->averageppm,
3752 &info->changeid,
3753 &info->c_setprinter,
3754 &info->setuptime,
3755 info->servername,
3756 info->printername,
3757 info->sharename,
3758 info->portname,
3759 info->drivername,
3760 info->comment,
3761 info->location,
3762 info->sepfile,
3763 info->printprocessor,
3764 info->datatype,
3765 info->parameters);
3767 /* Samba has to have shared raw drivers. */
3768 info->attributes |= PRINTER_ATTRIBUTE_SAMBA;
3769 info->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA;
3771 /* Restore the stripped strings. */
3772 slprintf(info->servername, sizeof(info->servername)-1, "\\\\%s", servername);
3774 if ( lp_force_printername(snum) ) {
3775 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, sharename );
3776 } else {
3777 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", servername, info->printername);
3780 fstrcpy(info->printername, printername);
3782 len += unpack_devicemode(&info->devmode,dbuf.dptr+len, dbuf.dsize-len);
3785 * Some client drivers freak out if there is a NULL devmode
3786 * (probably the driver is not checking before accessing
3787 * the devmode pointer) --jerry
3789 * See comments in get_a_printer_2_default()
3792 if (lp_default_devmode(snum) && !info->devmode) {
3793 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3794 printername));
3795 info->devmode = construct_nt_devicemode(printername);
3798 slprintf( adevice, sizeof(adevice), "%s", info->printername );
3799 if (info->devmode) {
3800 fstrcpy(info->devmode->devicename, adevice);
3803 if ( !(info->data = TALLOC_ZERO_P( info, NT_PRINTER_DATA )) ) {
3804 DEBUG(0,("unpack_values: talloc() failed!\n"));
3805 SAFE_FREE(dbuf.dptr);
3806 return WERR_NOMEM;
3808 len += unpack_values( info->data, dbuf.dptr+len, dbuf.dsize-len );
3810 /* This will get the current RPC talloc context, but we should be
3811 passing this as a parameter... fixme... JRA ! */
3813 if (!nt_printing_getsec(info, sharename, &info->secdesc_buf)) {
3814 SAFE_FREE(dbuf.dptr);
3815 return WERR_NOMEM;
3818 /* Fix for OS/2 drivers. */
3820 if (get_remote_arch() == RA_OS2) {
3821 map_to_os2_driver(info->drivername);
3824 SAFE_FREE(dbuf.dptr);
3826 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3827 sharename, info->printername, info->drivername));
3829 return WERR_OK;
3832 /****************************************************************************
3833 Debugging function, dump at level 6 the struct in the logs.
3834 ****************************************************************************/
3835 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3837 uint32 result;
3838 NT_PRINTER_INFO_LEVEL_2 *info2;
3840 DEBUG(106,("Dumping printer at level [%d]\n", level));
3842 switch (level) {
3843 case 2:
3845 if (printer->info_2 == NULL)
3846 result=5;
3847 else
3849 info2=printer->info_2;
3851 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3852 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3853 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3854 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3855 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3856 DEBUGADD(106,("status:[%d]\n", info2->status));
3857 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3858 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3859 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3860 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3861 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3863 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3864 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3865 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3866 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3867 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3868 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3869 DEBUGADD(106,("location:[%s]\n", info2->location));
3870 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3871 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3872 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3873 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3874 result=0;
3876 break;
3878 default:
3879 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3880 result=1;
3881 break;
3884 return result;
3887 /****************************************************************************
3888 Update the changeid time.
3889 This is SO NASTY as some drivers need this to change, others need it
3890 static. This value will change every second, and I must hope that this
3891 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3892 UTAH ! JRA.
3893 ****************************************************************************/
3895 static uint32 rev_changeid(void)
3897 struct timeval tv;
3899 get_process_uptime(&tv);
3901 #if 1 /* JERRY */
3902 /* Return changeid as msec since spooler restart */
3903 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3904 #else
3906 * This setting seems to work well but is too untested
3907 * to replace the above calculation. Left in for experiementation
3908 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3910 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3911 #endif
3916 * The function below are the high level ones.
3917 * only those ones must be called from the spoolss code.
3918 * JFM.
3921 /****************************************************************************
3922 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3923 ****************************************************************************/
3925 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3927 WERROR result;
3929 dump_a_printer(printer, level);
3931 switch (level) {
3932 case 2:
3935 * Update the changestamp. Emperical tests show that the
3936 * ChangeID is always updated,but c_setprinter is
3937 * global spooler variable (not per printer).
3940 /* ChangeID **must** be increasing over the lifetime
3941 of client's spoolss service in order for the
3942 client's cache to show updates */
3944 printer->info_2->changeid = rev_changeid();
3947 * Because one day someone will ask:
3948 * NT->NT An admin connection to a remote
3949 * printer show changes imeediately in
3950 * the properities dialog
3952 * A non-admin connection will only show the
3953 * changes after viewing the properites page
3954 * 2 times. Seems to be related to a
3955 * race condition in the client between the spooler
3956 * updating the local cache and the Explorer.exe GUI
3957 * actually displaying the properties.
3959 * This is fixed in Win2k. admin/non-admin
3960 * connections both display changes immediately.
3962 * 14/12/01 --jerry
3965 result=update_a_printer_2(printer->info_2);
3967 break;
3969 default:
3970 result=WERR_UNKNOWN_LEVEL;
3971 break;
3974 return result;
3977 /****************************************************************************
3978 Initialize printer devmode & data with previously saved driver init values.
3979 ****************************************************************************/
3981 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3983 int len = 0;
3984 pstring key;
3985 TDB_DATA kbuf, dbuf;
3986 NT_PRINTER_INFO_LEVEL_2 info;
3989 ZERO_STRUCT(info);
3992 * Delete any printer data 'values' already set. When called for driver
3993 * replace, there will generally be some, but during an add printer, there
3994 * should not be any (if there are delete them).
3997 if ( info_ptr->data )
3998 delete_all_printer_data( info_ptr, "" );
4000 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
4002 kbuf.dptr = key;
4003 kbuf.dsize = strlen(key)+1;
4005 dbuf = tdb_fetch(tdb_drivers, kbuf);
4006 if (!dbuf.dptr) {
4008 * When changing to a driver that has no init info in the tdb, remove
4009 * the previous drivers init info and leave the new on blank.
4011 free_nt_devicemode(&info_ptr->devmode);
4012 return False;
4016 * Get the saved DEVMODE..
4019 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
4022 * The saved DEVMODE contains the devicename from the printer used during
4023 * the initialization save. Change it to reflect the new printer.
4026 if ( info.devmode ) {
4027 ZERO_STRUCT(info.devmode->devicename);
4028 fstrcpy(info.devmode->devicename, info_ptr->printername);
4032 * NT/2k does not change out the entire DeviceMode of a printer
4033 * when changing the driver. Only the driverextra, private, &
4034 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
4036 * Later examination revealed that Windows NT/2k does reset the
4037 * the printer's device mode, bit **only** when you change a
4038 * property of the device mode such as the page orientation.
4039 * --jerry
4043 /* Bind the saved DEVMODE to the new the printer */
4045 free_nt_devicemode(&info_ptr->devmode);
4046 info_ptr->devmode = info.devmode;
4048 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
4049 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
4051 /* Add the printer data 'values' to the new printer */
4053 if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) {
4054 DEBUG(0,("set_driver_init_2: talloc() failed!\n"));
4055 return False;
4058 len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
4061 SAFE_FREE(dbuf.dptr);
4063 return True;
4066 /****************************************************************************
4067 Initialize printer devmode & data with previously saved driver init values.
4068 When a printer is created using AddPrinter, the drivername bound to the
4069 printer is used to lookup previously saved driver initialization info, which
4070 is bound to the new printer.
4071 ****************************************************************************/
4073 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
4075 BOOL result = False;
4077 switch (level) {
4078 case 2:
4079 result = set_driver_init_2(printer->info_2);
4080 break;
4082 default:
4083 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
4084 level));
4085 break;
4088 return result;
4091 /****************************************************************************
4092 Delete driver init data stored for a specified driver
4093 ****************************************************************************/
4095 BOOL del_driver_init(char *drivername)
4097 pstring key;
4098 TDB_DATA kbuf;
4100 if (!drivername || !*drivername) {
4101 DEBUG(3,("del_driver_init: No drivername specified!\n"));
4102 return False;
4105 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
4107 kbuf.dptr = key;
4108 kbuf.dsize = strlen(key)+1;
4110 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
4112 return (tdb_delete(tdb_drivers, kbuf) == 0);
4115 /****************************************************************************
4116 Pack up the DEVMODE and values for a printer into a 'driver init' entry
4117 in the tdb. Note: this is different from the driver entry and the printer
4118 entry. There should be a single driver init entry for each driver regardless
4119 of whether it was installed from NT or 2K. Technically, they should be
4120 different, but they work out to the same struct.
4121 ****************************************************************************/
4123 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
4125 pstring key;
4126 char *buf;
4127 int buflen, len, ret;
4128 TDB_DATA kbuf, dbuf;
4130 buf = NULL;
4131 buflen = 0;
4133 again:
4134 len = 0;
4135 len += pack_devicemode(info->devmode, buf+len, buflen-len);
4137 len += pack_values( info->data, buf+len, buflen-len );
4139 if (buflen < len) {
4140 buf = (char *)SMB_REALLOC(buf, len);
4141 if (!buf) {
4142 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
4143 ret = -1;
4144 goto done;
4146 buflen = len;
4147 goto again;
4150 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
4152 kbuf.dptr = key;
4153 kbuf.dsize = strlen(key)+1;
4154 dbuf.dptr = buf;
4155 dbuf.dsize = len;
4157 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
4159 done:
4160 if (ret == -1)
4161 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
4163 SAFE_FREE(buf);
4165 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
4166 info->sharename, info->drivername));
4168 return ret;
4171 /****************************************************************************
4172 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
4173 ****************************************************************************/
4175 static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
4177 uint32 result;
4179 dump_a_printer(printer, level);
4181 switch (level) {
4182 case 2:
4183 result = update_driver_init_2(printer->info_2);
4184 break;
4185 default:
4186 result = 1;
4187 break;
4190 return result;
4193 /****************************************************************************
4194 Convert the printer data value, a REG_BINARY array, into an initialization
4195 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
4196 got to keep the endians happy :).
4197 ****************************************************************************/
4199 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
4201 BOOL result = False;
4202 prs_struct ps;
4203 DEVICEMODE devmode;
4205 ZERO_STRUCT(devmode);
4207 prs_init(&ps, 0, ctx, UNMARSHALL);
4208 ps.data_p = (char *)data;
4209 ps.buffer_size = data_len;
4211 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
4212 result = convert_devicemode("", &devmode, &nt_devmode);
4213 else
4214 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
4216 return result;
4219 /****************************************************************************
4220 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
4222 1. Use the driver's config DLL to this UNC printername and:
4223 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
4224 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
4225 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
4227 The last step triggers saving the "driver initialization" information for
4228 this printer into the tdb. Later, new printers that use this driver will
4229 have this initialization information bound to them. This simulates the
4230 driver initialization, as if it had run on the Samba server (as it would
4231 have done on NT).
4233 The Win32 client side code requirement sucks! But until we can run arbitrary
4234 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
4236 It would have been easier to use SetPrinter because all the UNMARSHALLING of
4237 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
4238 about it and you will realize why. JRR 010720
4239 ****************************************************************************/
4241 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
4243 WERROR status = WERR_OK;
4244 TALLOC_CTX *ctx = NULL;
4245 NT_DEVICEMODE *nt_devmode = NULL;
4246 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
4249 * When the DEVMODE is already set on the printer, don't try to unpack it.
4251 DEBUG(8,("save_driver_init_2: Enter...\n"));
4253 if ( !printer->info_2->devmode && data_len ) {
4255 * Set devmode on printer info, so entire printer initialization can be
4256 * saved to tdb.
4259 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
4260 return WERR_NOMEM;
4262 if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
4263 status = WERR_NOMEM;
4264 goto done;
4267 ZERO_STRUCTP(nt_devmode);
4270 * The DEVMODE is held in the 'data' component of the param in raw binary.
4271 * Convert it to to a devmode structure
4273 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
4274 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
4275 status = WERR_INVALID_PARAM;
4276 goto done;
4279 printer->info_2->devmode = nt_devmode;
4283 * Pack up and add (or update) the DEVMODE and any current printer data to
4284 * a 'driver init' element in the tdb
4288 if ( update_driver_init(printer, 2) != 0 ) {
4289 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
4290 status = WERR_NOMEM;
4291 goto done;
4295 * If driver initialization info was successfully saved, set the current
4296 * printer to match it. This allows initialization of the current printer
4297 * as well as the driver.
4299 status = mod_a_printer(printer, 2);
4300 if (!W_ERROR_IS_OK(status)) {
4301 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
4302 printer->info_2->printername));
4305 done:
4306 talloc_destroy(ctx);
4307 free_nt_devicemode( &nt_devmode );
4309 printer->info_2->devmode = tmp_devmode;
4311 return status;
4314 /****************************************************************************
4315 Update the driver init info (DEVMODE and specifics) for a printer
4316 ****************************************************************************/
4318 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
4320 WERROR status = WERR_OK;
4322 switch (level) {
4323 case 2:
4324 status = save_driver_init_2( printer, data, data_len );
4325 break;
4326 default:
4327 status = WERR_UNKNOWN_LEVEL;
4328 break;
4331 return status;
4334 /****************************************************************************
4335 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
4337 Previously the code had a memory allocation problem because it always
4338 used the TALLOC_CTX from the Printer_entry*. This context lasts
4339 as a long as the original handle is open. So if the client made a lot
4340 of getprinter[data]() calls, the memory usage would climb. Now we use
4341 a short lived TALLOC_CTX for printer_info_2 objects returned. We
4342 still use the Printer_entry->ctx for maintaining the cache copy though
4343 since that object must live as long as the handle by definition.
4344 --jerry
4346 ****************************************************************************/
4348 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
4349 const char *sharename)
4351 WERROR result;
4352 fstring servername;
4354 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
4356 if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
4357 DEBUG(0,("get_a_printer: talloc() fail.\n"));
4358 return WERR_NOMEM;
4361 switch (level) {
4362 case 2:
4363 if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
4364 DEBUG(0,("get_a_printer: talloc() fail.\n"));
4365 TALLOC_FREE( *pp_printer );
4366 return WERR_NOMEM;
4369 if ( print_hnd )
4370 fstrcpy( servername, print_hnd->servername );
4371 else {
4372 fstrcpy( servername, "%L" );
4373 standard_sub_basic( "", "", servername,
4374 sizeof(servername)-1 );
4377 result = get_a_printer_2( (*pp_printer)->info_2, servername, sharename );
4380 /* we have a new printer now. Save it with this handle */
4382 if ( !W_ERROR_IS_OK(result) ) {
4383 TALLOC_FREE( *pp_printer );
4384 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n",
4385 sharename, (unsigned int)level, dos_errstr(result)));
4386 return result;
4389 dump_a_printer( *pp_printer, level);
4391 break;
4393 default:
4394 TALLOC_FREE( *pp_printer );
4395 return WERR_UNKNOWN_LEVEL;
4398 return WERR_OK;
4401 /****************************************************************************
4402 Deletes a NT_PRINTER_INFO_LEVEL struct.
4403 ****************************************************************************/
4405 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
4407 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
4409 if ( !printer )
4410 return 0;
4412 switch (level) {
4413 case 2:
4414 if ( printer->info_2 )
4415 free_nt_printer_info_level_2(&printer->info_2);
4416 break;
4418 default:
4419 DEBUG(0,("free_a_printer: unknown level! [%d]\n", level ));
4420 return 1;
4423 TALLOC_FREE(*pp_printer);
4425 return 0;
4428 /****************************************************************************
4429 ****************************************************************************/
4430 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4432 uint32 result;
4433 DEBUG(104,("adding a printer at level [%d]\n", level));
4434 dump_a_printer_driver(driver, level);
4436 switch (level) {
4437 case 3:
4438 result=add_a_printer_driver_3(driver.info_3);
4439 break;
4441 case 6:
4442 result=add_a_printer_driver_6(driver.info_6);
4443 break;
4445 default:
4446 result=1;
4447 break;
4450 return result;
4452 /****************************************************************************
4453 ****************************************************************************/
4455 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4456 fstring drivername, const char *architecture, uint32 version)
4458 WERROR result;
4460 switch (level) {
4461 case 3:
4462 /* Sometime we just want any version of the driver */
4464 if ( version == DRIVER_ANY_VERSION ) {
4465 /* look for Win2k first and then for NT4 */
4466 result = get_a_printer_driver_3(&driver->info_3, drivername,
4467 architecture, 3);
4469 if ( !W_ERROR_IS_OK(result) ) {
4470 result = get_a_printer_driver_3( &driver->info_3,
4471 drivername, architecture, 2 );
4473 } else {
4474 result = get_a_printer_driver_3(&driver->info_3, drivername,
4475 architecture, version);
4477 break;
4479 default:
4480 result=W_ERROR(1);
4481 break;
4484 if (W_ERROR_IS_OK(result))
4485 dump_a_printer_driver(*driver, level);
4487 return result;
4490 /****************************************************************************
4491 ****************************************************************************/
4492 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4494 uint32 result;
4496 switch (level) {
4497 case 3:
4499 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4500 if (driver.info_3 != NULL)
4502 info3=driver.info_3;
4503 SAFE_FREE(info3->dependentfiles);
4504 ZERO_STRUCTP(info3);
4505 SAFE_FREE(info3);
4506 result=0;
4507 } else {
4508 result=4;
4510 break;
4512 case 6:
4514 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4515 if (driver.info_6 != NULL) {
4516 info6=driver.info_6;
4517 SAFE_FREE(info6->dependentfiles);
4518 SAFE_FREE(info6->previousnames);
4519 ZERO_STRUCTP(info6);
4520 SAFE_FREE(info6);
4521 result=0;
4522 } else {
4523 result=4;
4525 break;
4527 default:
4528 result=1;
4529 break;
4531 return result;
4535 /****************************************************************************
4536 Determine whether or not a particular driver is currently assigned
4537 to a printer
4538 ****************************************************************************/
4540 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4542 int snum;
4543 int n_services = lp_numservices();
4544 NT_PRINTER_INFO_LEVEL *printer = NULL;
4545 BOOL in_use = False;
4547 if ( !info_3 )
4548 return False;
4550 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4552 /* loop through the printers.tdb and check for the drivername */
4554 for (snum=0; snum<n_services && !in_use; snum++) {
4555 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4556 continue;
4558 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4559 continue;
4561 if ( strequal(info_3->name, printer->info_2->drivername) )
4562 in_use = True;
4564 free_a_printer( &printer, 2 );
4567 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4569 if ( in_use ) {
4570 NT_PRINTER_DRIVER_INFO_LEVEL d;
4571 WERROR werr;
4573 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
4575 /* we can still remove the driver if there is one of
4576 "Windows NT x86" version 2 or 3 left */
4578 if ( !strequal( "Windows NT x86", info_3->environment ) ) {
4579 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );
4581 else {
4582 switch ( info_3->cversion ) {
4583 case 2:
4584 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
4585 break;
4586 case 3:
4587 werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
4588 break;
4589 default:
4590 DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n",
4591 info_3->cversion));
4592 werr = WERR_UNKNOWN_PRINTER_DRIVER;
4593 break;
4597 /* now check the error code */
4599 if ( W_ERROR_IS_OK(werr) ) {
4600 /* it's ok to remove the driver, we have other architctures left */
4601 in_use = False;
4602 free_a_printer_driver( d, 3 );
4606 /* report that the driver is not in use by default */
4608 return in_use;
4612 /**********************************************************************
4613 Check to see if a ogiven file is in use by *info
4614 *********************************************************************/
4616 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4618 int i = 0;
4620 if ( !info )
4621 return False;
4623 if ( strequal(file, info->driverpath) )
4624 return True;
4626 if ( strequal(file, info->datafile) )
4627 return True;
4629 if ( strequal(file, info->configfile) )
4630 return True;
4632 if ( strequal(file, info->helpfile) )
4633 return True;
4635 /* see of there are any dependent files to examine */
4637 if ( !info->dependentfiles )
4638 return False;
4640 while ( *info->dependentfiles[i] ) {
4641 if ( strequal(file, info->dependentfiles[i]) )
4642 return True;
4643 i++;
4646 return False;
4650 /**********************************************************************
4651 Utility function to remove the dependent file pointed to by the
4652 input parameter from the list
4653 *********************************************************************/
4655 static void trim_dependent_file( fstring files[], int idx )
4658 /* bump everything down a slot */
4660 while( *files[idx+1] ) {
4661 fstrcpy( files[idx], files[idx+1] );
4662 idx++;
4665 *files[idx] = '\0';
4667 return;
4670 /**********************************************************************
4671 Check if any of the files used by src are also used by drv
4672 *********************************************************************/
4674 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4675 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4677 BOOL in_use = False;
4678 int i = 0;
4680 if ( !src || !drv )
4681 return False;
4683 /* check each file. Remove it from the src structure if it overlaps */
4685 if ( drv_file_in_use(src->driverpath, drv) ) {
4686 in_use = True;
4687 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4688 fstrcpy( src->driverpath, "" );
4691 if ( drv_file_in_use(src->datafile, drv) ) {
4692 in_use = True;
4693 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4694 fstrcpy( src->datafile, "" );
4697 if ( drv_file_in_use(src->configfile, drv) ) {
4698 in_use = True;
4699 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4700 fstrcpy( src->configfile, "" );
4703 if ( drv_file_in_use(src->helpfile, drv) ) {
4704 in_use = True;
4705 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4706 fstrcpy( src->helpfile, "" );
4709 /* are there any dependentfiles to examine? */
4711 if ( !src->dependentfiles )
4712 return in_use;
4714 while ( *src->dependentfiles[i] ) {
4715 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4716 in_use = True;
4717 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4718 trim_dependent_file( src->dependentfiles, i );
4719 } else
4720 i++;
4723 return in_use;
4726 /****************************************************************************
4727 Determine whether or not a particular driver files are currently being
4728 used by any other driver.
4730 Return value is True if any files were in use by other drivers
4731 and False otherwise.
4733 Upon return, *info has been modified to only contain the driver files
4734 which are not in use
4735 ****************************************************************************/
4737 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4739 int i;
4740 int ndrivers;
4741 uint32 version;
4742 fstring *list = NULL;
4743 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4745 if ( !info )
4746 return False;
4748 version = info->cversion;
4750 /* loop over all driver versions */
4752 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4754 /* get the list of drivers */
4756 list = NULL;
4757 ndrivers = get_ntdrivers(&list, info->environment, version);
4759 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4760 ndrivers, info->environment, version));
4762 /* check each driver for overlap in files */
4764 for (i=0; i<ndrivers; i++) {
4765 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4767 ZERO_STRUCT(driver);
4769 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4770 SAFE_FREE(list);
4771 return True;
4774 /* check if d2 uses any files from d1 */
4775 /* only if this is a different driver than the one being deleted */
4777 if ( !strequal(info->name, driver.info_3->name) ) {
4778 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4779 free_a_printer_driver(driver, 3);
4780 SAFE_FREE( list );
4781 return True;
4785 free_a_printer_driver(driver, 3);
4788 SAFE_FREE(list);
4790 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4792 driver.info_3 = info;
4794 if ( DEBUGLEVEL >= 20 )
4795 dump_a_printer_driver( driver, 3 );
4797 return False;
4800 /****************************************************************************
4801 Actually delete the driver files. Make sure that
4802 printer_driver_files_in_use() return False before calling
4803 this.
4804 ****************************************************************************/
4806 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4808 int i = 0;
4809 char *s;
4810 pstring file;
4811 connection_struct *conn;
4812 DATA_BLOB null_pw;
4813 NTSTATUS nt_status;
4814 fstring res_type;
4815 BOOL bad_path;
4816 SMB_STRUCT_STAT st;
4818 if ( !info_3 )
4819 return False;
4821 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4824 * Connect to the print$ share under the same account as the
4825 * user connected to the rpc pipe. Note we must be root to
4826 * do this.
4829 null_pw = data_blob( NULL, 0 );
4830 fstrcpy(res_type, "A:");
4831 become_root();
4832 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4833 unbecome_root();
4835 if ( !conn ) {
4836 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4837 return False;
4840 if ( !CAN_WRITE(conn) ) {
4841 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
4842 return False;
4845 /* Save who we are - we are temporarily becoming the connection user. */
4847 if ( !become_user(conn, conn->vuid) ) {
4848 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4849 return False;
4852 /* now delete the files; must strip the '\print$' string from
4853 fron of path */
4855 if ( *info_3->driverpath ) {
4856 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4857 pstrcpy( file, s );
4858 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4859 DEBUG(10,("deleting driverfile [%s]\n", s));
4860 unlink_internals(conn, 0, file, False);
4864 if ( *info_3->configfile ) {
4865 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4866 pstrcpy( file, s );
4867 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4868 DEBUG(10,("deleting configfile [%s]\n", s));
4869 unlink_internals(conn, 0, file, False);
4873 if ( *info_3->datafile ) {
4874 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4875 pstrcpy( file, s );
4876 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4877 DEBUG(10,("deleting datafile [%s]\n", s));
4878 unlink_internals(conn, 0, file, False);
4882 if ( *info_3->helpfile ) {
4883 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4884 pstrcpy( file, s );
4885 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4886 DEBUG(10,("deleting helpfile [%s]\n", s));
4887 unlink_internals(conn, 0, file, False);
4891 /* check if we are done removing files */
4893 if ( info_3->dependentfiles ) {
4894 while ( info_3->dependentfiles[i][0] ) {
4895 char *p;
4897 /* bypass the "\print$" portion of the path */
4899 if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4900 pstrcpy( file, p );
4901 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4902 DEBUG(10,("deleting dependent file [%s]\n", file));
4903 unlink_internals(conn, 0, file, False);
4906 i++;
4910 unbecome_user();
4912 return True;
4915 /****************************************************************************
4916 Remove a printer driver from the TDB. This assumes that the the driver was
4917 previously looked up.
4918 ***************************************************************************/
4920 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4921 uint32 version, BOOL delete_files )
4923 pstring key;
4924 const char *arch;
4925 TDB_DATA kbuf, dbuf;
4926 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4928 /* delete the tdb data first */
4930 arch = get_short_archi(info_3->environment);
4931 if (!arch) {
4932 return WERR_UNKNOWN_PRINTER_DRIVER;
4934 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4935 arch, version, info_3->name);
4937 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4938 key, delete_files ? "TRUE" : "FALSE" ));
4940 ctr.info_3 = info_3;
4941 dump_a_printer_driver( ctr, 3 );
4943 kbuf.dptr=key;
4944 kbuf.dsize=strlen(key)+1;
4946 /* check if the driver actually exists for this environment */
4948 dbuf = tdb_fetch( tdb_drivers, kbuf );
4949 if ( !dbuf.dptr ) {
4950 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4951 return WERR_UNKNOWN_PRINTER_DRIVER;
4954 SAFE_FREE( dbuf.dptr );
4956 /* ok... the driver exists so the delete should return success */
4958 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4959 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4960 return WERR_ACCESS_DENIED;
4964 * now delete any associated files if delete_files == True
4965 * even if this part failes, we return succes because the
4966 * driver doesn not exist any more
4969 if ( delete_files )
4970 delete_driver_files( info_3, user );
4973 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4975 return WERR_OK;
4978 /****************************************************************************
4979 Store a security desc for a printer.
4980 ****************************************************************************/
4982 WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
4984 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4985 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4986 prs_struct ps;
4987 TALLOC_CTX *mem_ctx = NULL;
4988 char *key;
4989 WERROR status;
4991 mem_ctx = talloc_init("nt_printing_setsec");
4992 if (mem_ctx == NULL)
4993 return WERR_NOMEM;
4995 /* The old owner and group sids of the security descriptor are not
4996 present when new ACEs are added or removed by changing printer
4997 permissions through NT. If they are NULL in the new security
4998 descriptor then copy them over from the old one. */
5000 if (!secdesc_ctr->sd->owner_sid || !secdesc_ctr->sd->group_sid) {
5001 DOM_SID *owner_sid, *group_sid;
5002 SEC_ACL *dacl, *sacl;
5003 SEC_DESC *psd = NULL;
5004 size_t size;
5006 if (!nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr)) {
5007 status = WERR_NOMEM;
5008 goto out;
5011 /* Pick out correct owner and group sids */
5013 owner_sid = secdesc_ctr->sd->owner_sid ?
5014 secdesc_ctr->sd->owner_sid :
5015 old_secdesc_ctr->sd->owner_sid;
5017 group_sid = secdesc_ctr->sd->group_sid ?
5018 secdesc_ctr->sd->group_sid :
5019 old_secdesc_ctr->sd->group_sid;
5021 dacl = secdesc_ctr->sd->dacl ?
5022 secdesc_ctr->sd->dacl :
5023 old_secdesc_ctr->sd->dacl;
5025 sacl = secdesc_ctr->sd->sacl ?
5026 secdesc_ctr->sd->sacl :
5027 old_secdesc_ctr->sd->sacl;
5029 /* Make a deep copy of the security descriptor */
5031 psd = make_sec_desc(mem_ctx, secdesc_ctr->sd->revision, secdesc_ctr->sd->type,
5032 owner_sid, group_sid,
5033 sacl,
5034 dacl,
5035 &size);
5037 if (!psd) {
5038 status = WERR_NOMEM;
5039 goto out;
5042 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
5045 if (!new_secdesc_ctr) {
5046 new_secdesc_ctr = secdesc_ctr;
5049 /* Store the security descriptor in a tdb */
5051 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sd) +
5052 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
5054 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
5055 &ps, 1)) {
5056 status = WERR_BADFUNC;
5057 goto out;
5060 key = make_printers_secdesc_tdbkey( sharename );
5062 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
5063 status = WERR_OK;
5064 } else {
5065 DEBUG(1,("Failed to store secdesc for %s\n", sharename));
5066 status = WERR_BADFUNC;
5069 /* Free malloc'ed memory */
5071 out:
5073 prs_mem_free(&ps);
5074 if (mem_ctx)
5075 talloc_destroy(mem_ctx);
5076 return status;
5079 /****************************************************************************
5080 Construct a default security descriptor buffer for a printer.
5081 ****************************************************************************/
5083 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
5085 SEC_ACE ace[5]; /* max number of ace entries */
5086 int i = 0;
5087 SEC_ACCESS sa;
5088 SEC_ACL *psa = NULL;
5089 SEC_DESC_BUF *sdb = NULL;
5090 SEC_DESC *psd = NULL;
5091 DOM_SID adm_sid;
5092 size_t sd_size;
5094 /* Create an ACE where Everyone is allowed to print */
5096 init_sec_access(&sa, PRINTER_ACE_PRINT);
5097 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
5098 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5100 /* Add the domain admins group if we are a DC */
5102 if ( IS_DC ) {
5103 DOM_SID domadmins_sid;
5105 sid_copy(&domadmins_sid, get_global_sam_sid());
5106 sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
5108 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5109 init_sec_ace(&ace[i++], &domadmins_sid,
5110 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5111 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5112 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5113 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5115 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
5116 sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
5118 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5119 init_sec_ace(&ace[i++], &adm_sid,
5120 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5121 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5122 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
5123 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5126 /* add BUILTIN\Administrators as FULL CONTROL */
5128 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
5129 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5130 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
5131 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
5132 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
5133 SEC_ACE_TYPE_ACCESS_ALLOWED,
5134 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
5136 /* Make the security descriptor owned by the BUILTIN\Administrators */
5138 /* The ACL revision number in rpc_secdesc.h differs from the one
5139 created by NT when setting ACE entries in printer
5140 descriptors. NT4 complains about the property being edited by a
5141 NT5 machine. */
5143 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
5144 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
5145 &global_sid_Builtin_Administrators,
5146 &global_sid_Builtin_Administrators,
5147 NULL, psa, &sd_size);
5150 if (!psd) {
5151 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
5152 return NULL;
5155 sdb = make_sec_desc_buf(ctx, sd_size, psd);
5157 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
5158 (unsigned int)sd_size));
5160 return sdb;
5163 /****************************************************************************
5164 Get a security desc for a printer.
5165 ****************************************************************************/
5167 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
5169 prs_struct ps;
5170 char *key;
5171 char *temp;
5173 if (strlen(sharename) > 2 && (temp = strchr(sharename + 2, '\\'))) {
5174 sharename = temp + 1;
5177 ZERO_STRUCT(ps);
5179 /* Fetch security descriptor from tdb */
5181 key = make_printers_secdesc_tdbkey( sharename );
5183 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
5184 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
5186 prs_mem_free(&ps);
5188 DEBUG(4,("using default secdesc for %s\n", sharename));
5190 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
5191 return False;
5194 /* Save default security descriptor for later */
5196 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sd) +
5197 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
5199 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
5200 tdb_prs_store(tdb_printers, key, &ps);
5203 prs_mem_free(&ps);
5205 return True;
5208 prs_mem_free(&ps);
5210 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
5211 this security descriptor has been created when winbindd was
5212 down. Take ownership of security descriptor. */
5214 if (sid_equal((*secdesc_ctr)->sd->owner_sid, &global_sid_World)) {
5215 DOM_SID owner_sid;
5217 /* Change sd owner to workgroup administrator */
5219 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
5220 SEC_DESC_BUF *new_secdesc_ctr = NULL;
5221 SEC_DESC *psd = NULL;
5222 size_t size;
5224 /* Create new sd */
5226 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
5228 psd = make_sec_desc(ctx, (*secdesc_ctr)->sd->revision, (*secdesc_ctr)->sd->type,
5229 &owner_sid,
5230 (*secdesc_ctr)->sd->group_sid,
5231 (*secdesc_ctr)->sd->sacl,
5232 (*secdesc_ctr)->sd->dacl,
5233 &size);
5235 if (!psd) {
5236 return False;
5239 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
5240 if (!new_secdesc_ctr) {
5241 return False;
5244 /* Swap with other one */
5246 *secdesc_ctr = new_secdesc_ctr;
5248 /* Set it */
5250 nt_printing_setsec(sharename, *secdesc_ctr);
5254 if (DEBUGLEVEL >= 10) {
5255 SEC_ACL *the_acl = (*secdesc_ctr)->sd->dacl;
5256 int i;
5258 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
5259 sharename, the_acl->num_aces));
5261 for (i = 0; i < the_acl->num_aces; i++) {
5262 fstring sid_str;
5264 sid_to_string(sid_str, &the_acl->aces[i].trustee);
5266 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
5267 the_acl->aces[i].type, the_acl->aces[i].flags,
5268 the_acl->aces[i].access_mask));
5272 return True;
5275 /* error code:
5276 0: everything OK
5277 1: level not implemented
5278 2: file doesn't exist
5279 3: can't allocate memory
5280 4: can't free memory
5281 5: non existant struct
5285 A printer and a printer driver are 2 different things.
5286 NT manages them separatelly, Samba does the same.
5287 Why ? Simply because it's easier and it makes sense !
5289 Now explanation: You have 3 printers behind your samba server,
5290 2 of them are the same make and model (laser A and B). But laser B
5291 has an 3000 sheet feeder and laser A doesn't such an option.
5292 Your third printer is an old dot-matrix model for the accounting :-).
5294 If the /usr/local/samba/lib directory (default dir), you will have
5295 5 files to describe all of this.
5297 3 files for the printers (1 by printer):
5298 NTprinter_laser A
5299 NTprinter_laser B
5300 NTprinter_accounting
5301 2 files for the drivers (1 for the laser and 1 for the dot matrix)
5302 NTdriver_printer model X
5303 NTdriver_printer model Y
5305 jfm: I should use this comment for the text file to explain
5306 same thing for the forms BTW.
5307 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
5311 /* Convert generic access rights to printer object specific access rights.
5312 It turns out that NT4 security descriptors use generic access rights and
5313 NT5 the object specific ones. */
5315 void map_printer_permissions(SEC_DESC *sd)
5317 int i;
5319 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
5320 se_map_generic(&sd->dacl->aces[i].access_mask,
5321 &printer_generic_mapping);
5325 /****************************************************************************
5326 Check a user has permissions to perform the given operation. We use the
5327 permission constants defined in include/rpc_spoolss.h to check the various
5328 actions we perform when checking printer access.
5330 PRINTER_ACCESS_ADMINISTER:
5331 print_queue_pause, print_queue_resume, update_printer_sec,
5332 update_printer, spoolss_addprinterex_level_2,
5333 _spoolss_setprinterdata
5335 PRINTER_ACCESS_USE:
5336 print_job_start
5338 JOB_ACCESS_ADMINISTER:
5339 print_job_delete, print_job_pause, print_job_resume,
5340 print_queue_purge
5342 Try access control in the following order (for performance reasons):
5343 1) root ans SE_PRINT_OPERATOR can do anything (easy check)
5344 2) check security descriptor (bit comparisons in memory)
5345 3) "printer admins" (may result in numerous calls to winbind)
5347 ****************************************************************************/
5348 BOOL print_access_check(struct current_user *user, int snum, int access_type)
5350 SEC_DESC_BUF *secdesc = NULL;
5351 uint32 access_granted;
5352 NTSTATUS status;
5353 BOOL result;
5354 const char *pname;
5355 TALLOC_CTX *mem_ctx = NULL;
5356 SE_PRIV se_printop = SE_PRINT_OPERATOR;
5358 /* If user is NULL then use the current_user structure */
5360 if (!user)
5361 user = &current_user;
5363 /* Always allow root or SE_PRINT_OPERATROR to do anything */
5365 if ( user->ut.uid == 0 || user_has_privileges(user->nt_user_token, &se_printop ) ) {
5366 return True;
5369 /* Get printer name */
5371 pname = PRINTERNAME(snum);
5373 if (!pname || !*pname) {
5374 errno = EACCES;
5375 return False;
5378 /* Get printer security descriptor */
5380 if(!(mem_ctx = talloc_init("print_access_check"))) {
5381 errno = ENOMEM;
5382 return False;
5385 if (!nt_printing_getsec(mem_ctx, pname, &secdesc)) {
5386 talloc_destroy(mem_ctx);
5387 errno = ENOMEM;
5388 return False;
5391 if (access_type == JOB_ACCESS_ADMINISTER) {
5392 SEC_DESC_BUF *parent_secdesc = secdesc;
5394 /* Create a child security descriptor to check permissions
5395 against. This is because print jobs are child objects
5396 objects of a printer. */
5398 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sd, False);
5400 if (!secdesc) {
5401 talloc_destroy(mem_ctx);
5402 errno = ENOMEM;
5403 return False;
5406 /* Now this is the bit that really confuses me. The access
5407 type needs to be changed from JOB_ACCESS_ADMINISTER to
5408 PRINTER_ACCESS_ADMINISTER for this to work. Something
5409 to do with the child (job) object becoming like a
5410 printer?? -tpot */
5412 access_type = PRINTER_ACCESS_ADMINISTER;
5415 /* Check access */
5417 map_printer_permissions(secdesc->sd);
5419 result = se_access_check(secdesc->sd, user->nt_user_token, access_type,
5420 &access_granted, &status);
5422 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
5424 /* see if we need to try the printer admin list */
5426 if ((access_granted == 0) &&
5427 (token_contains_name_in_list(uidtoname(user->ut.uid), NULL,
5428 user->nt_user_token,
5429 lp_printer_admin(snum)))) {
5430 talloc_destroy(mem_ctx);
5431 return True;
5434 talloc_destroy(mem_ctx);
5436 if (!result) {
5437 errno = EACCES;
5440 return result;
5443 /****************************************************************************
5444 Check the time parameters allow a print operation.
5445 *****************************************************************************/
5447 BOOL print_time_access_check(const char *servicename)
5449 NT_PRINTER_INFO_LEVEL *printer = NULL;
5450 BOOL ok = False;
5451 time_t now = time(NULL);
5452 struct tm *t;
5453 uint32 mins;
5455 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
5456 return False;
5458 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
5459 ok = True;
5461 t = gmtime(&now);
5462 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
5464 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
5465 ok = True;
5467 free_a_printer(&printer, 2);
5469 if (!ok)
5470 errno = EACCES;
5472 return ok;
5475 /****************************************************************************
5476 Fill in the servername sent in the _spoolss_open_printer_ex() call
5477 ****************************************************************************/
5479 char* get_server_name( Printer_entry *printer )
5481 return printer->servername;