sync 3.0 into HEAD for the last time
[Samba.git] / source / printing / nt_printing.c
blob4859d785be68deb0967505f07b10234d6d0eab51
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2003.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 extern DOM_SID global_sid_World;
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 */
42 #define NTDRIVERS_DATABASE_VERSION NTDRIVERS_DATABASE_VERSION_3
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"
213 static const struct table_node archi_table[]= {
215 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
216 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
217 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
218 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
219 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
220 {NULL, "", -1 }
223 static BOOL upgrade_to_version_3(void)
225 TDB_DATA kbuf, newkey, dbuf;
227 DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
229 for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
230 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
232 dbuf = tdb_fetch(tdb_drivers, kbuf);
234 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
235 DEBUG(0,("upgrade_to_version_3:moving form\n"));
236 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
237 SAFE_FREE(dbuf.dptr);
238 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
239 return False;
241 if (tdb_delete(tdb_drivers, kbuf) != 0) {
242 SAFE_FREE(dbuf.dptr);
243 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
244 return False;
248 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
249 DEBUG(0,("upgrade_to_version_3:moving printer\n"));
250 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
251 SAFE_FREE(dbuf.dptr);
252 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
253 return False;
255 if (tdb_delete(tdb_drivers, kbuf) != 0) {
256 SAFE_FREE(dbuf.dptr);
257 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
258 return False;
262 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
263 DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
264 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
265 SAFE_FREE(dbuf.dptr);
266 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
267 return False;
269 if (tdb_delete(tdb_drivers, kbuf) != 0) {
270 SAFE_FREE(dbuf.dptr);
271 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
272 return False;
276 SAFE_FREE(dbuf.dptr);
279 return True;
282 /****************************************************************************
283 Open the NT printing tdbs. Done once before fork().
284 ****************************************************************************/
286 BOOL nt_printing_init(void)
288 static pid_t local_pid;
289 const char *vstring = "INFO/version";
291 if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
292 return True;
294 if (tdb_drivers)
295 tdb_close(tdb_drivers);
296 tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
297 if (!tdb_drivers) {
298 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
299 lock_path("ntdrivers.tdb"), strerror(errno) ));
300 return False;
303 if (tdb_printers)
304 tdb_close(tdb_printers);
305 tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
306 if (!tdb_printers) {
307 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
308 lock_path("ntprinters.tdb"), strerror(errno) ));
309 return False;
312 if (tdb_forms)
313 tdb_close(tdb_forms);
314 tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
315 if (!tdb_forms) {
316 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
317 lock_path("ntforms.tdb"), strerror(errno) ));
318 return False;
321 local_pid = sys_getpid();
323 /* handle a Samba upgrade */
324 tdb_lock_bystring(tdb_drivers, vstring, 0);
326 int32 vers_id;
328 /* Cope with byte-reversed older versions of the db. */
329 vers_id = tdb_fetch_int32(tdb_drivers, vstring);
330 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
331 /* Written on a bigendian machine with old fetch_int code. Save as le. */
332 /* The only upgrade between V2 and V3 is to save the version in little-endian. */
333 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
334 vers_id = NTDRIVERS_DATABASE_VERSION;
337 if (vers_id != NTDRIVERS_DATABASE_VERSION) {
339 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
340 if (!upgrade_to_version_3())
341 return False;
342 } else
343 tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL);
345 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
348 tdb_unlock_bystring(tdb_drivers, vstring);
350 update_c_setprinter(True);
353 * register callback to handle updating printers as new
354 * drivers are installed
357 message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
360 * register callback to handle updating printer data
361 * when a driver is initialized
364 message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
367 return True;
370 /*******************************************************************
371 tdb traversal function for counting printers.
372 ********************************************************************/
374 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
375 TDB_DATA data, void *context)
377 int *printer_count = (int*)context;
379 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
380 (*printer_count)++;
381 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
384 return 0;
387 /*******************************************************************
388 Update the spooler global c_setprinter. This variable is initialized
389 when the parent smbd starts with the number of existing printers. It
390 is monotonically increased by the current number of printers *after*
391 each add or delete printer RPC. Only Microsoft knows why... JRR020119
392 ********************************************************************/
394 uint32 update_c_setprinter(BOOL initialize)
396 int32 c_setprinter;
397 int32 printer_count = 0;
399 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0);
401 /* Traverse the tdb, counting the printers */
402 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
404 /* If initializing, set c_setprinter to current printers count
405 * otherwise, bump it by the current printer count
407 if (!initialize)
408 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
409 else
410 c_setprinter = printer_count;
412 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
413 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
415 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
417 return (uint32)c_setprinter;
420 /*******************************************************************
421 Get the spooler global c_setprinter, accounting for initialization.
422 ********************************************************************/
424 uint32 get_c_setprinter(void)
426 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
428 if (c_setprinter == (int32)-1)
429 c_setprinter = update_c_setprinter(True);
431 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
433 return (uint32)c_setprinter;
436 /****************************************************************************
437 Get builtin form struct list.
438 ****************************************************************************/
440 int get_builtin_ntforms(nt_forms_struct **list)
442 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
443 return sizeof(default_forms) / sizeof(default_forms[0]);
446 /****************************************************************************
447 get a builtin form struct
448 ****************************************************************************/
450 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
452 int i,count;
453 fstring form_name;
454 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
455 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
456 count = sizeof(default_forms) / sizeof(default_forms[0]);
457 for (i=0;i<count;i++) {
458 if (strequal(form_name,default_forms[i].name)) {
459 DEBUGADD(6,("Found builtin form %s \n", form_name));
460 memcpy(form,&default_forms[i],sizeof(*form));
461 break;
465 return (i !=count);
468 /****************************************************************************
469 get a form struct list
470 ****************************************************************************/
471 int get_ntforms(nt_forms_struct **list)
473 TDB_DATA kbuf, newkey, dbuf;
474 nt_forms_struct *tl;
475 nt_forms_struct form;
476 int ret;
477 int i;
478 int n = 0;
480 for (kbuf = tdb_firstkey(tdb_forms);
481 kbuf.dptr;
482 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
484 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
485 continue;
487 dbuf = tdb_fetch(tdb_forms, kbuf);
488 if (!dbuf.dptr)
489 continue;
491 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
492 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
493 &i, &form.flag, &form.width, &form.length, &form.left,
494 &form.top, &form.right, &form.bottom);
495 SAFE_FREE(dbuf.dptr);
496 if (ret != dbuf.dsize)
497 continue;
499 tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
500 if (!tl) {
501 DEBUG(0,("get_ntforms: Realloc fail.\n"));
502 return 0;
504 *list = tl;
505 (*list)[n] = form;
506 n++;
510 return n;
513 /****************************************************************************
514 write a form struct list
515 ****************************************************************************/
516 int write_ntforms(nt_forms_struct **list, int number)
518 pstring buf, key;
519 int len;
520 TDB_DATA kbuf,dbuf;
521 int i;
523 for (i=0;i<number;i++) {
524 /* save index, so list is rebuilt in correct order */
525 len = tdb_pack(buf, sizeof(buf), "dddddddd",
526 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
527 (*list)[i].left, (*list)[i].top, (*list)[i].right,
528 (*list)[i].bottom);
529 if (len > sizeof(buf)) break;
530 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
531 kbuf.dsize = strlen(key)+1;
532 kbuf.dptr = key;
533 dbuf.dsize = len;
534 dbuf.dptr = buf;
535 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
538 return i;
541 /****************************************************************************
542 add a form struct at the end of the list
543 ****************************************************************************/
544 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
546 int n=0;
547 BOOL update;
548 fstring form_name;
549 nt_forms_struct *tl;
552 * NT tries to add forms even when
553 * they are already in the base
554 * only update the values if already present
557 update=False;
559 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
560 for (n=0; n<*count; n++) {
561 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
562 DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
563 update=True;
564 break;
568 if (update==False) {
569 if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
570 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
571 return False;
573 *list = tl;
574 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
575 (*count)++;
578 (*list)[n].flag=form->flags;
579 (*list)[n].width=form->size_x;
580 (*list)[n].length=form->size_y;
581 (*list)[n].left=form->left;
582 (*list)[n].top=form->top;
583 (*list)[n].right=form->right;
584 (*list)[n].bottom=form->bottom;
586 return True;
589 /****************************************************************************
590 Delete a named form struct.
591 ****************************************************************************/
593 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
595 pstring key;
596 TDB_DATA kbuf;
597 int n=0;
598 fstring form_name;
600 *ret = WERR_OK;
602 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
604 for (n=0; n<*count; n++) {
605 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
606 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
607 break;
611 if (n == *count) {
612 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
613 *ret = WERR_INVALID_PARAM;
614 return False;
617 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
618 kbuf.dsize = strlen(key)+1;
619 kbuf.dptr = key;
620 if (tdb_delete(tdb_forms, kbuf) != 0) {
621 *ret = WERR_NOMEM;
622 return False;
625 return True;
628 /****************************************************************************
629 Update a form struct.
630 ****************************************************************************/
632 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
634 int n=0;
635 fstring form_name;
636 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
638 DEBUG(106, ("[%s]\n", form_name));
639 for (n=0; n<count; n++) {
640 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
641 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
642 break;
645 if (n==count) return;
647 (*list)[n].flag=form->flags;
648 (*list)[n].width=form->size_x;
649 (*list)[n].length=form->size_y;
650 (*list)[n].left=form->left;
651 (*list)[n].top=form->top;
652 (*list)[n].right=form->right;
653 (*list)[n].bottom=form->bottom;
656 /****************************************************************************
657 Get the nt drivers list.
658 Traverse the database and look-up the matching names.
659 ****************************************************************************/
660 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
662 int total=0;
663 const char *short_archi;
664 fstring *fl;
665 pstring key;
666 TDB_DATA kbuf, newkey;
668 short_archi = get_short_archi(architecture);
669 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
671 for (kbuf = tdb_firstkey(tdb_drivers);
672 kbuf.dptr;
673 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
675 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
676 continue;
678 if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
679 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
680 return -1;
682 else *list = fl;
684 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
685 total++;
688 return(total);
691 /****************************************************************************
692 function to do the mapping between the long architecture name and
693 the short one.
694 ****************************************************************************/
695 const char *get_short_archi(const char *long_archi)
697 int i=-1;
699 DEBUG(107,("Getting architecture dependant directory\n"));
700 do {
701 i++;
702 } while ( (archi_table[i].long_archi!=NULL ) &&
703 StrCaseCmp(long_archi, archi_table[i].long_archi) );
705 if (archi_table[i].long_archi==NULL) {
706 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
707 return NULL;
710 /* this might be client code - but shouldn't this be an fstrcpy etc? */
713 DEBUGADD(108,("index: [%d]\n", i));
714 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
715 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
717 return archi_table[i].short_archi;
720 /****************************************************************************
721 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
722 There are two case to be covered here: PE (Portable Executable) and NE (New
723 Executable) files. Both files support the same INFO structure, but PE files
724 store the signature in unicode, and NE files store it as !unicode.
725 returns -1 on error, 1 on version info found, and 0 on no version info found.
726 ****************************************************************************/
728 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
730 int i;
731 char *buf;
732 ssize_t byte_count;
734 if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
735 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
736 fname, PE_HEADER_SIZE));
737 goto error_exit;
740 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
741 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
742 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n",
743 fname, byte_count));
744 goto no_version_info;
747 /* Is this really a DOS header? */
748 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
749 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
750 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
751 goto no_version_info;
754 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
755 if (SMB_VFS_LSEEK(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
756 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
757 fname, errno));
758 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
759 goto no_version_info;
762 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
763 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n",
764 fname, byte_count));
765 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
766 goto no_version_info;
769 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
770 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
771 int num_sections;
772 int section_table_bytes;
774 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
775 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
776 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
777 /* At this point, we assume the file is in error. It still could be somthing
778 * else besides a PE file, but it unlikely at this point.
780 goto error_exit;
783 /* get the section table */
784 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
785 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
786 SAFE_FREE(buf);
787 if ((buf=malloc(section_table_bytes)) == NULL) {
788 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
789 fname, section_table_bytes));
790 goto error_exit;
793 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
794 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n",
795 fname, byte_count));
796 goto error_exit;
799 /* Iterate the section table looking for the resource section ".rsrc" */
800 for (i = 0; i < num_sections; i++) {
801 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
803 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
804 int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
805 int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
807 SAFE_FREE(buf);
808 if ((buf=malloc(section_bytes)) == NULL) {
809 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
810 fname, section_bytes));
811 goto error_exit;
814 /* Seek to the start of the .rsrc section info */
815 if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
816 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
817 fname, errno));
818 goto error_exit;
821 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
822 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n",
823 fname, byte_count));
824 goto error_exit;
827 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
828 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
829 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
830 /* Align to next long address */
831 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
833 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
834 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
835 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
837 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
838 fname, *major, *minor,
839 (*major>>16)&0xffff, *major&0xffff,
840 (*minor>>16)&0xffff, *minor&0xffff));
841 SAFE_FREE(buf);
842 return 1;
849 /* Version info not found, fall back to origin date/time */
850 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
851 SAFE_FREE(buf);
852 return 0;
854 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
855 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
856 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
857 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
858 /* At this point, we assume the file is in error. It still could be somthing
859 * else besides a NE file, but it unlikely at this point. */
860 goto error_exit;
863 /* Allocate a bit more space to speed up things */
864 SAFE_FREE(buf);
865 if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
866 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
867 fname, PE_HEADER_SIZE));
868 goto error_exit;
871 /* This is a HACK! I got tired of trying to sort through the messy
872 * 'NE' file format. If anyone wants to clean this up please have at
873 * it, but this works. 'NE' files will eventually fade away. JRR */
874 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
875 /* Cover case that should not occur in a well formed 'NE' .dll file */
876 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
878 for(i=0; i<byte_count; i++) {
879 /* Fast skip past data that can't possibly match */
880 if (buf[i] != 'V') continue;
882 /* Potential match data crosses buf boundry, move it to beginning
883 * of buf, and fill the buf with as much as it will hold. */
884 if (i>byte_count-VS_VERSION_INFO_SIZE) {
885 int bc;
887 memcpy(buf, &buf[i], byte_count-i);
888 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
889 (byte_count-i))) < 0) {
891 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
892 fname, errno));
893 goto error_exit;
896 byte_count = bc + (byte_count - i);
897 if (byte_count<VS_VERSION_INFO_SIZE) break;
899 i = 0;
902 /* Check that the full signature string and the magic number that
903 * follows exist (not a perfect solution, but the chances that this
904 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
905 * twice, as it is simpler to read the code. */
906 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
907 /* Compute skip alignment to next long address */
908 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
909 sizeof(VS_SIGNATURE)) & 3;
910 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
912 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
913 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
914 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
915 fname, *major, *minor,
916 (*major>>16)&0xffff, *major&0xffff,
917 (*minor>>16)&0xffff, *minor&0xffff));
918 SAFE_FREE(buf);
919 return 1;
924 /* Version info not found, fall back to origin date/time */
925 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
926 SAFE_FREE(buf);
927 return 0;
929 } else
930 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
931 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
932 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
934 no_version_info:
935 SAFE_FREE(buf);
936 return 0;
938 error_exit:
939 SAFE_FREE(buf);
940 return -1;
943 /****************************************************************************
944 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
945 share one or more files. During the MS installation process files are checked
946 to insure that only a newer version of a shared file is installed over an
947 older version. There are several possibilities for this comparison. If there
948 is no previous version, the new one is newer (obviously). If either file is
949 missing the version info structure, compare the creation date (on Unix use
950 the modification date). Otherwise chose the numerically larger version number.
951 ****************************************************************************/
953 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
955 BOOL use_version = True;
956 pstring filepath;
958 uint32 new_major;
959 uint32 new_minor;
960 time_t new_create_time;
962 uint32 old_major;
963 uint32 old_minor;
964 time_t old_create_time;
966 int access_mode;
967 int action;
968 files_struct *fsp = NULL;
969 SMB_STRUCT_STAT st;
970 SMB_STRUCT_STAT stat_buf;
971 BOOL bad_path;
973 ZERO_STRUCT(st);
974 ZERO_STRUCT(stat_buf);
975 new_create_time = (time_t)0;
976 old_create_time = (time_t)0;
978 /* Get file version info (if available) for previous file (if it exists) */
979 pstrcpy(filepath, old_file);
981 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
983 fsp = open_file_shared(conn, filepath, &stat_buf,
984 SET_OPEN_MODE(DOS_OPEN_RDONLY),
985 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
986 0, 0, &access_mode, &action);
987 if (!fsp) {
988 /* Old file not found, so by definition new file is in fact newer */
989 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
990 filepath, errno));
991 return True;
993 } else {
994 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
995 if (ret == -1) goto error_exit;
997 if (!ret) {
998 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
999 old_file));
1000 use_version = False;
1001 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1002 old_create_time = st.st_mtime;
1003 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1006 close_file(fsp, True);
1008 /* Get file version info (if available) for new file */
1009 pstrcpy(filepath, new_file);
1010 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1012 fsp = open_file_shared(conn, filepath, &stat_buf,
1013 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1014 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1015 0, 0, &access_mode, &action);
1016 if (!fsp) {
1017 /* New file not found, this shouldn't occur if the caller did its job */
1018 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1019 filepath, errno));
1020 goto error_exit;
1022 } else {
1023 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1024 if (ret == -1) goto error_exit;
1026 if (!ret) {
1027 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1028 new_file));
1029 use_version = False;
1030 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1031 new_create_time = st.st_mtime;
1032 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1035 close_file(fsp, True);
1037 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1038 /* Compare versions and choose the larger version number */
1039 if (new_major > old_major ||
1040 (new_major == old_major && new_minor > old_minor)) {
1042 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1043 return True;
1045 else {
1046 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1047 return False;
1050 } else {
1051 /* Compare modification time/dates and choose the newest time/date */
1052 if (new_create_time > old_create_time) {
1053 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1054 return True;
1056 else {
1057 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1058 return False;
1062 error_exit:
1063 if(fsp)
1064 close_file(fsp, True);
1065 return -1;
1068 /****************************************************************************
1069 Determine the correct cVersion associated with an architecture and driver
1070 ****************************************************************************/
1071 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1072 struct current_user *user, WERROR *perr)
1074 int cversion;
1075 int access_mode;
1076 int action;
1077 NTSTATUS nt_status;
1078 pstring driverpath;
1079 DATA_BLOB null_pw;
1080 fstring res_type;
1081 files_struct *fsp = NULL;
1082 BOOL bad_path;
1083 SMB_STRUCT_STAT st;
1084 connection_struct *conn;
1086 ZERO_STRUCT(st);
1088 *perr = WERR_INVALID_PARAM;
1090 /* If architecture is Windows 95/98/ME, the version is always 0. */
1091 if (strcmp(architecture, "WIN40") == 0) {
1092 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1093 *perr = WERR_OK;
1094 return 0;
1098 * Connect to the print$ share under the same account as the user connected
1099 * to the rpc pipe. Note we must still be root to do this.
1102 /* Null password is ok - we are already an authenticated user... */
1103 null_pw = data_blob(NULL, 0);
1104 fstrcpy(res_type, "A:");
1105 become_root();
1106 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1107 unbecome_root();
1109 if (conn == NULL) {
1110 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1111 *perr = ntstatus_to_werror(nt_status);
1112 return -1;
1115 /* We are temporarily becoming the connection user. */
1116 if (!become_user(conn, user->vuid)) {
1117 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1118 *perr = WERR_ACCESS_DENIED;
1119 return -1;
1122 /* Open the driver file (Portable Executable format) and determine the
1123 * deriver the cversion. */
1124 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1126 unix_convert(driverpath,conn,NULL,&bad_path,&st);
1128 fsp = open_file_shared(conn, driverpath, &st,
1129 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1130 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1131 0, 0, &access_mode, &action);
1132 if (!fsp) {
1133 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1134 driverpath, errno));
1135 *perr = WERR_ACCESS_DENIED;
1136 goto error_exit;
1138 else {
1139 uint32 major;
1140 uint32 minor;
1141 int ret = get_file_version(fsp, driverpath, &major, &minor);
1142 if (ret == -1) goto error_exit;
1144 if (!ret) {
1145 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1146 goto error_exit;
1150 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1151 * for more details. Version in this case is not just the version of the
1152 * file, but the version in the sense of kernal mode (2) vs. user mode
1153 * (3) drivers. Other bits of the version fields are the version info.
1154 * JRR 010716
1156 cversion = major & 0x0000ffff;
1157 switch (cversion) {
1158 case 2: /* WinNT drivers */
1159 case 3: /* Win2K drivers */
1160 break;
1162 default:
1163 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1164 driverpath, cversion));
1165 goto error_exit;
1168 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1169 driverpath, major, minor));
1172 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1173 driverpath, cversion));
1175 close_file(fsp, True);
1176 close_cnum(conn, user->vuid);
1177 unbecome_user();
1178 *perr = WERR_OK;
1179 return cversion;
1182 error_exit:
1184 if(fsp)
1185 close_file(fsp, True);
1187 close_cnum(conn, user->vuid);
1188 unbecome_user();
1189 return -1;
1192 /****************************************************************************
1193 ****************************************************************************/
1194 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1195 struct current_user *user)
1197 const char *architecture;
1198 fstring new_name;
1199 char *p;
1200 int i;
1201 WERROR err;
1203 /* clean up the driver name.
1204 * we can get .\driver.dll
1205 * or worse c:\windows\system\driver.dll !
1207 /* using an intermediate string to not have overlaping memcpy()'s */
1208 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1209 fstrcpy(new_name, p+1);
1210 fstrcpy(driver->driverpath, new_name);
1213 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1214 fstrcpy(new_name, p+1);
1215 fstrcpy(driver->datafile, new_name);
1218 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1219 fstrcpy(new_name, p+1);
1220 fstrcpy(driver->configfile, new_name);
1223 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1224 fstrcpy(new_name, p+1);
1225 fstrcpy(driver->helpfile, new_name);
1228 if (driver->dependentfiles) {
1229 for (i=0; *driver->dependentfiles[i]; i++) {
1230 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1231 fstrcpy(new_name, p+1);
1232 fstrcpy(driver->dependentfiles[i], new_name);
1237 architecture = get_short_archi(driver->environment);
1239 /* jfm:7/16/2000 the client always sends the cversion=0.
1240 * The server should check which version the driver is by reading
1241 * the PE header of driver->driverpath.
1243 * For Windows 95/98 the version is 0 (so the value sent is correct)
1244 * For Windows NT (the architecture doesn't matter)
1245 * NT 3.1: cversion=0
1246 * NT 3.5/3.51: cversion=1
1247 * NT 4: cversion=2
1248 * NT2K: cversion=3
1250 if ((driver->cversion = get_correct_cversion( architecture,
1251 driver->driverpath, user, &err)) == -1)
1252 return err;
1254 return WERR_OK;
1257 /****************************************************************************
1258 ****************************************************************************/
1259 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1261 const char *architecture;
1262 fstring new_name;
1263 char *p;
1264 int i;
1265 WERROR err;
1267 /* clean up the driver name.
1268 * we can get .\driver.dll
1269 * or worse c:\windows\system\driver.dll !
1271 /* using an intermediate string to not have overlaping memcpy()'s */
1272 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1273 fstrcpy(new_name, p+1);
1274 fstrcpy(driver->driverpath, new_name);
1277 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1278 fstrcpy(new_name, p+1);
1279 fstrcpy(driver->datafile, new_name);
1282 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1283 fstrcpy(new_name, p+1);
1284 fstrcpy(driver->configfile, new_name);
1287 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1288 fstrcpy(new_name, p+1);
1289 fstrcpy(driver->helpfile, new_name);
1292 if (driver->dependentfiles) {
1293 for (i=0; *driver->dependentfiles[i]; i++) {
1294 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1295 fstrcpy(new_name, p+1);
1296 fstrcpy(driver->dependentfiles[i], new_name);
1301 architecture = get_short_archi(driver->environment);
1303 /* jfm:7/16/2000 the client always sends the cversion=0.
1304 * The server should check which version the driver is by reading
1305 * the PE header of driver->driverpath.
1307 * For Windows 95/98 the version is 0 (so the value sent is correct)
1308 * For Windows NT (the architecture doesn't matter)
1309 * NT 3.1: cversion=0
1310 * NT 3.5/3.51: cversion=1
1311 * NT 4: cversion=2
1312 * NT2K: cversion=3
1314 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1315 return err;
1317 return WERR_OK;
1320 /****************************************************************************
1321 ****************************************************************************/
1322 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1323 uint32 level, struct current_user *user)
1325 switch (level) {
1326 case 3:
1328 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1329 driver=driver_abstract.info_3;
1330 return clean_up_driver_struct_level_3(driver, user);
1332 case 6:
1334 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1335 driver=driver_abstract.info_6;
1336 return clean_up_driver_struct_level_6(driver, user);
1338 default:
1339 return WERR_INVALID_PARAM;
1343 /****************************************************************************
1344 This function sucks and should be replaced. JRA.
1345 ****************************************************************************/
1347 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1349 dst->cversion = src->version;
1351 fstrcpy( dst->name, src->name);
1352 fstrcpy( dst->environment, src->environment);
1353 fstrcpy( dst->driverpath, src->driverpath);
1354 fstrcpy( dst->datafile, src->datafile);
1355 fstrcpy( dst->configfile, src->configfile);
1356 fstrcpy( dst->helpfile, src->helpfile);
1357 fstrcpy( dst->monitorname, src->monitorname);
1358 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1359 dst->dependentfiles = src->dependentfiles;
1362 #if 0 /* Debugging function */
1364 static char* ffmt(unsigned char *c){
1365 int i;
1366 static char ffmt_str[17];
1368 for (i=0; i<16; i++) {
1369 if ((c[i] < ' ') || (c[i] > '~'))
1370 ffmt_str[i]='.';
1371 else
1372 ffmt_str[i]=c[i];
1374 ffmt_str[16]='\0';
1375 return ffmt_str;
1378 #endif
1380 /****************************************************************************
1381 ****************************************************************************/
1382 BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1383 struct current_user *user, WERROR *perr)
1385 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1386 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1387 const char *architecture;
1388 pstring new_dir;
1389 pstring old_name;
1390 pstring new_name;
1391 DATA_BLOB null_pw;
1392 connection_struct *conn;
1393 NTSTATUS nt_status;
1394 pstring inbuf;
1395 pstring outbuf;
1396 fstring res_type;
1397 int ver = 0;
1398 int i;
1400 memset(inbuf, '\0', sizeof(inbuf));
1401 memset(outbuf, '\0', sizeof(outbuf));
1402 *perr = WERR_OK;
1404 if (level==3)
1405 driver=driver_abstract.info_3;
1406 else if (level==6) {
1407 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1408 driver = &converted_driver;
1409 } else {
1410 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1411 return False;
1414 architecture = get_short_archi(driver->environment);
1417 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1418 * Note we must be root to do this.
1421 null_pw = data_blob(NULL, 0);
1422 fstrcpy(res_type, "A:");
1423 become_root();
1424 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1425 unbecome_root();
1427 if (conn == NULL) {
1428 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1429 *perr = ntstatus_to_werror(nt_status);
1430 return False;
1434 * Save who we are - we are temporarily becoming the connection user.
1437 if (!become_user(conn, conn->vuid)) {
1438 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1439 return False;
1443 * make the directories version and version\driver_name
1444 * under the architecture directory.
1446 DEBUG(5,("Creating first directory\n"));
1447 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1448 mkdir_internal(conn, new_dir);
1450 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1451 * listed for this driver which has already been moved, skip it (note:
1452 * drivers may list the same file name several times. Then check if the
1453 * file already exists in archi\cversion\, if so, check that the version
1454 * info (or time stamps if version info is unavailable) is newer (or the
1455 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1456 * Otherwise, delete the file.
1458 * If a file is not moved to archi\cversion\ because of an error, all the
1459 * rest of the 'unmoved' driver files are removed from archi\. If one or
1460 * more of the driver's files was already moved to archi\cversion\, it
1461 * potentially leaves the driver in a partially updated state. Version
1462 * trauma will most likely occur if an client attempts to use any printer
1463 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1464 * done is appropriate... later JRR
1467 DEBUG(5,("Moving files now !\n"));
1469 if (driver->driverpath && strlen(driver->driverpath)) {
1470 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1471 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1472 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1473 NTSTATUS status;
1474 status = rename_internals(conn, new_name, old_name, True);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1477 new_name, old_name));
1478 *perr = ntstatus_to_werror(status);
1479 unlink_internals(conn, 0, new_name);
1480 ver = -1;
1483 else
1484 unlink_internals(conn, 0, new_name);
1487 if (driver->datafile && strlen(driver->datafile)) {
1488 if (!strequal(driver->datafile, driver->driverpath)) {
1489 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1490 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1491 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1492 NTSTATUS status;
1493 status = rename_internals(conn, new_name, old_name, True);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1496 new_name, old_name));
1497 *perr = ntstatus_to_werror(status);
1498 unlink_internals(conn, 0, new_name);
1499 ver = -1;
1502 else
1503 unlink_internals(conn, 0, new_name);
1507 if (driver->configfile && strlen(driver->configfile)) {
1508 if (!strequal(driver->configfile, driver->driverpath) &&
1509 !strequal(driver->configfile, driver->datafile)) {
1510 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1511 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1512 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1513 NTSTATUS status;
1514 status = rename_internals(conn, new_name, old_name, True);
1515 if (!NT_STATUS_IS_OK(status)) {
1516 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1517 new_name, old_name));
1518 *perr = ntstatus_to_werror(status);
1519 unlink_internals(conn, 0, new_name);
1520 ver = -1;
1523 else
1524 unlink_internals(conn, 0, new_name);
1528 if (driver->helpfile && strlen(driver->helpfile)) {
1529 if (!strequal(driver->helpfile, driver->driverpath) &&
1530 !strequal(driver->helpfile, driver->datafile) &&
1531 !strequal(driver->helpfile, driver->configfile)) {
1532 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1533 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1534 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1535 NTSTATUS status;
1536 status = rename_internals(conn, new_name, old_name, True);
1537 if (!NT_STATUS_IS_OK(status)) {
1538 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1539 new_name, old_name));
1540 *perr = ntstatus_to_werror(status);
1541 unlink_internals(conn, 0, new_name);
1542 ver = -1;
1545 else
1546 unlink_internals(conn, 0, new_name);
1550 if (driver->dependentfiles) {
1551 for (i=0; *driver->dependentfiles[i]; i++) {
1552 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1553 !strequal(driver->dependentfiles[i], driver->datafile) &&
1554 !strequal(driver->dependentfiles[i], driver->configfile) &&
1555 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1556 int j;
1557 for (j=0; j < i; j++) {
1558 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1559 goto NextDriver;
1563 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1564 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1565 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1566 NTSTATUS status;
1567 status = rename_internals(conn, new_name, old_name, True);
1568 if (!NT_STATUS_IS_OK(status)) {
1569 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1570 new_name, old_name));
1571 *perr = ntstatus_to_werror(status);
1572 unlink_internals(conn, 0, new_name);
1573 ver = -1;
1576 else
1577 unlink_internals(conn, 0, new_name);
1579 NextDriver: ;
1583 close_cnum(conn, user->vuid);
1584 unbecome_user();
1586 return ver == -1 ? False : True;
1589 /****************************************************************************
1590 ****************************************************************************/
1591 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1593 int len, buflen;
1594 const char *architecture;
1595 pstring directory;
1596 fstring temp_name;
1597 pstring key;
1598 char *buf;
1599 int i, ret;
1600 TDB_DATA kbuf, dbuf;
1602 architecture = get_short_archi(driver->environment);
1604 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1605 * \\server is added in the rpc server layer.
1606 * It does make sense to NOT store the server's name in the printer TDB.
1609 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1611 /* .inf files do not always list a file for each of the four standard files.
1612 * Don't prepend a path to a null filename, or client claims:
1613 * "The server on which the printer resides does not have a suitable
1614 * <printer driver name> printer driver installed. Click OK if you
1615 * wish to install the driver on your local machine."
1617 if (strlen(driver->driverpath)) {
1618 fstrcpy(temp_name, driver->driverpath);
1619 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1622 if (strlen(driver->datafile)) {
1623 fstrcpy(temp_name, driver->datafile);
1624 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1627 if (strlen(driver->configfile)) {
1628 fstrcpy(temp_name, driver->configfile);
1629 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1632 if (strlen(driver->helpfile)) {
1633 fstrcpy(temp_name, driver->helpfile);
1634 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1637 if (driver->dependentfiles) {
1638 for (i=0; *driver->dependentfiles[i]; i++) {
1639 fstrcpy(temp_name, driver->dependentfiles[i]);
1640 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1644 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1646 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1648 buf = NULL;
1649 len = buflen = 0;
1651 again:
1652 len = 0;
1653 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1654 driver->cversion,
1655 driver->name,
1656 driver->environment,
1657 driver->driverpath,
1658 driver->datafile,
1659 driver->configfile,
1660 driver->helpfile,
1661 driver->monitorname,
1662 driver->defaultdatatype);
1664 if (driver->dependentfiles) {
1665 for (i=0; *driver->dependentfiles[i]; i++) {
1666 len += tdb_pack(buf+len, buflen-len, "f",
1667 driver->dependentfiles[i]);
1671 if (len != buflen) {
1672 char *tb;
1674 tb = (char *)Realloc(buf, len);
1675 if (!tb) {
1676 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1677 ret = -1;
1678 goto done;
1680 else buf = tb;
1681 buflen = len;
1682 goto again;
1686 kbuf.dptr = key;
1687 kbuf.dsize = strlen(key)+1;
1688 dbuf.dptr = buf;
1689 dbuf.dsize = len;
1691 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1693 done:
1694 if (ret)
1695 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1697 SAFE_FREE(buf);
1698 return ret;
1701 /****************************************************************************
1702 ****************************************************************************/
1703 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
1705 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
1707 ZERO_STRUCT(info3);
1708 info3.cversion = driver->version;
1709 fstrcpy(info3.name,driver->name);
1710 fstrcpy(info3.environment,driver->environment);
1711 fstrcpy(info3.driverpath,driver->driverpath);
1712 fstrcpy(info3.datafile,driver->datafile);
1713 fstrcpy(info3.configfile,driver->configfile);
1714 fstrcpy(info3.helpfile,driver->helpfile);
1715 fstrcpy(info3.monitorname,driver->monitorname);
1716 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
1717 info3.dependentfiles = driver->dependentfiles;
1719 return add_a_printer_driver_3(&info3);
1723 /****************************************************************************
1724 ****************************************************************************/
1725 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
1727 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
1729 ZERO_STRUCT(info);
1731 fstrcpy(info.name, driver);
1732 fstrcpy(info.defaultdatatype, "RAW");
1734 fstrcpy(info.driverpath, "");
1735 fstrcpy(info.datafile, "");
1736 fstrcpy(info.configfile, "");
1737 fstrcpy(info.helpfile, "");
1739 if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
1740 return WERR_NOMEM;
1742 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
1743 fstrcpy(info.dependentfiles[0], "");
1745 *info_ptr = memdup(&info, sizeof(info));
1747 return WERR_OK;
1750 /****************************************************************************
1751 ****************************************************************************/
1752 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
1754 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
1755 TDB_DATA kbuf, dbuf;
1756 const char *architecture;
1757 int len = 0;
1758 int i;
1759 pstring key;
1761 ZERO_STRUCT(driver);
1763 architecture = get_short_archi(arch);
1765 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
1767 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
1768 version = 0;
1770 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
1772 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
1774 kbuf.dptr = key;
1775 kbuf.dsize = strlen(key)+1;
1777 dbuf = tdb_fetch(tdb_drivers, kbuf);
1778 if (!dbuf.dptr)
1779 return WERR_UNKNOWN_PRINTER_DRIVER;
1781 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
1782 &driver.cversion,
1783 driver.name,
1784 driver.environment,
1785 driver.driverpath,
1786 driver.datafile,
1787 driver.configfile,
1788 driver.helpfile,
1789 driver.monitorname,
1790 driver.defaultdatatype);
1792 i=0;
1793 while (len < dbuf.dsize) {
1794 fstring *tddfs;
1796 tddfs = (fstring *)Realloc(driver.dependentfiles,
1797 sizeof(fstring)*(i+2));
1798 if (tddfs == NULL) {
1799 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
1800 break;
1802 else driver.dependentfiles = tddfs;
1804 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
1805 &driver.dependentfiles[i]);
1806 i++;
1809 if (driver.dependentfiles != NULL)
1810 fstrcpy(driver.dependentfiles[i], "");
1812 SAFE_FREE(dbuf.dptr);
1814 if (len != dbuf.dsize) {
1815 SAFE_FREE(driver.dependentfiles);
1817 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
1820 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
1822 return WERR_OK;
1825 /****************************************************************************
1826 Debugging function, dump at level 6 the struct in the logs.
1827 ****************************************************************************/
1829 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1831 uint32 result;
1832 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
1833 int i;
1835 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
1837 switch (level)
1839 case 3:
1841 if (driver.info_3 == NULL)
1842 result=5;
1843 else {
1844 info3=driver.info_3;
1846 DEBUGADD(20,("version:[%d]\n", info3->cversion));
1847 DEBUGADD(20,("name:[%s]\n", info3->name));
1848 DEBUGADD(20,("environment:[%s]\n", info3->environment));
1849 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
1850 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
1851 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
1852 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
1853 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
1854 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
1856 for (i=0; info3->dependentfiles &&
1857 *info3->dependentfiles[i]; i++) {
1858 DEBUGADD(20,("dependentfile:[%s]\n",
1859 info3->dependentfiles[i]));
1861 result=0;
1863 break;
1865 default:
1866 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
1867 result=1;
1868 break;
1871 return result;
1874 /****************************************************************************
1875 ****************************************************************************/
1876 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
1878 int len = 0;
1880 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
1882 if (!nt_devmode)
1883 return len;
1885 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
1886 nt_devmode->devicename,
1887 nt_devmode->formname,
1889 nt_devmode->specversion,
1890 nt_devmode->driverversion,
1891 nt_devmode->size,
1892 nt_devmode->driverextra,
1893 nt_devmode->orientation,
1894 nt_devmode->papersize,
1895 nt_devmode->paperlength,
1896 nt_devmode->paperwidth,
1897 nt_devmode->scale,
1898 nt_devmode->copies,
1899 nt_devmode->defaultsource,
1900 nt_devmode->printquality,
1901 nt_devmode->color,
1902 nt_devmode->duplex,
1903 nt_devmode->yresolution,
1904 nt_devmode->ttoption,
1905 nt_devmode->collate,
1906 nt_devmode->logpixels,
1908 nt_devmode->fields,
1909 nt_devmode->bitsperpel,
1910 nt_devmode->pelswidth,
1911 nt_devmode->pelsheight,
1912 nt_devmode->displayflags,
1913 nt_devmode->displayfrequency,
1914 nt_devmode->icmmethod,
1915 nt_devmode->icmintent,
1916 nt_devmode->mediatype,
1917 nt_devmode->dithertype,
1918 nt_devmode->reserved1,
1919 nt_devmode->reserved2,
1920 nt_devmode->panningwidth,
1921 nt_devmode->panningheight,
1922 nt_devmode->private);
1925 if (nt_devmode->private) {
1926 len += tdb_pack(buf+len, buflen-len, "B",
1927 nt_devmode->driverextra,
1928 nt_devmode->private);
1931 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
1933 return len;
1936 /****************************************************************************
1937 Pack all values in all printer keys
1938 ***************************************************************************/
1940 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
1942 int len = 0;
1943 int i, j;
1944 REGISTRY_VALUE *val;
1945 REGVAL_CTR *val_ctr;
1946 pstring path;
1947 int num_values;
1949 if ( !data )
1950 return 0;
1952 /* loop over all keys */
1954 for ( i=0; i<data->num_keys; i++ ) {
1955 val_ctr = &data->keys[i].values;
1956 num_values = regval_ctr_numvals( val_ctr );
1958 /* loop over all values */
1960 for ( j=0; j<num_values; j++ ) {
1961 /* pathname should be stored as <key>\<value> */
1963 val = regval_ctr_specific_value( val_ctr, j );
1964 pstrcpy( path, data->keys[i].name );
1965 pstrcat( path, "\\" );
1966 pstrcat( path, regval_name(val) );
1968 len += tdb_pack(buf+len, buflen-len, "pPdB",
1969 val,
1970 path,
1971 regval_type(val),
1972 regval_size(val),
1973 regval_data_p(val) );
1978 /* terminator */
1980 len += tdb_pack(buf+len, buflen-len, "p", NULL);
1982 return len;
1986 /****************************************************************************
1987 Delete a printer - this just deletes the printer info file, any open
1988 handles are not affected.
1989 ****************************************************************************/
1991 uint32 del_a_printer(char *sharename)
1993 pstring key;
1994 TDB_DATA kbuf;
1996 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
1998 kbuf.dptr=key;
1999 kbuf.dsize=strlen(key)+1;
2001 tdb_delete(tdb_printers, kbuf);
2002 return 0;
2005 /* FIXME!!! Reorder so this forward declaration is not necessary --jerry */
2006 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, const char* sharename);
2007 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **);
2008 /****************************************************************************
2009 ****************************************************************************/
2010 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2012 pstring key;
2013 char *buf;
2014 int buflen, len;
2015 WERROR ret;
2016 TDB_DATA kbuf, dbuf;
2019 * in addprinter: no servername and the printer is the name
2020 * in setprinter: servername is \\server
2021 * and printer is \\server\\printer
2023 * Samba manages only local printers.
2024 * we currently don't support things like path=\\other_server\printer
2027 if (info->servername[0]!='\0') {
2028 trim_string(info->printername, info->servername, NULL);
2029 trim_char(info->printername, '\\', '\0');
2030 info->servername[0]='\0';
2034 * JFM: one day I'll forget.
2035 * below that's info->portname because that's the SAMBA sharename
2036 * and I made NT 'thinks' it's the portname
2037 * the info->sharename is the thing you can name when you add a printer
2038 * that's the short-name when you create shared printer for 95/98
2039 * So I've made a limitation in SAMBA: you can only have 1 printer model
2040 * behind a SAMBA share.
2043 buf = NULL;
2044 buflen = 0;
2046 again:
2047 len = 0;
2048 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2049 info->attributes,
2050 info->priority,
2051 info->default_priority,
2052 info->starttime,
2053 info->untiltime,
2054 info->status,
2055 info->cjobs,
2056 info->averageppm,
2057 info->changeid,
2058 info->c_setprinter,
2059 info->setuptime,
2060 info->servername,
2061 info->printername,
2062 info->sharename,
2063 info->portname,
2064 info->drivername,
2065 info->comment,
2066 info->location,
2067 info->sepfile,
2068 info->printprocessor,
2069 info->datatype,
2070 info->parameters);
2072 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2074 len += pack_values( &info->data, buf+len, buflen-len );
2076 if (buflen != len) {
2077 char *tb;
2079 tb = (char *)Realloc(buf, len);
2080 if (!tb) {
2081 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2082 ret = WERR_NOMEM;
2083 goto done;
2085 else buf = tb;
2086 buflen = len;
2087 goto again;
2091 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
2093 kbuf.dptr = key;
2094 kbuf.dsize = strlen(key)+1;
2095 dbuf.dptr = buf;
2096 dbuf.dsize = len;
2098 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2100 done:
2101 if (!W_ERROR_IS_OK(ret))
2102 DEBUG(8, ("error updating printer to tdb on disk\n"));
2104 SAFE_FREE(buf);
2106 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2107 info->sharename, info->drivername, info->portname, len));
2109 return ret;
2113 /****************************************************************************
2114 Malloc and return an NT devicemode.
2115 ****************************************************************************/
2117 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2120 char adevice[MAXDEVICENAME];
2121 NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
2123 if (nt_devmode == NULL) {
2124 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2125 return NULL;
2128 ZERO_STRUCTP(nt_devmode);
2130 safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
2131 fstrcpy(nt_devmode->devicename, adevice);
2133 fstrcpy(nt_devmode->formname, "Letter");
2135 nt_devmode->specversion = 0x0401;
2136 nt_devmode->driverversion = 0x0400;
2137 nt_devmode->size = 0x00DC;
2138 nt_devmode->driverextra = 0x0000;
2139 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2140 DEFAULTSOURCE | COPIES | SCALE |
2141 PAPERSIZE | ORIENTATION;
2142 nt_devmode->orientation = 1;
2143 nt_devmode->papersize = PAPER_LETTER;
2144 nt_devmode->paperlength = 0;
2145 nt_devmode->paperwidth = 0;
2146 nt_devmode->scale = 0x64;
2147 nt_devmode->copies = 1;
2148 nt_devmode->defaultsource = BIN_FORMSOURCE;
2149 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2150 nt_devmode->color = COLOR_MONOCHROME;
2151 nt_devmode->duplex = DUP_SIMPLEX;
2152 nt_devmode->yresolution = 0;
2153 nt_devmode->ttoption = TT_SUBDEV;
2154 nt_devmode->collate = COLLATE_FALSE;
2155 nt_devmode->icmmethod = 0;
2156 nt_devmode->icmintent = 0;
2157 nt_devmode->mediatype = 0;
2158 nt_devmode->dithertype = 0;
2160 /* non utilisés par un driver d'imprimante */
2161 nt_devmode->logpixels = 0;
2162 nt_devmode->bitsperpel = 0;
2163 nt_devmode->pelswidth = 0;
2164 nt_devmode->pelsheight = 0;
2165 nt_devmode->displayflags = 0;
2166 nt_devmode->displayfrequency = 0;
2167 nt_devmode->reserved1 = 0;
2168 nt_devmode->reserved2 = 0;
2169 nt_devmode->panningwidth = 0;
2170 nt_devmode->panningheight = 0;
2172 nt_devmode->private = NULL;
2173 return nt_devmode;
2176 /****************************************************************************
2177 Deepcopy an NT devicemode.
2178 ****************************************************************************/
2180 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2182 NT_DEVICEMODE *new_nt_devicemode = NULL;
2184 if ( !nt_devicemode )
2185 return NULL;
2187 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2188 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2189 return NULL;
2192 new_nt_devicemode->private = NULL;
2193 if (nt_devicemode->private != NULL) {
2194 if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
2195 SAFE_FREE(new_nt_devicemode);
2196 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2197 return NULL;
2201 return new_nt_devicemode;
2204 /****************************************************************************
2205 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2206 ****************************************************************************/
2208 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2210 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2212 if(nt_devmode == NULL)
2213 return;
2215 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2217 SAFE_FREE(nt_devmode->private);
2218 SAFE_FREE(*devmode_ptr);
2221 /****************************************************************************
2222 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2223 ****************************************************************************/
2224 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2226 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2227 NT_PRINTER_DATA *data;
2228 int i;
2230 if ( !info )
2231 return;
2233 DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
2235 free_nt_devicemode(&info->devmode);
2237 /* clean up all registry keys */
2239 data = &info->data;
2240 for ( i=0; i<data->num_keys; i++ ) {
2241 SAFE_FREE( data->keys[i].name );
2242 regval_ctr_destroy( &data->keys[i].values );
2244 SAFE_FREE( data->keys );
2246 /* finally the top level structure */
2248 SAFE_FREE( *info_ptr );
2252 /****************************************************************************
2253 ****************************************************************************/
2254 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2256 int len = 0;
2257 int extra_len = 0;
2258 NT_DEVICEMODE devmode;
2260 ZERO_STRUCT(devmode);
2262 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2264 if (!*nt_devmode) return len;
2266 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2267 devmode.devicename,
2268 devmode.formname,
2270 &devmode.specversion,
2271 &devmode.driverversion,
2272 &devmode.size,
2273 &devmode.driverextra,
2274 &devmode.orientation,
2275 &devmode.papersize,
2276 &devmode.paperlength,
2277 &devmode.paperwidth,
2278 &devmode.scale,
2279 &devmode.copies,
2280 &devmode.defaultsource,
2281 &devmode.printquality,
2282 &devmode.color,
2283 &devmode.duplex,
2284 &devmode.yresolution,
2285 &devmode.ttoption,
2286 &devmode.collate,
2287 &devmode.logpixels,
2289 &devmode.fields,
2290 &devmode.bitsperpel,
2291 &devmode.pelswidth,
2292 &devmode.pelsheight,
2293 &devmode.displayflags,
2294 &devmode.displayfrequency,
2295 &devmode.icmmethod,
2296 &devmode.icmintent,
2297 &devmode.mediatype,
2298 &devmode.dithertype,
2299 &devmode.reserved1,
2300 &devmode.reserved2,
2301 &devmode.panningwidth,
2302 &devmode.panningheight,
2303 &devmode.private);
2305 if (devmode.private) {
2306 /* the len in tdb_unpack is an int value and
2307 * devmode.driverextra is only a short
2309 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
2310 devmode.driverextra=(uint16)extra_len;
2312 /* check to catch an invalid TDB entry so we don't segfault */
2313 if (devmode.driverextra == 0) {
2314 devmode.private = NULL;
2318 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2320 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2321 if (devmode.private)
2322 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2324 return len;
2327 /****************************************************************************
2328 Allocate and initialize a new slot.
2329 ***************************************************************************/
2331 static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2333 NT_PRINTER_KEY *d;
2334 int key_index;
2336 if ( !data || !name )
2337 return -1;
2339 /* allocate another slot in the NT_PRINTER_KEY array */
2341 d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
2342 if ( d )
2343 data->keys = d;
2345 key_index = data->num_keys;
2347 /* initialze new key */
2349 data->num_keys++;
2350 data->keys[key_index].name = strdup( name );
2352 ZERO_STRUCTP( &data->keys[key_index].values );
2354 regval_ctr_init( &data->keys[key_index].values );
2356 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2358 return key_index;
2361 /****************************************************************************
2362 search for a registry key name in the existing printer data
2363 ***************************************************************************/
2365 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2367 int key_index = -1;
2368 int i;
2370 if ( !data || !name )
2371 return -1;
2373 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2375 /* loop over all existing keys */
2377 for ( i=0; i<data->num_keys; i++ ) {
2378 if ( strequal(data->keys[i].name, name) ) {
2379 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2380 key_index = i;
2381 break;
2386 return key_index;
2389 /****************************************************************************
2390 ***************************************************************************/
2392 uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2394 int i, j;
2395 int key_len;
2396 int num_subkeys = 0;
2397 char *p;
2398 fstring *ptr, *subkeys_ptr = NULL;
2399 fstring subkeyname;
2401 if ( !data )
2402 return 0;
2404 for ( i=0; i<data->num_keys; i++ ) {
2405 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2406 /* match sure it is a subkey and not the key itself */
2408 key_len = strlen( key );
2409 if ( strlen(data->keys[i].name) == key_len )
2410 continue;
2412 /* get subkey path */
2414 p = data->keys[i].name + key_len;
2415 if ( *p == '\\' )
2416 p++;
2417 fstrcpy( subkeyname, p );
2418 if ( (p = strchr( subkeyname, '\\' )) )
2419 *p = '\0';
2421 /* don't add a key more than once */
2423 for ( j=0; j<num_subkeys; j++ ) {
2424 if ( strequal( subkeys_ptr[j], subkeyname ) )
2425 break;
2428 if ( j != num_subkeys )
2429 continue;
2431 /* found a match, so allocate space and copy the name */
2433 if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
2434 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2435 num_subkeys+1));
2436 SAFE_FREE( subkeys );
2437 return 0;
2440 subkeys_ptr = ptr;
2441 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2442 num_subkeys++;
2447 /* tag of the end */
2449 if (num_subkeys)
2450 fstrcpy(subkeys_ptr[num_subkeys], "" );
2452 *subkeys = subkeys_ptr;
2454 return num_subkeys;
2457 #ifdef HAVE_ADS
2458 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2459 const char *sz)
2461 smb_ucs2_t conv_str[1024];
2462 size_t str_size;
2464 regval_ctr_delvalue(ctr, val_name);
2465 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2466 STR_TERMINATE | STR_NOALIGN);
2467 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2468 (char *) conv_str, str_size);
2471 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2472 uint32 dword)
2474 regval_ctr_delvalue(ctr, val_name);
2475 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2476 (char *) &dword, sizeof(dword));
2479 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2480 BOOL b)
2482 uint8 bin_bool = (b ? 1 : 0);
2483 regval_ctr_delvalue(ctr, val_name);
2484 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2485 (char *) &bin_bool, sizeof(bin_bool));
2488 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2489 const char *multi_sz)
2491 smb_ucs2_t *conv_strs = NULL;
2492 size_t str_size;
2494 /* a multi-sz has to have a null string terminator, i.e., the last
2495 string must be followed by two nulls */
2496 str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
2497 conv_strs = calloc(str_size, 1);
2499 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2500 STR_TERMINATE | STR_NOALIGN);
2502 regval_ctr_delvalue(ctr, val_name);
2503 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2504 (char *) conv_strs, str_size);
2505 safe_free(conv_strs);
2509 /****************************************************************************
2510 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2512 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2513 * @return BOOL indicating success or failure
2514 ***************************************************************************/
2516 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2518 REGVAL_CTR *ctr = NULL;
2519 fstring longname;
2520 char *allocated_string = NULL;
2521 const char *ascii_str;
2522 int i;
2524 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2525 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2526 ctr = &info2->data.keys[i].values;
2528 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2529 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2531 get_myfullname(longname);
2532 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2534 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2535 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2536 SAFE_FREE(allocated_string);
2538 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2539 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2540 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2541 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2542 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2543 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2544 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2545 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2546 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2548 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2549 (info2->attributes &
2550 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2552 switch (info2->attributes & 0x3) {
2553 case 0:
2554 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2555 break;
2556 case 1:
2557 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2558 break;
2559 case 2:
2560 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2561 break;
2562 default:
2563 ascii_str = "unknown";
2565 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2567 return True;
2570 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, GUID guid)
2572 int i;
2573 REGVAL_CTR *ctr=NULL;
2575 /* find the DsSpooler key */
2576 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2577 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2578 ctr = &info2->data.keys[i].values;
2580 regval_ctr_delvalue(ctr, "objectGUID");
2581 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2582 (char *) &guid, sizeof(GUID));
2585 static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
2587 ADS_STATUS ads_rc;
2588 TALLOC_CTX *ctx = talloc_init("publish_it");
2589 ADS_MODLIST mods = ads_init_mods(ctx);
2590 char *prt_dn = NULL, *srv_dn, **srv_cn;
2591 void *res = NULL;
2592 ADS_STRUCT *ads;
2593 const char *attrs[] = {"objectGUID", NULL};
2594 GUID guid;
2595 WERROR win_rc = WERR_OK;
2597 ZERO_STRUCT(guid);
2598 /* set the DsSpooler info and attributes */
2599 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2)))
2600 return WERR_NOMEM;
2601 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
2602 win_rc = mod_a_printer(*printer, 2);
2603 if (!W_ERROR_IS_OK(win_rc)) {
2604 DEBUG(3, ("err %d saving data\n",
2605 W_ERROR_V(win_rc)));
2606 return win_rc;
2609 /* Build the ads mods */
2610 get_local_printer_publishing_data(ctx, &mods,
2611 &printer->info_2->data);
2612 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
2613 printer->info_2->sharename);
2615 /* initial ads structure */
2617 ads = ads_init(NULL, NULL, NULL);
2618 if (!ads) {
2619 DEBUG(3, ("ads_init() failed\n"));
2620 return WERR_SERVER_UNAVAILABLE;
2622 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2623 SAFE_FREE(ads->auth.password);
2624 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2625 NULL, NULL);
2627 /* ads_connect() will find the DC for us */
2628 ads_rc = ads_connect(ads);
2629 if (!ADS_ERR_OK(ads_rc)) {
2630 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2631 ads_destroy(&ads);
2632 return WERR_ACCESS_DENIED;
2635 /* figure out where to publish */
2636 ads_find_machine_acct(ads, &res, global_myname());
2637 srv_dn = ldap_get_dn(ads->ld, res);
2638 ads_msgfree(ads, res);
2639 srv_cn = ldap_explode_dn(srv_dn, 1);
2640 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0],
2641 printer->info_2->sharename, srv_dn);
2642 ads_memfree(ads, srv_dn);
2644 /* publish it */
2645 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
2646 if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
2647 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx,&mods);
2649 /* retreive the guid and store it locally */
2650 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
2651 ads_memfree(ads, prt_dn);
2652 ads_pull_guid(ads, res, &guid);
2653 ads_msgfree(ads, res);
2654 store_printer_guid(printer->info_2, guid);
2655 win_rc = mod_a_printer(*printer, 2);
2658 safe_free(prt_dn);
2659 ads_destroy(&ads);
2661 return WERR_OK;
2664 WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
2666 ADS_STATUS ads_rc;
2667 ADS_STRUCT *ads;
2668 void *res;
2669 char *prt_dn = NULL;
2670 WERROR win_rc;
2672 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
2673 win_rc = mod_a_printer(*printer, 2);
2674 if (!W_ERROR_IS_OK(win_rc)) {
2675 DEBUG(3, ("err %d saving data\n",
2676 W_ERROR_V(win_rc)));
2677 return win_rc;
2680 ads = ads_init(NULL, NULL, NULL);
2681 if (!ads) {
2682 DEBUG(3, ("ads_init() failed\n"));
2683 return WERR_SERVER_UNAVAILABLE;
2685 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2686 SAFE_FREE(ads->auth.password);
2687 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2688 NULL, NULL);
2690 /* ads_connect() will find the DC for us */
2691 ads_rc = ads_connect(ads);
2692 if (!ADS_ERR_OK(ads_rc)) {
2693 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2694 ads_destroy(&ads);
2695 return WERR_ACCESS_DENIED;
2698 /* remove the printer from the directory */
2699 ads_rc = ads_find_printer_on_server(ads, &res,
2700 printer->info_2->sharename, global_myname());
2701 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
2702 prt_dn = ads_get_dn(ads, res);
2703 ads_msgfree(ads, res);
2704 ads_rc = ads_del_dn(ads, prt_dn);
2705 ads_memfree(ads, prt_dn);
2708 ads_destroy(&ads);
2709 return WERR_OK;
2712 /****************************************************************************
2713 * Publish a printer in the directory
2715 * @param snum describing printer service
2716 * @return WERROR indicating status of publishing
2717 ***************************************************************************/
2719 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2721 NT_PRINTER_INFO_LEVEL *printer = NULL;
2722 WERROR win_rc;
2724 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2725 if (!W_ERROR_IS_OK(win_rc))
2726 return win_rc;
2728 switch(action) {
2729 case SPOOL_DS_PUBLISH:
2730 case SPOOL_DS_UPDATE:
2731 win_rc = publish_it(printer);
2732 break;
2733 case SPOOL_DS_UNPUBLISH:
2734 win_rc = unpublish_it(printer);
2735 break;
2736 default:
2737 win_rc = WERR_NOT_SUPPORTED;
2741 free_a_printer(&printer, 2);
2742 return win_rc;
2745 BOOL is_printer_published(Printer_entry *print_hnd, int snum, GUID *guid)
2747 NT_PRINTER_INFO_LEVEL *printer = NULL;
2748 REGVAL_CTR *ctr;
2749 REGISTRY_VALUE *guid_val;
2750 WERROR win_rc;
2751 int i;
2754 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2755 if (!W_ERROR_IS_OK(win_rc))
2756 return False;
2758 if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
2759 return False;
2761 if ((i = lookup_printerkey(&printer->info_2->data,
2762 SPOOL_DSSPOOLER_KEY)) < 0)
2763 return False;
2765 if (!(ctr = &printer->info_2->data.keys[i].values)) {
2766 return False;
2769 if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
2770 return False;
2773 if (regval_size(guid_val) == sizeof(GUID))
2774 memcpy(guid, regval_data_p(guid_val), sizeof(GUID));
2776 return True;
2779 #else
2780 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2782 return WERR_OK;
2784 BOOL is_printer_published(Printer_entry *print_hnd, int snum, GUID *guid)
2786 return False;
2788 #endif
2789 /****************************************************************************
2790 ***************************************************************************/
2792 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
2794 NT_PRINTER_DATA *data;
2795 int i;
2796 int removed_keys = 0;
2797 int empty_slot;
2799 data = &p2->data;
2800 empty_slot = data->num_keys;
2802 if ( !key )
2803 return WERR_INVALID_PARAM;
2805 /* remove all keys */
2807 if ( !strlen(key) ) {
2808 for ( i=0; i<data->num_keys; i++ ) {
2809 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2810 data->keys[i].name));
2812 SAFE_FREE( data->keys[i].name );
2813 regval_ctr_destroy( &data->keys[i].values );
2816 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
2817 p2->printername ));
2819 SAFE_FREE( data->keys );
2820 ZERO_STRUCTP( data );
2822 return WERR_OK;
2825 /* remove a specific key (and all subkeys) */
2827 for ( i=0; i<data->num_keys; i++ ) {
2828 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
2829 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2830 data->keys[i].name));
2832 SAFE_FREE( data->keys[i].name );
2833 regval_ctr_destroy( &data->keys[i].values );
2835 /* mark the slot as empty */
2837 ZERO_STRUCTP( &data->keys[i] );
2841 /* find the first empty slot */
2843 for ( i=0; i<data->num_keys; i++ ) {
2844 if ( !data->keys[i].name ) {
2845 empty_slot = i;
2846 removed_keys++;
2847 break;
2851 if ( i == data->num_keys )
2852 /* nothing was removed */
2853 return WERR_INVALID_PARAM;
2855 /* move everything down */
2857 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
2858 if ( data->keys[i].name ) {
2859 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
2860 ZERO_STRUCTP( &data->keys[i] );
2861 empty_slot++;
2862 removed_keys++;
2866 /* update count */
2868 data->num_keys -= removed_keys;
2870 /* sanity check to see if anything is left */
2872 if ( !data->num_keys ) {
2873 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
2875 SAFE_FREE( data->keys );
2876 ZERO_STRUCTP( data );
2879 return WERR_OK;
2882 /****************************************************************************
2883 ***************************************************************************/
2885 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2887 WERROR result = WERR_OK;
2888 int key_index;
2890 /* we must have names on non-zero length */
2892 if ( !key || !*key|| !value || !*value )
2893 return WERR_INVALID_NAME;
2895 /* find the printer key first */
2897 key_index = lookup_printerkey( &p2->data, key );
2898 if ( key_index == -1 )
2899 return WERR_OK;
2901 /* make sure the value exists so we can return the correct error code */
2903 if ( !regval_ctr_getvalue( &p2->data.keys[key_index].values, value ) )
2904 return WERR_BADFILE;
2906 regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
2908 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
2909 key, value ));
2911 return result;
2914 /****************************************************************************
2915 ***************************************************************************/
2917 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
2918 uint32 type, uint8 *data, int real_len )
2920 WERROR result = WERR_OK;
2921 int key_index;
2923 /* we must have names on non-zero length */
2925 if ( !key || !*key|| !value || !*value )
2926 return WERR_INVALID_NAME;
2928 /* find the printer key first */
2930 key_index = lookup_printerkey( &p2->data, key );
2931 if ( key_index == -1 )
2932 key_index = add_new_printer_key( &p2->data, key );
2934 if ( key_index == -1 )
2935 return WERR_NOMEM;
2937 regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
2938 type, (const char *)data, real_len );
2940 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
2941 key, value, type, real_len ));
2943 return result;
2946 /****************************************************************************
2947 ***************************************************************************/
2949 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2951 int key_index;
2953 if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
2954 return NULL;
2956 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
2957 key, value ));
2959 return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
2962 /****************************************************************************
2963 Unpack a list of registry values frem the TDB
2964 ***************************************************************************/
2966 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
2968 int len = 0;
2969 uint32 type;
2970 pstring string, valuename, keyname;
2971 char *str;
2972 int size;
2973 uint8 *data_p;
2974 REGISTRY_VALUE *regval_p;
2975 int key_index;
2977 /* add the "PrinterDriverData" key first for performance reasons */
2979 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
2981 /* loop and unpack the rest of the registry values */
2983 while ( True ) {
2985 /* check to see if there are any more registry values */
2987 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
2988 if ( !regval_p )
2989 break;
2991 /* unpack the next regval */
2993 len += tdb_unpack(buf+len, buflen-len, "fdB",
2994 string,
2995 &type,
2996 &size,
2997 &data_p);
3000 * break of the keyname from the value name.
3001 * Should only be one '\' in the string returned.
3004 str = strrchr( string, '\\');
3006 /* Put in "PrinterDriverData" is no key specified */
3008 if ( !str ) {
3009 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3010 pstrcpy( valuename, string );
3012 else {
3013 *str = '\0';
3014 pstrcpy( keyname, string );
3015 pstrcpy( valuename, str+1 );
3018 /* see if we need a new key */
3020 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3021 key_index = add_new_printer_key( printer_data, keyname );
3023 if ( key_index == -1 ) {
3024 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3025 keyname));
3026 break;
3029 /* add the new value */
3031 regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3033 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3035 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3038 return len;
3041 /****************************************************************************
3042 ***************************************************************************/
3044 static void map_to_os2_driver(fstring drivername)
3046 static BOOL initialised=False;
3047 static fstring last_from,last_to;
3048 char *mapfile = lp_os2_driver_map();
3049 char **lines = NULL;
3050 int numlines = 0;
3051 int i;
3053 if (!strlen(drivername))
3054 return;
3056 if (!*mapfile)
3057 return;
3059 if (!initialised) {
3060 *last_from = *last_to = 0;
3061 initialised = True;
3064 if (strequal(drivername,last_from)) {
3065 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3066 fstrcpy(drivername,last_to);
3067 return;
3070 lines = file_lines_load(mapfile, &numlines);
3071 if (numlines == 0) {
3072 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3073 return;
3076 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3078 for( i = 0; i < numlines; i++) {
3079 char *nt_name = lines[i];
3080 char *os2_name = strchr(nt_name,'=');
3082 if (!os2_name)
3083 continue;
3085 *os2_name++ = 0;
3087 while (isspace(*nt_name))
3088 nt_name++;
3090 if (!*nt_name || strchr("#;",*nt_name))
3091 continue;
3094 int l = strlen(nt_name);
3095 while (l && isspace(nt_name[l-1])) {
3096 nt_name[l-1] = 0;
3097 l--;
3101 while (isspace(*os2_name))
3102 os2_name++;
3105 int l = strlen(os2_name);
3106 while (l && isspace(os2_name[l-1])) {
3107 os2_name[l-1] = 0;
3108 l--;
3112 if (strequal(nt_name,drivername)) {
3113 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3114 fstrcpy(last_from,drivername);
3115 fstrcpy(last_to,os2_name);
3116 fstrcpy(drivername,os2_name);
3117 file_lines_free(lines);
3118 return;
3122 file_lines_free(lines);
3125 /****************************************************************************
3126 Get a default printer info 2 struct.
3127 ****************************************************************************/
3128 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3130 int snum;
3131 NT_PRINTER_INFO_LEVEL_2 info;
3133 ZERO_STRUCT(info);
3135 snum = lp_servicenumber(sharename);
3137 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3138 slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
3139 get_called_name(), sharename);
3140 fstrcpy(info.sharename, sharename);
3141 fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
3143 /* by setting the driver name to an empty string, a local NT admin
3144 can now run the **local** APW to install a local printer driver
3145 for a Samba shared printer in 2.2. Without this, drivers **must** be
3146 installed on the Samba server for NT clients --jerry */
3147 #if 0 /* JERRY --do not uncomment-- */
3148 if (!*info.drivername)
3149 fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3150 #endif
3153 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
3155 pstrcpy(info.comment, "");
3156 fstrcpy(info.printprocessor, "winprint");
3157 fstrcpy(info.datatype, "RAW");
3159 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3161 info.starttime = 0; /* Minutes since 12:00am GMT */
3162 info.untiltime = 0; /* Minutes since 12:00am GMT */
3163 info.priority = 1;
3164 info.default_priority = 1;
3165 info.setuptime = (uint32)time(NULL);
3168 * I changed this as I think it is better to have a generic
3169 * DEVMODE than to crash Win2k explorer.exe --jerry
3170 * See the HP Deskjet 990c Win2k drivers for an example.
3172 * However the default devmode appears to cause problems
3173 * with the HP CLJ 8500 PCL driver. Hence the addition of
3174 * the "default devmode" parameter --jerry 22/01/2002
3177 if (lp_default_devmode(snum)) {
3178 if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
3179 goto fail;
3181 else {
3182 info.devmode = NULL;
3185 /* This will get the current RPC talloc context, but we should be
3186 passing this as a parameter... fixme... JRA ! */
3188 if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
3189 goto fail;
3191 *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
3192 if (! *info_ptr) {
3193 DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
3194 goto fail;
3197 return WERR_OK;
3199 fail:
3200 if (info.devmode)
3201 free_nt_devicemode(&info.devmode);
3202 return WERR_ACCESS_DENIED;
3205 /****************************************************************************
3206 ****************************************************************************/
3207 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3209 pstring key;
3210 NT_PRINTER_INFO_LEVEL_2 info;
3211 int len = 0;
3212 TDB_DATA kbuf, dbuf;
3213 fstring printername;
3214 char adevice[MAXDEVICENAME];
3216 ZERO_STRUCT(info);
3218 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
3220 kbuf.dptr = key;
3221 kbuf.dsize = strlen(key)+1;
3223 dbuf = tdb_fetch(tdb_printers, kbuf);
3224 if (!dbuf.dptr)
3225 return get_a_printer_2_default(info_ptr, sharename);
3227 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3228 &info.attributes,
3229 &info.priority,
3230 &info.default_priority,
3231 &info.starttime,
3232 &info.untiltime,
3233 &info.status,
3234 &info.cjobs,
3235 &info.averageppm,
3236 &info.changeid,
3237 &info.c_setprinter,
3238 &info.setuptime,
3239 info.servername,
3240 info.printername,
3241 info.sharename,
3242 info.portname,
3243 info.drivername,
3244 info.comment,
3245 info.location,
3246 info.sepfile,
3247 info.printprocessor,
3248 info.datatype,
3249 info.parameters);
3251 /* Samba has to have shared raw drivers. */
3252 info.attributes |= PRINTER_ATTRIBUTE_SAMBA;
3254 /* Restore the stripped strings. */
3255 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3256 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", get_called_name(),
3257 info.printername);
3258 fstrcpy(info.printername, printername);
3260 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3263 * Some client drivers freak out if there is a NULL devmode
3264 * (probably the driver is not checking before accessing
3265 * the devmode pointer) --jerry
3267 * See comments in get_a_printer_2_default()
3270 if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
3271 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3272 printername));
3273 info.devmode = construct_nt_devicemode(printername);
3276 safe_strcpy(adevice, info.printername, sizeof(adevice)-1);
3277 fstrcpy(info.devmode->devicename, adevice);
3280 len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
3282 /* This will get the current RPC talloc context, but we should be
3283 passing this as a parameter... fixme... JRA ! */
3285 nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
3287 /* Fix for OS/2 drivers. */
3289 if (get_remote_arch() == RA_OS2)
3290 map_to_os2_driver(info.drivername);
3292 SAFE_FREE(dbuf.dptr);
3293 *info_ptr=memdup(&info, sizeof(info));
3295 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3296 sharename, info.printername, info.drivername));
3298 return WERR_OK;
3301 /****************************************************************************
3302 Debugging function, dump at level 6 the struct in the logs.
3303 ****************************************************************************/
3304 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3306 uint32 result;
3307 NT_PRINTER_INFO_LEVEL_2 *info2;
3309 DEBUG(106,("Dumping printer at level [%d]\n", level));
3311 switch (level) {
3312 case 2:
3314 if (printer.info_2 == NULL)
3315 result=5;
3316 else
3318 info2=printer.info_2;
3320 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3321 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3322 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3323 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3324 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3325 DEBUGADD(106,("status:[%d]\n", info2->status));
3326 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3327 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3328 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3329 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3330 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3332 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3333 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3334 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3335 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3336 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3337 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3338 DEBUGADD(106,("location:[%s]\n", info2->location));
3339 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3340 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3341 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3342 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3343 result=0;
3345 break;
3347 default:
3348 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3349 result=1;
3350 break;
3353 return result;
3356 /****************************************************************************
3357 Update the changeid time.
3358 This is SO NASTY as some drivers need this to change, others need it
3359 static. This value will change every second, and I must hope that this
3360 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3361 UTAH ! JRA.
3362 ****************************************************************************/
3364 static uint32 rev_changeid(void)
3366 struct timeval tv;
3368 get_process_uptime(&tv);
3370 #if 1 /* JERRY */
3371 /* Return changeid as msec since spooler restart */
3372 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3373 #else
3375 * This setting seems to work well but is too untested
3376 * to replace the above calculation. Left in for experiementation
3377 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3379 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3380 #endif
3384 * The function below are the high level ones.
3385 * only those ones must be called from the spoolss code.
3386 * JFM.
3389 /****************************************************************************
3390 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3391 ****************************************************************************/
3393 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3395 WERROR result;
3397 dump_a_printer(printer, level);
3400 * invalidate cache for all open handles to this printer.
3401 * cache for a given handle will be updated on the next
3402 * get_a_printer()
3405 invalidate_printer_hnd_cache( printer.info_2->sharename );
3407 switch (level) {
3408 case 2:
3411 * Update the changestamp. Emperical tests show that the
3412 * ChangeID is always updated,but c_setprinter is
3413 * global spooler variable (not per printer).
3416 /* ChangeID **must** be increasing over the lifetime
3417 of client's spoolss service in order for the
3418 client's cache to show updates */
3420 printer.info_2->changeid = rev_changeid();
3423 * Because one day someone will ask:
3424 * NT->NT An admin connection to a remote
3425 * printer show changes imeediately in
3426 * the properities dialog
3428 * A non-admin connection will only show the
3429 * changes after viewing the properites page
3430 * 2 times. Seems to be related to a
3431 * race condition in the client between the spooler
3432 * updating the local cache and the Explorer.exe GUI
3433 * actually displaying the properties.
3435 * This is fixed in Win2k. admin/non-admin
3436 * connections both display changes immediately.
3438 * 14/12/01 --jerry
3441 result=update_a_printer_2(printer.info_2);
3443 break;
3445 default:
3446 result=WERR_UNKNOWN_LEVEL;
3447 break;
3450 return result;
3453 /****************************************************************************
3454 Initialize printer devmode & data with previously saved driver init values.
3455 ****************************************************************************/
3457 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3459 int len = 0;
3460 pstring key;
3461 TDB_DATA kbuf, dbuf;
3462 NT_PRINTER_INFO_LEVEL_2 info;
3465 ZERO_STRUCT(info);
3468 * Delete any printer data 'values' already set. When called for driver
3469 * replace, there will generally be some, but during an add printer, there
3470 * should not be any (if there are delete them).
3473 delete_all_printer_data( info_ptr, "" );
3475 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3477 kbuf.dptr = key;
3478 kbuf.dsize = strlen(key)+1;
3480 dbuf = tdb_fetch(tdb_drivers, kbuf);
3481 if (!dbuf.dptr) {
3483 * When changing to a driver that has no init info in the tdb, remove
3484 * the previous drivers init info and leave the new on blank.
3486 free_nt_devicemode(&info_ptr->devmode);
3487 return False;
3491 * Get the saved DEVMODE..
3494 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3497 * The saved DEVMODE contains the devicename from the printer used during
3498 * the initialization save. Change it to reflect the new printer.
3501 if ( info.devmode ) {
3502 ZERO_STRUCT(info.devmode->devicename);
3503 fstrcpy(info.devmode->devicename, info_ptr->printername);
3507 * NT/2k does not change out the entire DeviceMode of a printer
3508 * when changing the driver. Only the driverextra, private, &
3509 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3511 * Later examination revealed that Windows NT/2k does reset the
3512 * the printer's device mode, bit **only** when you change a
3513 * property of the device mode such as the page orientation.
3514 * --jerry
3518 /* Bind the saved DEVMODE to the new the printer */
3520 free_nt_devicemode(&info_ptr->devmode);
3521 info_ptr->devmode = info.devmode;
3523 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3524 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3526 /* Add the printer data 'values' to the new printer */
3528 len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3531 SAFE_FREE(dbuf.dptr);
3533 return True;
3536 /****************************************************************************
3537 Initialize printer devmode & data with previously saved driver init values.
3538 When a printer is created using AddPrinter, the drivername bound to the
3539 printer is used to lookup previously saved driver initialization info, which
3540 is bound to the new printer.
3541 ****************************************************************************/
3543 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3545 BOOL result = False;
3547 switch (level) {
3548 case 2:
3549 result = set_driver_init_2(printer->info_2);
3550 break;
3552 default:
3553 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
3554 level));
3555 break;
3558 return result;
3561 /****************************************************************************
3562 Delete driver init data stored for a specified driver
3563 ****************************************************************************/
3565 BOOL del_driver_init(char *drivername)
3567 pstring key;
3568 TDB_DATA kbuf;
3570 if (!drivername || !*drivername) {
3571 DEBUG(3,("del_driver_init: No drivername specified!\n"));
3572 return False;
3575 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
3577 kbuf.dptr = key;
3578 kbuf.dsize = strlen(key)+1;
3580 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
3582 return (tdb_delete(tdb_drivers, kbuf) == 0);
3585 /****************************************************************************
3586 Pack up the DEVMODE and values for a printer into a 'driver init' entry
3587 in the tdb. Note: this is different from the driver entry and the printer
3588 entry. There should be a single driver init entry for each driver regardless
3589 of whether it was installed from NT or 2K. Technically, they should be
3590 different, but they work out to the same struct.
3591 ****************************************************************************/
3593 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
3595 pstring key;
3596 char *buf;
3597 int buflen, len, ret;
3598 TDB_DATA kbuf, dbuf;
3600 buf = NULL;
3601 buflen = 0;
3603 again:
3604 len = 0;
3605 len += pack_devicemode(info->devmode, buf+len, buflen-len);
3607 len += pack_values( &info->data, buf+len, buflen-len );
3609 if (buflen != len) {
3610 char *tb;
3612 tb = (char *)Realloc(buf, len);
3613 if (!tb) {
3614 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
3615 ret = -1;
3616 goto done;
3618 else
3619 buf = tb;
3620 buflen = len;
3621 goto again;
3624 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
3626 kbuf.dptr = key;
3627 kbuf.dsize = strlen(key)+1;
3628 dbuf.dptr = buf;
3629 dbuf.dsize = len;
3631 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
3633 done:
3634 if (ret == -1)
3635 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
3637 SAFE_FREE(buf);
3639 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
3640 info->sharename, info->drivername));
3642 return ret;
3645 /****************************************************************************
3646 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
3647 ****************************************************************************/
3649 uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3651 uint32 result;
3653 dump_a_printer(printer, level);
3655 switch (level) {
3656 case 2:
3657 result = update_driver_init_2(printer.info_2);
3658 break;
3659 default:
3660 result = 1;
3661 break;
3664 return result;
3667 /****************************************************************************
3668 Convert the printer data value, a REG_BINARY array, into an initialization
3669 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
3670 got to keep the endians happy :).
3671 ****************************************************************************/
3673 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
3675 BOOL result = False;
3676 prs_struct ps;
3677 DEVICEMODE devmode;
3679 ZERO_STRUCT(devmode);
3681 prs_init(&ps, 0, ctx, UNMARSHALL);
3682 ps.data_p = (char *)data;
3683 ps.buffer_size = data_len;
3685 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
3686 result = convert_devicemode("", &devmode, &nt_devmode);
3687 else
3688 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
3690 return result;
3693 /****************************************************************************
3694 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
3696 1. Use the driver's config DLL to this UNC printername and:
3697 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
3698 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
3699 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
3701 The last step triggers saving the "driver initialization" information for
3702 this printer into the tdb. Later, new printers that use this driver will
3703 have this initialization information bound to them. This simulates the
3704 driver initialization, as if it had run on the Samba server (as it would
3705 have done on NT).
3707 The Win32 client side code requirement sucks! But until we can run arbitrary
3708 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
3710 It would have been easier to use SetPrinter because all the UNMARSHALLING of
3711 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
3712 about it and you will realize why. JRR 010720
3713 ****************************************************************************/
3715 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
3717 WERROR status = WERR_OK;
3718 TALLOC_CTX *ctx = NULL;
3719 NT_DEVICEMODE *nt_devmode = NULL;
3720 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
3723 * When the DEVMODE is already set on the printer, don't try to unpack it.
3725 DEBUG(8,("save_driver_init_2: Enter...\n"));
3727 if ( !printer->info_2->devmode && data_len ) {
3729 * Set devmode on printer info, so entire printer initialization can be
3730 * saved to tdb.
3733 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
3734 return WERR_NOMEM;
3736 if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
3737 status = WERR_NOMEM;
3738 goto done;
3741 ZERO_STRUCTP(nt_devmode);
3744 * The DEVMODE is held in the 'data' component of the param in raw binary.
3745 * Convert it to to a devmode structure
3747 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
3748 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
3749 status = WERR_INVALID_PARAM;
3750 goto done;
3753 printer->info_2->devmode = nt_devmode;
3757 * Pack up and add (or update) the DEVMODE and any current printer data to
3758 * a 'driver init' element in the tdb
3762 if ( update_driver_init(*printer, 2) != 0 ) {
3763 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
3764 status = WERR_NOMEM;
3765 goto done;
3769 * If driver initialization info was successfully saved, set the current
3770 * printer to match it. This allows initialization of the current printer
3771 * as well as the driver.
3773 status = mod_a_printer(*printer, 2);
3774 if (!W_ERROR_IS_OK(status)) {
3775 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
3776 printer->info_2->printername));
3779 done:
3780 talloc_destroy(ctx);
3781 free_nt_devicemode( &nt_devmode );
3783 printer->info_2->devmode = tmp_devmode;
3785 return status;
3788 /****************************************************************************
3789 Update the driver init info (DEVMODE and specifics) for a printer
3790 ****************************************************************************/
3792 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
3794 WERROR status = WERR_OK;
3796 switch (level) {
3797 case 2:
3798 status = save_driver_init_2( printer, data, data_len );
3799 break;
3800 default:
3801 status = WERR_UNKNOWN_LEVEL;
3802 break;
3805 return status;
3808 /****************************************************************************
3809 Deep copy a NT_PRINTER_DATA
3810 ****************************************************************************/
3812 static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src )
3814 int i, j, num_vals, new_key_index;
3815 REGVAL_CTR *src_key, *dst_key;
3817 if ( !dst || !src )
3818 return NT_STATUS_NO_MEMORY;
3820 for ( i=0; i<src->num_keys; i++ ) {
3822 /* create a new instance of the printerkey in the destination
3823 printer_data object */
3825 new_key_index = add_new_printer_key( dst, src->keys[i].name );
3826 dst_key = &dst->keys[new_key_index].values;
3828 src_key = &src->keys[i].values;
3829 num_vals = regval_ctr_numvals( src_key );
3831 /* dup the printer entire printer key */
3833 for ( j=0; j<num_vals; j++ ) {
3834 regval_ctr_copyvalue( dst_key, regval_ctr_specific_value(src_key, j) );
3838 return NT_STATUS_OK;
3841 /****************************************************************************
3842 Deep copy a NT_PRINTER_INFO_LEVEL_2 structure using malloc()'d memeory
3843 Caller must free.
3844 ****************************************************************************/
3846 NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 *printer )
3848 NT_PRINTER_INFO_LEVEL_2 *copy;
3850 if ( !printer )
3851 return NULL;
3853 if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
3854 return NULL;
3856 memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
3858 /* malloc()'d members copied here */
3860 copy->devmode = dup_nt_devicemode( printer->devmode );
3862 ZERO_STRUCT( copy->data );
3863 copy_printer_data( &copy->data, &printer->data );
3865 /* this is talloc()'d; very ugly that we have a structure that
3866 is half malloc()'d and half talloc()'d but that is the way
3867 that the PRINTER_INFO stuff is written right now. --jerry */
3869 copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf );
3871 return copy;
3874 /****************************************************************************
3875 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
3876 ****************************************************************************/
3878 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
3879 const char *sharename)
3881 WERROR result;
3882 NT_PRINTER_INFO_LEVEL *printer = NULL;
3884 *pp_printer = NULL;
3886 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
3888 switch (level) {
3889 case 2:
3890 if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
3891 DEBUG(0,("get_a_printer: malloc fail.\n"));
3892 return WERR_NOMEM;
3894 ZERO_STRUCTP(printer);
3897 * check for cache first. A Printer handle cannot changed
3898 * to another printer object so we only check that the printer
3899 * is actually for a printer and that the printer_info pointer
3900 * is valid
3902 if ( print_hnd
3903 && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)
3904 && print_hnd->printer_info )
3906 if ( !(printer->info_2 = dup_printer_2(print_hnd->ctx, print_hnd->printer_info->info_2)) ) {
3907 DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
3909 SAFE_FREE(printer);
3910 return WERR_NOMEM;
3913 DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n"));
3915 *pp_printer = printer;
3916 result = WERR_OK;
3918 break;
3921 /* no cache for this handle; see if we can match one from another handle */
3923 if ( print_hnd )
3924 result = find_printer_in_print_hnd_cache(print_hnd->ctx, &printer->info_2, sharename);
3926 /* fail to disk if we don't have it with any open handle */
3928 if ( !print_hnd || !W_ERROR_IS_OK(result) )
3929 result = get_a_printer_2(&printer->info_2, sharename);
3931 /* we have a new printer now. Save it with this handle */
3933 if ( W_ERROR_IS_OK(result) ) {
3934 dump_a_printer(*printer, level);
3936 /* save a copy in cache */
3937 if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
3938 if ( !print_hnd->printer_info )
3939 print_hnd->printer_info = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL));
3941 if ( print_hnd->printer_info ) {
3942 print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2);
3944 /* don't fail the lookup just because the cache update failed */
3945 if ( !print_hnd->printer_info->info_2 )
3946 DEBUG(0,("get_a_printer: unable to copy new printer info!\n"));
3949 *pp_printer = printer;
3951 else
3952 SAFE_FREE(printer);
3954 break;
3956 default:
3957 result=WERR_UNKNOWN_LEVEL;
3958 break;
3961 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result)));
3963 return result;
3966 /****************************************************************************
3967 Deletes a NT_PRINTER_INFO_LEVEL struct.
3968 ****************************************************************************/
3970 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
3972 uint32 result;
3973 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
3975 DEBUG(104,("freeing a printer at level [%d]\n", level));
3977 if (printer == NULL)
3978 return 0;
3980 switch (level) {
3981 case 2:
3982 if (printer->info_2 != NULL) {
3983 free_nt_printer_info_level_2(&printer->info_2);
3984 result=0;
3985 } else
3986 result=4;
3987 break;
3989 default:
3990 result=1;
3991 break;
3994 SAFE_FREE(*pp_printer);
3995 return result;
3998 /****************************************************************************
3999 ****************************************************************************/
4000 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4002 uint32 result;
4003 DEBUG(104,("adding a printer at level [%d]\n", level));
4004 dump_a_printer_driver(driver, level);
4006 switch (level) {
4007 case 3:
4008 result=add_a_printer_driver_3(driver.info_3);
4009 break;
4011 case 6:
4012 result=add_a_printer_driver_6(driver.info_6);
4013 break;
4015 default:
4016 result=1;
4017 break;
4020 return result;
4022 /****************************************************************************
4023 ****************************************************************************/
4025 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4026 fstring drivername, const char *architecture, uint32 version)
4028 WERROR result;
4030 switch (level) {
4031 case 3:
4032 /* Sometime we just want any version of the driver */
4034 if ( version == DRIVER_ANY_VERSION ) {
4035 /* look for Win2k first and then for NT4 */
4036 result = get_a_printer_driver_3(&driver->info_3, drivername,
4037 architecture, 3);
4039 if ( !W_ERROR_IS_OK(result) ) {
4040 result = get_a_printer_driver_3( &driver->info_3,
4041 drivername, architecture, 2 );
4043 } else {
4044 result = get_a_printer_driver_3(&driver->info_3, drivername,
4045 architecture, version);
4047 break;
4049 default:
4050 result=W_ERROR(1);
4051 break;
4054 if (W_ERROR_IS_OK(result))
4055 dump_a_printer_driver(*driver, level);
4057 return result;
4060 /****************************************************************************
4061 ****************************************************************************/
4062 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4064 uint32 result;
4066 switch (level) {
4067 case 3:
4069 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4070 if (driver.info_3 != NULL)
4072 info3=driver.info_3;
4073 SAFE_FREE(info3->dependentfiles);
4074 ZERO_STRUCTP(info3);
4075 SAFE_FREE(info3);
4076 result=0;
4077 } else {
4078 result=4;
4080 break;
4082 case 6:
4084 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4085 if (driver.info_6 != NULL) {
4086 info6=driver.info_6;
4087 SAFE_FREE(info6->dependentfiles);
4088 SAFE_FREE(info6->previousnames);
4089 ZERO_STRUCTP(info6);
4090 SAFE_FREE(info6);
4091 result=0;
4092 } else {
4093 result=4;
4095 break;
4097 default:
4098 result=1;
4099 break;
4101 return result;
4105 /****************************************************************************
4106 Determine whether or not a particular driver is currently assigned
4107 to a printer
4108 ****************************************************************************/
4110 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4112 int snum;
4113 int n_services = lp_numservices();
4114 NT_PRINTER_INFO_LEVEL *printer = NULL;
4116 if ( !info_3 )
4117 return False;
4119 DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4121 /* loop through the printers.tdb and check for the drivername */
4123 for (snum=0; snum<n_services; snum++) {
4124 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4125 continue;
4127 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4128 continue;
4130 if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
4131 free_a_printer( &printer, 2 );
4132 return True;
4135 free_a_printer( &printer, 2 );
4138 DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4140 /* report that the driver is not in use by default */
4142 return False;
4146 /**********************************************************************
4147 Check to see if a ogiven file is in use by *info
4148 *********************************************************************/
4150 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4152 int i = 0;
4154 if ( !info )
4155 return False;
4157 if ( strequal(file, info->driverpath) )
4158 return True;
4160 if ( strequal(file, info->datafile) )
4161 return True;
4163 if ( strequal(file, info->configfile) )
4164 return True;
4166 if ( strequal(file, info->helpfile) )
4167 return True;
4169 /* see of there are any dependent files to examine */
4171 if ( !info->dependentfiles )
4172 return False;
4174 while ( *info->dependentfiles[i] ) {
4175 if ( strequal(file, info->dependentfiles[i]) )
4176 return True;
4177 i++;
4180 return False;
4184 /**********************************************************************
4185 Utility function to remove the dependent file pointed to by the
4186 input parameter from the list
4187 *********************************************************************/
4189 static void trim_dependent_file( fstring files[], int idx )
4192 /* bump everything down a slot */
4194 while( *files[idx+1] ) {
4195 fstrcpy( files[idx], files[idx+1] );
4196 idx++;
4199 *files[idx] = '\0';
4201 return;
4204 /**********************************************************************
4205 Check if any of the files used by src are also used by drv
4206 *********************************************************************/
4208 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4209 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4211 BOOL in_use = False;
4212 int i = 0;
4214 if ( !src || !drv )
4215 return False;
4217 /* check each file. Remove it from the src structure if it overlaps */
4219 if ( drv_file_in_use(src->driverpath, drv) ) {
4220 in_use = True;
4221 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4222 fstrcpy( src->driverpath, "" );
4225 if ( drv_file_in_use(src->datafile, drv) ) {
4226 in_use = True;
4227 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4228 fstrcpy( src->datafile, "" );
4231 if ( drv_file_in_use(src->configfile, drv) ) {
4232 in_use = True;
4233 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4234 fstrcpy( src->configfile, "" );
4237 if ( drv_file_in_use(src->helpfile, drv) ) {
4238 in_use = True;
4239 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4240 fstrcpy( src->helpfile, "" );
4243 /* are there any dependentfiles to examine? */
4245 if ( !src->dependentfiles )
4246 return in_use;
4248 while ( *src->dependentfiles[i] ) {
4249 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4250 in_use = True;
4251 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4252 trim_dependent_file( src->dependentfiles, i );
4253 } else
4254 i++;
4257 return in_use;
4260 /****************************************************************************
4261 Determine whether or not a particular driver files are currently being
4262 used by any other driver.
4264 Return value is True if any files were in use by other drivers
4265 and False otherwise.
4267 Upon return, *info has been modified to only contain the driver files
4268 which are not in use
4269 ****************************************************************************/
4271 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4273 int i;
4274 int ndrivers;
4275 uint32 version;
4276 fstring *list = NULL;
4277 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4279 if ( !info )
4280 return False;
4282 version = info->cversion;
4284 /* loop over all driver versions */
4286 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4288 /* get the list of drivers */
4290 list = NULL;
4291 ndrivers = get_ntdrivers(&list, info->environment, version);
4293 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4294 ndrivers, info->environment, version));
4296 /* check each driver for overlap in files */
4298 for (i=0; i<ndrivers; i++) {
4299 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4301 ZERO_STRUCT(driver);
4303 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4304 SAFE_FREE(list);
4305 return True;
4308 /* check if d2 uses any files from d1 */
4309 /* only if this is a different driver than the one being deleted */
4311 if ( !strequal(info->name, driver.info_3->name) ) {
4312 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4313 free_a_printer_driver(driver, 3);
4314 SAFE_FREE( list );
4315 return True;
4319 free_a_printer_driver(driver, 3);
4322 SAFE_FREE(list);
4324 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4326 driver.info_3 = info;
4328 if ( DEBUGLEVEL >= 20 )
4329 dump_a_printer_driver( driver, 3 );
4331 return False;
4334 /****************************************************************************
4335 Actually delete the driver files. Make sure that
4336 printer_driver_files_in_use() return False before calling
4337 this.
4338 ****************************************************************************/
4340 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4342 int i = 0;
4343 char *s;
4344 connection_struct *conn;
4345 DATA_BLOB null_pw;
4346 NTSTATUS nt_status;
4347 fstring res_type;
4349 if ( !info_3 )
4350 return False;
4352 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4355 * Connect to the print$ share under the same account as the
4356 * user connected to the rpc pipe. Note we must be root to
4357 * do this.
4360 null_pw = data_blob( NULL, 0 );
4361 fstrcpy(res_type, "A:");
4362 become_root();
4363 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4364 unbecome_root();
4366 if ( !conn ) {
4367 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4368 return False;
4371 /* Save who we are - we are temporarily becoming the connection user. */
4373 if ( !become_user(conn, conn->vuid) ) {
4374 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4375 return False;
4378 /* now delete the files; must strip the '\print$' string from
4379 fron of path */
4381 if ( *info_3->driverpath ) {
4382 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4383 DEBUG(10,("deleting driverfile [%s]\n", s));
4384 unlink_internals(conn, 0, s);
4388 if ( *info_3->configfile ) {
4389 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4390 DEBUG(10,("deleting configfile [%s]\n", s));
4391 unlink_internals(conn, 0, s);
4395 if ( *info_3->datafile ) {
4396 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4397 DEBUG(10,("deleting datafile [%s]\n", s));
4398 unlink_internals(conn, 0, s);
4402 if ( *info_3->helpfile ) {
4403 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4404 DEBUG(10,("deleting helpfile [%s]\n", s));
4405 unlink_internals(conn, 0, s);
4409 /* check if we are done removing files */
4411 if ( info_3->dependentfiles ) {
4412 while ( *info_3->dependentfiles[i] ) {
4413 char *file;
4415 /* bypass the "\print$" portion of the path */
4417 if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4418 DEBUG(10,("deleting dependent file [%s]\n", file));
4419 unlink_internals(conn, 0, file );
4422 i++;
4426 unbecome_user();
4428 return True;
4431 /****************************************************************************
4432 Remove a printer driver from the TDB. This assumes that the the driver was
4433 previously looked up.
4434 ***************************************************************************/
4436 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4437 uint32 version, BOOL delete_files )
4439 pstring key;
4440 const char *arch;
4441 TDB_DATA kbuf, dbuf;
4442 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4444 /* delete the tdb data first */
4446 arch = get_short_archi(info_3->environment);
4447 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4448 arch, version, info_3->name);
4450 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4451 key, delete_files ? "TRUE" : "FALSE" ));
4453 ctr.info_3 = info_3;
4454 dump_a_printer_driver( ctr, 3 );
4456 kbuf.dptr=key;
4457 kbuf.dsize=strlen(key)+1;
4459 /* check if the driver actually exists for this environment */
4461 dbuf = tdb_fetch( tdb_drivers, kbuf );
4462 if ( !dbuf.dptr ) {
4463 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4464 return WERR_UNKNOWN_PRINTER_DRIVER;
4467 SAFE_FREE( dbuf.dptr );
4469 /* ok... the driver exists so the delete should return success */
4471 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4472 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4473 return WERR_ACCESS_DENIED;
4477 * now delete any associated files if delete_files == True
4478 * even if this part failes, we return succes because the
4479 * driver doesn not exist any more
4482 if ( delete_files )
4483 delete_driver_files( info_3, user );
4486 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4488 return WERR_OK;
4491 /****************************************************************************
4492 Store a security desc for a printer.
4493 ****************************************************************************/
4495 WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
4497 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4498 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4499 prs_struct ps;
4500 TALLOC_CTX *mem_ctx = NULL;
4501 fstring key;
4502 WERROR status;
4504 mem_ctx = talloc_init("nt_printing_setsec");
4505 if (mem_ctx == NULL)
4506 return WERR_NOMEM;
4508 /* The old owner and group sids of the security descriptor are not
4509 present when new ACEs are added or removed by changing printer
4510 permissions through NT. If they are NULL in the new security
4511 descriptor then copy them over from the old one. */
4513 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4514 DOM_SID *owner_sid, *group_sid;
4515 SEC_ACL *dacl, *sacl;
4516 SEC_DESC *psd = NULL;
4517 size_t size;
4519 nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
4521 /* Pick out correct owner and group sids */
4523 owner_sid = secdesc_ctr->sec->owner_sid ?
4524 secdesc_ctr->sec->owner_sid :
4525 old_secdesc_ctr->sec->owner_sid;
4527 group_sid = secdesc_ctr->sec->grp_sid ?
4528 secdesc_ctr->sec->grp_sid :
4529 old_secdesc_ctr->sec->grp_sid;
4531 dacl = secdesc_ctr->sec->dacl ?
4532 secdesc_ctr->sec->dacl :
4533 old_secdesc_ctr->sec->dacl;
4535 sacl = secdesc_ctr->sec->sacl ?
4536 secdesc_ctr->sec->sacl :
4537 old_secdesc_ctr->sec->sacl;
4539 /* Make a deep copy of the security descriptor */
4541 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision,
4542 owner_sid, group_sid,
4543 sacl,
4544 dacl,
4545 &size);
4547 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4550 if (!new_secdesc_ctr) {
4551 new_secdesc_ctr = secdesc_ctr;
4554 /* Store the security descriptor in a tdb */
4556 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4557 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4559 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4560 &ps, 1)) {
4561 status = WERR_BADFUNC;
4562 goto out;
4565 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4567 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4568 status = WERR_OK;
4569 } else {
4570 DEBUG(1,("Failed to store secdesc for %s\n", printername));
4571 status = WERR_BADFUNC;
4574 /* Free malloc'ed memory */
4576 out:
4578 prs_mem_free(&ps);
4579 if (mem_ctx)
4580 talloc_destroy(mem_ctx);
4581 return status;
4584 /****************************************************************************
4585 Construct a default security descriptor buffer for a printer.
4586 ****************************************************************************/
4588 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
4590 SEC_ACE ace[3];
4591 SEC_ACCESS sa;
4592 SEC_ACL *psa = NULL;
4593 SEC_DESC_BUF *sdb = NULL;
4594 SEC_DESC *psd = NULL;
4595 DOM_SID owner_sid;
4596 size_t sd_size;
4598 /* Create an ACE where Everyone is allowed to print */
4600 init_sec_access(&sa, PRINTER_ACE_PRINT);
4601 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
4602 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4604 /* Make the security descriptor owned by the Administrators group
4605 on the PDC of the domain. */
4607 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4608 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4609 } else {
4611 /* Backup plan - make printer owned by admins.
4612 This should emulate a lanman printer as security
4613 settings can't be changed. */
4615 sid_copy(&owner_sid, get_global_sam_sid());
4616 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4619 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4620 init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4621 sa, SEC_ACE_FLAG_OBJECT_INHERIT |
4622 SEC_ACE_FLAG_INHERIT_ONLY);
4624 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4625 init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4626 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4628 /* The ACL revision number in rpc_secdesc.h differs from the one
4629 created by NT when setting ACE entries in printer
4630 descriptors. NT4 complains about the property being edited by a
4631 NT5 machine. */
4633 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
4634 psd = make_sec_desc(ctx, SEC_DESC_REVISION,
4635 &owner_sid, NULL,
4636 NULL, psa, &sd_size);
4639 if (!psd) {
4640 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
4641 return NULL;
4644 sdb = make_sec_desc_buf(ctx, sd_size, psd);
4646 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
4647 (unsigned int)sd_size));
4649 return sdb;
4652 /****************************************************************************
4653 Get a security desc for a printer.
4654 ****************************************************************************/
4656 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
4658 prs_struct ps;
4659 fstring key;
4660 char *temp;
4662 if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
4663 printername = temp + 1;
4666 /* Fetch security descriptor from tdb */
4668 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4670 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
4671 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
4673 DEBUG(4,("using default secdesc for %s\n", printername));
4675 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
4676 return False;
4679 /* Save default security descriptor for later */
4681 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
4682 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
4684 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
4685 tdb_prs_store(tdb_printers, key, &ps);
4687 prs_mem_free(&ps);
4689 return True;
4692 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
4693 this security descriptor has been created when winbindd was
4694 down. Take ownership of security descriptor. */
4696 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
4697 DOM_SID owner_sid;
4699 /* Change sd owner to workgroup administrator */
4701 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4702 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4703 SEC_DESC *psd = NULL;
4704 size_t size;
4706 /* Create new sd */
4708 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4710 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision,
4711 &owner_sid,
4712 (*secdesc_ctr)->sec->grp_sid,
4713 (*secdesc_ctr)->sec->sacl,
4714 (*secdesc_ctr)->sec->dacl,
4715 &size);
4717 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
4719 /* Swap with other one */
4721 *secdesc_ctr = new_secdesc_ctr;
4723 /* Set it */
4725 nt_printing_setsec(printername, *secdesc_ctr);
4729 if (DEBUGLEVEL >= 10) {
4730 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
4731 int i;
4733 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
4734 printername, the_acl->num_aces));
4736 for (i = 0; i < the_acl->num_aces; i++) {
4737 fstring sid_str;
4739 sid_to_string(sid_str, &the_acl->ace[i].trustee);
4741 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
4742 the_acl->ace[i].type, the_acl->ace[i].flags,
4743 the_acl->ace[i].info.mask));
4747 prs_mem_free(&ps);
4748 return True;
4751 /* error code:
4752 0: everything OK
4753 1: level not implemented
4754 2: file doesn't exist
4755 3: can't allocate memory
4756 4: can't free memory
4757 5: non existant struct
4761 A printer and a printer driver are 2 different things.
4762 NT manages them separatelly, Samba does the same.
4763 Why ? Simply because it's easier and it makes sense !
4765 Now explanation: You have 3 printers behind your samba server,
4766 2 of them are the same make and model (laser A and B). But laser B
4767 has an 3000 sheet feeder and laser A doesn't such an option.
4768 Your third printer is an old dot-matrix model for the accounting :-).
4770 If the /usr/local/samba/lib directory (default dir), you will have
4771 5 files to describe all of this.
4773 3 files for the printers (1 by printer):
4774 NTprinter_laser A
4775 NTprinter_laser B
4776 NTprinter_accounting
4777 2 files for the drivers (1 for the laser and 1 for the dot matrix)
4778 NTdriver_printer model X
4779 NTdriver_printer model Y
4781 jfm: I should use this comment for the text file to explain
4782 same thing for the forms BTW.
4783 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
4787 /* Convert generic access rights to printer object specific access rights.
4788 It turns out that NT4 security descriptors use generic access rights and
4789 NT5 the object specific ones. */
4791 void map_printer_permissions(SEC_DESC *sd)
4793 int i;
4795 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
4796 se_map_generic(&sd->dacl->ace[i].info.mask,
4797 &printer_generic_mapping);
4801 /****************************************************************************
4802 Check a user has permissions to perform the given operation. We use the
4803 permission constants defined in include/rpc_spoolss.h to check the various
4804 actions we perform when checking printer access.
4806 PRINTER_ACCESS_ADMINISTER:
4807 print_queue_pause, print_queue_resume, update_printer_sec,
4808 update_printer, spoolss_addprinterex_level_2,
4809 _spoolss_setprinterdata
4811 PRINTER_ACCESS_USE:
4812 print_job_start
4814 JOB_ACCESS_ADMINISTER:
4815 print_job_delete, print_job_pause, print_job_resume,
4816 print_queue_purge
4818 ****************************************************************************/
4819 BOOL print_access_check(struct current_user *user, int snum, int access_type)
4821 SEC_DESC_BUF *secdesc = NULL;
4822 uint32 access_granted;
4823 NTSTATUS status;
4824 BOOL result;
4825 const char *pname;
4826 TALLOC_CTX *mem_ctx = NULL;
4827 extern struct current_user current_user;
4829 /* If user is NULL then use the current_user structure */
4831 if (!user)
4832 user = &current_user;
4834 /* Always allow root or printer admins to do anything */
4836 if (user->uid == 0 ||
4837 user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
4838 return True;
4841 /* Get printer name */
4843 pname = PRINTERNAME(snum);
4845 if (!pname || !*pname) {
4846 errno = EACCES;
4847 return False;
4850 /* Get printer security descriptor */
4852 if(!(mem_ctx = talloc_init("print_access_check"))) {
4853 errno = ENOMEM;
4854 return False;
4857 nt_printing_getsec(mem_ctx, pname, &secdesc);
4859 if (access_type == JOB_ACCESS_ADMINISTER) {
4860 SEC_DESC_BUF *parent_secdesc = secdesc;
4862 /* Create a child security descriptor to check permissions
4863 against. This is because print jobs are child objects
4864 objects of a printer. */
4866 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
4868 /* Now this is the bit that really confuses me. The access
4869 type needs to be changed from JOB_ACCESS_ADMINISTER to
4870 PRINTER_ACCESS_ADMINISTER for this to work. Something
4871 to do with the child (job) object becoming like a
4872 printer?? -tpot */
4874 access_type = PRINTER_ACCESS_ADMINISTER;
4877 /* Check access */
4879 map_printer_permissions(secdesc->sec);
4881 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
4882 &access_granted, &status);
4884 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
4886 talloc_destroy(mem_ctx);
4888 if (!result)
4889 errno = EACCES;
4891 return result;
4894 /****************************************************************************
4895 Check the time parameters allow a print operation.
4896 *****************************************************************************/
4898 BOOL print_time_access_check(int snum)
4900 NT_PRINTER_INFO_LEVEL *printer = NULL;
4901 BOOL ok = False;
4902 time_t now = time(NULL);
4903 struct tm *t;
4904 uint32 mins;
4906 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
4907 return False;
4909 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
4910 ok = True;
4912 t = gmtime(&now);
4913 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
4915 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
4916 ok = True;
4918 free_a_printer(&printer, 2);
4920 if (!ok)
4921 errno = EACCES;
4923 return ok;