r415: Return NT_STATUS_ACCESS_DENIED not some LOCK message ...
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blob675794c4c271b7929064401e7a2efd9d4d29e8e1
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 = NULL;
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 = %lu\n",
743 fname, (unsigned long)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 = %lu\n",
764 fname, (unsigned long)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 unsigned int num_sections;
772 unsigned 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 if (section_table_bytes == 0)
787 goto error_exit;
789 SAFE_FREE(buf);
790 if ((buf=malloc(section_table_bytes)) == NULL) {
791 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
792 fname, section_table_bytes));
793 goto error_exit;
796 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
797 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
798 fname, (unsigned long)byte_count));
799 goto error_exit;
802 /* Iterate the section table looking for the resource section ".rsrc" */
803 for (i = 0; i < num_sections; i++) {
804 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
806 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
807 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
808 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
810 if (section_bytes == 0)
811 goto error_exit;
813 SAFE_FREE(buf);
814 if ((buf=malloc(section_bytes)) == NULL) {
815 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
816 fname, section_bytes));
817 goto error_exit;
820 /* Seek to the start of the .rsrc section info */
821 if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
822 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
823 fname, errno));
824 goto error_exit;
827 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
828 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
829 fname, (unsigned long)byte_count));
830 goto error_exit;
833 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
834 goto error_exit;
836 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
837 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
838 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
839 /* Align to next long address */
840 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
842 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
843 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
844 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
846 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
847 fname, *major, *minor,
848 (*major>>16)&0xffff, *major&0xffff,
849 (*minor>>16)&0xffff, *minor&0xffff));
850 SAFE_FREE(buf);
851 return 1;
858 /* Version info not found, fall back to origin date/time */
859 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
860 SAFE_FREE(buf);
861 return 0;
863 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
864 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
865 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
866 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
867 /* At this point, we assume the file is in error. It still could be somthing
868 * else besides a NE file, but it unlikely at this point. */
869 goto error_exit;
872 /* Allocate a bit more space to speed up things */
873 SAFE_FREE(buf);
874 if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
875 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
876 fname, PE_HEADER_SIZE));
877 goto error_exit;
880 /* This is a HACK! I got tired of trying to sort through the messy
881 * 'NE' file format. If anyone wants to clean this up please have at
882 * it, but this works. 'NE' files will eventually fade away. JRR */
883 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
884 /* Cover case that should not occur in a well formed 'NE' .dll file */
885 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
887 for(i=0; i<byte_count; i++) {
888 /* Fast skip past data that can't possibly match */
889 if (buf[i] != 'V') continue;
891 /* Potential match data crosses buf boundry, move it to beginning
892 * of buf, and fill the buf with as much as it will hold. */
893 if (i>byte_count-VS_VERSION_INFO_SIZE) {
894 int bc;
896 memcpy(buf, &buf[i], byte_count-i);
897 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
898 (byte_count-i))) < 0) {
900 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
901 fname, errno));
902 goto error_exit;
905 byte_count = bc + (byte_count - i);
906 if (byte_count<VS_VERSION_INFO_SIZE) break;
908 i = 0;
911 /* Check that the full signature string and the magic number that
912 * follows exist (not a perfect solution, but the chances that this
913 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
914 * twice, as it is simpler to read the code. */
915 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
916 /* Compute skip alignment to next long address */
917 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
918 sizeof(VS_SIGNATURE)) & 3;
919 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
921 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
922 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
923 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
924 fname, *major, *minor,
925 (*major>>16)&0xffff, *major&0xffff,
926 (*minor>>16)&0xffff, *minor&0xffff));
927 SAFE_FREE(buf);
928 return 1;
933 /* Version info not found, fall back to origin date/time */
934 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
935 SAFE_FREE(buf);
936 return 0;
938 } else
939 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
940 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
941 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
943 no_version_info:
944 SAFE_FREE(buf);
945 return 0;
947 error_exit:
948 SAFE_FREE(buf);
949 return -1;
952 /****************************************************************************
953 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
954 share one or more files. During the MS installation process files are checked
955 to insure that only a newer version of a shared file is installed over an
956 older version. There are several possibilities for this comparison. If there
957 is no previous version, the new one is newer (obviously). If either file is
958 missing the version info structure, compare the creation date (on Unix use
959 the modification date). Otherwise chose the numerically larger version number.
960 ****************************************************************************/
962 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
964 BOOL use_version = True;
965 pstring filepath;
967 uint32 new_major;
968 uint32 new_minor;
969 time_t new_create_time;
971 uint32 old_major;
972 uint32 old_minor;
973 time_t old_create_time;
975 int access_mode;
976 int action;
977 files_struct *fsp = NULL;
978 SMB_STRUCT_STAT st;
979 SMB_STRUCT_STAT stat_buf;
980 BOOL bad_path;
982 ZERO_STRUCT(st);
983 ZERO_STRUCT(stat_buf);
984 new_create_time = (time_t)0;
985 old_create_time = (time_t)0;
987 /* Get file version info (if available) for previous file (if it exists) */
988 pstrcpy(filepath, old_file);
990 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
992 fsp = open_file_shared(conn, filepath, &stat_buf,
993 SET_OPEN_MODE(DOS_OPEN_RDONLY),
994 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
995 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
996 if (!fsp) {
997 /* Old file not found, so by definition new file is in fact newer */
998 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
999 filepath, errno));
1000 return True;
1002 } else {
1003 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
1004 if (ret == -1) goto error_exit;
1006 if (!ret) {
1007 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1008 old_file));
1009 use_version = False;
1010 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1011 old_create_time = st.st_mtime;
1012 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1015 close_file(fsp, True);
1017 /* Get file version info (if available) for new file */
1018 pstrcpy(filepath, new_file);
1019 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1021 fsp = open_file_shared(conn, filepath, &stat_buf,
1022 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1023 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1024 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
1025 if (!fsp) {
1026 /* New file not found, this shouldn't occur if the caller did its job */
1027 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1028 filepath, errno));
1029 goto error_exit;
1031 } else {
1032 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1033 if (ret == -1) goto error_exit;
1035 if (!ret) {
1036 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1037 new_file));
1038 use_version = False;
1039 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1040 new_create_time = st.st_mtime;
1041 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1044 close_file(fsp, True);
1046 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1047 /* Compare versions and choose the larger version number */
1048 if (new_major > old_major ||
1049 (new_major == old_major && new_minor > old_minor)) {
1051 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1052 return True;
1054 else {
1055 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1056 return False;
1059 } else {
1060 /* Compare modification time/dates and choose the newest time/date */
1061 if (new_create_time > old_create_time) {
1062 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1063 return True;
1065 else {
1066 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1067 return False;
1071 error_exit:
1072 if(fsp)
1073 close_file(fsp, True);
1074 return -1;
1077 /****************************************************************************
1078 Determine the correct cVersion associated with an architecture and driver
1079 ****************************************************************************/
1080 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1081 struct current_user *user, WERROR *perr)
1083 int cversion;
1084 int access_mode;
1085 int action;
1086 NTSTATUS nt_status;
1087 pstring driverpath;
1088 DATA_BLOB null_pw;
1089 fstring res_type;
1090 files_struct *fsp = NULL;
1091 BOOL bad_path;
1092 SMB_STRUCT_STAT st;
1093 connection_struct *conn;
1095 ZERO_STRUCT(st);
1097 *perr = WERR_INVALID_PARAM;
1099 /* If architecture is Windows 95/98/ME, the version is always 0. */
1100 if (strcmp(architecture, "WIN40") == 0) {
1101 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1102 *perr = WERR_OK;
1103 return 0;
1107 * Connect to the print$ share under the same account as the user connected
1108 * to the rpc pipe. Note we must still be root to do this.
1111 /* Null password is ok - we are already an authenticated user... */
1112 null_pw = data_blob(NULL, 0);
1113 fstrcpy(res_type, "A:");
1114 become_root();
1115 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1116 unbecome_root();
1118 if (conn == NULL) {
1119 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1120 *perr = ntstatus_to_werror(nt_status);
1121 return -1;
1124 /* We are temporarily becoming the connection user. */
1125 if (!become_user(conn, user->vuid)) {
1126 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1127 *perr = WERR_ACCESS_DENIED;
1128 return -1;
1131 /* Open the driver file (Portable Executable format) and determine the
1132 * deriver the cversion. */
1133 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1135 unix_convert(driverpath,conn,NULL,&bad_path,&st);
1137 fsp = open_file_shared(conn, driverpath, &st,
1138 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1139 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1140 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
1141 if (!fsp) {
1142 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1143 driverpath, errno));
1144 *perr = WERR_ACCESS_DENIED;
1145 goto error_exit;
1147 else {
1148 uint32 major;
1149 uint32 minor;
1150 int ret = get_file_version(fsp, driverpath, &major, &minor);
1151 if (ret == -1) goto error_exit;
1153 if (!ret) {
1154 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1155 goto error_exit;
1159 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1160 * for more details. Version in this case is not just the version of the
1161 * file, but the version in the sense of kernal mode (2) vs. user mode
1162 * (3) drivers. Other bits of the version fields are the version info.
1163 * JRR 010716
1165 cversion = major & 0x0000ffff;
1166 switch (cversion) {
1167 case 2: /* WinNT drivers */
1168 case 3: /* Win2K drivers */
1169 break;
1171 default:
1172 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1173 driverpath, cversion));
1174 goto error_exit;
1177 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1178 driverpath, major, minor));
1181 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1182 driverpath, cversion));
1184 close_file(fsp, True);
1185 close_cnum(conn, user->vuid);
1186 unbecome_user();
1187 *perr = WERR_OK;
1188 return cversion;
1191 error_exit:
1193 if(fsp)
1194 close_file(fsp, True);
1196 close_cnum(conn, user->vuid);
1197 unbecome_user();
1198 return -1;
1201 /****************************************************************************
1202 ****************************************************************************/
1203 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1204 struct current_user *user)
1206 const char *architecture;
1207 fstring new_name;
1208 char *p;
1209 int i;
1210 WERROR err;
1212 /* clean up the driver name.
1213 * we can get .\driver.dll
1214 * or worse c:\windows\system\driver.dll !
1216 /* using an intermediate string to not have overlaping memcpy()'s */
1217 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1218 fstrcpy(new_name, p+1);
1219 fstrcpy(driver->driverpath, new_name);
1222 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1223 fstrcpy(new_name, p+1);
1224 fstrcpy(driver->datafile, new_name);
1227 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1228 fstrcpy(new_name, p+1);
1229 fstrcpy(driver->configfile, new_name);
1232 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1233 fstrcpy(new_name, p+1);
1234 fstrcpy(driver->helpfile, new_name);
1237 if (driver->dependentfiles) {
1238 for (i=0; *driver->dependentfiles[i]; i++) {
1239 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1240 fstrcpy(new_name, p+1);
1241 fstrcpy(driver->dependentfiles[i], new_name);
1246 architecture = get_short_archi(driver->environment);
1248 /* jfm:7/16/2000 the client always sends the cversion=0.
1249 * The server should check which version the driver is by reading
1250 * the PE header of driver->driverpath.
1252 * For Windows 95/98 the version is 0 (so the value sent is correct)
1253 * For Windows NT (the architecture doesn't matter)
1254 * NT 3.1: cversion=0
1255 * NT 3.5/3.51: cversion=1
1256 * NT 4: cversion=2
1257 * NT2K: cversion=3
1259 if ((driver->cversion = get_correct_cversion( architecture,
1260 driver->driverpath, user, &err)) == -1)
1261 return err;
1263 return WERR_OK;
1266 /****************************************************************************
1267 ****************************************************************************/
1268 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1270 const char *architecture;
1271 fstring new_name;
1272 char *p;
1273 int i;
1274 WERROR err;
1276 /* clean up the driver name.
1277 * we can get .\driver.dll
1278 * or worse c:\windows\system\driver.dll !
1280 /* using an intermediate string to not have overlaping memcpy()'s */
1281 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1282 fstrcpy(new_name, p+1);
1283 fstrcpy(driver->driverpath, new_name);
1286 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1287 fstrcpy(new_name, p+1);
1288 fstrcpy(driver->datafile, new_name);
1291 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1292 fstrcpy(new_name, p+1);
1293 fstrcpy(driver->configfile, new_name);
1296 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1297 fstrcpy(new_name, p+1);
1298 fstrcpy(driver->helpfile, new_name);
1301 if (driver->dependentfiles) {
1302 for (i=0; *driver->dependentfiles[i]; i++) {
1303 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1304 fstrcpy(new_name, p+1);
1305 fstrcpy(driver->dependentfiles[i], new_name);
1310 architecture = get_short_archi(driver->environment);
1312 /* jfm:7/16/2000 the client always sends the cversion=0.
1313 * The server should check which version the driver is by reading
1314 * the PE header of driver->driverpath.
1316 * For Windows 95/98 the version is 0 (so the value sent is correct)
1317 * For Windows NT (the architecture doesn't matter)
1318 * NT 3.1: cversion=0
1319 * NT 3.5/3.51: cversion=1
1320 * NT 4: cversion=2
1321 * NT2K: cversion=3
1323 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1324 return err;
1326 return WERR_OK;
1329 /****************************************************************************
1330 ****************************************************************************/
1331 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1332 uint32 level, struct current_user *user)
1334 switch (level) {
1335 case 3:
1337 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1338 driver=driver_abstract.info_3;
1339 return clean_up_driver_struct_level_3(driver, user);
1341 case 6:
1343 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1344 driver=driver_abstract.info_6;
1345 return clean_up_driver_struct_level_6(driver, user);
1347 default:
1348 return WERR_INVALID_PARAM;
1352 /****************************************************************************
1353 This function sucks and should be replaced. JRA.
1354 ****************************************************************************/
1356 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1358 dst->cversion = src->version;
1360 fstrcpy( dst->name, src->name);
1361 fstrcpy( dst->environment, src->environment);
1362 fstrcpy( dst->driverpath, src->driverpath);
1363 fstrcpy( dst->datafile, src->datafile);
1364 fstrcpy( dst->configfile, src->configfile);
1365 fstrcpy( dst->helpfile, src->helpfile);
1366 fstrcpy( dst->monitorname, src->monitorname);
1367 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1368 dst->dependentfiles = src->dependentfiles;
1371 #if 0 /* Debugging function */
1373 static char* ffmt(unsigned char *c){
1374 int i;
1375 static char ffmt_str[17];
1377 for (i=0; i<16; i++) {
1378 if ((c[i] < ' ') || (c[i] > '~'))
1379 ffmt_str[i]='.';
1380 else
1381 ffmt_str[i]=c[i];
1383 ffmt_str[16]='\0';
1384 return ffmt_str;
1387 #endif
1389 /****************************************************************************
1390 ****************************************************************************/
1391 BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1392 struct current_user *user, WERROR *perr)
1394 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1395 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1396 const char *architecture;
1397 pstring new_dir;
1398 pstring old_name;
1399 pstring new_name;
1400 DATA_BLOB null_pw;
1401 connection_struct *conn;
1402 NTSTATUS nt_status;
1403 pstring inbuf;
1404 pstring outbuf;
1405 fstring res_type;
1406 int ver = 0;
1407 int i;
1409 memset(inbuf, '\0', sizeof(inbuf));
1410 memset(outbuf, '\0', sizeof(outbuf));
1411 *perr = WERR_OK;
1413 if (level==3)
1414 driver=driver_abstract.info_3;
1415 else if (level==6) {
1416 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1417 driver = &converted_driver;
1418 } else {
1419 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1420 return False;
1423 architecture = get_short_archi(driver->environment);
1426 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1427 * Note we must be root to do this.
1430 null_pw = data_blob(NULL, 0);
1431 fstrcpy(res_type, "A:");
1432 become_root();
1433 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1434 unbecome_root();
1436 if (conn == NULL) {
1437 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1438 *perr = ntstatus_to_werror(nt_status);
1439 return False;
1443 * Save who we are - we are temporarily becoming the connection user.
1446 if (!become_user(conn, conn->vuid)) {
1447 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1448 return False;
1452 * make the directories version and version\driver_name
1453 * under the architecture directory.
1455 DEBUG(5,("Creating first directory\n"));
1456 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1457 mkdir_internal(conn, new_dir);
1459 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1460 * listed for this driver which has already been moved, skip it (note:
1461 * drivers may list the same file name several times. Then check if the
1462 * file already exists in archi\cversion\, if so, check that the version
1463 * info (or time stamps if version info is unavailable) is newer (or the
1464 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1465 * Otherwise, delete the file.
1467 * If a file is not moved to archi\cversion\ because of an error, all the
1468 * rest of the 'unmoved' driver files are removed from archi\. If one or
1469 * more of the driver's files was already moved to archi\cversion\, it
1470 * potentially leaves the driver in a partially updated state. Version
1471 * trauma will most likely occur if an client attempts to use any printer
1472 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1473 * done is appropriate... later JRR
1476 DEBUG(5,("Moving files now !\n"));
1478 if (driver->driverpath && strlen(driver->driverpath)) {
1479 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1480 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1481 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1482 NTSTATUS status;
1483 status = rename_internals(conn, new_name, old_name, 0, True);
1484 if (!NT_STATUS_IS_OK(status)) {
1485 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1486 new_name, old_name));
1487 *perr = ntstatus_to_werror(status);
1488 unlink_internals(conn, 0, new_name);
1489 ver = -1;
1492 else
1493 unlink_internals(conn, 0, new_name);
1496 if (driver->datafile && strlen(driver->datafile)) {
1497 if (!strequal(driver->datafile, driver->driverpath)) {
1498 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1499 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1500 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1501 NTSTATUS status;
1502 status = rename_internals(conn, new_name, old_name, 0, True);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1505 new_name, old_name));
1506 *perr = ntstatus_to_werror(status);
1507 unlink_internals(conn, 0, new_name);
1508 ver = -1;
1511 else
1512 unlink_internals(conn, 0, new_name);
1516 if (driver->configfile && strlen(driver->configfile)) {
1517 if (!strequal(driver->configfile, driver->driverpath) &&
1518 !strequal(driver->configfile, driver->datafile)) {
1519 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1520 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1521 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1522 NTSTATUS status;
1523 status = rename_internals(conn, new_name, old_name, 0, True);
1524 if (!NT_STATUS_IS_OK(status)) {
1525 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1526 new_name, old_name));
1527 *perr = ntstatus_to_werror(status);
1528 unlink_internals(conn, 0, new_name);
1529 ver = -1;
1532 else
1533 unlink_internals(conn, 0, new_name);
1537 if (driver->helpfile && strlen(driver->helpfile)) {
1538 if (!strequal(driver->helpfile, driver->driverpath) &&
1539 !strequal(driver->helpfile, driver->datafile) &&
1540 !strequal(driver->helpfile, driver->configfile)) {
1541 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1542 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1543 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1544 NTSTATUS status;
1545 status = rename_internals(conn, new_name, old_name, 0, True);
1546 if (!NT_STATUS_IS_OK(status)) {
1547 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1548 new_name, old_name));
1549 *perr = ntstatus_to_werror(status);
1550 unlink_internals(conn, 0, new_name);
1551 ver = -1;
1554 else
1555 unlink_internals(conn, 0, new_name);
1559 if (driver->dependentfiles) {
1560 for (i=0; *driver->dependentfiles[i]; i++) {
1561 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1562 !strequal(driver->dependentfiles[i], driver->datafile) &&
1563 !strequal(driver->dependentfiles[i], driver->configfile) &&
1564 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1565 int j;
1566 for (j=0; j < i; j++) {
1567 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1568 goto NextDriver;
1572 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1573 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1574 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1575 NTSTATUS status;
1576 status = rename_internals(conn, new_name, old_name, 0, True);
1577 if (!NT_STATUS_IS_OK(status)) {
1578 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1579 new_name, old_name));
1580 *perr = ntstatus_to_werror(status);
1581 unlink_internals(conn, 0, new_name);
1582 ver = -1;
1585 else
1586 unlink_internals(conn, 0, new_name);
1588 NextDriver: ;
1592 close_cnum(conn, user->vuid);
1593 unbecome_user();
1595 return ver == -1 ? False : True;
1598 /****************************************************************************
1599 ****************************************************************************/
1600 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1602 int len, buflen;
1603 const char *architecture;
1604 pstring directory;
1605 fstring temp_name;
1606 pstring key;
1607 char *buf;
1608 int i, ret;
1609 TDB_DATA kbuf, dbuf;
1611 architecture = get_short_archi(driver->environment);
1613 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1614 * \\server is added in the rpc server layer.
1615 * It does make sense to NOT store the server's name in the printer TDB.
1618 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1620 /* .inf files do not always list a file for each of the four standard files.
1621 * Don't prepend a path to a null filename, or client claims:
1622 * "The server on which the printer resides does not have a suitable
1623 * <printer driver name> printer driver installed. Click OK if you
1624 * wish to install the driver on your local machine."
1626 if (strlen(driver->driverpath)) {
1627 fstrcpy(temp_name, driver->driverpath);
1628 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1631 if (strlen(driver->datafile)) {
1632 fstrcpy(temp_name, driver->datafile);
1633 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1636 if (strlen(driver->configfile)) {
1637 fstrcpy(temp_name, driver->configfile);
1638 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1641 if (strlen(driver->helpfile)) {
1642 fstrcpy(temp_name, driver->helpfile);
1643 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1646 if (driver->dependentfiles) {
1647 for (i=0; *driver->dependentfiles[i]; i++) {
1648 fstrcpy(temp_name, driver->dependentfiles[i]);
1649 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1653 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1655 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1657 buf = NULL;
1658 len = buflen = 0;
1660 again:
1661 len = 0;
1662 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1663 driver->cversion,
1664 driver->name,
1665 driver->environment,
1666 driver->driverpath,
1667 driver->datafile,
1668 driver->configfile,
1669 driver->helpfile,
1670 driver->monitorname,
1671 driver->defaultdatatype);
1673 if (driver->dependentfiles) {
1674 for (i=0; *driver->dependentfiles[i]; i++) {
1675 len += tdb_pack(buf+len, buflen-len, "f",
1676 driver->dependentfiles[i]);
1680 if (len != buflen) {
1681 char *tb;
1683 tb = (char *)Realloc(buf, len);
1684 if (!tb) {
1685 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1686 ret = -1;
1687 goto done;
1689 else buf = tb;
1690 buflen = len;
1691 goto again;
1695 kbuf.dptr = key;
1696 kbuf.dsize = strlen(key)+1;
1697 dbuf.dptr = buf;
1698 dbuf.dsize = len;
1700 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1702 done:
1703 if (ret)
1704 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1706 SAFE_FREE(buf);
1707 return ret;
1710 /****************************************************************************
1711 ****************************************************************************/
1712 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
1714 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
1716 ZERO_STRUCT(info3);
1717 info3.cversion = driver->version;
1718 fstrcpy(info3.name,driver->name);
1719 fstrcpy(info3.environment,driver->environment);
1720 fstrcpy(info3.driverpath,driver->driverpath);
1721 fstrcpy(info3.datafile,driver->datafile);
1722 fstrcpy(info3.configfile,driver->configfile);
1723 fstrcpy(info3.helpfile,driver->helpfile);
1724 fstrcpy(info3.monitorname,driver->monitorname);
1725 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
1726 info3.dependentfiles = driver->dependentfiles;
1728 return add_a_printer_driver_3(&info3);
1732 /****************************************************************************
1733 ****************************************************************************/
1734 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
1736 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
1738 ZERO_STRUCT(info);
1740 fstrcpy(info.name, driver);
1741 fstrcpy(info.defaultdatatype, "RAW");
1743 fstrcpy(info.driverpath, "");
1744 fstrcpy(info.datafile, "");
1745 fstrcpy(info.configfile, "");
1746 fstrcpy(info.helpfile, "");
1748 if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
1749 return WERR_NOMEM;
1751 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
1752 fstrcpy(info.dependentfiles[0], "");
1754 *info_ptr = memdup(&info, sizeof(info));
1756 return WERR_OK;
1759 /****************************************************************************
1760 ****************************************************************************/
1761 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
1763 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
1764 TDB_DATA kbuf, dbuf;
1765 const char *architecture;
1766 int len = 0;
1767 int i;
1768 pstring key;
1770 ZERO_STRUCT(driver);
1772 architecture = get_short_archi(arch);
1774 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
1776 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
1777 version = 0;
1779 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
1781 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
1783 kbuf.dptr = key;
1784 kbuf.dsize = strlen(key)+1;
1786 dbuf = tdb_fetch(tdb_drivers, kbuf);
1787 if (!dbuf.dptr)
1788 return WERR_UNKNOWN_PRINTER_DRIVER;
1790 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
1791 &driver.cversion,
1792 driver.name,
1793 driver.environment,
1794 driver.driverpath,
1795 driver.datafile,
1796 driver.configfile,
1797 driver.helpfile,
1798 driver.monitorname,
1799 driver.defaultdatatype);
1801 i=0;
1802 while (len < dbuf.dsize) {
1803 fstring *tddfs;
1805 tddfs = (fstring *)Realloc(driver.dependentfiles,
1806 sizeof(fstring)*(i+2));
1807 if (tddfs == NULL) {
1808 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
1809 break;
1811 else driver.dependentfiles = tddfs;
1813 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
1814 &driver.dependentfiles[i]);
1815 i++;
1818 if (driver.dependentfiles != NULL)
1819 fstrcpy(driver.dependentfiles[i], "");
1821 SAFE_FREE(dbuf.dptr);
1823 if (len != dbuf.dsize) {
1824 SAFE_FREE(driver.dependentfiles);
1826 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
1829 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
1831 return WERR_OK;
1834 /****************************************************************************
1835 Debugging function, dump at level 6 the struct in the logs.
1836 ****************************************************************************/
1838 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1840 uint32 result;
1841 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
1842 int i;
1844 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
1846 switch (level)
1848 case 3:
1850 if (driver.info_3 == NULL)
1851 result=5;
1852 else {
1853 info3=driver.info_3;
1855 DEBUGADD(20,("version:[%d]\n", info3->cversion));
1856 DEBUGADD(20,("name:[%s]\n", info3->name));
1857 DEBUGADD(20,("environment:[%s]\n", info3->environment));
1858 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
1859 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
1860 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
1861 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
1862 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
1863 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
1865 for (i=0; info3->dependentfiles &&
1866 *info3->dependentfiles[i]; i++) {
1867 DEBUGADD(20,("dependentfile:[%s]\n",
1868 info3->dependentfiles[i]));
1870 result=0;
1872 break;
1874 default:
1875 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
1876 result=1;
1877 break;
1880 return result;
1883 /****************************************************************************
1884 ****************************************************************************/
1885 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
1887 int len = 0;
1889 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
1891 if (!nt_devmode)
1892 return len;
1894 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
1895 nt_devmode->devicename,
1896 nt_devmode->formname,
1898 nt_devmode->specversion,
1899 nt_devmode->driverversion,
1900 nt_devmode->size,
1901 nt_devmode->driverextra,
1902 nt_devmode->orientation,
1903 nt_devmode->papersize,
1904 nt_devmode->paperlength,
1905 nt_devmode->paperwidth,
1906 nt_devmode->scale,
1907 nt_devmode->copies,
1908 nt_devmode->defaultsource,
1909 nt_devmode->printquality,
1910 nt_devmode->color,
1911 nt_devmode->duplex,
1912 nt_devmode->yresolution,
1913 nt_devmode->ttoption,
1914 nt_devmode->collate,
1915 nt_devmode->logpixels,
1917 nt_devmode->fields,
1918 nt_devmode->bitsperpel,
1919 nt_devmode->pelswidth,
1920 nt_devmode->pelsheight,
1921 nt_devmode->displayflags,
1922 nt_devmode->displayfrequency,
1923 nt_devmode->icmmethod,
1924 nt_devmode->icmintent,
1925 nt_devmode->mediatype,
1926 nt_devmode->dithertype,
1927 nt_devmode->reserved1,
1928 nt_devmode->reserved2,
1929 nt_devmode->panningwidth,
1930 nt_devmode->panningheight,
1931 nt_devmode->private);
1934 if (nt_devmode->private) {
1935 len += tdb_pack(buf+len, buflen-len, "B",
1936 nt_devmode->driverextra,
1937 nt_devmode->private);
1940 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
1942 return len;
1945 /****************************************************************************
1946 Pack all values in all printer keys
1947 ***************************************************************************/
1949 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
1951 int len = 0;
1952 int i, j;
1953 REGISTRY_VALUE *val;
1954 REGVAL_CTR *val_ctr;
1955 pstring path;
1956 int num_values;
1958 if ( !data )
1959 return 0;
1961 /* loop over all keys */
1963 for ( i=0; i<data->num_keys; i++ ) {
1964 val_ctr = &data->keys[i].values;
1965 num_values = regval_ctr_numvals( val_ctr );
1967 /* loop over all values */
1969 for ( j=0; j<num_values; j++ ) {
1970 /* pathname should be stored as <key>\<value> */
1972 val = regval_ctr_specific_value( val_ctr, j );
1973 pstrcpy( path, data->keys[i].name );
1974 pstrcat( path, "\\" );
1975 pstrcat( path, regval_name(val) );
1977 len += tdb_pack(buf+len, buflen-len, "pPdB",
1978 val,
1979 path,
1980 regval_type(val),
1981 regval_size(val),
1982 regval_data_p(val) );
1987 /* terminator */
1989 len += tdb_pack(buf+len, buflen-len, "p", NULL);
1991 return len;
1995 /****************************************************************************
1996 Delete a printer - this just deletes the printer info file, any open
1997 handles are not affected.
1998 ****************************************************************************/
2000 uint32 del_a_printer(char *sharename)
2002 pstring key;
2003 TDB_DATA kbuf;
2005 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
2007 kbuf.dptr=key;
2008 kbuf.dsize=strlen(key)+1;
2010 tdb_delete(tdb_printers, kbuf);
2011 return 0;
2014 /* FIXME!!! Reorder so this forward declaration is not necessary --jerry */
2015 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, const char* sharename);
2016 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **);
2017 /****************************************************************************
2018 ****************************************************************************/
2019 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2021 pstring key;
2022 char *buf;
2023 int buflen, len;
2024 WERROR ret;
2025 TDB_DATA kbuf, dbuf;
2028 * in addprinter: no servername and the printer is the name
2029 * in setprinter: servername is \\server
2030 * and printer is \\server\\printer
2032 * Samba manages only local printers.
2033 * we currently don't support things like path=\\other_server\printer
2036 if (info->servername[0]!='\0') {
2037 trim_string(info->printername, info->servername, NULL);
2038 trim_char(info->printername, '\\', '\0');
2039 info->servername[0]='\0';
2043 * JFM: one day I'll forget.
2044 * below that's info->portname because that's the SAMBA sharename
2045 * and I made NT 'thinks' it's the portname
2046 * the info->sharename is the thing you can name when you add a printer
2047 * that's the short-name when you create shared printer for 95/98
2048 * So I've made a limitation in SAMBA: you can only have 1 printer model
2049 * behind a SAMBA share.
2052 buf = NULL;
2053 buflen = 0;
2055 again:
2056 len = 0;
2057 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2058 info->attributes,
2059 info->priority,
2060 info->default_priority,
2061 info->starttime,
2062 info->untiltime,
2063 info->status,
2064 info->cjobs,
2065 info->averageppm,
2066 info->changeid,
2067 info->c_setprinter,
2068 info->setuptime,
2069 info->servername,
2070 info->printername,
2071 info->sharename,
2072 info->portname,
2073 info->drivername,
2074 info->comment,
2075 info->location,
2076 info->sepfile,
2077 info->printprocessor,
2078 info->datatype,
2079 info->parameters);
2081 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2083 len += pack_values( &info->data, buf+len, buflen-len );
2085 if (buflen != len) {
2086 char *tb;
2088 tb = (char *)Realloc(buf, len);
2089 if (!tb) {
2090 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2091 ret = WERR_NOMEM;
2092 goto done;
2094 else buf = tb;
2095 buflen = len;
2096 goto again;
2100 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
2102 kbuf.dptr = key;
2103 kbuf.dsize = strlen(key)+1;
2104 dbuf.dptr = buf;
2105 dbuf.dsize = len;
2107 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2109 done:
2110 if (!W_ERROR_IS_OK(ret))
2111 DEBUG(8, ("error updating printer to tdb on disk\n"));
2113 SAFE_FREE(buf);
2115 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2116 info->sharename, info->drivername, info->portname, len));
2118 return ret;
2122 /****************************************************************************
2123 Malloc and return an NT devicemode.
2124 ****************************************************************************/
2126 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2129 char adevice[MAXDEVICENAME];
2130 NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
2132 if (nt_devmode == NULL) {
2133 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2134 return NULL;
2137 ZERO_STRUCTP(nt_devmode);
2139 safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
2140 fstrcpy(nt_devmode->devicename, adevice);
2142 fstrcpy(nt_devmode->formname, "Letter");
2144 nt_devmode->specversion = 0x0401;
2145 nt_devmode->driverversion = 0x0400;
2146 nt_devmode->size = 0x00DC;
2147 nt_devmode->driverextra = 0x0000;
2148 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2149 DEFAULTSOURCE | COPIES | SCALE |
2150 PAPERSIZE | ORIENTATION;
2151 nt_devmode->orientation = 1;
2152 nt_devmode->papersize = PAPER_LETTER;
2153 nt_devmode->paperlength = 0;
2154 nt_devmode->paperwidth = 0;
2155 nt_devmode->scale = 0x64;
2156 nt_devmode->copies = 1;
2157 nt_devmode->defaultsource = BIN_FORMSOURCE;
2158 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2159 nt_devmode->color = COLOR_MONOCHROME;
2160 nt_devmode->duplex = DUP_SIMPLEX;
2161 nt_devmode->yresolution = 0;
2162 nt_devmode->ttoption = TT_SUBDEV;
2163 nt_devmode->collate = COLLATE_FALSE;
2164 nt_devmode->icmmethod = 0;
2165 nt_devmode->icmintent = 0;
2166 nt_devmode->mediatype = 0;
2167 nt_devmode->dithertype = 0;
2169 /* non utilisés par un driver d'imprimante */
2170 nt_devmode->logpixels = 0;
2171 nt_devmode->bitsperpel = 0;
2172 nt_devmode->pelswidth = 0;
2173 nt_devmode->pelsheight = 0;
2174 nt_devmode->displayflags = 0;
2175 nt_devmode->displayfrequency = 0;
2176 nt_devmode->reserved1 = 0;
2177 nt_devmode->reserved2 = 0;
2178 nt_devmode->panningwidth = 0;
2179 nt_devmode->panningheight = 0;
2181 nt_devmode->private = NULL;
2182 return nt_devmode;
2185 /****************************************************************************
2186 Deepcopy an NT devicemode.
2187 ****************************************************************************/
2189 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2191 NT_DEVICEMODE *new_nt_devicemode = NULL;
2193 if ( !nt_devicemode )
2194 return NULL;
2196 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2197 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2198 return NULL;
2201 new_nt_devicemode->private = NULL;
2202 if (nt_devicemode->private != NULL) {
2203 if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
2204 SAFE_FREE(new_nt_devicemode);
2205 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2206 return NULL;
2210 return new_nt_devicemode;
2213 /****************************************************************************
2214 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2215 ****************************************************************************/
2217 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2219 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2221 if(nt_devmode == NULL)
2222 return;
2224 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2226 SAFE_FREE(nt_devmode->private);
2227 SAFE_FREE(*devmode_ptr);
2230 /****************************************************************************
2231 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2232 ****************************************************************************/
2233 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2235 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2236 NT_PRINTER_DATA *data;
2237 int i;
2239 if ( !info )
2240 return;
2242 DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
2244 free_nt_devicemode(&info->devmode);
2246 /* clean up all registry keys */
2248 data = &info->data;
2249 for ( i=0; i<data->num_keys; i++ ) {
2250 SAFE_FREE( data->keys[i].name );
2251 regval_ctr_destroy( &data->keys[i].values );
2253 SAFE_FREE( data->keys );
2255 /* finally the top level structure */
2257 SAFE_FREE( *info_ptr );
2261 /****************************************************************************
2262 ****************************************************************************/
2263 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2265 int len = 0;
2266 int extra_len = 0;
2267 NT_DEVICEMODE devmode;
2269 ZERO_STRUCT(devmode);
2271 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2273 if (!*nt_devmode) return len;
2275 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2276 devmode.devicename,
2277 devmode.formname,
2279 &devmode.specversion,
2280 &devmode.driverversion,
2281 &devmode.size,
2282 &devmode.driverextra,
2283 &devmode.orientation,
2284 &devmode.papersize,
2285 &devmode.paperlength,
2286 &devmode.paperwidth,
2287 &devmode.scale,
2288 &devmode.copies,
2289 &devmode.defaultsource,
2290 &devmode.printquality,
2291 &devmode.color,
2292 &devmode.duplex,
2293 &devmode.yresolution,
2294 &devmode.ttoption,
2295 &devmode.collate,
2296 &devmode.logpixels,
2298 &devmode.fields,
2299 &devmode.bitsperpel,
2300 &devmode.pelswidth,
2301 &devmode.pelsheight,
2302 &devmode.displayflags,
2303 &devmode.displayfrequency,
2304 &devmode.icmmethod,
2305 &devmode.icmintent,
2306 &devmode.mediatype,
2307 &devmode.dithertype,
2308 &devmode.reserved1,
2309 &devmode.reserved2,
2310 &devmode.panningwidth,
2311 &devmode.panningheight,
2312 &devmode.private);
2314 if (devmode.private) {
2315 /* the len in tdb_unpack is an int value and
2316 * devmode.driverextra is only a short
2318 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
2319 devmode.driverextra=(uint16)extra_len;
2321 /* check to catch an invalid TDB entry so we don't segfault */
2322 if (devmode.driverextra == 0) {
2323 devmode.private = NULL;
2327 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2329 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2330 if (devmode.private)
2331 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2333 return len;
2336 /****************************************************************************
2337 Allocate and initialize a new slot.
2338 ***************************************************************************/
2340 static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2342 NT_PRINTER_KEY *d;
2343 int key_index;
2345 if ( !data || !name )
2346 return -1;
2348 /* allocate another slot in the NT_PRINTER_KEY array */
2350 d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
2351 if ( d )
2352 data->keys = d;
2354 key_index = data->num_keys;
2356 /* initialze new key */
2358 data->num_keys++;
2359 data->keys[key_index].name = strdup( name );
2361 ZERO_STRUCTP( &data->keys[key_index].values );
2363 regval_ctr_init( &data->keys[key_index].values );
2365 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2367 return key_index;
2370 /****************************************************************************
2371 search for a registry key name in the existing printer data
2372 ***************************************************************************/
2374 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2376 int key_index = -1;
2377 int i;
2379 if ( !data || !name )
2380 return -1;
2382 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2384 /* loop over all existing keys */
2386 for ( i=0; i<data->num_keys; i++ ) {
2387 if ( strequal(data->keys[i].name, name) ) {
2388 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2389 key_index = i;
2390 break;
2395 return key_index;
2398 /****************************************************************************
2399 ***************************************************************************/
2401 uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2403 int i, j;
2404 int key_len;
2405 int num_subkeys = 0;
2406 char *p;
2407 fstring *ptr, *subkeys_ptr = NULL;
2408 fstring subkeyname;
2410 if ( !data )
2411 return 0;
2413 for ( i=0; i<data->num_keys; i++ ) {
2414 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2415 /* match sure it is a subkey and not the key itself */
2417 key_len = strlen( key );
2418 if ( strlen(data->keys[i].name) == key_len )
2419 continue;
2421 /* get subkey path */
2423 p = data->keys[i].name + key_len;
2424 if ( *p == '\\' )
2425 p++;
2426 fstrcpy( subkeyname, p );
2427 if ( (p = strchr( subkeyname, '\\' )) )
2428 *p = '\0';
2430 /* don't add a key more than once */
2432 for ( j=0; j<num_subkeys; j++ ) {
2433 if ( strequal( subkeys_ptr[j], subkeyname ) )
2434 break;
2437 if ( j != num_subkeys )
2438 continue;
2440 /* found a match, so allocate space and copy the name */
2442 if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
2443 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2444 num_subkeys+1));
2445 SAFE_FREE( subkeys );
2446 return 0;
2449 subkeys_ptr = ptr;
2450 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2451 num_subkeys++;
2456 /* tag of the end */
2458 if (num_subkeys)
2459 fstrcpy(subkeys_ptr[num_subkeys], "" );
2461 *subkeys = subkeys_ptr;
2463 return num_subkeys;
2466 #ifdef HAVE_ADS
2467 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2468 const char *sz)
2470 smb_ucs2_t conv_str[1024];
2471 size_t str_size;
2473 regval_ctr_delvalue(ctr, val_name);
2474 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2475 STR_TERMINATE | STR_NOALIGN);
2476 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2477 (char *) conv_str, str_size);
2480 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2481 uint32 dword)
2483 regval_ctr_delvalue(ctr, val_name);
2484 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2485 (char *) &dword, sizeof(dword));
2488 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2489 BOOL b)
2491 uint8 bin_bool = (b ? 1 : 0);
2492 regval_ctr_delvalue(ctr, val_name);
2493 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2494 (char *) &bin_bool, sizeof(bin_bool));
2497 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2498 const char *multi_sz)
2500 smb_ucs2_t *conv_strs = NULL;
2501 size_t str_size;
2503 /* a multi-sz has to have a null string terminator, i.e., the last
2504 string must be followed by two nulls */
2505 str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
2506 conv_strs = calloc(str_size, 1);
2508 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2509 STR_TERMINATE | STR_NOALIGN);
2511 regval_ctr_delvalue(ctr, val_name);
2512 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2513 (char *) conv_strs, str_size);
2514 safe_free(conv_strs);
2518 /****************************************************************************
2519 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2521 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2522 * @return BOOL indicating success or failure
2523 ***************************************************************************/
2525 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2527 REGVAL_CTR *ctr = NULL;
2528 fstring longname;
2529 char *allocated_string = NULL;
2530 const char *ascii_str;
2531 int i;
2533 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2534 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2535 ctr = &info2->data.keys[i].values;
2537 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2538 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2540 get_mydnsfullname(longname);
2541 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2543 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2544 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2545 SAFE_FREE(allocated_string);
2547 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2548 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2549 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2550 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2551 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2552 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2553 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2554 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2555 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2557 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2558 (info2->attributes &
2559 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2561 switch (info2->attributes & 0x3) {
2562 case 0:
2563 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2564 break;
2565 case 1:
2566 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2567 break;
2568 case 2:
2569 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2570 break;
2571 default:
2572 ascii_str = "unknown";
2574 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2576 return True;
2579 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
2580 struct uuid guid)
2582 int i;
2583 REGVAL_CTR *ctr=NULL;
2585 /* find the DsSpooler key */
2586 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2587 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2588 ctr = &info2->data.keys[i].values;
2590 regval_ctr_delvalue(ctr, "objectGUID");
2591 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2592 (char *) &guid, sizeof(struct uuid));
2595 static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
2597 ADS_STATUS ads_rc;
2598 TALLOC_CTX *ctx = talloc_init("publish_it");
2599 ADS_MODLIST mods = ads_init_mods(ctx);
2600 char *prt_dn = NULL, *srv_dn, *srv_cn_0;
2601 char *srv_dn_utf8, **srv_cn_utf8;
2602 void *res = NULL;
2603 ADS_STRUCT *ads;
2604 const char *attrs[] = {"objectGUID", NULL};
2605 struct uuid guid;
2606 WERROR win_rc = WERR_OK;
2608 ZERO_STRUCT(guid);
2609 /* set the DsSpooler info and attributes */
2610 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2)))
2611 return WERR_NOMEM;
2612 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
2613 win_rc = mod_a_printer(*printer, 2);
2614 if (!W_ERROR_IS_OK(win_rc)) {
2615 DEBUG(3, ("err %d saving data\n",
2616 W_ERROR_V(win_rc)));
2617 return win_rc;
2620 /* Build the ads mods */
2621 get_local_printer_publishing_data(ctx, &mods,
2622 &printer->info_2->data);
2623 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
2624 printer->info_2->sharename);
2626 /* initial ads structure */
2628 ads = ads_init(NULL, NULL, NULL);
2629 if (!ads) {
2630 DEBUG(3, ("ads_init() failed\n"));
2631 return WERR_SERVER_UNAVAILABLE;
2633 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2634 SAFE_FREE(ads->auth.password);
2635 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2636 NULL, NULL);
2638 /* ads_connect() will find the DC for us */
2639 ads_rc = ads_connect(ads);
2640 if (!ADS_ERR_OK(ads_rc)) {
2641 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2642 ads_destroy(&ads);
2643 return WERR_ACCESS_DENIED;
2646 /* figure out where to publish */
2647 ads_find_machine_acct(ads, &res, global_myname());
2649 /* We use ldap_get_dn here as we need the answer
2650 * in utf8 to call ldap_explode_dn(). JRA. */
2652 srv_dn_utf8 = ldap_get_dn(ads->ld, res);
2653 if (!srv_dn_utf8) {
2654 ads_destroy(&ads);
2655 return WERR_SERVER_UNAVAILABLE;
2657 ads_msgfree(ads, res);
2658 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
2659 if (!srv_cn_utf8) {
2660 ldap_memfree(srv_dn_utf8);
2661 ads_destroy(&ads);
2662 return WERR_SERVER_UNAVAILABLE;
2664 /* Now convert to CH_UNIX. */
2665 if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
2666 ldap_memfree(srv_dn_utf8);
2667 ldap_memfree(srv_cn_utf8);
2668 ads_destroy(&ads);
2669 return WERR_SERVER_UNAVAILABLE;
2671 if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
2672 ldap_memfree(srv_dn_utf8);
2673 ldap_memfree(srv_cn_utf8);
2674 ads_destroy(&ads);
2675 SAFE_FREE(srv_dn);
2676 return WERR_SERVER_UNAVAILABLE;
2679 ldap_memfree(srv_dn_utf8);
2680 ldap_memfree(srv_cn_utf8);
2682 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0,
2683 printer->info_2->sharename, srv_dn);
2685 SAFE_FREE(srv_dn);
2686 SAFE_FREE(srv_cn_0);
2688 /* publish it */
2689 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
2690 if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
2691 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx,&mods);
2693 /* retreive the guid and store it locally */
2694 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
2695 ads_memfree(ads, prt_dn);
2696 ads_pull_guid(ads, res, &guid);
2697 ads_msgfree(ads, res);
2698 store_printer_guid(printer->info_2, guid);
2699 win_rc = mod_a_printer(*printer, 2);
2702 safe_free(prt_dn);
2703 ads_destroy(&ads);
2705 return WERR_OK;
2708 WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
2710 ADS_STATUS ads_rc;
2711 ADS_STRUCT *ads;
2712 void *res;
2713 char *prt_dn = NULL;
2714 WERROR win_rc;
2716 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
2717 win_rc = mod_a_printer(*printer, 2);
2718 if (!W_ERROR_IS_OK(win_rc)) {
2719 DEBUG(3, ("err %d saving data\n",
2720 W_ERROR_V(win_rc)));
2721 return win_rc;
2724 ads = ads_init(NULL, NULL, NULL);
2725 if (!ads) {
2726 DEBUG(3, ("ads_init() failed\n"));
2727 return WERR_SERVER_UNAVAILABLE;
2729 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2730 SAFE_FREE(ads->auth.password);
2731 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2732 NULL, NULL);
2734 /* ads_connect() will find the DC for us */
2735 ads_rc = ads_connect(ads);
2736 if (!ADS_ERR_OK(ads_rc)) {
2737 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2738 ads_destroy(&ads);
2739 return WERR_ACCESS_DENIED;
2742 /* remove the printer from the directory */
2743 ads_rc = ads_find_printer_on_server(ads, &res,
2744 printer->info_2->sharename, global_myname());
2745 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
2746 prt_dn = ads_get_dn(ads, res);
2747 ads_msgfree(ads, res);
2748 ads_rc = ads_del_dn(ads, prt_dn);
2749 ads_memfree(ads, prt_dn);
2752 ads_destroy(&ads);
2753 return WERR_OK;
2756 /****************************************************************************
2757 * Publish a printer in the directory
2759 * @param snum describing printer service
2760 * @return WERROR indicating status of publishing
2761 ***************************************************************************/
2763 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2765 NT_PRINTER_INFO_LEVEL *printer = NULL;
2766 WERROR win_rc;
2768 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2769 if (!W_ERROR_IS_OK(win_rc))
2770 return win_rc;
2772 switch(action) {
2773 case SPOOL_DS_PUBLISH:
2774 case SPOOL_DS_UPDATE:
2775 win_rc = publish_it(printer);
2776 break;
2777 case SPOOL_DS_UNPUBLISH:
2778 win_rc = unpublish_it(printer);
2779 break;
2780 default:
2781 win_rc = WERR_NOT_SUPPORTED;
2785 free_a_printer(&printer, 2);
2786 return win_rc;
2789 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
2790 struct uuid *guid)
2792 NT_PRINTER_INFO_LEVEL *printer = NULL;
2793 REGVAL_CTR *ctr;
2794 REGISTRY_VALUE *guid_val;
2795 WERROR win_rc;
2796 int i;
2799 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2800 if (!W_ERROR_IS_OK(win_rc))
2801 return False;
2803 if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
2804 return False;
2806 if ((i = lookup_printerkey(&printer->info_2->data,
2807 SPOOL_DSSPOOLER_KEY)) < 0)
2808 return False;
2810 if (!(ctr = &printer->info_2->data.keys[i].values)) {
2811 return False;
2814 if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
2815 return False;
2818 if (regval_size(guid_val) == sizeof(struct uuid))
2819 memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
2821 return True;
2824 #else
2825 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2827 return WERR_OK;
2829 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
2830 struct uuid *guid)
2832 return False;
2834 #endif
2835 /****************************************************************************
2836 ***************************************************************************/
2838 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
2840 NT_PRINTER_DATA *data;
2841 int i;
2842 int removed_keys = 0;
2843 int empty_slot;
2845 data = &p2->data;
2846 empty_slot = data->num_keys;
2848 if ( !key )
2849 return WERR_INVALID_PARAM;
2851 /* remove all keys */
2853 if ( !strlen(key) ) {
2854 for ( i=0; i<data->num_keys; i++ ) {
2855 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2856 data->keys[i].name));
2858 SAFE_FREE( data->keys[i].name );
2859 regval_ctr_destroy( &data->keys[i].values );
2862 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
2863 p2->printername ));
2865 SAFE_FREE( data->keys );
2866 ZERO_STRUCTP( data );
2868 return WERR_OK;
2871 /* remove a specific key (and all subkeys) */
2873 for ( i=0; i<data->num_keys; i++ ) {
2874 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
2875 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2876 data->keys[i].name));
2878 SAFE_FREE( data->keys[i].name );
2879 regval_ctr_destroy( &data->keys[i].values );
2881 /* mark the slot as empty */
2883 ZERO_STRUCTP( &data->keys[i] );
2887 /* find the first empty slot */
2889 for ( i=0; i<data->num_keys; i++ ) {
2890 if ( !data->keys[i].name ) {
2891 empty_slot = i;
2892 removed_keys++;
2893 break;
2897 if ( i == data->num_keys )
2898 /* nothing was removed */
2899 return WERR_INVALID_PARAM;
2901 /* move everything down */
2903 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
2904 if ( data->keys[i].name ) {
2905 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
2906 ZERO_STRUCTP( &data->keys[i] );
2907 empty_slot++;
2908 removed_keys++;
2912 /* update count */
2914 data->num_keys -= removed_keys;
2916 /* sanity check to see if anything is left */
2918 if ( !data->num_keys ) {
2919 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
2921 SAFE_FREE( data->keys );
2922 ZERO_STRUCTP( data );
2925 return WERR_OK;
2928 /****************************************************************************
2929 ***************************************************************************/
2931 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2933 WERROR result = WERR_OK;
2934 int key_index;
2936 /* we must have names on non-zero length */
2938 if ( !key || !*key|| !value || !*value )
2939 return WERR_INVALID_NAME;
2941 /* find the printer key first */
2943 key_index = lookup_printerkey( &p2->data, key );
2944 if ( key_index == -1 )
2945 return WERR_OK;
2947 /* make sure the value exists so we can return the correct error code */
2949 if ( !regval_ctr_getvalue( &p2->data.keys[key_index].values, value ) )
2950 return WERR_BADFILE;
2952 regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
2954 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
2955 key, value ));
2957 return result;
2960 /****************************************************************************
2961 ***************************************************************************/
2963 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
2964 uint32 type, uint8 *data, int real_len )
2966 WERROR result = WERR_OK;
2967 int key_index;
2969 /* we must have names on non-zero length */
2971 if ( !key || !*key|| !value || !*value )
2972 return WERR_INVALID_NAME;
2974 /* find the printer key first */
2976 key_index = lookup_printerkey( &p2->data, key );
2977 if ( key_index == -1 )
2978 key_index = add_new_printer_key( &p2->data, key );
2980 if ( key_index == -1 )
2981 return WERR_NOMEM;
2983 regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
2984 type, (const char *)data, real_len );
2986 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
2987 key, value, type, real_len ));
2989 return result;
2992 /****************************************************************************
2993 ***************************************************************************/
2995 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2997 int key_index;
2999 if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
3000 return NULL;
3002 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
3003 key, value ));
3005 return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
3008 /****************************************************************************
3009 Unpack a list of registry values frem the TDB
3010 ***************************************************************************/
3012 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
3014 int len = 0;
3015 uint32 type;
3016 pstring string, valuename, keyname;
3017 char *str;
3018 int size;
3019 uint8 *data_p;
3020 REGISTRY_VALUE *regval_p;
3021 int key_index;
3023 /* add the "PrinterDriverData" key first for performance reasons */
3025 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
3027 /* loop and unpack the rest of the registry values */
3029 while ( True ) {
3031 /* check to see if there are any more registry values */
3033 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
3034 if ( !regval_p )
3035 break;
3037 /* unpack the next regval */
3039 len += tdb_unpack(buf+len, buflen-len, "fdB",
3040 string,
3041 &type,
3042 &size,
3043 &data_p);
3046 * break of the keyname from the value name.
3047 * Should only be one '\' in the string returned.
3050 str = strrchr( string, '\\');
3052 /* Put in "PrinterDriverData" is no key specified */
3054 if ( !str ) {
3055 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3056 pstrcpy( valuename, string );
3058 else {
3059 *str = '\0';
3060 pstrcpy( keyname, string );
3061 pstrcpy( valuename, str+1 );
3064 /* see if we need a new key */
3066 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3067 key_index = add_new_printer_key( printer_data, keyname );
3069 if ( key_index == -1 ) {
3070 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3071 keyname));
3072 break;
3075 /* add the new value */
3077 regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3079 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3081 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3084 return len;
3087 /****************************************************************************
3088 ***************************************************************************/
3090 static void map_to_os2_driver(fstring drivername)
3092 static BOOL initialised=False;
3093 static fstring last_from,last_to;
3094 char *mapfile = lp_os2_driver_map();
3095 char **lines = NULL;
3096 int numlines = 0;
3097 int i;
3099 if (!strlen(drivername))
3100 return;
3102 if (!*mapfile)
3103 return;
3105 if (!initialised) {
3106 *last_from = *last_to = 0;
3107 initialised = True;
3110 if (strequal(drivername,last_from)) {
3111 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3112 fstrcpy(drivername,last_to);
3113 return;
3116 lines = file_lines_load(mapfile, &numlines);
3117 if (numlines == 0) {
3118 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3119 return;
3122 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3124 for( i = 0; i < numlines; i++) {
3125 char *nt_name = lines[i];
3126 char *os2_name = strchr(nt_name,'=');
3128 if (!os2_name)
3129 continue;
3131 *os2_name++ = 0;
3133 while (isspace(*nt_name))
3134 nt_name++;
3136 if (!*nt_name || strchr("#;",*nt_name))
3137 continue;
3140 int l = strlen(nt_name);
3141 while (l && isspace(nt_name[l-1])) {
3142 nt_name[l-1] = 0;
3143 l--;
3147 while (isspace(*os2_name))
3148 os2_name++;
3151 int l = strlen(os2_name);
3152 while (l && isspace(os2_name[l-1])) {
3153 os2_name[l-1] = 0;
3154 l--;
3158 if (strequal(nt_name,drivername)) {
3159 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3160 fstrcpy(last_from,drivername);
3161 fstrcpy(last_to,os2_name);
3162 fstrcpy(drivername,os2_name);
3163 file_lines_free(lines);
3164 return;
3168 file_lines_free(lines);
3171 /****************************************************************************
3172 Get a default printer info 2 struct.
3173 ****************************************************************************/
3174 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3176 int snum;
3177 NT_PRINTER_INFO_LEVEL_2 info;
3179 ZERO_STRUCT(info);
3181 snum = lp_servicenumber(sharename);
3183 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3184 slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
3185 get_called_name(), sharename);
3186 fstrcpy(info.sharename, sharename);
3187 fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
3189 /* by setting the driver name to an empty string, a local NT admin
3190 can now run the **local** APW to install a local printer driver
3191 for a Samba shared printer in 2.2. Without this, drivers **must** be
3192 installed on the Samba server for NT clients --jerry */
3193 #if 0 /* JERRY --do not uncomment-- */
3194 if (!*info.drivername)
3195 fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3196 #endif
3199 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
3201 pstrcpy(info.comment, "");
3202 fstrcpy(info.printprocessor, "winprint");
3203 fstrcpy(info.datatype, "RAW");
3205 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3207 info.starttime = 0; /* Minutes since 12:00am GMT */
3208 info.untiltime = 0; /* Minutes since 12:00am GMT */
3209 info.priority = 1;
3210 info.default_priority = 1;
3211 info.setuptime = (uint32)time(NULL);
3214 * I changed this as I think it is better to have a generic
3215 * DEVMODE than to crash Win2k explorer.exe --jerry
3216 * See the HP Deskjet 990c Win2k drivers for an example.
3218 * However the default devmode appears to cause problems
3219 * with the HP CLJ 8500 PCL driver. Hence the addition of
3220 * the "default devmode" parameter --jerry 22/01/2002
3223 if (lp_default_devmode(snum)) {
3224 if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
3225 goto fail;
3227 else {
3228 info.devmode = NULL;
3231 /* This will get the current RPC talloc context, but we should be
3232 passing this as a parameter... fixme... JRA ! */
3234 if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
3235 goto fail;
3237 *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
3238 if (! *info_ptr) {
3239 DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
3240 goto fail;
3243 return WERR_OK;
3245 fail:
3246 if (info.devmode)
3247 free_nt_devicemode(&info.devmode);
3248 return WERR_ACCESS_DENIED;
3251 /****************************************************************************
3252 ****************************************************************************/
3253 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3255 pstring key;
3256 NT_PRINTER_INFO_LEVEL_2 info;
3257 int len = 0;
3258 TDB_DATA kbuf, dbuf;
3259 fstring printername;
3260 char adevice[MAXDEVICENAME];
3262 ZERO_STRUCT(info);
3264 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
3266 kbuf.dptr = key;
3267 kbuf.dsize = strlen(key)+1;
3269 dbuf = tdb_fetch(tdb_printers, kbuf);
3270 if (!dbuf.dptr)
3271 return get_a_printer_2_default(info_ptr, sharename);
3273 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3274 &info.attributes,
3275 &info.priority,
3276 &info.default_priority,
3277 &info.starttime,
3278 &info.untiltime,
3279 &info.status,
3280 &info.cjobs,
3281 &info.averageppm,
3282 &info.changeid,
3283 &info.c_setprinter,
3284 &info.setuptime,
3285 info.servername,
3286 info.printername,
3287 info.sharename,
3288 info.portname,
3289 info.drivername,
3290 info.comment,
3291 info.location,
3292 info.sepfile,
3293 info.printprocessor,
3294 info.datatype,
3295 info.parameters);
3297 /* Samba has to have shared raw drivers. */
3298 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3300 /* Restore the stripped strings. */
3301 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3302 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", get_called_name(),
3303 info.printername);
3304 fstrcpy(info.printername, printername);
3306 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3309 * Some client drivers freak out if there is a NULL devmode
3310 * (probably the driver is not checking before accessing
3311 * the devmode pointer) --jerry
3313 * See comments in get_a_printer_2_default()
3316 if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
3317 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3318 printername));
3319 info.devmode = construct_nt_devicemode(printername);
3322 safe_strcpy(adevice, info.printername, sizeof(adevice)-1);
3323 if (info.devmode) {
3324 fstrcpy(info.devmode->devicename, adevice);
3327 len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
3329 /* This will get the current RPC talloc context, but we should be
3330 passing this as a parameter... fixme... JRA ! */
3332 nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
3334 /* Fix for OS/2 drivers. */
3336 if (get_remote_arch() == RA_OS2)
3337 map_to_os2_driver(info.drivername);
3339 SAFE_FREE(dbuf.dptr);
3340 *info_ptr=memdup(&info, sizeof(info));
3342 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3343 sharename, info.printername, info.drivername));
3345 return WERR_OK;
3348 /****************************************************************************
3349 Debugging function, dump at level 6 the struct in the logs.
3350 ****************************************************************************/
3351 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3353 uint32 result;
3354 NT_PRINTER_INFO_LEVEL_2 *info2;
3356 DEBUG(106,("Dumping printer at level [%d]\n", level));
3358 switch (level) {
3359 case 2:
3361 if (printer.info_2 == NULL)
3362 result=5;
3363 else
3365 info2=printer.info_2;
3367 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3368 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3369 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3370 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3371 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3372 DEBUGADD(106,("status:[%d]\n", info2->status));
3373 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3374 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3375 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3376 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3377 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3379 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3380 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3381 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3382 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3383 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3384 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3385 DEBUGADD(106,("location:[%s]\n", info2->location));
3386 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3387 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3388 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3389 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3390 result=0;
3392 break;
3394 default:
3395 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3396 result=1;
3397 break;
3400 return result;
3403 /****************************************************************************
3404 Update the changeid time.
3405 This is SO NASTY as some drivers need this to change, others need it
3406 static. This value will change every second, and I must hope that this
3407 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3408 UTAH ! JRA.
3409 ****************************************************************************/
3411 static uint32 rev_changeid(void)
3413 struct timeval tv;
3415 get_process_uptime(&tv);
3417 #if 1 /* JERRY */
3418 /* Return changeid as msec since spooler restart */
3419 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3420 #else
3422 * This setting seems to work well but is too untested
3423 * to replace the above calculation. Left in for experiementation
3424 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3426 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3427 #endif
3431 * The function below are the high level ones.
3432 * only those ones must be called from the spoolss code.
3433 * JFM.
3436 /****************************************************************************
3437 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3438 ****************************************************************************/
3440 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3442 WERROR result;
3444 dump_a_printer(printer, level);
3447 * invalidate cache for all open handles to this printer.
3448 * cache for a given handle will be updated on the next
3449 * get_a_printer()
3452 invalidate_printer_hnd_cache( printer.info_2->sharename );
3454 switch (level) {
3455 case 2:
3458 * Update the changestamp. Emperical tests show that the
3459 * ChangeID is always updated,but c_setprinter is
3460 * global spooler variable (not per printer).
3463 /* ChangeID **must** be increasing over the lifetime
3464 of client's spoolss service in order for the
3465 client's cache to show updates */
3467 printer.info_2->changeid = rev_changeid();
3470 * Because one day someone will ask:
3471 * NT->NT An admin connection to a remote
3472 * printer show changes imeediately in
3473 * the properities dialog
3475 * A non-admin connection will only show the
3476 * changes after viewing the properites page
3477 * 2 times. Seems to be related to a
3478 * race condition in the client between the spooler
3479 * updating the local cache and the Explorer.exe GUI
3480 * actually displaying the properties.
3482 * This is fixed in Win2k. admin/non-admin
3483 * connections both display changes immediately.
3485 * 14/12/01 --jerry
3488 result=update_a_printer_2(printer.info_2);
3490 break;
3492 default:
3493 result=WERR_UNKNOWN_LEVEL;
3494 break;
3497 return result;
3500 /****************************************************************************
3501 Initialize printer devmode & data with previously saved driver init values.
3502 ****************************************************************************/
3504 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3506 int len = 0;
3507 pstring key;
3508 TDB_DATA kbuf, dbuf;
3509 NT_PRINTER_INFO_LEVEL_2 info;
3512 ZERO_STRUCT(info);
3515 * Delete any printer data 'values' already set. When called for driver
3516 * replace, there will generally be some, but during an add printer, there
3517 * should not be any (if there are delete them).
3520 delete_all_printer_data( info_ptr, "" );
3522 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3524 kbuf.dptr = key;
3525 kbuf.dsize = strlen(key)+1;
3527 dbuf = tdb_fetch(tdb_drivers, kbuf);
3528 if (!dbuf.dptr) {
3530 * When changing to a driver that has no init info in the tdb, remove
3531 * the previous drivers init info and leave the new on blank.
3533 free_nt_devicemode(&info_ptr->devmode);
3534 return False;
3538 * Get the saved DEVMODE..
3541 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3544 * The saved DEVMODE contains the devicename from the printer used during
3545 * the initialization save. Change it to reflect the new printer.
3548 if ( info.devmode ) {
3549 ZERO_STRUCT(info.devmode->devicename);
3550 fstrcpy(info.devmode->devicename, info_ptr->printername);
3554 * NT/2k does not change out the entire DeviceMode of a printer
3555 * when changing the driver. Only the driverextra, private, &
3556 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3558 * Later examination revealed that Windows NT/2k does reset the
3559 * the printer's device mode, bit **only** when you change a
3560 * property of the device mode such as the page orientation.
3561 * --jerry
3565 /* Bind the saved DEVMODE to the new the printer */
3567 free_nt_devicemode(&info_ptr->devmode);
3568 info_ptr->devmode = info.devmode;
3570 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3571 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3573 /* Add the printer data 'values' to the new printer */
3575 len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3578 SAFE_FREE(dbuf.dptr);
3580 return True;
3583 /****************************************************************************
3584 Initialize printer devmode & data with previously saved driver init values.
3585 When a printer is created using AddPrinter, the drivername bound to the
3586 printer is used to lookup previously saved driver initialization info, which
3587 is bound to the new printer.
3588 ****************************************************************************/
3590 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3592 BOOL result = False;
3594 switch (level) {
3595 case 2:
3596 result = set_driver_init_2(printer->info_2);
3597 break;
3599 default:
3600 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
3601 level));
3602 break;
3605 return result;
3608 /****************************************************************************
3609 Delete driver init data stored for a specified driver
3610 ****************************************************************************/
3612 BOOL del_driver_init(char *drivername)
3614 pstring key;
3615 TDB_DATA kbuf;
3617 if (!drivername || !*drivername) {
3618 DEBUG(3,("del_driver_init: No drivername specified!\n"));
3619 return False;
3622 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
3624 kbuf.dptr = key;
3625 kbuf.dsize = strlen(key)+1;
3627 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
3629 return (tdb_delete(tdb_drivers, kbuf) == 0);
3632 /****************************************************************************
3633 Pack up the DEVMODE and values for a printer into a 'driver init' entry
3634 in the tdb. Note: this is different from the driver entry and the printer
3635 entry. There should be a single driver init entry for each driver regardless
3636 of whether it was installed from NT or 2K. Technically, they should be
3637 different, but they work out to the same struct.
3638 ****************************************************************************/
3640 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
3642 pstring key;
3643 char *buf;
3644 int buflen, len, ret;
3645 TDB_DATA kbuf, dbuf;
3647 buf = NULL;
3648 buflen = 0;
3650 again:
3651 len = 0;
3652 len += pack_devicemode(info->devmode, buf+len, buflen-len);
3654 len += pack_values( &info->data, buf+len, buflen-len );
3656 if (buflen != len) {
3657 char *tb;
3659 tb = (char *)Realloc(buf, len);
3660 if (!tb) {
3661 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
3662 ret = -1;
3663 goto done;
3665 else
3666 buf = tb;
3667 buflen = len;
3668 goto again;
3671 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
3673 kbuf.dptr = key;
3674 kbuf.dsize = strlen(key)+1;
3675 dbuf.dptr = buf;
3676 dbuf.dsize = len;
3678 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
3680 done:
3681 if (ret == -1)
3682 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
3684 SAFE_FREE(buf);
3686 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
3687 info->sharename, info->drivername));
3689 return ret;
3692 /****************************************************************************
3693 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
3694 ****************************************************************************/
3696 uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3698 uint32 result;
3700 dump_a_printer(printer, level);
3702 switch (level) {
3703 case 2:
3704 result = update_driver_init_2(printer.info_2);
3705 break;
3706 default:
3707 result = 1;
3708 break;
3711 return result;
3714 /****************************************************************************
3715 Convert the printer data value, a REG_BINARY array, into an initialization
3716 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
3717 got to keep the endians happy :).
3718 ****************************************************************************/
3720 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
3722 BOOL result = False;
3723 prs_struct ps;
3724 DEVICEMODE devmode;
3726 ZERO_STRUCT(devmode);
3728 prs_init(&ps, 0, ctx, UNMARSHALL);
3729 ps.data_p = (char *)data;
3730 ps.buffer_size = data_len;
3732 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
3733 result = convert_devicemode("", &devmode, &nt_devmode);
3734 else
3735 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
3737 return result;
3740 /****************************************************************************
3741 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
3743 1. Use the driver's config DLL to this UNC printername and:
3744 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
3745 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
3746 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
3748 The last step triggers saving the "driver initialization" information for
3749 this printer into the tdb. Later, new printers that use this driver will
3750 have this initialization information bound to them. This simulates the
3751 driver initialization, as if it had run on the Samba server (as it would
3752 have done on NT).
3754 The Win32 client side code requirement sucks! But until we can run arbitrary
3755 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
3757 It would have been easier to use SetPrinter because all the UNMARSHALLING of
3758 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
3759 about it and you will realize why. JRR 010720
3760 ****************************************************************************/
3762 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
3764 WERROR status = WERR_OK;
3765 TALLOC_CTX *ctx = NULL;
3766 NT_DEVICEMODE *nt_devmode = NULL;
3767 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
3770 * When the DEVMODE is already set on the printer, don't try to unpack it.
3772 DEBUG(8,("save_driver_init_2: Enter...\n"));
3774 if ( !printer->info_2->devmode && data_len ) {
3776 * Set devmode on printer info, so entire printer initialization can be
3777 * saved to tdb.
3780 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
3781 return WERR_NOMEM;
3783 if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
3784 status = WERR_NOMEM;
3785 goto done;
3788 ZERO_STRUCTP(nt_devmode);
3791 * The DEVMODE is held in the 'data' component of the param in raw binary.
3792 * Convert it to to a devmode structure
3794 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
3795 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
3796 status = WERR_INVALID_PARAM;
3797 goto done;
3800 printer->info_2->devmode = nt_devmode;
3804 * Pack up and add (or update) the DEVMODE and any current printer data to
3805 * a 'driver init' element in the tdb
3809 if ( update_driver_init(*printer, 2) != 0 ) {
3810 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
3811 status = WERR_NOMEM;
3812 goto done;
3816 * If driver initialization info was successfully saved, set the current
3817 * printer to match it. This allows initialization of the current printer
3818 * as well as the driver.
3820 status = mod_a_printer(*printer, 2);
3821 if (!W_ERROR_IS_OK(status)) {
3822 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
3823 printer->info_2->printername));
3826 done:
3827 talloc_destroy(ctx);
3828 free_nt_devicemode( &nt_devmode );
3830 printer->info_2->devmode = tmp_devmode;
3832 return status;
3835 /****************************************************************************
3836 Update the driver init info (DEVMODE and specifics) for a printer
3837 ****************************************************************************/
3839 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
3841 WERROR status = WERR_OK;
3843 switch (level) {
3844 case 2:
3845 status = save_driver_init_2( printer, data, data_len );
3846 break;
3847 default:
3848 status = WERR_UNKNOWN_LEVEL;
3849 break;
3852 return status;
3855 /****************************************************************************
3856 Deep copy a NT_PRINTER_DATA
3857 ****************************************************************************/
3859 static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src )
3861 int i, j, num_vals, new_key_index;
3862 REGVAL_CTR *src_key, *dst_key;
3864 if ( !dst || !src )
3865 return NT_STATUS_NO_MEMORY;
3867 for ( i=0; i<src->num_keys; i++ ) {
3869 /* create a new instance of the printerkey in the destination
3870 printer_data object */
3872 new_key_index = add_new_printer_key( dst, src->keys[i].name );
3873 dst_key = &dst->keys[new_key_index].values;
3875 src_key = &src->keys[i].values;
3876 num_vals = regval_ctr_numvals( src_key );
3878 /* dup the printer entire printer key */
3880 for ( j=0; j<num_vals; j++ ) {
3881 regval_ctr_copyvalue( dst_key, regval_ctr_specific_value(src_key, j) );
3885 return NT_STATUS_OK;
3888 /****************************************************************************
3889 Deep copy a NT_PRINTER_INFO_LEVEL_2 structure using malloc()'d memeory
3890 Caller must free.
3891 ****************************************************************************/
3893 NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 *printer )
3895 NT_PRINTER_INFO_LEVEL_2 *copy;
3897 if ( !printer )
3898 return NULL;
3900 if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
3901 return NULL;
3903 memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
3905 /* malloc()'d members copied here */
3907 copy->devmode = dup_nt_devicemode( printer->devmode );
3909 ZERO_STRUCT( copy->data );
3910 copy_printer_data( &copy->data, &printer->data );
3912 /* this is talloc()'d; very ugly that we have a structure that
3913 is half malloc()'d and half talloc()'d but that is the way
3914 that the PRINTER_INFO stuff is written right now. --jerry */
3916 copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf );
3918 return copy;
3921 /****************************************************************************
3922 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
3924 Previously the code had a memory allocation problem because it always
3925 used the TALLOC_CTX from the Printer_entry*. This context lasts
3926 as a long as the original handle is open. So if the client made a lot
3927 of getprinter[data]() calls, the memory usage would climb. Now we use
3928 a short lived TALLOC_CTX for printer_info_2 objects returned. We
3929 still use the Printer_entry->ctx for maintaining the cache copy though
3930 since that object must live as long as the handle by definition.
3931 --jerry
3933 ****************************************************************************/
3935 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
3936 const char *sharename)
3938 WERROR result;
3939 NT_PRINTER_INFO_LEVEL *printer = NULL;
3941 *pp_printer = NULL;
3943 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
3945 switch (level) {
3946 case 2:
3947 if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
3948 DEBUG(0,("get_a_printer: malloc fail.\n"));
3949 return WERR_NOMEM;
3951 ZERO_STRUCTP(printer);
3954 * check for cache first. A Printer handle cannot changed
3955 * to another printer object so we only check that the printer
3956 * is actually for a printer and that the printer_info pointer
3957 * is valid
3959 if ( print_hnd
3960 && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)
3961 && print_hnd->printer_info )
3963 /* get_talloc_ctx() works here because we need a short
3964 lived talloc context */
3966 if ( !(printer->info_2 = dup_printer_2(get_talloc_ctx(), print_hnd->printer_info->info_2)) )
3968 DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
3970 SAFE_FREE(printer);
3971 return WERR_NOMEM;
3974 DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n"));
3976 *pp_printer = printer;
3977 result = WERR_OK;
3979 break;
3982 /* no cache for this handle; see if we can match one from another handle.
3983 Make sure to use a short lived talloc ctx */
3985 if ( print_hnd )
3986 result = find_printer_in_print_hnd_cache(get_talloc_ctx(), &printer->info_2, sharename);
3988 /* fail to disk if we don't have it with any open handle */
3990 if ( !print_hnd || !W_ERROR_IS_OK(result) )
3991 result = get_a_printer_2(&printer->info_2, sharename);
3993 /* we have a new printer now. Save it with this handle */
3995 if ( W_ERROR_IS_OK(result) ) {
3996 dump_a_printer(*printer, level);
3998 /* save a copy in cache */
3999 if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
4000 if ( !print_hnd->printer_info )
4001 print_hnd->printer_info = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL));
4003 if ( print_hnd->printer_info ) {
4004 /* make sure to use the handle's talloc ctx here since
4005 the printer_2 object must last until the handle is closed */
4007 print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2);
4009 /* don't fail the lookup just because the cache update failed */
4010 if ( !print_hnd->printer_info->info_2 )
4011 DEBUG(0,("get_a_printer: unable to copy new printer info!\n"));
4014 *pp_printer = printer;
4016 else
4017 SAFE_FREE(printer);
4019 break;
4021 default:
4022 result=WERR_UNKNOWN_LEVEL;
4023 break;
4026 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result)));
4028 return result;
4031 /****************************************************************************
4032 Deletes a NT_PRINTER_INFO_LEVEL struct.
4033 ****************************************************************************/
4035 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
4037 uint32 result;
4038 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
4040 DEBUG(104,("freeing a printer at level [%d]\n", level));
4042 if (printer == NULL)
4043 return 0;
4045 switch (level) {
4046 case 2:
4047 if (printer->info_2 != NULL) {
4048 free_nt_printer_info_level_2(&printer->info_2);
4049 result=0;
4050 } else
4051 result=4;
4052 break;
4054 default:
4055 result=1;
4056 break;
4059 SAFE_FREE(*pp_printer);
4060 return result;
4063 /****************************************************************************
4064 ****************************************************************************/
4065 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4067 uint32 result;
4068 DEBUG(104,("adding a printer at level [%d]\n", level));
4069 dump_a_printer_driver(driver, level);
4071 switch (level) {
4072 case 3:
4073 result=add_a_printer_driver_3(driver.info_3);
4074 break;
4076 case 6:
4077 result=add_a_printer_driver_6(driver.info_6);
4078 break;
4080 default:
4081 result=1;
4082 break;
4085 return result;
4087 /****************************************************************************
4088 ****************************************************************************/
4090 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4091 fstring drivername, const char *architecture, uint32 version)
4093 WERROR result;
4095 switch (level) {
4096 case 3:
4097 /* Sometime we just want any version of the driver */
4099 if ( version == DRIVER_ANY_VERSION ) {
4100 /* look for Win2k first and then for NT4 */
4101 result = get_a_printer_driver_3(&driver->info_3, drivername,
4102 architecture, 3);
4104 if ( !W_ERROR_IS_OK(result) ) {
4105 result = get_a_printer_driver_3( &driver->info_3,
4106 drivername, architecture, 2 );
4108 } else {
4109 result = get_a_printer_driver_3(&driver->info_3, drivername,
4110 architecture, version);
4112 break;
4114 default:
4115 result=W_ERROR(1);
4116 break;
4119 if (W_ERROR_IS_OK(result))
4120 dump_a_printer_driver(*driver, level);
4122 return result;
4125 /****************************************************************************
4126 ****************************************************************************/
4127 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4129 uint32 result;
4131 switch (level) {
4132 case 3:
4134 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4135 if (driver.info_3 != NULL)
4137 info3=driver.info_3;
4138 SAFE_FREE(info3->dependentfiles);
4139 ZERO_STRUCTP(info3);
4140 SAFE_FREE(info3);
4141 result=0;
4142 } else {
4143 result=4;
4145 break;
4147 case 6:
4149 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4150 if (driver.info_6 != NULL) {
4151 info6=driver.info_6;
4152 SAFE_FREE(info6->dependentfiles);
4153 SAFE_FREE(info6->previousnames);
4154 ZERO_STRUCTP(info6);
4155 SAFE_FREE(info6);
4156 result=0;
4157 } else {
4158 result=4;
4160 break;
4162 default:
4163 result=1;
4164 break;
4166 return result;
4170 /****************************************************************************
4171 Determine whether or not a particular driver is currently assigned
4172 to a printer
4173 ****************************************************************************/
4175 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4177 int snum;
4178 int n_services = lp_numservices();
4179 NT_PRINTER_INFO_LEVEL *printer = NULL;
4181 if ( !info_3 )
4182 return False;
4184 DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4186 /* loop through the printers.tdb and check for the drivername */
4188 for (snum=0; snum<n_services; snum++) {
4189 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4190 continue;
4192 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4193 continue;
4195 if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
4196 free_a_printer( &printer, 2 );
4197 return True;
4200 free_a_printer( &printer, 2 );
4203 DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4205 /* report that the driver is not in use by default */
4207 return False;
4211 /**********************************************************************
4212 Check to see if a ogiven file is in use by *info
4213 *********************************************************************/
4215 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4217 int i = 0;
4219 if ( !info )
4220 return False;
4222 if ( strequal(file, info->driverpath) )
4223 return True;
4225 if ( strequal(file, info->datafile) )
4226 return True;
4228 if ( strequal(file, info->configfile) )
4229 return True;
4231 if ( strequal(file, info->helpfile) )
4232 return True;
4234 /* see of there are any dependent files to examine */
4236 if ( !info->dependentfiles )
4237 return False;
4239 while ( *info->dependentfiles[i] ) {
4240 if ( strequal(file, info->dependentfiles[i]) )
4241 return True;
4242 i++;
4245 return False;
4249 /**********************************************************************
4250 Utility function to remove the dependent file pointed to by the
4251 input parameter from the list
4252 *********************************************************************/
4254 static void trim_dependent_file( fstring files[], int idx )
4257 /* bump everything down a slot */
4259 while( *files[idx+1] ) {
4260 fstrcpy( files[idx], files[idx+1] );
4261 idx++;
4264 *files[idx] = '\0';
4266 return;
4269 /**********************************************************************
4270 Check if any of the files used by src are also used by drv
4271 *********************************************************************/
4273 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4274 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4276 BOOL in_use = False;
4277 int i = 0;
4279 if ( !src || !drv )
4280 return False;
4282 /* check each file. Remove it from the src structure if it overlaps */
4284 if ( drv_file_in_use(src->driverpath, drv) ) {
4285 in_use = True;
4286 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4287 fstrcpy( src->driverpath, "" );
4290 if ( drv_file_in_use(src->datafile, drv) ) {
4291 in_use = True;
4292 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4293 fstrcpy( src->datafile, "" );
4296 if ( drv_file_in_use(src->configfile, drv) ) {
4297 in_use = True;
4298 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4299 fstrcpy( src->configfile, "" );
4302 if ( drv_file_in_use(src->helpfile, drv) ) {
4303 in_use = True;
4304 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4305 fstrcpy( src->helpfile, "" );
4308 /* are there any dependentfiles to examine? */
4310 if ( !src->dependentfiles )
4311 return in_use;
4313 while ( *src->dependentfiles[i] ) {
4314 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4315 in_use = True;
4316 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4317 trim_dependent_file( src->dependentfiles, i );
4318 } else
4319 i++;
4322 return in_use;
4325 /****************************************************************************
4326 Determine whether or not a particular driver files are currently being
4327 used by any other driver.
4329 Return value is True if any files were in use by other drivers
4330 and False otherwise.
4332 Upon return, *info has been modified to only contain the driver files
4333 which are not in use
4334 ****************************************************************************/
4336 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4338 int i;
4339 int ndrivers;
4340 uint32 version;
4341 fstring *list = NULL;
4342 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4344 if ( !info )
4345 return False;
4347 version = info->cversion;
4349 /* loop over all driver versions */
4351 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4353 /* get the list of drivers */
4355 list = NULL;
4356 ndrivers = get_ntdrivers(&list, info->environment, version);
4358 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4359 ndrivers, info->environment, version));
4361 /* check each driver for overlap in files */
4363 for (i=0; i<ndrivers; i++) {
4364 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4366 ZERO_STRUCT(driver);
4368 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4369 SAFE_FREE(list);
4370 return True;
4373 /* check if d2 uses any files from d1 */
4374 /* only if this is a different driver than the one being deleted */
4376 if ( !strequal(info->name, driver.info_3->name) ) {
4377 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4378 free_a_printer_driver(driver, 3);
4379 SAFE_FREE( list );
4380 return True;
4384 free_a_printer_driver(driver, 3);
4387 SAFE_FREE(list);
4389 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4391 driver.info_3 = info;
4393 if ( DEBUGLEVEL >= 20 )
4394 dump_a_printer_driver( driver, 3 );
4396 return False;
4399 /****************************************************************************
4400 Actually delete the driver files. Make sure that
4401 printer_driver_files_in_use() return False before calling
4402 this.
4403 ****************************************************************************/
4405 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4407 int i = 0;
4408 char *s;
4409 connection_struct *conn;
4410 DATA_BLOB null_pw;
4411 NTSTATUS nt_status;
4412 fstring res_type;
4414 if ( !info_3 )
4415 return False;
4417 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4420 * Connect to the print$ share under the same account as the
4421 * user connected to the rpc pipe. Note we must be root to
4422 * do this.
4425 null_pw = data_blob( NULL, 0 );
4426 fstrcpy(res_type, "A:");
4427 become_root();
4428 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4429 unbecome_root();
4431 if ( !conn ) {
4432 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4433 return False;
4436 /* Save who we are - we are temporarily becoming the connection user. */
4438 if ( !become_user(conn, conn->vuid) ) {
4439 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4440 return False;
4443 /* now delete the files; must strip the '\print$' string from
4444 fron of path */
4446 if ( *info_3->driverpath ) {
4447 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4448 DEBUG(10,("deleting driverfile [%s]\n", s));
4449 unlink_internals(conn, 0, s);
4453 if ( *info_3->configfile ) {
4454 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4455 DEBUG(10,("deleting configfile [%s]\n", s));
4456 unlink_internals(conn, 0, s);
4460 if ( *info_3->datafile ) {
4461 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4462 DEBUG(10,("deleting datafile [%s]\n", s));
4463 unlink_internals(conn, 0, s);
4467 if ( *info_3->helpfile ) {
4468 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4469 DEBUG(10,("deleting helpfile [%s]\n", s));
4470 unlink_internals(conn, 0, s);
4474 /* check if we are done removing files */
4476 if ( info_3->dependentfiles ) {
4477 while ( *info_3->dependentfiles[i] ) {
4478 char *file;
4480 /* bypass the "\print$" portion of the path */
4482 if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4483 DEBUG(10,("deleting dependent file [%s]\n", file));
4484 unlink_internals(conn, 0, file );
4487 i++;
4491 unbecome_user();
4493 return True;
4496 /****************************************************************************
4497 Remove a printer driver from the TDB. This assumes that the the driver was
4498 previously looked up.
4499 ***************************************************************************/
4501 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4502 uint32 version, BOOL delete_files )
4504 pstring key;
4505 const char *arch;
4506 TDB_DATA kbuf, dbuf;
4507 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4509 /* delete the tdb data first */
4511 arch = get_short_archi(info_3->environment);
4512 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4513 arch, version, info_3->name);
4515 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4516 key, delete_files ? "TRUE" : "FALSE" ));
4518 ctr.info_3 = info_3;
4519 dump_a_printer_driver( ctr, 3 );
4521 kbuf.dptr=key;
4522 kbuf.dsize=strlen(key)+1;
4524 /* check if the driver actually exists for this environment */
4526 dbuf = tdb_fetch( tdb_drivers, kbuf );
4527 if ( !dbuf.dptr ) {
4528 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4529 return WERR_UNKNOWN_PRINTER_DRIVER;
4532 SAFE_FREE( dbuf.dptr );
4534 /* ok... the driver exists so the delete should return success */
4536 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4537 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4538 return WERR_ACCESS_DENIED;
4542 * now delete any associated files if delete_files == True
4543 * even if this part failes, we return succes because the
4544 * driver doesn not exist any more
4547 if ( delete_files )
4548 delete_driver_files( info_3, user );
4551 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4553 return WERR_OK;
4556 /****************************************************************************
4557 Store a security desc for a printer.
4558 ****************************************************************************/
4560 WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
4562 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4563 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4564 prs_struct ps;
4565 TALLOC_CTX *mem_ctx = NULL;
4566 fstring key;
4567 WERROR status;
4569 mem_ctx = talloc_init("nt_printing_setsec");
4570 if (mem_ctx == NULL)
4571 return WERR_NOMEM;
4573 /* The old owner and group sids of the security descriptor are not
4574 present when new ACEs are added or removed by changing printer
4575 permissions through NT. If they are NULL in the new security
4576 descriptor then copy them over from the old one. */
4578 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4579 DOM_SID *owner_sid, *group_sid;
4580 SEC_ACL *dacl, *sacl;
4581 SEC_DESC *psd = NULL;
4582 size_t size;
4584 nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
4586 /* Pick out correct owner and group sids */
4588 owner_sid = secdesc_ctr->sec->owner_sid ?
4589 secdesc_ctr->sec->owner_sid :
4590 old_secdesc_ctr->sec->owner_sid;
4592 group_sid = secdesc_ctr->sec->grp_sid ?
4593 secdesc_ctr->sec->grp_sid :
4594 old_secdesc_ctr->sec->grp_sid;
4596 dacl = secdesc_ctr->sec->dacl ?
4597 secdesc_ctr->sec->dacl :
4598 old_secdesc_ctr->sec->dacl;
4600 sacl = secdesc_ctr->sec->sacl ?
4601 secdesc_ctr->sec->sacl :
4602 old_secdesc_ctr->sec->sacl;
4604 /* Make a deep copy of the security descriptor */
4606 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type,
4607 owner_sid, group_sid,
4608 sacl,
4609 dacl,
4610 &size);
4612 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4615 if (!new_secdesc_ctr) {
4616 new_secdesc_ctr = secdesc_ctr;
4619 /* Store the security descriptor in a tdb */
4621 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4622 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4624 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4625 &ps, 1)) {
4626 status = WERR_BADFUNC;
4627 goto out;
4630 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4632 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4633 status = WERR_OK;
4634 } else {
4635 DEBUG(1,("Failed to store secdesc for %s\n", printername));
4636 status = WERR_BADFUNC;
4639 /* Free malloc'ed memory */
4641 out:
4643 prs_mem_free(&ps);
4644 if (mem_ctx)
4645 talloc_destroy(mem_ctx);
4646 return status;
4649 /****************************************************************************
4650 Construct a default security descriptor buffer for a printer.
4651 ****************************************************************************/
4653 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
4655 SEC_ACE ace[3];
4656 SEC_ACCESS sa;
4657 SEC_ACL *psa = NULL;
4658 SEC_DESC_BUF *sdb = NULL;
4659 SEC_DESC *psd = NULL;
4660 DOM_SID owner_sid;
4661 size_t sd_size;
4663 /* Create an ACE where Everyone is allowed to print */
4665 init_sec_access(&sa, PRINTER_ACE_PRINT);
4666 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
4667 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4669 /* Make the security descriptor owned by the Administrators group
4670 on the PDC of the domain. */
4672 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4673 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4674 } else {
4676 /* Backup plan - make printer owned by admins.
4677 This should emulate a lanman printer as security
4678 settings can't be changed. */
4680 sid_copy(&owner_sid, get_global_sam_sid());
4681 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4684 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4685 init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4686 sa, SEC_ACE_FLAG_OBJECT_INHERIT |
4687 SEC_ACE_FLAG_INHERIT_ONLY);
4689 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4690 init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4691 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4693 /* The ACL revision number in rpc_secdesc.h differs from the one
4694 created by NT when setting ACE entries in printer
4695 descriptors. NT4 complains about the property being edited by a
4696 NT5 machine. */
4698 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
4699 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
4700 &owner_sid, NULL,
4701 NULL, psa, &sd_size);
4704 if (!psd) {
4705 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
4706 return NULL;
4709 sdb = make_sec_desc_buf(ctx, sd_size, psd);
4711 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
4712 (unsigned int)sd_size));
4714 return sdb;
4717 /****************************************************************************
4718 Get a security desc for a printer.
4719 ****************************************************************************/
4721 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
4723 prs_struct ps;
4724 fstring key;
4725 char *temp;
4727 if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
4728 printername = temp + 1;
4731 /* Fetch security descriptor from tdb */
4733 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4735 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
4736 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
4738 DEBUG(4,("using default secdesc for %s\n", printername));
4740 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
4741 return False;
4744 /* Save default security descriptor for later */
4746 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
4747 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
4749 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
4750 tdb_prs_store(tdb_printers, key, &ps);
4752 prs_mem_free(&ps);
4754 return True;
4757 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
4758 this security descriptor has been created when winbindd was
4759 down. Take ownership of security descriptor. */
4761 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
4762 DOM_SID owner_sid;
4764 /* Change sd owner to workgroup administrator */
4766 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4767 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4768 SEC_DESC *psd = NULL;
4769 size_t size;
4771 /* Create new sd */
4773 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4775 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type,
4776 &owner_sid,
4777 (*secdesc_ctr)->sec->grp_sid,
4778 (*secdesc_ctr)->sec->sacl,
4779 (*secdesc_ctr)->sec->dacl,
4780 &size);
4782 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
4784 /* Swap with other one */
4786 *secdesc_ctr = new_secdesc_ctr;
4788 /* Set it */
4790 nt_printing_setsec(printername, *secdesc_ctr);
4794 if (DEBUGLEVEL >= 10) {
4795 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
4796 int i;
4798 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
4799 printername, the_acl->num_aces));
4801 for (i = 0; i < the_acl->num_aces; i++) {
4802 fstring sid_str;
4804 sid_to_string(sid_str, &the_acl->ace[i].trustee);
4806 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
4807 the_acl->ace[i].type, the_acl->ace[i].flags,
4808 the_acl->ace[i].info.mask));
4812 prs_mem_free(&ps);
4813 return True;
4816 /* error code:
4817 0: everything OK
4818 1: level not implemented
4819 2: file doesn't exist
4820 3: can't allocate memory
4821 4: can't free memory
4822 5: non existant struct
4826 A printer and a printer driver are 2 different things.
4827 NT manages them separatelly, Samba does the same.
4828 Why ? Simply because it's easier and it makes sense !
4830 Now explanation: You have 3 printers behind your samba server,
4831 2 of them are the same make and model (laser A and B). But laser B
4832 has an 3000 sheet feeder and laser A doesn't such an option.
4833 Your third printer is an old dot-matrix model for the accounting :-).
4835 If the /usr/local/samba/lib directory (default dir), you will have
4836 5 files to describe all of this.
4838 3 files for the printers (1 by printer):
4839 NTprinter_laser A
4840 NTprinter_laser B
4841 NTprinter_accounting
4842 2 files for the drivers (1 for the laser and 1 for the dot matrix)
4843 NTdriver_printer model X
4844 NTdriver_printer model Y
4846 jfm: I should use this comment for the text file to explain
4847 same thing for the forms BTW.
4848 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
4852 /* Convert generic access rights to printer object specific access rights.
4853 It turns out that NT4 security descriptors use generic access rights and
4854 NT5 the object specific ones. */
4856 void map_printer_permissions(SEC_DESC *sd)
4858 int i;
4860 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
4861 se_map_generic(&sd->dacl->ace[i].info.mask,
4862 &printer_generic_mapping);
4866 /****************************************************************************
4867 Check a user has permissions to perform the given operation. We use the
4868 permission constants defined in include/rpc_spoolss.h to check the various
4869 actions we perform when checking printer access.
4871 PRINTER_ACCESS_ADMINISTER:
4872 print_queue_pause, print_queue_resume, update_printer_sec,
4873 update_printer, spoolss_addprinterex_level_2,
4874 _spoolss_setprinterdata
4876 PRINTER_ACCESS_USE:
4877 print_job_start
4879 JOB_ACCESS_ADMINISTER:
4880 print_job_delete, print_job_pause, print_job_resume,
4881 print_queue_purge
4883 ****************************************************************************/
4884 BOOL print_access_check(struct current_user *user, int snum, int access_type)
4886 SEC_DESC_BUF *secdesc = NULL;
4887 uint32 access_granted;
4888 NTSTATUS status;
4889 BOOL result;
4890 const char *pname;
4891 TALLOC_CTX *mem_ctx = NULL;
4892 extern struct current_user current_user;
4894 /* If user is NULL then use the current_user structure */
4896 if (!user)
4897 user = &current_user;
4899 /* Always allow root or printer admins to do anything */
4901 if (user->uid == 0 ||
4902 user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
4903 return True;
4906 /* Get printer name */
4908 pname = PRINTERNAME(snum);
4910 if (!pname || !*pname) {
4911 errno = EACCES;
4912 return False;
4915 /* Get printer security descriptor */
4917 if(!(mem_ctx = talloc_init("print_access_check"))) {
4918 errno = ENOMEM;
4919 return False;
4922 nt_printing_getsec(mem_ctx, pname, &secdesc);
4924 if (access_type == JOB_ACCESS_ADMINISTER) {
4925 SEC_DESC_BUF *parent_secdesc = secdesc;
4927 /* Create a child security descriptor to check permissions
4928 against. This is because print jobs are child objects
4929 objects of a printer. */
4931 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
4933 /* Now this is the bit that really confuses me. The access
4934 type needs to be changed from JOB_ACCESS_ADMINISTER to
4935 PRINTER_ACCESS_ADMINISTER for this to work. Something
4936 to do with the child (job) object becoming like a
4937 printer?? -tpot */
4939 access_type = PRINTER_ACCESS_ADMINISTER;
4942 /* Check access */
4944 map_printer_permissions(secdesc->sec);
4946 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
4947 &access_granted, &status);
4949 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
4951 talloc_destroy(mem_ctx);
4953 if (!result)
4954 errno = EACCES;
4956 return result;
4959 /****************************************************************************
4960 Check the time parameters allow a print operation.
4961 *****************************************************************************/
4963 BOOL print_time_access_check(int snum)
4965 NT_PRINTER_INFO_LEVEL *printer = NULL;
4966 BOOL ok = False;
4967 time_t now = time(NULL);
4968 struct tm *t;
4969 uint32 mins;
4971 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
4972 return False;
4974 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
4975 ok = True;
4977 t = gmtime(&now);
4978 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
4980 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
4981 ok = True;
4983 free_a_printer(&printer, 2);
4985 if (!ok)
4986 errno = EACCES;
4988 return ok;