r689: removed unneeded forward declarations
[Samba/gbeck.git] / source / printing / nt_printing.c
blobccee2565e1c9959f38105cef39a057017c5c04b6
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 Function to allow filename parsing "the old way".
372 ********************************************************************/
374 static BOOL driver_unix_convert(char *name,connection_struct *conn,
375 char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst)
377 unix_format(name);
378 unix_clean_name(name);
379 trim_string(name,"/","/");
380 return unix_convert(name, conn, saved_last_component, bad_path, pst);
383 /*******************************************************************
384 tdb traversal function for counting printers.
385 ********************************************************************/
387 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
388 TDB_DATA data, void *context)
390 int *printer_count = (int*)context;
392 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
393 (*printer_count)++;
394 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
397 return 0;
400 /*******************************************************************
401 Update the spooler global c_setprinter. This variable is initialized
402 when the parent smbd starts with the number of existing printers. It
403 is monotonically increased by the current number of printers *after*
404 each add or delete printer RPC. Only Microsoft knows why... JRR020119
405 ********************************************************************/
407 uint32 update_c_setprinter(BOOL initialize)
409 int32 c_setprinter;
410 int32 printer_count = 0;
412 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0);
414 /* Traverse the tdb, counting the printers */
415 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
417 /* If initializing, set c_setprinter to current printers count
418 * otherwise, bump it by the current printer count
420 if (!initialize)
421 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
422 else
423 c_setprinter = printer_count;
425 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
426 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
428 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
430 return (uint32)c_setprinter;
433 /*******************************************************************
434 Get the spooler global c_setprinter, accounting for initialization.
435 ********************************************************************/
437 uint32 get_c_setprinter(void)
439 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
441 if (c_setprinter == (int32)-1)
442 c_setprinter = update_c_setprinter(True);
444 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
446 return (uint32)c_setprinter;
449 /****************************************************************************
450 Get builtin form struct list.
451 ****************************************************************************/
453 int get_builtin_ntforms(nt_forms_struct **list)
455 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
456 return sizeof(default_forms) / sizeof(default_forms[0]);
459 /****************************************************************************
460 get a builtin form struct
461 ****************************************************************************/
463 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
465 int i,count;
466 fstring form_name;
467 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
468 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
469 count = sizeof(default_forms) / sizeof(default_forms[0]);
470 for (i=0;i<count;i++) {
471 if (strequal(form_name,default_forms[i].name)) {
472 DEBUGADD(6,("Found builtin form %s \n", form_name));
473 memcpy(form,&default_forms[i],sizeof(*form));
474 break;
478 return (i !=count);
481 /****************************************************************************
482 get a form struct list
483 ****************************************************************************/
484 int get_ntforms(nt_forms_struct **list)
486 TDB_DATA kbuf, newkey, dbuf;
487 nt_forms_struct *tl;
488 nt_forms_struct form;
489 int ret;
490 int i;
491 int n = 0;
493 for (kbuf = tdb_firstkey(tdb_forms);
494 kbuf.dptr;
495 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
497 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
498 continue;
500 dbuf = tdb_fetch(tdb_forms, kbuf);
501 if (!dbuf.dptr)
502 continue;
504 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
505 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
506 &i, &form.flag, &form.width, &form.length, &form.left,
507 &form.top, &form.right, &form.bottom);
508 SAFE_FREE(dbuf.dptr);
509 if (ret != dbuf.dsize)
510 continue;
512 tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
513 if (!tl) {
514 DEBUG(0,("get_ntforms: Realloc fail.\n"));
515 return 0;
517 *list = tl;
518 (*list)[n] = form;
519 n++;
523 return n;
526 /****************************************************************************
527 write a form struct list
528 ****************************************************************************/
529 int write_ntforms(nt_forms_struct **list, int number)
531 pstring buf, key;
532 int len;
533 TDB_DATA kbuf,dbuf;
534 int i;
536 for (i=0;i<number;i++) {
537 /* save index, so list is rebuilt in correct order */
538 len = tdb_pack(buf, sizeof(buf), "dddddddd",
539 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
540 (*list)[i].left, (*list)[i].top, (*list)[i].right,
541 (*list)[i].bottom);
542 if (len > sizeof(buf)) break;
543 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
544 kbuf.dsize = strlen(key)+1;
545 kbuf.dptr = key;
546 dbuf.dsize = len;
547 dbuf.dptr = buf;
548 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
551 return i;
554 /****************************************************************************
555 add a form struct at the end of the list
556 ****************************************************************************/
557 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
559 int n=0;
560 BOOL update;
561 fstring form_name;
562 nt_forms_struct *tl;
565 * NT tries to add forms even when
566 * they are already in the base
567 * only update the values if already present
570 update=False;
572 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
573 for (n=0; n<*count; n++) {
574 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
575 DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
576 update=True;
577 break;
581 if (update==False) {
582 if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
583 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
584 return False;
586 *list = tl;
587 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
588 (*count)++;
591 (*list)[n].flag=form->flags;
592 (*list)[n].width=form->size_x;
593 (*list)[n].length=form->size_y;
594 (*list)[n].left=form->left;
595 (*list)[n].top=form->top;
596 (*list)[n].right=form->right;
597 (*list)[n].bottom=form->bottom;
599 return True;
602 /****************************************************************************
603 Delete a named form struct.
604 ****************************************************************************/
606 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
608 pstring key;
609 TDB_DATA kbuf;
610 int n=0;
611 fstring form_name;
613 *ret = WERR_OK;
615 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
617 for (n=0; n<*count; n++) {
618 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
619 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
620 break;
624 if (n == *count) {
625 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
626 *ret = WERR_INVALID_PARAM;
627 return False;
630 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
631 kbuf.dsize = strlen(key)+1;
632 kbuf.dptr = key;
633 if (tdb_delete(tdb_forms, kbuf) != 0) {
634 *ret = WERR_NOMEM;
635 return False;
638 return True;
641 /****************************************************************************
642 Update a form struct.
643 ****************************************************************************/
645 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
647 int n=0;
648 fstring form_name;
649 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
651 DEBUG(106, ("[%s]\n", form_name));
652 for (n=0; n<count; n++) {
653 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
654 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
655 break;
658 if (n==count) return;
660 (*list)[n].flag=form->flags;
661 (*list)[n].width=form->size_x;
662 (*list)[n].length=form->size_y;
663 (*list)[n].left=form->left;
664 (*list)[n].top=form->top;
665 (*list)[n].right=form->right;
666 (*list)[n].bottom=form->bottom;
669 /****************************************************************************
670 Get the nt drivers list.
671 Traverse the database and look-up the matching names.
672 ****************************************************************************/
673 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
675 int total=0;
676 const char *short_archi;
677 fstring *fl;
678 pstring key;
679 TDB_DATA kbuf, newkey;
681 short_archi = get_short_archi(architecture);
682 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
684 for (kbuf = tdb_firstkey(tdb_drivers);
685 kbuf.dptr;
686 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
688 if (strncmp(kbuf.dptr, key, strlen(key)) != 0)
689 continue;
691 if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
692 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
693 return -1;
695 else *list = fl;
697 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
698 total++;
701 return(total);
704 /****************************************************************************
705 function to do the mapping between the long architecture name and
706 the short one.
707 ****************************************************************************/
708 const char *get_short_archi(const char *long_archi)
710 int i=-1;
712 DEBUG(107,("Getting architecture dependant directory\n"));
713 do {
714 i++;
715 } while ( (archi_table[i].long_archi!=NULL ) &&
716 StrCaseCmp(long_archi, archi_table[i].long_archi) );
718 if (archi_table[i].long_archi==NULL) {
719 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
720 return NULL;
723 /* this might be client code - but shouldn't this be an fstrcpy etc? */
726 DEBUGADD(108,("index: [%d]\n", i));
727 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
728 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
730 return archi_table[i].short_archi;
733 /****************************************************************************
734 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
735 There are two case to be covered here: PE (Portable Executable) and NE (New
736 Executable) files. Both files support the same INFO structure, but PE files
737 store the signature in unicode, and NE files store it as !unicode.
738 returns -1 on error, 1 on version info found, and 0 on no version info found.
739 ****************************************************************************/
741 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
743 int i;
744 char *buf = NULL;
745 ssize_t byte_count;
747 if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
748 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
749 fname, PE_HEADER_SIZE));
750 goto error_exit;
753 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
754 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
755 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
756 fname, (unsigned long)byte_count));
757 goto no_version_info;
760 /* Is this really a DOS header? */
761 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
762 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
763 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
764 goto no_version_info;
767 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
768 if (SMB_VFS_LSEEK(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
769 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
770 fname, errno));
771 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
772 goto no_version_info;
775 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
776 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
777 fname, (unsigned long)byte_count));
778 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
779 goto no_version_info;
782 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
783 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
784 unsigned int num_sections;
785 unsigned int section_table_bytes;
787 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
788 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
789 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
790 /* At this point, we assume the file is in error. It still could be somthing
791 * else besides a PE file, but it unlikely at this point.
793 goto error_exit;
796 /* get the section table */
797 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
798 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
799 if (section_table_bytes == 0)
800 goto error_exit;
802 SAFE_FREE(buf);
803 if ((buf=malloc(section_table_bytes)) == NULL) {
804 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
805 fname, section_table_bytes));
806 goto error_exit;
809 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
810 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
811 fname, (unsigned long)byte_count));
812 goto error_exit;
815 /* Iterate the section table looking for the resource section ".rsrc" */
816 for (i = 0; i < num_sections; i++) {
817 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
819 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
820 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
821 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
823 if (section_bytes == 0)
824 goto error_exit;
826 SAFE_FREE(buf);
827 if ((buf=malloc(section_bytes)) == NULL) {
828 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
829 fname, section_bytes));
830 goto error_exit;
833 /* Seek to the start of the .rsrc section info */
834 if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
835 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
836 fname, errno));
837 goto error_exit;
840 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
841 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
842 fname, (unsigned long)byte_count));
843 goto error_exit;
846 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
847 goto error_exit;
849 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
850 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
851 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
852 /* Align to next long address */
853 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
855 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
856 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
857 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
859 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
860 fname, *major, *minor,
861 (*major>>16)&0xffff, *major&0xffff,
862 (*minor>>16)&0xffff, *minor&0xffff));
863 SAFE_FREE(buf);
864 return 1;
871 /* Version info not found, fall back to origin date/time */
872 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
873 SAFE_FREE(buf);
874 return 0;
876 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
877 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
878 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
879 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
880 /* At this point, we assume the file is in error. It still could be somthing
881 * else besides a NE file, but it unlikely at this point. */
882 goto error_exit;
885 /* Allocate a bit more space to speed up things */
886 SAFE_FREE(buf);
887 if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
888 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
889 fname, PE_HEADER_SIZE));
890 goto error_exit;
893 /* This is a HACK! I got tired of trying to sort through the messy
894 * 'NE' file format. If anyone wants to clean this up please have at
895 * it, but this works. 'NE' files will eventually fade away. JRR */
896 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
897 /* Cover case that should not occur in a well formed 'NE' .dll file */
898 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
900 for(i=0; i<byte_count; i++) {
901 /* Fast skip past data that can't possibly match */
902 if (buf[i] != 'V') continue;
904 /* Potential match data crosses buf boundry, move it to beginning
905 * of buf, and fill the buf with as much as it will hold. */
906 if (i>byte_count-VS_VERSION_INFO_SIZE) {
907 int bc;
909 memcpy(buf, &buf[i], byte_count-i);
910 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
911 (byte_count-i))) < 0) {
913 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
914 fname, errno));
915 goto error_exit;
918 byte_count = bc + (byte_count - i);
919 if (byte_count<VS_VERSION_INFO_SIZE) break;
921 i = 0;
924 /* Check that the full signature string and the magic number that
925 * follows exist (not a perfect solution, but the chances that this
926 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
927 * twice, as it is simpler to read the code. */
928 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
929 /* Compute skip alignment to next long address */
930 int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
931 sizeof(VS_SIGNATURE)) & 3;
932 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
934 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
935 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
936 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
937 fname, *major, *minor,
938 (*major>>16)&0xffff, *major&0xffff,
939 (*minor>>16)&0xffff, *minor&0xffff));
940 SAFE_FREE(buf);
941 return 1;
946 /* Version info not found, fall back to origin date/time */
947 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
948 SAFE_FREE(buf);
949 return 0;
951 } else
952 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
953 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
954 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
956 no_version_info:
957 SAFE_FREE(buf);
958 return 0;
960 error_exit:
961 SAFE_FREE(buf);
962 return -1;
965 /****************************************************************************
966 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
967 share one or more files. During the MS installation process files are checked
968 to insure that only a newer version of a shared file is installed over an
969 older version. There are several possibilities for this comparison. If there
970 is no previous version, the new one is newer (obviously). If either file is
971 missing the version info structure, compare the creation date (on Unix use
972 the modification date). Otherwise chose the numerically larger version number.
973 ****************************************************************************/
975 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
977 BOOL use_version = True;
978 pstring filepath;
980 uint32 new_major;
981 uint32 new_minor;
982 time_t new_create_time;
984 uint32 old_major;
985 uint32 old_minor;
986 time_t old_create_time;
988 int access_mode;
989 int action;
990 files_struct *fsp = NULL;
991 SMB_STRUCT_STAT st;
992 SMB_STRUCT_STAT stat_buf;
993 BOOL bad_path;
995 ZERO_STRUCT(st);
996 ZERO_STRUCT(stat_buf);
997 new_create_time = (time_t)0;
998 old_create_time = (time_t)0;
1000 /* Get file version info (if available) for previous file (if it exists) */
1001 pstrcpy(filepath, old_file);
1003 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1005 fsp = open_file_shared(conn, filepath, &stat_buf,
1006 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1007 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1008 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
1009 if (!fsp) {
1010 /* Old file not found, so by definition new file is in fact newer */
1011 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
1012 filepath, errno));
1013 return True;
1015 } else {
1016 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
1017 if (ret == -1) goto error_exit;
1019 if (!ret) {
1020 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1021 old_file));
1022 use_version = False;
1023 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1024 old_create_time = st.st_mtime;
1025 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1028 close_file(fsp, True);
1030 /* Get file version info (if available) for new file */
1031 pstrcpy(filepath, new_file);
1032 driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1034 fsp = open_file_shared(conn, filepath, &stat_buf,
1035 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1036 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1037 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
1038 if (!fsp) {
1039 /* New file not found, this shouldn't occur if the caller did its job */
1040 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1041 filepath, errno));
1042 goto error_exit;
1044 } else {
1045 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1046 if (ret == -1) goto error_exit;
1048 if (!ret) {
1049 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1050 new_file));
1051 use_version = False;
1052 if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit;
1053 new_create_time = st.st_mtime;
1054 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1057 close_file(fsp, True);
1059 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1060 /* Compare versions and choose the larger version number */
1061 if (new_major > old_major ||
1062 (new_major == old_major && new_minor > old_minor)) {
1064 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1065 return True;
1067 else {
1068 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1069 return False;
1072 } else {
1073 /* Compare modification time/dates and choose the newest time/date */
1074 if (new_create_time > old_create_time) {
1075 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1076 return True;
1078 else {
1079 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1080 return False;
1084 error_exit:
1085 if(fsp)
1086 close_file(fsp, True);
1087 return -1;
1090 /****************************************************************************
1091 Determine the correct cVersion associated with an architecture and driver
1092 ****************************************************************************/
1093 static uint32 get_correct_cversion(const char *architecture, fstring driverpath_in,
1094 struct current_user *user, WERROR *perr)
1096 int cversion;
1097 int access_mode;
1098 int action;
1099 NTSTATUS nt_status;
1100 pstring driverpath;
1101 DATA_BLOB null_pw;
1102 fstring res_type;
1103 files_struct *fsp = NULL;
1104 BOOL bad_path;
1105 SMB_STRUCT_STAT st;
1106 connection_struct *conn;
1108 ZERO_STRUCT(st);
1110 *perr = WERR_INVALID_PARAM;
1112 /* If architecture is Windows 95/98/ME, the version is always 0. */
1113 if (strcmp(architecture, "WIN40") == 0) {
1114 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1115 *perr = WERR_OK;
1116 return 0;
1120 * Connect to the print$ share under the same account as the user connected
1121 * to the rpc pipe. Note we must still be root to do this.
1124 /* Null password is ok - we are already an authenticated user... */
1125 null_pw = data_blob(NULL, 0);
1126 fstrcpy(res_type, "A:");
1127 become_root();
1128 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1129 unbecome_root();
1131 if (conn == NULL) {
1132 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1133 *perr = ntstatus_to_werror(nt_status);
1134 return -1;
1137 /* We are temporarily becoming the connection user. */
1138 if (!become_user(conn, user->vuid)) {
1139 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1140 *perr = WERR_ACCESS_DENIED;
1141 return -1;
1144 /* Open the driver file (Portable Executable format) and determine the
1145 * deriver the cversion. */
1146 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1148 driver_unix_convert(driverpath,conn,NULL,&bad_path,&st);
1150 fsp = open_file_shared(conn, driverpath, &st,
1151 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1152 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1153 FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &action);
1154 if (!fsp) {
1155 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1156 driverpath, errno));
1157 *perr = WERR_ACCESS_DENIED;
1158 goto error_exit;
1160 else {
1161 uint32 major;
1162 uint32 minor;
1163 int ret = get_file_version(fsp, driverpath, &major, &minor);
1164 if (ret == -1) goto error_exit;
1166 if (!ret) {
1167 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1168 goto error_exit;
1172 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1173 * for more details. Version in this case is not just the version of the
1174 * file, but the version in the sense of kernal mode (2) vs. user mode
1175 * (3) drivers. Other bits of the version fields are the version info.
1176 * JRR 010716
1178 cversion = major & 0x0000ffff;
1179 switch (cversion) {
1180 case 2: /* WinNT drivers */
1181 case 3: /* Win2K drivers */
1182 break;
1184 default:
1185 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1186 driverpath, cversion));
1187 goto error_exit;
1190 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1191 driverpath, major, minor));
1194 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1195 driverpath, cversion));
1197 close_file(fsp, True);
1198 close_cnum(conn, user->vuid);
1199 unbecome_user();
1200 *perr = WERR_OK;
1201 return cversion;
1204 error_exit:
1206 if(fsp)
1207 close_file(fsp, True);
1209 close_cnum(conn, user->vuid);
1210 unbecome_user();
1211 return -1;
1214 /****************************************************************************
1215 ****************************************************************************/
1216 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1217 struct current_user *user)
1219 const char *architecture;
1220 fstring new_name;
1221 char *p;
1222 int i;
1223 WERROR err;
1225 /* clean up the driver name.
1226 * we can get .\driver.dll
1227 * or worse c:\windows\system\driver.dll !
1229 /* using an intermediate string to not have overlaping memcpy()'s */
1230 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1231 fstrcpy(new_name, p+1);
1232 fstrcpy(driver->driverpath, new_name);
1235 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1236 fstrcpy(new_name, p+1);
1237 fstrcpy(driver->datafile, new_name);
1240 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1241 fstrcpy(new_name, p+1);
1242 fstrcpy(driver->configfile, new_name);
1245 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1246 fstrcpy(new_name, p+1);
1247 fstrcpy(driver->helpfile, new_name);
1250 if (driver->dependentfiles) {
1251 for (i=0; *driver->dependentfiles[i]; i++) {
1252 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1253 fstrcpy(new_name, p+1);
1254 fstrcpy(driver->dependentfiles[i], new_name);
1259 architecture = get_short_archi(driver->environment);
1261 /* jfm:7/16/2000 the client always sends the cversion=0.
1262 * The server should check which version the driver is by reading
1263 * the PE header of driver->driverpath.
1265 * For Windows 95/98 the version is 0 (so the value sent is correct)
1266 * For Windows NT (the architecture doesn't matter)
1267 * NT 3.1: cversion=0
1268 * NT 3.5/3.51: cversion=1
1269 * NT 4: cversion=2
1270 * NT2K: cversion=3
1272 if ((driver->cversion = get_correct_cversion( architecture,
1273 driver->driverpath, user, &err)) == -1)
1274 return err;
1276 return WERR_OK;
1279 /****************************************************************************
1280 ****************************************************************************/
1281 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1283 const char *architecture;
1284 fstring new_name;
1285 char *p;
1286 int i;
1287 WERROR err;
1289 /* clean up the driver name.
1290 * we can get .\driver.dll
1291 * or worse c:\windows\system\driver.dll !
1293 /* using an intermediate string to not have overlaping memcpy()'s */
1294 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1295 fstrcpy(new_name, p+1);
1296 fstrcpy(driver->driverpath, new_name);
1299 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1300 fstrcpy(new_name, p+1);
1301 fstrcpy(driver->datafile, new_name);
1304 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1305 fstrcpy(new_name, p+1);
1306 fstrcpy(driver->configfile, new_name);
1309 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1310 fstrcpy(new_name, p+1);
1311 fstrcpy(driver->helpfile, new_name);
1314 if (driver->dependentfiles) {
1315 for (i=0; *driver->dependentfiles[i]; i++) {
1316 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1317 fstrcpy(new_name, p+1);
1318 fstrcpy(driver->dependentfiles[i], new_name);
1323 architecture = get_short_archi(driver->environment);
1325 /* jfm:7/16/2000 the client always sends the cversion=0.
1326 * The server should check which version the driver is by reading
1327 * the PE header of driver->driverpath.
1329 * For Windows 95/98 the version is 0 (so the value sent is correct)
1330 * For Windows NT (the architecture doesn't matter)
1331 * NT 3.1: cversion=0
1332 * NT 3.5/3.51: cversion=1
1333 * NT 4: cversion=2
1334 * NT2K: cversion=3
1336 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1337 return err;
1339 return WERR_OK;
1342 /****************************************************************************
1343 ****************************************************************************/
1344 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1345 uint32 level, struct current_user *user)
1347 switch (level) {
1348 case 3:
1350 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1351 driver=driver_abstract.info_3;
1352 return clean_up_driver_struct_level_3(driver, user);
1354 case 6:
1356 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1357 driver=driver_abstract.info_6;
1358 return clean_up_driver_struct_level_6(driver, user);
1360 default:
1361 return WERR_INVALID_PARAM;
1365 /****************************************************************************
1366 This function sucks and should be replaced. JRA.
1367 ****************************************************************************/
1369 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1371 dst->cversion = src->version;
1373 fstrcpy( dst->name, src->name);
1374 fstrcpy( dst->environment, src->environment);
1375 fstrcpy( dst->driverpath, src->driverpath);
1376 fstrcpy( dst->datafile, src->datafile);
1377 fstrcpy( dst->configfile, src->configfile);
1378 fstrcpy( dst->helpfile, src->helpfile);
1379 fstrcpy( dst->monitorname, src->monitorname);
1380 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1381 dst->dependentfiles = src->dependentfiles;
1384 #if 0 /* Debugging function */
1386 static char* ffmt(unsigned char *c){
1387 int i;
1388 static char ffmt_str[17];
1390 for (i=0; i<16; i++) {
1391 if ((c[i] < ' ') || (c[i] > '~'))
1392 ffmt_str[i]='.';
1393 else
1394 ffmt_str[i]=c[i];
1396 ffmt_str[16]='\0';
1397 return ffmt_str;
1400 #endif
1402 /****************************************************************************
1403 ****************************************************************************/
1404 BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1405 struct current_user *user, WERROR *perr)
1407 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1408 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1409 const char *architecture;
1410 pstring new_dir;
1411 pstring old_name;
1412 pstring new_name;
1413 DATA_BLOB null_pw;
1414 connection_struct *conn;
1415 NTSTATUS nt_status;
1416 pstring inbuf;
1417 pstring outbuf;
1418 fstring res_type;
1419 BOOL bad_path;
1420 SMB_STRUCT_STAT st;
1421 int ver = 0;
1422 int i;
1424 memset(inbuf, '\0', sizeof(inbuf));
1425 memset(outbuf, '\0', sizeof(outbuf));
1426 *perr = WERR_OK;
1428 if (level==3)
1429 driver=driver_abstract.info_3;
1430 else if (level==6) {
1431 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1432 driver = &converted_driver;
1433 } else {
1434 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1435 return False;
1438 architecture = get_short_archi(driver->environment);
1441 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1442 * Note we must be root to do this.
1445 null_pw = data_blob(NULL, 0);
1446 fstrcpy(res_type, "A:");
1447 become_root();
1448 conn = make_connection_with_chdir("print$", null_pw, res_type, user->vuid, &nt_status);
1449 unbecome_root();
1451 if (conn == NULL) {
1452 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1453 *perr = ntstatus_to_werror(nt_status);
1454 return False;
1458 * Save who we are - we are temporarily becoming the connection user.
1461 if (!become_user(conn, conn->vuid)) {
1462 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1463 return False;
1467 * make the directories version and version\driver_name
1468 * under the architecture directory.
1470 DEBUG(5,("Creating first directory\n"));
1471 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1472 driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
1473 mkdir_internal(conn, new_dir);
1475 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1476 * listed for this driver which has already been moved, skip it (note:
1477 * drivers may list the same file name several times. Then check if the
1478 * file already exists in archi\cversion\, if so, check that the version
1479 * info (or time stamps if version info is unavailable) is newer (or the
1480 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1481 * Otherwise, delete the file.
1483 * If a file is not moved to archi\cversion\ because of an error, all the
1484 * rest of the 'unmoved' driver files are removed from archi\. If one or
1485 * more of the driver's files was already moved to archi\cversion\, it
1486 * potentially leaves the driver in a partially updated state. Version
1487 * trauma will most likely occur if an client attempts to use any printer
1488 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1489 * done is appropriate... later JRR
1492 DEBUG(5,("Moving files now !\n"));
1494 if (driver->driverpath && strlen(driver->driverpath)) {
1495 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1496 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1497 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1498 NTSTATUS status;
1499 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1500 status = rename_internals(conn, new_name, old_name, 0, True);
1501 if (!NT_STATUS_IS_OK(status)) {
1502 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1503 new_name, old_name));
1504 *perr = ntstatus_to_werror(status);
1505 unlink_internals(conn, 0, new_name);
1506 ver = -1;
1508 } else {
1509 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1510 unlink_internals(conn, 0, new_name);
1514 if (driver->datafile && strlen(driver->datafile)) {
1515 if (!strequal(driver->datafile, driver->driverpath)) {
1516 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1517 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1518 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1519 NTSTATUS status;
1520 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1521 status = rename_internals(conn, new_name, old_name, 0, True);
1522 if (!NT_STATUS_IS_OK(status)) {
1523 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1524 new_name, old_name));
1525 *perr = ntstatus_to_werror(status);
1526 unlink_internals(conn, 0, new_name);
1527 ver = -1;
1529 } else {
1530 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1531 unlink_internals(conn, 0, new_name);
1536 if (driver->configfile && strlen(driver->configfile)) {
1537 if (!strequal(driver->configfile, driver->driverpath) &&
1538 !strequal(driver->configfile, driver->datafile)) {
1539 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1540 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1541 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1542 NTSTATUS status;
1543 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1544 status = rename_internals(conn, new_name, old_name, 0, True);
1545 if (!NT_STATUS_IS_OK(status)) {
1546 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1547 new_name, old_name));
1548 *perr = ntstatus_to_werror(status);
1549 unlink_internals(conn, 0, new_name);
1550 ver = -1;
1552 } else {
1553 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1554 unlink_internals(conn, 0, new_name);
1559 if (driver->helpfile && strlen(driver->helpfile)) {
1560 if (!strequal(driver->helpfile, driver->driverpath) &&
1561 !strequal(driver->helpfile, driver->datafile) &&
1562 !strequal(driver->helpfile, driver->configfile)) {
1563 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1564 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1565 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1566 NTSTATUS status;
1567 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1568 status = rename_internals(conn, new_name, old_name, 0, True);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1571 new_name, old_name));
1572 *perr = ntstatus_to_werror(status);
1573 unlink_internals(conn, 0, new_name);
1574 ver = -1;
1576 } else {
1577 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1578 unlink_internals(conn, 0, new_name);
1583 if (driver->dependentfiles) {
1584 for (i=0; *driver->dependentfiles[i]; i++) {
1585 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1586 !strequal(driver->dependentfiles[i], driver->datafile) &&
1587 !strequal(driver->dependentfiles[i], driver->configfile) &&
1588 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1589 int j;
1590 for (j=0; j < i; j++) {
1591 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1592 goto NextDriver;
1596 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1597 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1598 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1599 NTSTATUS status;
1600 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1601 status = rename_internals(conn, new_name, old_name, 0, True);
1602 if (!NT_STATUS_IS_OK(status)) {
1603 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1604 new_name, old_name));
1605 *perr = ntstatus_to_werror(status);
1606 unlink_internals(conn, 0, new_name);
1607 ver = -1;
1609 } else {
1610 driver_unix_convert(new_name, conn, NULL, &bad_path, &st);
1611 unlink_internals(conn, 0, new_name);
1614 NextDriver: ;
1618 close_cnum(conn, user->vuid);
1619 unbecome_user();
1621 return ver == -1 ? False : True;
1624 /****************************************************************************
1625 ****************************************************************************/
1626 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1628 int len, buflen;
1629 const char *architecture;
1630 pstring directory;
1631 fstring temp_name;
1632 pstring key;
1633 char *buf;
1634 int i, ret;
1635 TDB_DATA kbuf, dbuf;
1637 architecture = get_short_archi(driver->environment);
1639 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1640 * \\server is added in the rpc server layer.
1641 * It does make sense to NOT store the server's name in the printer TDB.
1644 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1646 /* .inf files do not always list a file for each of the four standard files.
1647 * Don't prepend a path to a null filename, or client claims:
1648 * "The server on which the printer resides does not have a suitable
1649 * <printer driver name> printer driver installed. Click OK if you
1650 * wish to install the driver on your local machine."
1652 if (strlen(driver->driverpath)) {
1653 fstrcpy(temp_name, driver->driverpath);
1654 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1657 if (strlen(driver->datafile)) {
1658 fstrcpy(temp_name, driver->datafile);
1659 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1662 if (strlen(driver->configfile)) {
1663 fstrcpy(temp_name, driver->configfile);
1664 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1667 if (strlen(driver->helpfile)) {
1668 fstrcpy(temp_name, driver->helpfile);
1669 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1672 if (driver->dependentfiles) {
1673 for (i=0; *driver->dependentfiles[i]; i++) {
1674 fstrcpy(temp_name, driver->dependentfiles[i]);
1675 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1679 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1681 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1683 buf = NULL;
1684 len = buflen = 0;
1686 again:
1687 len = 0;
1688 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1689 driver->cversion,
1690 driver->name,
1691 driver->environment,
1692 driver->driverpath,
1693 driver->datafile,
1694 driver->configfile,
1695 driver->helpfile,
1696 driver->monitorname,
1697 driver->defaultdatatype);
1699 if (driver->dependentfiles) {
1700 for (i=0; *driver->dependentfiles[i]; i++) {
1701 len += tdb_pack(buf+len, buflen-len, "f",
1702 driver->dependentfiles[i]);
1706 if (len != buflen) {
1707 char *tb;
1709 tb = (char *)Realloc(buf, len);
1710 if (!tb) {
1711 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1712 ret = -1;
1713 goto done;
1715 else buf = tb;
1716 buflen = len;
1717 goto again;
1721 kbuf.dptr = key;
1722 kbuf.dsize = strlen(key)+1;
1723 dbuf.dptr = buf;
1724 dbuf.dsize = len;
1726 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1728 done:
1729 if (ret)
1730 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1732 SAFE_FREE(buf);
1733 return ret;
1736 /****************************************************************************
1737 ****************************************************************************/
1738 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
1740 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
1742 ZERO_STRUCT(info3);
1743 info3.cversion = driver->version;
1744 fstrcpy(info3.name,driver->name);
1745 fstrcpy(info3.environment,driver->environment);
1746 fstrcpy(info3.driverpath,driver->driverpath);
1747 fstrcpy(info3.datafile,driver->datafile);
1748 fstrcpy(info3.configfile,driver->configfile);
1749 fstrcpy(info3.helpfile,driver->helpfile);
1750 fstrcpy(info3.monitorname,driver->monitorname);
1751 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
1752 info3.dependentfiles = driver->dependentfiles;
1754 return add_a_printer_driver_3(&info3);
1758 /****************************************************************************
1759 ****************************************************************************/
1760 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
1762 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
1764 ZERO_STRUCT(info);
1766 fstrcpy(info.name, driver);
1767 fstrcpy(info.defaultdatatype, "RAW");
1769 fstrcpy(info.driverpath, "");
1770 fstrcpy(info.datafile, "");
1771 fstrcpy(info.configfile, "");
1772 fstrcpy(info.helpfile, "");
1774 if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
1775 return WERR_NOMEM;
1777 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
1778 fstrcpy(info.dependentfiles[0], "");
1780 *info_ptr = memdup(&info, sizeof(info));
1782 return WERR_OK;
1785 /****************************************************************************
1786 ****************************************************************************/
1787 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
1789 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
1790 TDB_DATA kbuf, dbuf;
1791 const char *architecture;
1792 int len = 0;
1793 int i;
1794 pstring key;
1796 ZERO_STRUCT(driver);
1798 architecture = get_short_archi(arch);
1800 /* Windows 4.0 (i.e. win9x) should always use a version of 0 */
1802 if ( strcmp( architecture, SPL_ARCH_WIN40 ) == 0 )
1803 version = 0;
1805 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
1807 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
1809 kbuf.dptr = key;
1810 kbuf.dsize = strlen(key)+1;
1812 dbuf = tdb_fetch(tdb_drivers, kbuf);
1813 if (!dbuf.dptr)
1814 return WERR_UNKNOWN_PRINTER_DRIVER;
1816 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
1817 &driver.cversion,
1818 driver.name,
1819 driver.environment,
1820 driver.driverpath,
1821 driver.datafile,
1822 driver.configfile,
1823 driver.helpfile,
1824 driver.monitorname,
1825 driver.defaultdatatype);
1827 i=0;
1828 while (len < dbuf.dsize) {
1829 fstring *tddfs;
1831 tddfs = (fstring *)Realloc(driver.dependentfiles,
1832 sizeof(fstring)*(i+2));
1833 if (tddfs == NULL) {
1834 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
1835 break;
1837 else driver.dependentfiles = tddfs;
1839 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
1840 &driver.dependentfiles[i]);
1841 i++;
1844 if (driver.dependentfiles != NULL)
1845 fstrcpy(driver.dependentfiles[i], "");
1847 SAFE_FREE(dbuf.dptr);
1849 if (len != dbuf.dsize) {
1850 SAFE_FREE(driver.dependentfiles);
1852 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
1855 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
1857 return WERR_OK;
1860 /****************************************************************************
1861 Debugging function, dump at level 6 the struct in the logs.
1862 ****************************************************************************/
1864 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1866 uint32 result;
1867 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
1868 int i;
1870 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
1872 switch (level)
1874 case 3:
1876 if (driver.info_3 == NULL)
1877 result=5;
1878 else {
1879 info3=driver.info_3;
1881 DEBUGADD(20,("version:[%d]\n", info3->cversion));
1882 DEBUGADD(20,("name:[%s]\n", info3->name));
1883 DEBUGADD(20,("environment:[%s]\n", info3->environment));
1884 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
1885 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
1886 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
1887 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
1888 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
1889 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
1891 for (i=0; info3->dependentfiles &&
1892 *info3->dependentfiles[i]; i++) {
1893 DEBUGADD(20,("dependentfile:[%s]\n",
1894 info3->dependentfiles[i]));
1896 result=0;
1898 break;
1900 default:
1901 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
1902 result=1;
1903 break;
1906 return result;
1909 /****************************************************************************
1910 ****************************************************************************/
1911 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
1913 int len = 0;
1915 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
1917 if (!nt_devmode)
1918 return len;
1920 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
1921 nt_devmode->devicename,
1922 nt_devmode->formname,
1924 nt_devmode->specversion,
1925 nt_devmode->driverversion,
1926 nt_devmode->size,
1927 nt_devmode->driverextra,
1928 nt_devmode->orientation,
1929 nt_devmode->papersize,
1930 nt_devmode->paperlength,
1931 nt_devmode->paperwidth,
1932 nt_devmode->scale,
1933 nt_devmode->copies,
1934 nt_devmode->defaultsource,
1935 nt_devmode->printquality,
1936 nt_devmode->color,
1937 nt_devmode->duplex,
1938 nt_devmode->yresolution,
1939 nt_devmode->ttoption,
1940 nt_devmode->collate,
1941 nt_devmode->logpixels,
1943 nt_devmode->fields,
1944 nt_devmode->bitsperpel,
1945 nt_devmode->pelswidth,
1946 nt_devmode->pelsheight,
1947 nt_devmode->displayflags,
1948 nt_devmode->displayfrequency,
1949 nt_devmode->icmmethod,
1950 nt_devmode->icmintent,
1951 nt_devmode->mediatype,
1952 nt_devmode->dithertype,
1953 nt_devmode->reserved1,
1954 nt_devmode->reserved2,
1955 nt_devmode->panningwidth,
1956 nt_devmode->panningheight,
1957 nt_devmode->private);
1960 if (nt_devmode->private) {
1961 len += tdb_pack(buf+len, buflen-len, "B",
1962 nt_devmode->driverextra,
1963 nt_devmode->private);
1966 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
1968 return len;
1971 /****************************************************************************
1972 Pack all values in all printer keys
1973 ***************************************************************************/
1975 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
1977 int len = 0;
1978 int i, j;
1979 REGISTRY_VALUE *val;
1980 REGVAL_CTR *val_ctr;
1981 pstring path;
1982 int num_values;
1984 if ( !data )
1985 return 0;
1987 /* loop over all keys */
1989 for ( i=0; i<data->num_keys; i++ ) {
1990 val_ctr = &data->keys[i].values;
1991 num_values = regval_ctr_numvals( val_ctr );
1993 /* loop over all values */
1995 for ( j=0; j<num_values; j++ ) {
1996 /* pathname should be stored as <key>\<value> */
1998 val = regval_ctr_specific_value( val_ctr, j );
1999 pstrcpy( path, data->keys[i].name );
2000 pstrcat( path, "\\" );
2001 pstrcat( path, regval_name(val) );
2003 len += tdb_pack(buf+len, buflen-len, "pPdB",
2004 val,
2005 path,
2006 regval_type(val),
2007 regval_size(val),
2008 regval_data_p(val) );
2013 /* terminator */
2015 len += tdb_pack(buf+len, buflen-len, "p", NULL);
2017 return len;
2021 /****************************************************************************
2022 Delete a printer - this just deletes the printer info file, any open
2023 handles are not affected.
2024 ****************************************************************************/
2026 uint32 del_a_printer(char *sharename)
2028 pstring key;
2029 TDB_DATA kbuf;
2031 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
2033 kbuf.dptr=key;
2034 kbuf.dsize=strlen(key)+1;
2036 tdb_delete(tdb_printers, kbuf);
2037 return 0;
2040 /****************************************************************************
2041 ****************************************************************************/
2042 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2044 pstring key;
2045 char *buf;
2046 int buflen, len;
2047 WERROR ret;
2048 TDB_DATA kbuf, dbuf;
2051 * in addprinter: no servername and the printer is the name
2052 * in setprinter: servername is \\server
2053 * and printer is \\server\\printer
2055 * Samba manages only local printers.
2056 * we currently don't support things like path=\\other_server\printer
2059 if (info->servername[0]!='\0') {
2060 trim_string(info->printername, info->servername, NULL);
2061 trim_char(info->printername, '\\', '\0');
2062 info->servername[0]='\0';
2066 * JFM: one day I'll forget.
2067 * below that's info->portname because that's the SAMBA sharename
2068 * and I made NT 'thinks' it's the portname
2069 * the info->sharename is the thing you can name when you add a printer
2070 * that's the short-name when you create shared printer for 95/98
2071 * So I've made a limitation in SAMBA: you can only have 1 printer model
2072 * behind a SAMBA share.
2075 buf = NULL;
2076 buflen = 0;
2078 again:
2079 len = 0;
2080 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2081 info->attributes,
2082 info->priority,
2083 info->default_priority,
2084 info->starttime,
2085 info->untiltime,
2086 info->status,
2087 info->cjobs,
2088 info->averageppm,
2089 info->changeid,
2090 info->c_setprinter,
2091 info->setuptime,
2092 info->servername,
2093 info->printername,
2094 info->sharename,
2095 info->portname,
2096 info->drivername,
2097 info->comment,
2098 info->location,
2099 info->sepfile,
2100 info->printprocessor,
2101 info->datatype,
2102 info->parameters);
2104 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2106 len += pack_values( &info->data, buf+len, buflen-len );
2108 if (buflen != len) {
2109 char *tb;
2111 tb = (char *)Realloc(buf, len);
2112 if (!tb) {
2113 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2114 ret = WERR_NOMEM;
2115 goto done;
2117 else buf = tb;
2118 buflen = len;
2119 goto again;
2123 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
2125 kbuf.dptr = key;
2126 kbuf.dsize = strlen(key)+1;
2127 dbuf.dptr = buf;
2128 dbuf.dsize = len;
2130 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2132 done:
2133 if (!W_ERROR_IS_OK(ret))
2134 DEBUG(8, ("error updating printer to tdb on disk\n"));
2136 SAFE_FREE(buf);
2138 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2139 info->sharename, info->drivername, info->portname, len));
2141 return ret;
2145 /****************************************************************************
2146 Malloc and return an NT devicemode.
2147 ****************************************************************************/
2149 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2152 char adevice[MAXDEVICENAME];
2153 NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
2155 if (nt_devmode == NULL) {
2156 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2157 return NULL;
2160 ZERO_STRUCTP(nt_devmode);
2162 safe_strcpy(adevice, default_devicename, sizeof(adevice)-1);
2163 fstrcpy(nt_devmode->devicename, adevice);
2165 fstrcpy(nt_devmode->formname, "Letter");
2167 nt_devmode->specversion = 0x0401;
2168 nt_devmode->driverversion = 0x0400;
2169 nt_devmode->size = 0x00DC;
2170 nt_devmode->driverextra = 0x0000;
2171 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2172 DEFAULTSOURCE | COPIES | SCALE |
2173 PAPERSIZE | ORIENTATION;
2174 nt_devmode->orientation = 1;
2175 nt_devmode->papersize = PAPER_LETTER;
2176 nt_devmode->paperlength = 0;
2177 nt_devmode->paperwidth = 0;
2178 nt_devmode->scale = 0x64;
2179 nt_devmode->copies = 1;
2180 nt_devmode->defaultsource = BIN_FORMSOURCE;
2181 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2182 nt_devmode->color = COLOR_MONOCHROME;
2183 nt_devmode->duplex = DUP_SIMPLEX;
2184 nt_devmode->yresolution = 0;
2185 nt_devmode->ttoption = TT_SUBDEV;
2186 nt_devmode->collate = COLLATE_FALSE;
2187 nt_devmode->icmmethod = 0;
2188 nt_devmode->icmintent = 0;
2189 nt_devmode->mediatype = 0;
2190 nt_devmode->dithertype = 0;
2192 /* non utilisés par un driver d'imprimante */
2193 nt_devmode->logpixels = 0;
2194 nt_devmode->bitsperpel = 0;
2195 nt_devmode->pelswidth = 0;
2196 nt_devmode->pelsheight = 0;
2197 nt_devmode->displayflags = 0;
2198 nt_devmode->displayfrequency = 0;
2199 nt_devmode->reserved1 = 0;
2200 nt_devmode->reserved2 = 0;
2201 nt_devmode->panningwidth = 0;
2202 nt_devmode->panningheight = 0;
2204 nt_devmode->private = NULL;
2205 return nt_devmode;
2208 /****************************************************************************
2209 Deepcopy an NT devicemode.
2210 ****************************************************************************/
2212 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2214 NT_DEVICEMODE *new_nt_devicemode = NULL;
2216 if ( !nt_devicemode )
2217 return NULL;
2219 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2220 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2221 return NULL;
2224 new_nt_devicemode->private = NULL;
2225 if (nt_devicemode->private != NULL) {
2226 if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
2227 SAFE_FREE(new_nt_devicemode);
2228 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2229 return NULL;
2233 return new_nt_devicemode;
2236 /****************************************************************************
2237 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2238 ****************************************************************************/
2240 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2242 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2244 if(nt_devmode == NULL)
2245 return;
2247 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2249 SAFE_FREE(nt_devmode->private);
2250 SAFE_FREE(*devmode_ptr);
2253 /****************************************************************************
2254 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2255 ****************************************************************************/
2256 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2258 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2259 NT_PRINTER_DATA *data;
2260 int i;
2262 if ( !info )
2263 return;
2265 DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
2267 free_nt_devicemode(&info->devmode);
2269 /* clean up all registry keys */
2271 data = &info->data;
2272 for ( i=0; i<data->num_keys; i++ ) {
2273 SAFE_FREE( data->keys[i].name );
2274 regval_ctr_destroy( &data->keys[i].values );
2276 SAFE_FREE( data->keys );
2278 /* finally the top level structure */
2280 SAFE_FREE( *info_ptr );
2284 /****************************************************************************
2285 ****************************************************************************/
2286 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2288 int len = 0;
2289 int extra_len = 0;
2290 NT_DEVICEMODE devmode;
2292 ZERO_STRUCT(devmode);
2294 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2296 if (!*nt_devmode) return len;
2298 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2299 devmode.devicename,
2300 devmode.formname,
2302 &devmode.specversion,
2303 &devmode.driverversion,
2304 &devmode.size,
2305 &devmode.driverextra,
2306 &devmode.orientation,
2307 &devmode.papersize,
2308 &devmode.paperlength,
2309 &devmode.paperwidth,
2310 &devmode.scale,
2311 &devmode.copies,
2312 &devmode.defaultsource,
2313 &devmode.printquality,
2314 &devmode.color,
2315 &devmode.duplex,
2316 &devmode.yresolution,
2317 &devmode.ttoption,
2318 &devmode.collate,
2319 &devmode.logpixels,
2321 &devmode.fields,
2322 &devmode.bitsperpel,
2323 &devmode.pelswidth,
2324 &devmode.pelsheight,
2325 &devmode.displayflags,
2326 &devmode.displayfrequency,
2327 &devmode.icmmethod,
2328 &devmode.icmintent,
2329 &devmode.mediatype,
2330 &devmode.dithertype,
2331 &devmode.reserved1,
2332 &devmode.reserved2,
2333 &devmode.panningwidth,
2334 &devmode.panningheight,
2335 &devmode.private);
2337 if (devmode.private) {
2338 /* the len in tdb_unpack is an int value and
2339 * devmode.driverextra is only a short
2341 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
2342 devmode.driverextra=(uint16)extra_len;
2344 /* check to catch an invalid TDB entry so we don't segfault */
2345 if (devmode.driverextra == 0) {
2346 devmode.private = NULL;
2350 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2352 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2353 if (devmode.private)
2354 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2356 return len;
2359 /****************************************************************************
2360 Allocate and initialize a new slot.
2361 ***************************************************************************/
2363 static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2365 NT_PRINTER_KEY *d;
2366 int key_index;
2368 if ( !data || !name )
2369 return -1;
2371 /* allocate another slot in the NT_PRINTER_KEY array */
2373 d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
2374 if ( d )
2375 data->keys = d;
2377 key_index = data->num_keys;
2379 /* initialze new key */
2381 data->num_keys++;
2382 data->keys[key_index].name = strdup( name );
2384 ZERO_STRUCTP( &data->keys[key_index].values );
2386 regval_ctr_init( &data->keys[key_index].values );
2388 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2390 return key_index;
2393 /****************************************************************************
2394 search for a registry key name in the existing printer data
2395 ***************************************************************************/
2397 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2399 int key_index = -1;
2400 int i;
2402 if ( !data || !name )
2403 return -1;
2405 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2407 /* loop over all existing keys */
2409 for ( i=0; i<data->num_keys; i++ ) {
2410 if ( strequal(data->keys[i].name, name) ) {
2411 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2412 key_index = i;
2413 break;
2418 return key_index;
2421 /****************************************************************************
2422 ***************************************************************************/
2424 uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2426 int i, j;
2427 int key_len;
2428 int num_subkeys = 0;
2429 char *p;
2430 fstring *ptr, *subkeys_ptr = NULL;
2431 fstring subkeyname;
2433 if ( !data )
2434 return 0;
2436 for ( i=0; i<data->num_keys; i++ ) {
2437 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 ) {
2438 /* match sure it is a subkey and not the key itself */
2440 key_len = strlen( key );
2441 if ( strlen(data->keys[i].name) == key_len )
2442 continue;
2444 /* get subkey path */
2446 p = data->keys[i].name + key_len;
2447 if ( *p == '\\' )
2448 p++;
2449 fstrcpy( subkeyname, p );
2450 if ( (p = strchr( subkeyname, '\\' )) )
2451 *p = '\0';
2453 /* don't add a key more than once */
2455 for ( j=0; j<num_subkeys; j++ ) {
2456 if ( strequal( subkeys_ptr[j], subkeyname ) )
2457 break;
2460 if ( j != num_subkeys )
2461 continue;
2463 /* found a match, so allocate space and copy the name */
2465 if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
2466 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2467 num_subkeys+1));
2468 SAFE_FREE( subkeys );
2469 return 0;
2472 subkeys_ptr = ptr;
2473 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2474 num_subkeys++;
2479 /* tag of the end */
2481 if (num_subkeys)
2482 fstrcpy(subkeys_ptr[num_subkeys], "" );
2484 *subkeys = subkeys_ptr;
2486 return num_subkeys;
2489 #ifdef HAVE_ADS
2490 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2491 const char *sz)
2493 smb_ucs2_t conv_str[1024];
2494 size_t str_size;
2496 regval_ctr_delvalue(ctr, val_name);
2497 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2498 STR_TERMINATE | STR_NOALIGN);
2499 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2500 (char *) conv_str, str_size);
2503 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2504 uint32 dword)
2506 regval_ctr_delvalue(ctr, val_name);
2507 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2508 (char *) &dword, sizeof(dword));
2511 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2512 BOOL b)
2514 uint8 bin_bool = (b ? 1 : 0);
2515 regval_ctr_delvalue(ctr, val_name);
2516 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2517 (char *) &bin_bool, sizeof(bin_bool));
2520 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2521 const char *multi_sz)
2523 smb_ucs2_t *conv_strs = NULL;
2524 size_t str_size;
2526 /* a multi-sz has to have a null string terminator, i.e., the last
2527 string must be followed by two nulls */
2528 str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
2529 conv_strs = calloc(str_size, 1);
2531 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2532 STR_TERMINATE | STR_NOALIGN);
2534 regval_ctr_delvalue(ctr, val_name);
2535 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2536 (char *) conv_strs, str_size);
2537 safe_free(conv_strs);
2541 /****************************************************************************
2542 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2544 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2545 * @return BOOL indicating success or failure
2546 ***************************************************************************/
2548 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2550 REGVAL_CTR *ctr = NULL;
2551 fstring longname;
2552 char *allocated_string = NULL;
2553 const char *ascii_str;
2554 int i;
2556 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2557 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2558 ctr = &info2->data.keys[i].values;
2560 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2561 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2563 get_mydnsfullname(longname);
2564 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2566 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2567 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2568 SAFE_FREE(allocated_string);
2570 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2571 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2572 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2573 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2574 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2575 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2576 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2577 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2578 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2580 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2581 (info2->attributes &
2582 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2584 switch (info2->attributes & 0x3) {
2585 case 0:
2586 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2587 break;
2588 case 1:
2589 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2590 break;
2591 case 2:
2592 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2593 break;
2594 default:
2595 ascii_str = "unknown";
2597 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2599 return True;
2602 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
2603 struct uuid guid)
2605 int i;
2606 REGVAL_CTR *ctr=NULL;
2608 /* find the DsSpooler key */
2609 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2610 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2611 ctr = &info2->data.keys[i].values;
2613 regval_ctr_delvalue(ctr, "objectGUID");
2614 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2615 (char *) &guid, sizeof(struct uuid));
2618 static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
2620 ADS_STATUS ads_rc;
2621 TALLOC_CTX *ctx = talloc_init("publish_it");
2622 ADS_MODLIST mods = ads_init_mods(ctx);
2623 char *prt_dn = NULL, *srv_dn, *srv_cn_0;
2624 char *srv_dn_utf8, **srv_cn_utf8;
2625 void *res = NULL;
2626 ADS_STRUCT *ads;
2627 const char *attrs[] = {"objectGUID", NULL};
2628 struct uuid guid;
2629 WERROR win_rc = WERR_OK;
2631 ZERO_STRUCT(guid);
2632 /* set the DsSpooler info and attributes */
2633 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2)))
2634 return WERR_NOMEM;
2635 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
2636 win_rc = mod_a_printer(*printer, 2);
2637 if (!W_ERROR_IS_OK(win_rc)) {
2638 DEBUG(3, ("err %d saving data\n",
2639 W_ERROR_V(win_rc)));
2640 return win_rc;
2643 /* Build the ads mods */
2644 get_local_printer_publishing_data(ctx, &mods,
2645 &printer->info_2->data);
2646 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
2647 printer->info_2->sharename);
2649 /* initial ads structure */
2651 ads = ads_init(NULL, NULL, NULL);
2652 if (!ads) {
2653 DEBUG(3, ("ads_init() failed\n"));
2654 return WERR_SERVER_UNAVAILABLE;
2656 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2657 SAFE_FREE(ads->auth.password);
2658 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2659 NULL, NULL);
2661 /* ads_connect() will find the DC for us */
2662 ads_rc = ads_connect(ads);
2663 if (!ADS_ERR_OK(ads_rc)) {
2664 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2665 ads_destroy(&ads);
2666 return WERR_ACCESS_DENIED;
2669 /* figure out where to publish */
2670 ads_find_machine_acct(ads, &res, global_myname());
2672 /* We use ldap_get_dn here as we need the answer
2673 * in utf8 to call ldap_explode_dn(). JRA. */
2675 srv_dn_utf8 = ldap_get_dn(ads->ld, res);
2676 if (!srv_dn_utf8) {
2677 ads_destroy(&ads);
2678 return WERR_SERVER_UNAVAILABLE;
2680 ads_msgfree(ads, res);
2681 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
2682 if (!srv_cn_utf8) {
2683 ldap_memfree(srv_dn_utf8);
2684 ads_destroy(&ads);
2685 return WERR_SERVER_UNAVAILABLE;
2687 /* Now convert to CH_UNIX. */
2688 if (pull_utf8_allocate(&srv_dn, srv_dn_utf8) == (size_t)-1) {
2689 ldap_memfree(srv_dn_utf8);
2690 ldap_memfree(srv_cn_utf8);
2691 ads_destroy(&ads);
2692 return WERR_SERVER_UNAVAILABLE;
2694 if (pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0]) == (size_t)-1) {
2695 ldap_memfree(srv_dn_utf8);
2696 ldap_memfree(srv_cn_utf8);
2697 ads_destroy(&ads);
2698 SAFE_FREE(srv_dn);
2699 return WERR_SERVER_UNAVAILABLE;
2702 ldap_memfree(srv_dn_utf8);
2703 ldap_memfree(srv_cn_utf8);
2705 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_0,
2706 printer->info_2->sharename, srv_dn);
2708 SAFE_FREE(srv_dn);
2709 SAFE_FREE(srv_cn_0);
2711 /* publish it */
2712 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
2713 if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
2714 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx,&mods);
2716 /* retreive the guid and store it locally */
2717 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
2718 ads_pull_guid(ads, res, &guid);
2719 ads_msgfree(ads, res);
2720 store_printer_guid(printer->info_2, guid);
2721 win_rc = mod_a_printer(*printer, 2);
2724 SAFE_FREE(prt_dn);
2725 ads_destroy(&ads);
2727 return WERR_OK;
2730 WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
2732 ADS_STATUS ads_rc;
2733 ADS_STRUCT *ads;
2734 void *res;
2735 char *prt_dn = NULL;
2736 WERROR win_rc;
2738 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
2739 win_rc = mod_a_printer(*printer, 2);
2740 if (!W_ERROR_IS_OK(win_rc)) {
2741 DEBUG(3, ("err %d saving data\n",
2742 W_ERROR_V(win_rc)));
2743 return win_rc;
2746 ads = ads_init(NULL, NULL, NULL);
2747 if (!ads) {
2748 DEBUG(3, ("ads_init() failed\n"));
2749 return WERR_SERVER_UNAVAILABLE;
2751 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
2752 SAFE_FREE(ads->auth.password);
2753 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
2754 NULL, NULL);
2756 /* ads_connect() will find the DC for us */
2757 ads_rc = ads_connect(ads);
2758 if (!ADS_ERR_OK(ads_rc)) {
2759 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2760 ads_destroy(&ads);
2761 return WERR_ACCESS_DENIED;
2764 /* remove the printer from the directory */
2765 ads_rc = ads_find_printer_on_server(ads, &res,
2766 printer->info_2->sharename, global_myname());
2767 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
2768 prt_dn = ads_get_dn(ads, res);
2769 ads_msgfree(ads, res);
2770 ads_rc = ads_del_dn(ads, prt_dn);
2771 ads_memfree(ads, prt_dn);
2774 ads_destroy(&ads);
2775 return WERR_OK;
2778 /****************************************************************************
2779 * Publish a printer in the directory
2781 * @param snum describing printer service
2782 * @return WERROR indicating status of publishing
2783 ***************************************************************************/
2785 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2787 NT_PRINTER_INFO_LEVEL *printer = NULL;
2788 WERROR win_rc;
2790 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2791 if (!W_ERROR_IS_OK(win_rc))
2792 return win_rc;
2794 switch(action) {
2795 case SPOOL_DS_PUBLISH:
2796 case SPOOL_DS_UPDATE:
2797 win_rc = publish_it(printer);
2798 break;
2799 case SPOOL_DS_UNPUBLISH:
2800 win_rc = unpublish_it(printer);
2801 break;
2802 default:
2803 win_rc = WERR_NOT_SUPPORTED;
2807 free_a_printer(&printer, 2);
2808 return win_rc;
2811 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
2812 struct uuid *guid)
2814 NT_PRINTER_INFO_LEVEL *printer = NULL;
2815 REGVAL_CTR *ctr;
2816 REGISTRY_VALUE *guid_val;
2817 WERROR win_rc;
2818 int i;
2821 win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
2822 if (!W_ERROR_IS_OK(win_rc))
2823 return False;
2825 if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
2826 return False;
2828 if ((i = lookup_printerkey(&printer->info_2->data,
2829 SPOOL_DSSPOOLER_KEY)) < 0)
2830 return False;
2832 if (!(ctr = &printer->info_2->data.keys[i].values)) {
2833 return False;
2836 if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
2837 return False;
2840 if (regval_size(guid_val) == sizeof(struct uuid))
2841 memcpy(guid, regval_data_p(guid_val), sizeof(struct uuid));
2843 return True;
2846 #else
2847 WERROR nt_printer_publish(Printer_entry *print_hnd, int snum, int action)
2849 return WERR_OK;
2851 BOOL is_printer_published(Printer_entry *print_hnd, int snum,
2852 struct uuid *guid)
2854 return False;
2856 #endif
2857 /****************************************************************************
2858 ***************************************************************************/
2860 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
2862 NT_PRINTER_DATA *data;
2863 int i;
2864 int removed_keys = 0;
2865 int empty_slot;
2867 data = &p2->data;
2868 empty_slot = data->num_keys;
2870 if ( !key )
2871 return WERR_INVALID_PARAM;
2873 /* remove all keys */
2875 if ( !strlen(key) ) {
2876 for ( i=0; i<data->num_keys; i++ ) {
2877 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2878 data->keys[i].name));
2880 SAFE_FREE( data->keys[i].name );
2881 regval_ctr_destroy( &data->keys[i].values );
2884 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
2885 p2->printername ));
2887 SAFE_FREE( data->keys );
2888 ZERO_STRUCTP( data );
2890 return WERR_OK;
2893 /* remove a specific key (and all subkeys) */
2895 for ( i=0; i<data->num_keys; i++ ) {
2896 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 ) {
2897 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2898 data->keys[i].name));
2900 SAFE_FREE( data->keys[i].name );
2901 regval_ctr_destroy( &data->keys[i].values );
2903 /* mark the slot as empty */
2905 ZERO_STRUCTP( &data->keys[i] );
2909 /* find the first empty slot */
2911 for ( i=0; i<data->num_keys; i++ ) {
2912 if ( !data->keys[i].name ) {
2913 empty_slot = i;
2914 removed_keys++;
2915 break;
2919 if ( i == data->num_keys )
2920 /* nothing was removed */
2921 return WERR_INVALID_PARAM;
2923 /* move everything down */
2925 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
2926 if ( data->keys[i].name ) {
2927 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
2928 ZERO_STRUCTP( &data->keys[i] );
2929 empty_slot++;
2930 removed_keys++;
2934 /* update count */
2936 data->num_keys -= removed_keys;
2938 /* sanity check to see if anything is left */
2940 if ( !data->num_keys ) {
2941 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
2943 SAFE_FREE( data->keys );
2944 ZERO_STRUCTP( data );
2947 return WERR_OK;
2950 /****************************************************************************
2951 ***************************************************************************/
2953 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2955 WERROR result = WERR_OK;
2956 int key_index;
2958 /* we must have names on non-zero length */
2960 if ( !key || !*key|| !value || !*value )
2961 return WERR_INVALID_NAME;
2963 /* find the printer key first */
2965 key_index = lookup_printerkey( &p2->data, key );
2966 if ( key_index == -1 )
2967 return WERR_OK;
2969 /* make sure the value exists so we can return the correct error code */
2971 if ( !regval_ctr_getvalue( &p2->data.keys[key_index].values, value ) )
2972 return WERR_BADFILE;
2974 regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
2976 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
2977 key, value ));
2979 return result;
2982 /****************************************************************************
2983 ***************************************************************************/
2985 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
2986 uint32 type, uint8 *data, int real_len )
2988 WERROR result = WERR_OK;
2989 int key_index;
2991 /* we must have names on non-zero length */
2993 if ( !key || !*key|| !value || !*value )
2994 return WERR_INVALID_NAME;
2996 /* find the printer key first */
2998 key_index = lookup_printerkey( &p2->data, key );
2999 if ( key_index == -1 )
3000 key_index = add_new_printer_key( &p2->data, key );
3002 if ( key_index == -1 )
3003 return WERR_NOMEM;
3005 regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
3006 type, (const char *)data, real_len );
3008 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
3009 key, value, type, real_len ));
3011 return result;
3014 /****************************************************************************
3015 ***************************************************************************/
3017 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
3019 int key_index;
3021 if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
3022 return NULL;
3024 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
3025 key, value ));
3027 return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
3030 /****************************************************************************
3031 Unpack a list of registry values frem the TDB
3032 ***************************************************************************/
3034 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
3036 int len = 0;
3037 uint32 type;
3038 pstring string, valuename, keyname;
3039 char *str;
3040 int size;
3041 uint8 *data_p;
3042 REGISTRY_VALUE *regval_p;
3043 int key_index;
3045 /* add the "PrinterDriverData" key first for performance reasons */
3047 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
3049 /* loop and unpack the rest of the registry values */
3051 while ( True ) {
3053 /* check to see if there are any more registry values */
3055 regval_p = NULL;
3056 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
3057 if ( !regval_p )
3058 break;
3060 /* unpack the next regval */
3062 len += tdb_unpack(buf+len, buflen-len, "fdB",
3063 string,
3064 &type,
3065 &size,
3066 &data_p);
3069 * break of the keyname from the value name.
3070 * Should only be one '\' in the string returned.
3073 str = strrchr( string, '\\');
3075 /* Put in "PrinterDriverData" is no key specified */
3077 if ( !str ) {
3078 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
3079 pstrcpy( valuename, string );
3081 else {
3082 *str = '\0';
3083 pstrcpy( keyname, string );
3084 pstrcpy( valuename, str+1 );
3087 /* see if we need a new key */
3089 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
3090 key_index = add_new_printer_key( printer_data, keyname );
3092 if ( key_index == -1 ) {
3093 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3094 keyname));
3095 break;
3098 /* add the new value */
3100 regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, (const char *)data_p, size );
3102 SAFE_FREE(data_p); /* 'B' option to tdbpack does a malloc() */
3104 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3107 return len;
3110 /****************************************************************************
3111 ***************************************************************************/
3113 static void map_to_os2_driver(fstring drivername)
3115 static BOOL initialised=False;
3116 static fstring last_from,last_to;
3117 char *mapfile = lp_os2_driver_map();
3118 char **lines = NULL;
3119 int numlines = 0;
3120 int i;
3122 if (!strlen(drivername))
3123 return;
3125 if (!*mapfile)
3126 return;
3128 if (!initialised) {
3129 *last_from = *last_to = 0;
3130 initialised = True;
3133 if (strequal(drivername,last_from)) {
3134 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3135 fstrcpy(drivername,last_to);
3136 return;
3139 lines = file_lines_load(mapfile, &numlines);
3140 if (numlines == 0) {
3141 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3142 return;
3145 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3147 for( i = 0; i < numlines; i++) {
3148 char *nt_name = lines[i];
3149 char *os2_name = strchr(nt_name,'=');
3151 if (!os2_name)
3152 continue;
3154 *os2_name++ = 0;
3156 while (isspace(*nt_name))
3157 nt_name++;
3159 if (!*nt_name || strchr("#;",*nt_name))
3160 continue;
3163 int l = strlen(nt_name);
3164 while (l && isspace(nt_name[l-1])) {
3165 nt_name[l-1] = 0;
3166 l--;
3170 while (isspace(*os2_name))
3171 os2_name++;
3174 int l = strlen(os2_name);
3175 while (l && isspace(os2_name[l-1])) {
3176 os2_name[l-1] = 0;
3177 l--;
3181 if (strequal(nt_name,drivername)) {
3182 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3183 fstrcpy(last_from,drivername);
3184 fstrcpy(last_to,os2_name);
3185 fstrcpy(drivername,os2_name);
3186 file_lines_free(lines);
3187 return;
3191 file_lines_free(lines);
3194 /****************************************************************************
3195 Get a default printer info 2 struct.
3196 ****************************************************************************/
3197 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3199 int snum;
3200 NT_PRINTER_INFO_LEVEL_2 info;
3202 ZERO_STRUCT(info);
3204 snum = lp_servicenumber(sharename);
3206 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3207 slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
3208 get_called_name(), sharename);
3209 fstrcpy(info.sharename, sharename);
3210 fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
3212 /* by setting the driver name to an empty string, a local NT admin
3213 can now run the **local** APW to install a local printer driver
3214 for a Samba shared printer in 2.2. Without this, drivers **must** be
3215 installed on the Samba server for NT clients --jerry */
3216 #if 0 /* JERRY --do not uncomment-- */
3217 if (!*info.drivername)
3218 fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3219 #endif
3222 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
3224 pstrcpy(info.comment, "");
3225 fstrcpy(info.printprocessor, "winprint");
3226 fstrcpy(info.datatype, "RAW");
3228 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3230 info.starttime = 0; /* Minutes since 12:00am GMT */
3231 info.untiltime = 0; /* Minutes since 12:00am GMT */
3232 info.priority = 1;
3233 info.default_priority = 1;
3234 info.setuptime = (uint32)time(NULL);
3237 * I changed this as I think it is better to have a generic
3238 * DEVMODE than to crash Win2k explorer.exe --jerry
3239 * See the HP Deskjet 990c Win2k drivers for an example.
3241 * However the default devmode appears to cause problems
3242 * with the HP CLJ 8500 PCL driver. Hence the addition of
3243 * the "default devmode" parameter --jerry 22/01/2002
3246 if (lp_default_devmode(snum)) {
3247 if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
3248 goto fail;
3250 else {
3251 info.devmode = NULL;
3254 /* This will get the current RPC talloc context, but we should be
3255 passing this as a parameter... fixme... JRA ! */
3257 if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
3258 goto fail;
3260 *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
3261 if (! *info_ptr) {
3262 DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
3263 goto fail;
3266 return WERR_OK;
3268 fail:
3269 if (info.devmode)
3270 free_nt_devicemode(&info.devmode);
3271 return WERR_ACCESS_DENIED;
3274 /****************************************************************************
3275 ****************************************************************************/
3276 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, const char *sharename)
3278 pstring key;
3279 NT_PRINTER_INFO_LEVEL_2 info;
3280 int len = 0;
3281 TDB_DATA kbuf, dbuf;
3282 fstring printername;
3283 char adevice[MAXDEVICENAME];
3285 ZERO_STRUCT(info);
3287 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
3289 kbuf.dptr = key;
3290 kbuf.dsize = strlen(key)+1;
3292 dbuf = tdb_fetch(tdb_printers, kbuf);
3293 if (!dbuf.dptr)
3294 return get_a_printer_2_default(info_ptr, sharename);
3296 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3297 &info.attributes,
3298 &info.priority,
3299 &info.default_priority,
3300 &info.starttime,
3301 &info.untiltime,
3302 &info.status,
3303 &info.cjobs,
3304 &info.averageppm,
3305 &info.changeid,
3306 &info.c_setprinter,
3307 &info.setuptime,
3308 info.servername,
3309 info.printername,
3310 info.sharename,
3311 info.portname,
3312 info.drivername,
3313 info.comment,
3314 info.location,
3315 info.sepfile,
3316 info.printprocessor,
3317 info.datatype,
3318 info.parameters);
3320 /* Samba has to have shared raw drivers. */
3321 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3323 /* Restore the stripped strings. */
3324 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3325 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", get_called_name(),
3326 info.printername);
3327 fstrcpy(info.printername, printername);
3329 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3332 * Some client drivers freak out if there is a NULL devmode
3333 * (probably the driver is not checking before accessing
3334 * the devmode pointer) --jerry
3336 * See comments in get_a_printer_2_default()
3339 if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
3340 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3341 printername));
3342 info.devmode = construct_nt_devicemode(printername);
3345 safe_strcpy(adevice, info.printername, sizeof(adevice)-1);
3346 if (info.devmode) {
3347 fstrcpy(info.devmode->devicename, adevice);
3350 len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
3352 /* This will get the current RPC talloc context, but we should be
3353 passing this as a parameter... fixme... JRA ! */
3355 nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
3357 /* Fix for OS/2 drivers. */
3359 if (get_remote_arch() == RA_OS2)
3360 map_to_os2_driver(info.drivername);
3362 SAFE_FREE(dbuf.dptr);
3363 *info_ptr=memdup(&info, sizeof(info));
3365 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3366 sharename, info.printername, info.drivername));
3368 return WERR_OK;
3371 /****************************************************************************
3372 Debugging function, dump at level 6 the struct in the logs.
3373 ****************************************************************************/
3374 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3376 uint32 result;
3377 NT_PRINTER_INFO_LEVEL_2 *info2;
3379 DEBUG(106,("Dumping printer at level [%d]\n", level));
3381 switch (level) {
3382 case 2:
3384 if (printer.info_2 == NULL)
3385 result=5;
3386 else
3388 info2=printer.info_2;
3390 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3391 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3392 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3393 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3394 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3395 DEBUGADD(106,("status:[%d]\n", info2->status));
3396 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3397 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3398 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3399 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3400 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3402 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3403 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3404 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3405 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3406 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3407 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3408 DEBUGADD(106,("location:[%s]\n", info2->location));
3409 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3410 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3411 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3412 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3413 result=0;
3415 break;
3417 default:
3418 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3419 result=1;
3420 break;
3423 return result;
3426 /****************************************************************************
3427 Update the changeid time.
3428 This is SO NASTY as some drivers need this to change, others need it
3429 static. This value will change every second, and I must hope that this
3430 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3431 UTAH ! JRA.
3432 ****************************************************************************/
3434 static uint32 rev_changeid(void)
3436 struct timeval tv;
3438 get_process_uptime(&tv);
3440 #if 1 /* JERRY */
3441 /* Return changeid as msec since spooler restart */
3442 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3443 #else
3445 * This setting seems to work well but is too untested
3446 * to replace the above calculation. Left in for experiementation
3447 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3449 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3450 #endif
3454 * The function below are the high level ones.
3455 * only those ones must be called from the spoolss code.
3456 * JFM.
3459 /****************************************************************************
3460 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3461 ****************************************************************************/
3463 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3465 WERROR result;
3467 dump_a_printer(printer, level);
3470 * invalidate cache for all open handles to this printer.
3471 * cache for a given handle will be updated on the next
3472 * get_a_printer()
3475 invalidate_printer_hnd_cache( printer.info_2->sharename );
3477 switch (level) {
3478 case 2:
3481 * Update the changestamp. Emperical tests show that the
3482 * ChangeID is always updated,but c_setprinter is
3483 * global spooler variable (not per printer).
3486 /* ChangeID **must** be increasing over the lifetime
3487 of client's spoolss service in order for the
3488 client's cache to show updates */
3490 printer.info_2->changeid = rev_changeid();
3493 * Because one day someone will ask:
3494 * NT->NT An admin connection to a remote
3495 * printer show changes imeediately in
3496 * the properities dialog
3498 * A non-admin connection will only show the
3499 * changes after viewing the properites page
3500 * 2 times. Seems to be related to a
3501 * race condition in the client between the spooler
3502 * updating the local cache and the Explorer.exe GUI
3503 * actually displaying the properties.
3505 * This is fixed in Win2k. admin/non-admin
3506 * connections both display changes immediately.
3508 * 14/12/01 --jerry
3511 result=update_a_printer_2(printer.info_2);
3513 break;
3515 default:
3516 result=WERR_UNKNOWN_LEVEL;
3517 break;
3520 return result;
3523 /****************************************************************************
3524 Initialize printer devmode & data with previously saved driver init values.
3525 ****************************************************************************/
3527 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3529 int len = 0;
3530 pstring key;
3531 TDB_DATA kbuf, dbuf;
3532 NT_PRINTER_INFO_LEVEL_2 info;
3535 ZERO_STRUCT(info);
3538 * Delete any printer data 'values' already set. When called for driver
3539 * replace, there will generally be some, but during an add printer, there
3540 * should not be any (if there are delete them).
3543 delete_all_printer_data( info_ptr, "" );
3545 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3547 kbuf.dptr = key;
3548 kbuf.dsize = strlen(key)+1;
3550 dbuf = tdb_fetch(tdb_drivers, kbuf);
3551 if (!dbuf.dptr) {
3553 * When changing to a driver that has no init info in the tdb, remove
3554 * the previous drivers init info and leave the new on blank.
3556 free_nt_devicemode(&info_ptr->devmode);
3557 return False;
3561 * Get the saved DEVMODE..
3564 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3567 * The saved DEVMODE contains the devicename from the printer used during
3568 * the initialization save. Change it to reflect the new printer.
3571 if ( info.devmode ) {
3572 ZERO_STRUCT(info.devmode->devicename);
3573 fstrcpy(info.devmode->devicename, info_ptr->printername);
3577 * NT/2k does not change out the entire DeviceMode of a printer
3578 * when changing the driver. Only the driverextra, private, &
3579 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3581 * Later examination revealed that Windows NT/2k does reset the
3582 * the printer's device mode, bit **only** when you change a
3583 * property of the device mode such as the page orientation.
3584 * --jerry
3588 /* Bind the saved DEVMODE to the new the printer */
3590 free_nt_devicemode(&info_ptr->devmode);
3591 info_ptr->devmode = info.devmode;
3593 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3594 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3596 /* Add the printer data 'values' to the new printer */
3598 len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3601 SAFE_FREE(dbuf.dptr);
3603 return True;
3606 /****************************************************************************
3607 Initialize printer devmode & data with previously saved driver init values.
3608 When a printer is created using AddPrinter, the drivername bound to the
3609 printer is used to lookup previously saved driver initialization info, which
3610 is bound to the new printer.
3611 ****************************************************************************/
3613 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3615 BOOL result = False;
3617 switch (level) {
3618 case 2:
3619 result = set_driver_init_2(printer->info_2);
3620 break;
3622 default:
3623 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
3624 level));
3625 break;
3628 return result;
3631 /****************************************************************************
3632 Delete driver init data stored for a specified driver
3633 ****************************************************************************/
3635 BOOL del_driver_init(char *drivername)
3637 pstring key;
3638 TDB_DATA kbuf;
3640 if (!drivername || !*drivername) {
3641 DEBUG(3,("del_driver_init: No drivername specified!\n"));
3642 return False;
3645 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
3647 kbuf.dptr = key;
3648 kbuf.dsize = strlen(key)+1;
3650 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
3652 return (tdb_delete(tdb_drivers, kbuf) == 0);
3655 /****************************************************************************
3656 Pack up the DEVMODE and values for a printer into a 'driver init' entry
3657 in the tdb. Note: this is different from the driver entry and the printer
3658 entry. There should be a single driver init entry for each driver regardless
3659 of whether it was installed from NT or 2K. Technically, they should be
3660 different, but they work out to the same struct.
3661 ****************************************************************************/
3663 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
3665 pstring key;
3666 char *buf;
3667 int buflen, len, ret;
3668 TDB_DATA kbuf, dbuf;
3670 buf = NULL;
3671 buflen = 0;
3673 again:
3674 len = 0;
3675 len += pack_devicemode(info->devmode, buf+len, buflen-len);
3677 len += pack_values( &info->data, buf+len, buflen-len );
3679 if (buflen != len) {
3680 char *tb;
3682 tb = (char *)Realloc(buf, len);
3683 if (!tb) {
3684 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
3685 ret = -1;
3686 goto done;
3688 else
3689 buf = tb;
3690 buflen = len;
3691 goto again;
3694 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
3696 kbuf.dptr = key;
3697 kbuf.dsize = strlen(key)+1;
3698 dbuf.dptr = buf;
3699 dbuf.dsize = len;
3701 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
3703 done:
3704 if (ret == -1)
3705 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
3707 SAFE_FREE(buf);
3709 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
3710 info->sharename, info->drivername));
3712 return ret;
3715 /****************************************************************************
3716 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
3717 ****************************************************************************/
3719 uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3721 uint32 result;
3723 dump_a_printer(printer, level);
3725 switch (level) {
3726 case 2:
3727 result = update_driver_init_2(printer.info_2);
3728 break;
3729 default:
3730 result = 1;
3731 break;
3734 return result;
3737 /****************************************************************************
3738 Convert the printer data value, a REG_BINARY array, into an initialization
3739 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
3740 got to keep the endians happy :).
3741 ****************************************************************************/
3743 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
3745 BOOL result = False;
3746 prs_struct ps;
3747 DEVICEMODE devmode;
3749 ZERO_STRUCT(devmode);
3751 prs_init(&ps, 0, ctx, UNMARSHALL);
3752 ps.data_p = (char *)data;
3753 ps.buffer_size = data_len;
3755 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
3756 result = convert_devicemode("", &devmode, &nt_devmode);
3757 else
3758 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
3760 return result;
3763 /****************************************************************************
3764 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
3766 1. Use the driver's config DLL to this UNC printername and:
3767 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
3768 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
3769 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
3771 The last step triggers saving the "driver initialization" information for
3772 this printer into the tdb. Later, new printers that use this driver will
3773 have this initialization information bound to them. This simulates the
3774 driver initialization, as if it had run on the Samba server (as it would
3775 have done on NT).
3777 The Win32 client side code requirement sucks! But until we can run arbitrary
3778 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
3780 It would have been easier to use SetPrinter because all the UNMARSHALLING of
3781 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
3782 about it and you will realize why. JRR 010720
3783 ****************************************************************************/
3785 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
3787 WERROR status = WERR_OK;
3788 TALLOC_CTX *ctx = NULL;
3789 NT_DEVICEMODE *nt_devmode = NULL;
3790 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
3793 * When the DEVMODE is already set on the printer, don't try to unpack it.
3795 DEBUG(8,("save_driver_init_2: Enter...\n"));
3797 if ( !printer->info_2->devmode && data_len ) {
3799 * Set devmode on printer info, so entire printer initialization can be
3800 * saved to tdb.
3803 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
3804 return WERR_NOMEM;
3806 if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
3807 status = WERR_NOMEM;
3808 goto done;
3811 ZERO_STRUCTP(nt_devmode);
3814 * The DEVMODE is held in the 'data' component of the param in raw binary.
3815 * Convert it to to a devmode structure
3817 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
3818 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
3819 status = WERR_INVALID_PARAM;
3820 goto done;
3823 printer->info_2->devmode = nt_devmode;
3827 * Pack up and add (or update) the DEVMODE and any current printer data to
3828 * a 'driver init' element in the tdb
3832 if ( update_driver_init(*printer, 2) != 0 ) {
3833 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
3834 status = WERR_NOMEM;
3835 goto done;
3839 * If driver initialization info was successfully saved, set the current
3840 * printer to match it. This allows initialization of the current printer
3841 * as well as the driver.
3843 status = mod_a_printer(*printer, 2);
3844 if (!W_ERROR_IS_OK(status)) {
3845 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
3846 printer->info_2->printername));
3849 done:
3850 talloc_destroy(ctx);
3851 free_nt_devicemode( &nt_devmode );
3853 printer->info_2->devmode = tmp_devmode;
3855 return status;
3858 /****************************************************************************
3859 Update the driver init info (DEVMODE and specifics) for a printer
3860 ****************************************************************************/
3862 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
3864 WERROR status = WERR_OK;
3866 switch (level) {
3867 case 2:
3868 status = save_driver_init_2( printer, data, data_len );
3869 break;
3870 default:
3871 status = WERR_UNKNOWN_LEVEL;
3872 break;
3875 return status;
3878 /****************************************************************************
3879 Deep copy a NT_PRINTER_DATA
3880 ****************************************************************************/
3882 static NTSTATUS copy_printer_data( NT_PRINTER_DATA *dst, NT_PRINTER_DATA *src )
3884 int i, j, num_vals, new_key_index;
3885 REGVAL_CTR *src_key, *dst_key;
3887 if ( !dst || !src )
3888 return NT_STATUS_NO_MEMORY;
3890 for ( i=0; i<src->num_keys; i++ ) {
3892 /* create a new instance of the printerkey in the destination
3893 printer_data object */
3895 new_key_index = add_new_printer_key( dst, src->keys[i].name );
3896 dst_key = &dst->keys[new_key_index].values;
3898 src_key = &src->keys[i].values;
3899 num_vals = regval_ctr_numvals( src_key );
3901 /* dup the printer entire printer key */
3903 for ( j=0; j<num_vals; j++ ) {
3904 regval_ctr_copyvalue( dst_key, regval_ctr_specific_value(src_key, j) );
3908 return NT_STATUS_OK;
3911 /****************************************************************************
3912 Deep copy a NT_PRINTER_INFO_LEVEL_2 structure using malloc()'d memeory
3913 Caller must free.
3914 ****************************************************************************/
3916 NT_PRINTER_INFO_LEVEL_2* dup_printer_2( TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL_2 *printer )
3918 NT_PRINTER_INFO_LEVEL_2 *copy;
3920 if ( !printer )
3921 return NULL;
3923 if ( !(copy = (NT_PRINTER_INFO_LEVEL_2 *)malloc(sizeof(NT_PRINTER_INFO_LEVEL_2))) )
3924 return NULL;
3926 memcpy( copy, printer, sizeof(NT_PRINTER_INFO_LEVEL_2) );
3928 /* malloc()'d members copied here */
3930 copy->devmode = dup_nt_devicemode( printer->devmode );
3932 ZERO_STRUCT( copy->data );
3933 copy_printer_data( &copy->data, &printer->data );
3935 /* this is talloc()'d; very ugly that we have a structure that
3936 is half malloc()'d and half talloc()'d but that is the way
3937 that the PRINTER_INFO stuff is written right now. --jerry */
3939 copy->secdesc_buf = dup_sec_desc_buf( ctx, printer->secdesc_buf );
3941 return copy;
3944 /****************************************************************************
3945 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
3947 Previously the code had a memory allocation problem because it always
3948 used the TALLOC_CTX from the Printer_entry*. This context lasts
3949 as a long as the original handle is open. So if the client made a lot
3950 of getprinter[data]() calls, the memory usage would climb. Now we use
3951 a short lived TALLOC_CTX for printer_info_2 objects returned. We
3952 still use the Printer_entry->ctx for maintaining the cache copy though
3953 since that object must live as long as the handle by definition.
3954 --jerry
3956 ****************************************************************************/
3958 WERROR get_a_printer( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
3959 const char *sharename)
3961 WERROR result;
3962 NT_PRINTER_INFO_LEVEL *printer = NULL;
3964 *pp_printer = NULL;
3966 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
3968 switch (level) {
3969 case 2:
3970 if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
3971 DEBUG(0,("get_a_printer: malloc fail.\n"));
3972 return WERR_NOMEM;
3974 ZERO_STRUCTP(printer);
3977 * check for cache first. A Printer handle cannot changed
3978 * to another printer object so we only check that the printer
3979 * is actually for a printer and that the printer_info pointer
3980 * is valid
3982 if ( print_hnd
3983 && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)
3984 && print_hnd->printer_info )
3986 /* get_talloc_ctx() works here because we need a short
3987 lived talloc context */
3989 if ( !(printer->info_2 = dup_printer_2(get_talloc_ctx(), print_hnd->printer_info->info_2)) )
3991 DEBUG(0,("get_a_printer: unable to copy cached printer info!\n"));
3993 SAFE_FREE(printer);
3994 return WERR_NOMEM;
3997 DEBUG(10,("get_a_printer: using cached copy of printer_info_2\n"));
3999 *pp_printer = printer;
4000 result = WERR_OK;
4002 break;
4005 /* no cache for this handle; see if we can match one from another handle.
4006 Make sure to use a short lived talloc ctx */
4008 if ( print_hnd )
4009 result = find_printer_in_print_hnd_cache(get_talloc_ctx(), &printer->info_2, sharename);
4011 /* fail to disk if we don't have it with any open handle */
4013 if ( !print_hnd || !W_ERROR_IS_OK(result) )
4014 result = get_a_printer_2(&printer->info_2, sharename);
4016 /* we have a new printer now. Save it with this handle */
4018 if ( W_ERROR_IS_OK(result) ) {
4019 dump_a_printer(*printer, level);
4021 /* save a copy in cache */
4022 if ( print_hnd && (print_hnd->printer_type==PRINTER_HANDLE_IS_PRINTER)) {
4023 if ( !print_hnd->printer_info )
4024 print_hnd->printer_info = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL));
4026 if ( print_hnd->printer_info ) {
4027 /* make sure to use the handle's talloc ctx here since
4028 the printer_2 object must last until the handle is closed */
4030 print_hnd->printer_info->info_2 = dup_printer_2(print_hnd->ctx, printer->info_2);
4032 /* don't fail the lookup just because the cache update failed */
4033 if ( !print_hnd->printer_info->info_2 )
4034 DEBUG(0,("get_a_printer: unable to copy new printer info!\n"));
4037 *pp_printer = printer;
4039 else
4040 SAFE_FREE(printer);
4042 break;
4044 default:
4045 result=WERR_UNKNOWN_LEVEL;
4046 break;
4049 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result)));
4051 return result;
4054 /****************************************************************************
4055 Deletes a NT_PRINTER_INFO_LEVEL struct.
4056 ****************************************************************************/
4058 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
4060 uint32 result;
4061 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
4063 DEBUG(104,("freeing a printer at level [%d]\n", level));
4065 if (printer == NULL)
4066 return 0;
4068 switch (level) {
4069 case 2:
4070 if (printer->info_2 != NULL) {
4071 free_nt_printer_info_level_2(&printer->info_2);
4072 result=0;
4073 } else
4074 result=4;
4075 break;
4077 default:
4078 result=1;
4079 break;
4082 SAFE_FREE(*pp_printer);
4083 return result;
4086 /****************************************************************************
4087 ****************************************************************************/
4088 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4090 uint32 result;
4091 DEBUG(104,("adding a printer at level [%d]\n", level));
4092 dump_a_printer_driver(driver, level);
4094 switch (level) {
4095 case 3:
4096 result=add_a_printer_driver_3(driver.info_3);
4097 break;
4099 case 6:
4100 result=add_a_printer_driver_6(driver.info_6);
4101 break;
4103 default:
4104 result=1;
4105 break;
4108 return result;
4110 /****************************************************************************
4111 ****************************************************************************/
4113 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
4114 fstring drivername, const char *architecture, uint32 version)
4116 WERROR result;
4118 switch (level) {
4119 case 3:
4120 /* Sometime we just want any version of the driver */
4122 if ( version == DRIVER_ANY_VERSION ) {
4123 /* look for Win2k first and then for NT4 */
4124 result = get_a_printer_driver_3(&driver->info_3, drivername,
4125 architecture, 3);
4127 if ( !W_ERROR_IS_OK(result) ) {
4128 result = get_a_printer_driver_3( &driver->info_3,
4129 drivername, architecture, 2 );
4131 } else {
4132 result = get_a_printer_driver_3(&driver->info_3, drivername,
4133 architecture, version);
4135 break;
4137 default:
4138 result=W_ERROR(1);
4139 break;
4142 if (W_ERROR_IS_OK(result))
4143 dump_a_printer_driver(*driver, level);
4145 return result;
4148 /****************************************************************************
4149 ****************************************************************************/
4150 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
4152 uint32 result;
4154 switch (level) {
4155 case 3:
4157 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
4158 if (driver.info_3 != NULL)
4160 info3=driver.info_3;
4161 SAFE_FREE(info3->dependentfiles);
4162 ZERO_STRUCTP(info3);
4163 SAFE_FREE(info3);
4164 result=0;
4165 } else {
4166 result=4;
4168 break;
4170 case 6:
4172 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
4173 if (driver.info_6 != NULL) {
4174 info6=driver.info_6;
4175 SAFE_FREE(info6->dependentfiles);
4176 SAFE_FREE(info6->previousnames);
4177 ZERO_STRUCTP(info6);
4178 SAFE_FREE(info6);
4179 result=0;
4180 } else {
4181 result=4;
4183 break;
4185 default:
4186 result=1;
4187 break;
4189 return result;
4193 /****************************************************************************
4194 Determine whether or not a particular driver is currently assigned
4195 to a printer
4196 ****************************************************************************/
4198 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4200 int snum;
4201 int n_services = lp_numservices();
4202 NT_PRINTER_INFO_LEVEL *printer = NULL;
4204 if ( !info_3 )
4205 return False;
4207 DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4209 /* loop through the printers.tdb and check for the drivername */
4211 for (snum=0; snum<n_services; snum++) {
4212 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4213 continue;
4215 if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
4216 continue;
4218 if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
4219 free_a_printer( &printer, 2 );
4220 return True;
4223 free_a_printer( &printer, 2 );
4226 DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4228 /* report that the driver is not in use by default */
4230 return False;
4234 /**********************************************************************
4235 Check to see if a ogiven file is in use by *info
4236 *********************************************************************/
4238 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4240 int i = 0;
4242 if ( !info )
4243 return False;
4245 if ( strequal(file, info->driverpath) )
4246 return True;
4248 if ( strequal(file, info->datafile) )
4249 return True;
4251 if ( strequal(file, info->configfile) )
4252 return True;
4254 if ( strequal(file, info->helpfile) )
4255 return True;
4257 /* see of there are any dependent files to examine */
4259 if ( !info->dependentfiles )
4260 return False;
4262 while ( *info->dependentfiles[i] ) {
4263 if ( strequal(file, info->dependentfiles[i]) )
4264 return True;
4265 i++;
4268 return False;
4272 /**********************************************************************
4273 Utility function to remove the dependent file pointed to by the
4274 input parameter from the list
4275 *********************************************************************/
4277 static void trim_dependent_file( fstring files[], int idx )
4280 /* bump everything down a slot */
4282 while( *files[idx+1] ) {
4283 fstrcpy( files[idx], files[idx+1] );
4284 idx++;
4287 *files[idx] = '\0';
4289 return;
4292 /**********************************************************************
4293 Check if any of the files used by src are also used by drv
4294 *********************************************************************/
4296 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4297 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4299 BOOL in_use = False;
4300 int i = 0;
4302 if ( !src || !drv )
4303 return False;
4305 /* check each file. Remove it from the src structure if it overlaps */
4307 if ( drv_file_in_use(src->driverpath, drv) ) {
4308 in_use = True;
4309 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4310 fstrcpy( src->driverpath, "" );
4313 if ( drv_file_in_use(src->datafile, drv) ) {
4314 in_use = True;
4315 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4316 fstrcpy( src->datafile, "" );
4319 if ( drv_file_in_use(src->configfile, drv) ) {
4320 in_use = True;
4321 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4322 fstrcpy( src->configfile, "" );
4325 if ( drv_file_in_use(src->helpfile, drv) ) {
4326 in_use = True;
4327 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4328 fstrcpy( src->helpfile, "" );
4331 /* are there any dependentfiles to examine? */
4333 if ( !src->dependentfiles )
4334 return in_use;
4336 while ( *src->dependentfiles[i] ) {
4337 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4338 in_use = True;
4339 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4340 trim_dependent_file( src->dependentfiles, i );
4341 } else
4342 i++;
4345 return in_use;
4348 /****************************************************************************
4349 Determine whether or not a particular driver files are currently being
4350 used by any other driver.
4352 Return value is True if any files were in use by other drivers
4353 and False otherwise.
4355 Upon return, *info has been modified to only contain the driver files
4356 which are not in use
4357 ****************************************************************************/
4359 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4361 int i;
4362 int ndrivers;
4363 uint32 version;
4364 fstring *list = NULL;
4365 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4367 if ( !info )
4368 return False;
4370 version = info->cversion;
4372 /* loop over all driver versions */
4374 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4376 /* get the list of drivers */
4378 list = NULL;
4379 ndrivers = get_ntdrivers(&list, info->environment, version);
4381 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4382 ndrivers, info->environment, version));
4384 /* check each driver for overlap in files */
4386 for (i=0; i<ndrivers; i++) {
4387 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4389 ZERO_STRUCT(driver);
4391 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
4392 SAFE_FREE(list);
4393 return True;
4396 /* check if d2 uses any files from d1 */
4397 /* only if this is a different driver than the one being deleted */
4399 if ( !strequal(info->name, driver.info_3->name) ) {
4400 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4401 free_a_printer_driver(driver, 3);
4402 SAFE_FREE( list );
4403 return True;
4407 free_a_printer_driver(driver, 3);
4410 SAFE_FREE(list);
4412 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4414 driver.info_3 = info;
4416 if ( DEBUGLEVEL >= 20 )
4417 dump_a_printer_driver( driver, 3 );
4419 return False;
4422 /****************************************************************************
4423 Actually delete the driver files. Make sure that
4424 printer_driver_files_in_use() return False before calling
4425 this.
4426 ****************************************************************************/
4428 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4430 int i = 0;
4431 char *s;
4432 connection_struct *conn;
4433 DATA_BLOB null_pw;
4434 NTSTATUS nt_status;
4435 fstring res_type;
4436 BOOL bad_path;
4437 SMB_STRUCT_STAT st;
4439 if ( !info_3 )
4440 return False;
4442 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4445 * Connect to the print$ share under the same account as the
4446 * user connected to the rpc pipe. Note we must be root to
4447 * do this.
4450 null_pw = data_blob( NULL, 0 );
4451 fstrcpy(res_type, "A:");
4452 become_root();
4453 conn = make_connection_with_chdir( "print$", null_pw, res_type, user->vuid, &nt_status );
4454 unbecome_root();
4456 if ( !conn ) {
4457 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4458 return False;
4461 /* Save who we are - we are temporarily becoming the connection user. */
4463 if ( !become_user(conn, conn->vuid) ) {
4464 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4465 return False;
4468 /* now delete the files; must strip the '\print$' string from
4469 fron of path */
4471 if ( *info_3->driverpath ) {
4472 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4473 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4474 DEBUG(10,("deleting driverfile [%s]\n", s));
4475 unlink_internals(conn, 0, s);
4479 if ( *info_3->configfile ) {
4480 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4481 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4482 DEBUG(10,("deleting configfile [%s]\n", s));
4483 unlink_internals(conn, 0, s);
4487 if ( *info_3->datafile ) {
4488 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4489 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4490 DEBUG(10,("deleting datafile [%s]\n", s));
4491 unlink_internals(conn, 0, s);
4495 if ( *info_3->helpfile ) {
4496 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4497 driver_unix_convert(s, conn, NULL, &bad_path, &st);
4498 DEBUG(10,("deleting helpfile [%s]\n", s));
4499 unlink_internals(conn, 0, s);
4503 /* check if we are done removing files */
4505 if ( info_3->dependentfiles ) {
4506 while ( *info_3->dependentfiles[i] ) {
4507 char *file;
4509 /* bypass the "\print$" portion of the path */
4511 if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
4512 driver_unix_convert(file, conn, NULL, &bad_path, &st);
4513 DEBUG(10,("deleting dependent file [%s]\n", file));
4514 unlink_internals(conn, 0, file );
4517 i++;
4521 unbecome_user();
4523 return True;
4526 /****************************************************************************
4527 Remove a printer driver from the TDB. This assumes that the the driver was
4528 previously looked up.
4529 ***************************************************************************/
4531 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4532 uint32 version, BOOL delete_files )
4534 pstring key;
4535 const char *arch;
4536 TDB_DATA kbuf, dbuf;
4537 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4539 /* delete the tdb data first */
4541 arch = get_short_archi(info_3->environment);
4542 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4543 arch, version, info_3->name);
4545 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4546 key, delete_files ? "TRUE" : "FALSE" ));
4548 ctr.info_3 = info_3;
4549 dump_a_printer_driver( ctr, 3 );
4551 kbuf.dptr=key;
4552 kbuf.dsize=strlen(key)+1;
4554 /* check if the driver actually exists for this environment */
4556 dbuf = tdb_fetch( tdb_drivers, kbuf );
4557 if ( !dbuf.dptr ) {
4558 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4559 return WERR_UNKNOWN_PRINTER_DRIVER;
4562 SAFE_FREE( dbuf.dptr );
4564 /* ok... the driver exists so the delete should return success */
4566 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4567 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4568 return WERR_ACCESS_DENIED;
4572 * now delete any associated files if delete_files == True
4573 * even if this part failes, we return succes because the
4574 * driver doesn not exist any more
4577 if ( delete_files )
4578 delete_driver_files( info_3, user );
4581 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4583 return WERR_OK;
4586 /****************************************************************************
4587 Store a security desc for a printer.
4588 ****************************************************************************/
4590 WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
4592 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4593 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4594 prs_struct ps;
4595 TALLOC_CTX *mem_ctx = NULL;
4596 fstring key;
4597 WERROR status;
4599 mem_ctx = talloc_init("nt_printing_setsec");
4600 if (mem_ctx == NULL)
4601 return WERR_NOMEM;
4603 /* The old owner and group sids of the security descriptor are not
4604 present when new ACEs are added or removed by changing printer
4605 permissions through NT. If they are NULL in the new security
4606 descriptor then copy them over from the old one. */
4608 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4609 DOM_SID *owner_sid, *group_sid;
4610 SEC_ACL *dacl, *sacl;
4611 SEC_DESC *psd = NULL;
4612 size_t size;
4614 nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
4616 /* Pick out correct owner and group sids */
4618 owner_sid = secdesc_ctr->sec->owner_sid ?
4619 secdesc_ctr->sec->owner_sid :
4620 old_secdesc_ctr->sec->owner_sid;
4622 group_sid = secdesc_ctr->sec->grp_sid ?
4623 secdesc_ctr->sec->grp_sid :
4624 old_secdesc_ctr->sec->grp_sid;
4626 dacl = secdesc_ctr->sec->dacl ?
4627 secdesc_ctr->sec->dacl :
4628 old_secdesc_ctr->sec->dacl;
4630 sacl = secdesc_ctr->sec->sacl ?
4631 secdesc_ctr->sec->sacl :
4632 old_secdesc_ctr->sec->sacl;
4634 /* Make a deep copy of the security descriptor */
4636 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision, secdesc_ctr->sec->type,
4637 owner_sid, group_sid,
4638 sacl,
4639 dacl,
4640 &size);
4642 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4645 if (!new_secdesc_ctr) {
4646 new_secdesc_ctr = secdesc_ctr;
4649 /* Store the security descriptor in a tdb */
4651 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4652 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4654 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4655 &ps, 1)) {
4656 status = WERR_BADFUNC;
4657 goto out;
4660 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4662 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4663 status = WERR_OK;
4664 } else {
4665 DEBUG(1,("Failed to store secdesc for %s\n", printername));
4666 status = WERR_BADFUNC;
4669 /* Free malloc'ed memory */
4671 out:
4673 prs_mem_free(&ps);
4674 if (mem_ctx)
4675 talloc_destroy(mem_ctx);
4676 return status;
4679 /****************************************************************************
4680 Construct a default security descriptor buffer for a printer.
4681 ****************************************************************************/
4683 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
4685 SEC_ACE ace[3];
4686 SEC_ACCESS sa;
4687 SEC_ACL *psa = NULL;
4688 SEC_DESC_BUF *sdb = NULL;
4689 SEC_DESC *psd = NULL;
4690 DOM_SID owner_sid;
4691 size_t sd_size;
4693 /* Create an ACE where Everyone is allowed to print */
4695 init_sec_access(&sa, PRINTER_ACE_PRINT);
4696 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
4697 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4699 /* Make the security descriptor owned by the Administrators group
4700 on the PDC of the domain. */
4702 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4703 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4704 } else {
4706 /* Backup plan - make printer owned by admins.
4707 This should emulate a lanman printer as security
4708 settings can't be changed. */
4710 sid_copy(&owner_sid, get_global_sam_sid());
4711 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4714 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4715 init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4716 sa, SEC_ACE_FLAG_OBJECT_INHERIT |
4717 SEC_ACE_FLAG_INHERIT_ONLY);
4719 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4720 init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4721 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4723 /* The ACL revision number in rpc_secdesc.h differs from the one
4724 created by NT when setting ACE entries in printer
4725 descriptors. NT4 complains about the property being edited by a
4726 NT5 machine. */
4728 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
4729 psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
4730 &owner_sid, NULL,
4731 NULL, psa, &sd_size);
4734 if (!psd) {
4735 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
4736 return NULL;
4739 sdb = make_sec_desc_buf(ctx, sd_size, psd);
4741 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
4742 (unsigned int)sd_size));
4744 return sdb;
4747 /****************************************************************************
4748 Get a security desc for a printer.
4749 ****************************************************************************/
4751 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
4753 prs_struct ps;
4754 fstring key;
4755 char *temp;
4757 if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\'))) {
4758 printername = temp + 1;
4761 /* Fetch security descriptor from tdb */
4763 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4765 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
4766 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
4768 DEBUG(4,("using default secdesc for %s\n", printername));
4770 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
4771 return False;
4774 /* Save default security descriptor for later */
4776 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
4777 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
4779 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
4780 tdb_prs_store(tdb_printers, key, &ps);
4782 prs_mem_free(&ps);
4784 return True;
4787 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
4788 this security descriptor has been created when winbindd was
4789 down. Take ownership of security descriptor. */
4791 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
4792 DOM_SID owner_sid;
4794 /* Change sd owner to workgroup administrator */
4796 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4797 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4798 SEC_DESC *psd = NULL;
4799 size_t size;
4801 /* Create new sd */
4803 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4805 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision, (*secdesc_ctr)->sec->type,
4806 &owner_sid,
4807 (*secdesc_ctr)->sec->grp_sid,
4808 (*secdesc_ctr)->sec->sacl,
4809 (*secdesc_ctr)->sec->dacl,
4810 &size);
4812 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
4814 /* Swap with other one */
4816 *secdesc_ctr = new_secdesc_ctr;
4818 /* Set it */
4820 nt_printing_setsec(printername, *secdesc_ctr);
4824 if (DEBUGLEVEL >= 10) {
4825 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
4826 int i;
4828 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
4829 printername, the_acl->num_aces));
4831 for (i = 0; i < the_acl->num_aces; i++) {
4832 fstring sid_str;
4834 sid_to_string(sid_str, &the_acl->ace[i].trustee);
4836 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
4837 the_acl->ace[i].type, the_acl->ace[i].flags,
4838 the_acl->ace[i].info.mask));
4842 prs_mem_free(&ps);
4843 return True;
4846 /* error code:
4847 0: everything OK
4848 1: level not implemented
4849 2: file doesn't exist
4850 3: can't allocate memory
4851 4: can't free memory
4852 5: non existant struct
4856 A printer and a printer driver are 2 different things.
4857 NT manages them separatelly, Samba does the same.
4858 Why ? Simply because it's easier and it makes sense !
4860 Now explanation: You have 3 printers behind your samba server,
4861 2 of them are the same make and model (laser A and B). But laser B
4862 has an 3000 sheet feeder and laser A doesn't such an option.
4863 Your third printer is an old dot-matrix model for the accounting :-).
4865 If the /usr/local/samba/lib directory (default dir), you will have
4866 5 files to describe all of this.
4868 3 files for the printers (1 by printer):
4869 NTprinter_laser A
4870 NTprinter_laser B
4871 NTprinter_accounting
4872 2 files for the drivers (1 for the laser and 1 for the dot matrix)
4873 NTdriver_printer model X
4874 NTdriver_printer model Y
4876 jfm: I should use this comment for the text file to explain
4877 same thing for the forms BTW.
4878 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
4882 /* Convert generic access rights to printer object specific access rights.
4883 It turns out that NT4 security descriptors use generic access rights and
4884 NT5 the object specific ones. */
4886 void map_printer_permissions(SEC_DESC *sd)
4888 int i;
4890 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
4891 se_map_generic(&sd->dacl->ace[i].info.mask,
4892 &printer_generic_mapping);
4896 /****************************************************************************
4897 Check a user has permissions to perform the given operation. We use the
4898 permission constants defined in include/rpc_spoolss.h to check the various
4899 actions we perform when checking printer access.
4901 PRINTER_ACCESS_ADMINISTER:
4902 print_queue_pause, print_queue_resume, update_printer_sec,
4903 update_printer, spoolss_addprinterex_level_2,
4904 _spoolss_setprinterdata
4906 PRINTER_ACCESS_USE:
4907 print_job_start
4909 JOB_ACCESS_ADMINISTER:
4910 print_job_delete, print_job_pause, print_job_resume,
4911 print_queue_purge
4913 ****************************************************************************/
4914 BOOL print_access_check(struct current_user *user, int snum, int access_type)
4916 SEC_DESC_BUF *secdesc = NULL;
4917 uint32 access_granted;
4918 NTSTATUS status;
4919 BOOL result;
4920 const char *pname;
4921 TALLOC_CTX *mem_ctx = NULL;
4922 extern struct current_user current_user;
4924 /* If user is NULL then use the current_user structure */
4926 if (!user)
4927 user = &current_user;
4929 /* Always allow root or printer admins to do anything */
4931 if (user->uid == 0 ||
4932 user_in_list(uidtoname(user->uid), lp_printer_admin(snum), user->groups, user->ngroups)) {
4933 return True;
4936 /* Get printer name */
4938 pname = PRINTERNAME(snum);
4940 if (!pname || !*pname) {
4941 errno = EACCES;
4942 return False;
4945 /* Get printer security descriptor */
4947 if(!(mem_ctx = talloc_init("print_access_check"))) {
4948 errno = ENOMEM;
4949 return False;
4952 nt_printing_getsec(mem_ctx, pname, &secdesc);
4954 if (access_type == JOB_ACCESS_ADMINISTER) {
4955 SEC_DESC_BUF *parent_secdesc = secdesc;
4957 /* Create a child security descriptor to check permissions
4958 against. This is because print jobs are child objects
4959 objects of a printer. */
4961 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
4963 /* Now this is the bit that really confuses me. The access
4964 type needs to be changed from JOB_ACCESS_ADMINISTER to
4965 PRINTER_ACCESS_ADMINISTER for this to work. Something
4966 to do with the child (job) object becoming like a
4967 printer?? -tpot */
4969 access_type = PRINTER_ACCESS_ADMINISTER;
4972 /* Check access */
4974 map_printer_permissions(secdesc->sec);
4976 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
4977 &access_granted, &status);
4979 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
4981 talloc_destroy(mem_ctx);
4983 if (!result)
4984 errno = EACCES;
4986 return result;
4989 /****************************************************************************
4990 Check the time parameters allow a print operation.
4991 *****************************************************************************/
4993 BOOL print_time_access_check(int snum)
4995 NT_PRINTER_INFO_LEVEL *printer = NULL;
4996 BOOL ok = False;
4997 time_t now = time(NULL);
4998 struct tm *t;
4999 uint32 mins;
5001 if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))))
5002 return False;
5004 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
5005 ok = True;
5007 t = gmtime(&now);
5008 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
5010 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
5011 ok = True;
5013 free_a_printer(&printer, 2);
5015 if (!ok)
5016 errno = EACCES;
5018 return ok;