* set PRINTER_ATTRIBUTE_RAW_ONLY; CR 1736
[Samba.git] / source / printing / nt_printing.c
blob10d490a4c1f69cdc756aafce08f935e1b46bd530
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.
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 static BOOL upgrade_to_version_3(void)
203 TDB_DATA kbuf, newkey, dbuf;
205 DEBUG(0,("upgrade_to_version_3: upgrading print tdb's to version 3\n"));
207 for (kbuf = tdb_firstkey(tdb_drivers); kbuf.dptr;
208 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
210 dbuf = tdb_fetch(tdb_drivers, kbuf);
212 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) == 0) {
213 DEBUG(0,("upgrade_to_version_3:moving form\n"));
214 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) {
215 SAFE_FREE(dbuf.dptr);
216 DEBUG(0,("upgrade_to_version_3: failed to move form. Error (%s).\n", tdb_errorstr(tdb_forms)));
217 return False;
219 if (tdb_delete(tdb_drivers, kbuf) != 0) {
220 SAFE_FREE(dbuf.dptr);
221 DEBUG(0,("upgrade_to_version_3: failed to delete form. Error (%s)\n", tdb_errorstr(tdb_drivers)));
222 return False;
226 if (strncmp(kbuf.dptr, PRINTERS_PREFIX, strlen(PRINTERS_PREFIX)) == 0) {
227 DEBUG(0,("upgrade_to_version_3:moving printer\n"));
228 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
229 SAFE_FREE(dbuf.dptr);
230 DEBUG(0,("upgrade_to_version_3: failed to move printer. Error (%s)\n", tdb_errorstr(tdb_printers)));
231 return False;
233 if (tdb_delete(tdb_drivers, kbuf) != 0) {
234 SAFE_FREE(dbuf.dptr);
235 DEBUG(0,("upgrade_to_version_3: failed to delete printer. Error (%s)\n", tdb_errorstr(tdb_drivers)));
236 return False;
240 if (strncmp(kbuf.dptr, SECDESC_PREFIX, strlen(SECDESC_PREFIX)) == 0) {
241 DEBUG(0,("upgrade_to_version_3:moving secdesc\n"));
242 if (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) != 0) {
243 SAFE_FREE(dbuf.dptr);
244 DEBUG(0,("upgrade_to_version_3: failed to move secdesc. Error (%s)\n", tdb_errorstr(tdb_printers)));
245 return False;
247 if (tdb_delete(tdb_drivers, kbuf) != 0) {
248 SAFE_FREE(dbuf.dptr);
249 DEBUG(0,("upgrade_to_version_3: failed to delete secdesc. Error (%s)\n", tdb_errorstr(tdb_drivers)));
250 return False;
254 SAFE_FREE(dbuf.dptr);
257 return True;
260 /****************************************************************************
261 Open the NT printing tdbs. Done once before fork().
262 ****************************************************************************/
264 BOOL nt_printing_init(void)
266 static pid_t local_pid;
267 const char *vstring = "INFO/version";
269 if (tdb_drivers && tdb_printers && tdb_forms && local_pid == sys_getpid())
270 return True;
272 if (tdb_drivers)
273 tdb_close(tdb_drivers);
274 tdb_drivers = tdb_open_log(lock_path("ntdrivers.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
275 if (!tdb_drivers) {
276 DEBUG(0,("nt_printing_init: Failed to open nt drivers database %s (%s)\n",
277 lock_path("ntdrivers.tdb"), strerror(errno) ));
278 return False;
281 if (tdb_printers)
282 tdb_close(tdb_printers);
283 tdb_printers = tdb_open_log(lock_path("ntprinters.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
284 if (!tdb_printers) {
285 DEBUG(0,("nt_printing_init: Failed to open nt printers database %s (%s)\n",
286 lock_path("ntprinters.tdb"), strerror(errno) ));
287 return False;
290 if (tdb_forms)
291 tdb_close(tdb_forms);
292 tdb_forms = tdb_open_log(lock_path("ntforms.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
293 if (!tdb_forms) {
294 DEBUG(0,("nt_printing_init: Failed to open nt forms database %s (%s)\n",
295 lock_path("ntforms.tdb"), strerror(errno) ));
296 return False;
299 local_pid = sys_getpid();
301 /* handle a Samba upgrade */
302 tdb_lock_bystring(tdb_drivers, vstring, 0);
304 int32 vers_id;
306 /* Cope with byte-reversed older versions of the db. */
307 vers_id = tdb_fetch_int32(tdb_drivers, vstring);
308 if ((vers_id == NTDRIVERS_DATABASE_VERSION_2) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_2)) {
309 /* Written on a bigendian machine with old fetch_int code. Save as le. */
310 /* The only upgrade between V2 and V3 is to save the version in little-endian. */
311 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
312 vers_id = NTDRIVERS_DATABASE_VERSION;
315 if (vers_id != NTDRIVERS_DATABASE_VERSION) {
317 if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
318 if (!upgrade_to_version_3())
319 return False;
320 } else
321 tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL);
323 tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
326 tdb_unlock_bystring(tdb_drivers, vstring);
328 update_c_setprinter(True);
331 * register callback to handle updating printers as new
332 * drivers are installed
335 message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
338 * register callback to handle updating printer data
339 * when a driver is initialized
342 message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
345 return True;
348 /*******************************************************************
349 tdb traversal function for counting printers.
350 ********************************************************************/
352 static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
353 TDB_DATA data, void *context)
355 int *printer_count = (int*)context;
357 if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
358 (*printer_count)++;
359 DEBUG(10,("traverse_counting_printers: printer = [%s] printer_count = %d\n", key.dptr, *printer_count));
362 return 0;
365 /*******************************************************************
366 Update the spooler global c_setprinter. This variable is initialized
367 when the parent smbd starts with the number of existing printers. It
368 is monotonically increased by the current number of printers *after*
369 each add or delete printer RPC. Only Microsoft knows why... JRR020119
370 ********************************************************************/
372 uint32 update_c_setprinter(BOOL initialize)
374 int32 c_setprinter;
375 int32 printer_count = 0;
377 tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER, 0);
379 /* Traverse the tdb, counting the printers */
380 tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
382 /* If initializing, set c_setprinter to current printers count
383 * otherwise, bump it by the current printer count
385 if (!initialize)
386 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
387 else
388 c_setprinter = printer_count;
390 DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
391 tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
393 tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
395 return (uint32)c_setprinter;
398 /*******************************************************************
399 Get the spooler global c_setprinter, accounting for initialization.
400 ********************************************************************/
402 uint32 get_c_setprinter(void)
404 int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
406 if (c_setprinter == (int32)-1)
407 c_setprinter = update_c_setprinter(True);
409 DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
411 return (uint32)c_setprinter;
414 /****************************************************************************
415 Get builtin form struct list.
416 ****************************************************************************/
418 int get_builtin_ntforms(nt_forms_struct **list)
420 *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
421 return sizeof(default_forms) / sizeof(default_forms[0]);
424 /****************************************************************************
425 get a builtin form struct
426 ****************************************************************************/
428 BOOL get_a_builtin_ntform(UNISTR2 *uni_formname,nt_forms_struct *form)
430 int i,count;
431 fstring form_name;
432 unistr2_to_ascii(form_name, uni_formname, sizeof(form_name)-1);
433 DEBUGADD(6,("Looking for builtin form %s \n", form_name));
434 count = sizeof(default_forms) / sizeof(default_forms[0]);
435 for (i=0;i<count;i++) {
436 if (strequal(form_name,default_forms[i].name)) {
437 DEBUGADD(6,("Found builtin form %s \n", form_name));
438 memcpy(form,&default_forms[i],sizeof(*form));
439 break;
443 return (i !=count);
446 /****************************************************************************
447 get a form struct list
448 ****************************************************************************/
449 int get_ntforms(nt_forms_struct **list)
451 TDB_DATA kbuf, newkey, dbuf;
452 nt_forms_struct *tl;
453 nt_forms_struct form;
454 int ret;
455 int i;
456 int n = 0;
458 for (kbuf = tdb_firstkey(tdb_forms);
459 kbuf.dptr;
460 newkey = tdb_nextkey(tdb_forms, kbuf), safe_free(kbuf.dptr), kbuf=newkey)
462 if (strncmp(kbuf.dptr, FORMS_PREFIX, strlen(FORMS_PREFIX)) != 0)
463 continue;
465 dbuf = tdb_fetch(tdb_forms, kbuf);
466 if (!dbuf.dptr)
467 continue;
469 fstrcpy(form.name, kbuf.dptr+strlen(FORMS_PREFIX));
470 ret = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddddddd",
471 &i, &form.flag, &form.width, &form.length, &form.left,
472 &form.top, &form.right, &form.bottom);
473 SAFE_FREE(dbuf.dptr);
474 if (ret != dbuf.dsize)
475 continue;
477 tl = Realloc(*list, sizeof(nt_forms_struct)*(n+1));
478 if (!tl) {
479 DEBUG(0,("get_ntforms: Realloc fail.\n"));
480 return 0;
482 *list = tl;
483 (*list)[n] = form;
484 n++;
488 return n;
491 /****************************************************************************
492 write a form struct list
493 ****************************************************************************/
494 int write_ntforms(nt_forms_struct **list, int number)
496 pstring buf, key;
497 int len;
498 TDB_DATA kbuf,dbuf;
499 int i;
501 for (i=0;i<number;i++) {
502 /* save index, so list is rebuilt in correct order */
503 len = tdb_pack(buf, sizeof(buf), "dddddddd",
504 i, (*list)[i].flag, (*list)[i].width, (*list)[i].length,
505 (*list)[i].left, (*list)[i].top, (*list)[i].right,
506 (*list)[i].bottom);
507 if (len > sizeof(buf)) break;
508 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[i].name);
509 kbuf.dsize = strlen(key)+1;
510 kbuf.dptr = key;
511 dbuf.dsize = len;
512 dbuf.dptr = buf;
513 if (tdb_store(tdb_forms, kbuf, dbuf, TDB_REPLACE) != 0) break;
516 return i;
519 /****************************************************************************
520 add a form struct at the end of the list
521 ****************************************************************************/
522 BOOL add_a_form(nt_forms_struct **list, const FORM *form, int *count)
524 int n=0;
525 BOOL update;
526 fstring form_name;
527 nt_forms_struct *tl;
530 * NT tries to add forms even when
531 * they are already in the base
532 * only update the values if already present
535 update=False;
537 unistr2_to_ascii(form_name, &form->name, sizeof(form_name)-1);
538 for (n=0; n<*count; n++) {
539 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
540 DEBUG(103, ("NT workaround, [%s] already exists\n", form_name));
541 update=True;
542 break;
546 if (update==False) {
547 if((tl=Realloc(*list, (n+1)*sizeof(nt_forms_struct))) == NULL) {
548 DEBUG(0,("add_a_form: failed to enlarge forms list!\n"));
549 return False;
551 *list = tl;
552 unistr2_to_ascii((*list)[n].name, &form->name, sizeof((*list)[n].name)-1);
553 (*count)++;
556 (*list)[n].flag=form->flags;
557 (*list)[n].width=form->size_x;
558 (*list)[n].length=form->size_y;
559 (*list)[n].left=form->left;
560 (*list)[n].top=form->top;
561 (*list)[n].right=form->right;
562 (*list)[n].bottom=form->bottom;
564 return True;
567 /****************************************************************************
568 delete a named form struct
569 ****************************************************************************/
570 BOOL delete_a_form(nt_forms_struct **list, UNISTR2 *del_name, int *count, WERROR *ret)
572 pstring key;
573 TDB_DATA kbuf;
574 int n=0;
575 fstring form_name;
577 *ret = WERR_OK;
579 unistr2_to_ascii(form_name, del_name, sizeof(form_name)-1);
581 for (n=0; n<*count; n++) {
582 if (!strncmp((*list)[n].name, form_name, strlen(form_name))) {
583 DEBUG(103, ("delete_a_form, [%s] in list\n", form_name));
584 break;
588 if (n == *count) {
589 DEBUG(10,("delete_a_form, [%s] not found\n", form_name));
590 *ret = WERR_INVALID_PARAM;
591 return False;
594 slprintf(key, sizeof(key)-1, "%s%s", FORMS_PREFIX, (*list)[n].name);
595 kbuf.dsize = strlen(key)+1;
596 kbuf.dptr = key;
597 if (tdb_delete(tdb_forms, kbuf) != 0) {
598 *ret = WERR_NOMEM;
599 return False;
602 return True;
605 /****************************************************************************
606 update a form struct
607 ****************************************************************************/
608 void update_a_form(nt_forms_struct **list, const FORM *form, int count)
610 int n=0;
611 fstring form_name;
612 unistr2_to_ascii(form_name, &(form->name), sizeof(form_name)-1);
614 DEBUG(106, ("[%s]\n", form_name));
615 for (n=0; n<count; n++)
617 DEBUGADD(106, ("n [%d]:[%s]\n", n, (*list)[n].name));
618 if (!strncmp((*list)[n].name, form_name, strlen(form_name)))
619 break;
622 if (n==count) return;
624 (*list)[n].flag=form->flags;
625 (*list)[n].width=form->size_x;
626 (*list)[n].length=form->size_y;
627 (*list)[n].left=form->left;
628 (*list)[n].top=form->top;
629 (*list)[n].right=form->right;
630 (*list)[n].bottom=form->bottom;
633 /****************************************************************************
634 get the nt drivers list
636 traverse the database and look-up the matching names
637 ****************************************************************************/
638 int get_ntdrivers(fstring **list, const char *architecture, uint32 version)
640 int total=0;
641 fstring short_archi;
642 fstring *fl;
643 pstring key;
644 TDB_DATA kbuf, newkey;
646 get_short_archi(short_archi, architecture);
647 slprintf(key, sizeof(key)-1, "%s%s/%d/", DRIVERS_PREFIX, short_archi, version);
649 for (kbuf = tdb_firstkey(tdb_drivers);
650 kbuf.dptr;
651 newkey = tdb_nextkey(tdb_drivers, kbuf), safe_free(kbuf.dptr), kbuf=newkey) {
652 if (strncmp(kbuf.dptr, key, strlen(key)) != 0) continue;
654 if((fl = Realloc(*list, sizeof(fstring)*(total+1))) == NULL) {
655 DEBUG(0,("get_ntdrivers: failed to enlarge list!\n"));
656 return -1;
658 else *list = fl;
660 fstrcpy((*list)[total], kbuf.dptr+strlen(key));
661 total++;
664 return(total);
667 /****************************************************************************
668 function to do the mapping between the long architecture name and
669 the short one.
670 ****************************************************************************/
671 BOOL get_short_archi(char *short_archi, const char *long_archi)
673 struct table {
674 const char *long_archi;
675 const char *short_archi;
678 struct table archi_table[]=
680 {"Windows 4.0", "WIN40" },
681 {"Windows NT x86", "W32X86" },
682 {"Windows NT R4000", "W32MIPS" },
683 {"Windows NT Alpha_AXP", "W32ALPHA" },
684 {"Windows NT PowerPC", "W32PPC" },
685 {NULL, "" }
688 int i=-1;
690 DEBUG(107,("Getting architecture dependant directory\n"));
692 if (long_archi == NULL) {
693 DEBUGADD(107,("Bad long_archi param.!\n"));
694 return False;
697 do {
698 i++;
699 } while ( (archi_table[i].long_archi!=NULL ) &&
700 StrCaseCmp(long_archi, archi_table[i].long_archi) );
702 if (archi_table[i].long_archi==NULL) {
703 DEBUGADD(107,("Unknown architecture [%s] !\n", long_archi));
704 return False;
707 StrnCpy (short_archi, archi_table[i].short_archi, strlen(archi_table[i].short_archi));
709 DEBUGADD(108,("index: [%d]\n", i));
710 DEBUGADD(108,("long architecture: [%s]\n", long_archi));
711 DEBUGADD(108,("short architecture: [%s]\n", short_archi));
713 return True;
716 /****************************************************************************
717 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
718 There are two case to be covered here: PE (Portable Executable) and NE (New
719 Executable) files. Both files support the same INFO structure, but PE files
720 store the signature in unicode, and NE files store it as !unicode.
721 returns -1 on error, 1 on version info found, and 0 on no version info found.
722 ****************************************************************************/
724 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
726 int i;
727 char *buf;
728 ssize_t byte_count;
730 if ((buf=malloc(PE_HEADER_SIZE)) == NULL) {
731 DEBUG(0,("get_file_version: PE file [%s] PE Header malloc failed bytes = %d\n",
732 fname, PE_HEADER_SIZE));
733 goto error_exit;
736 /* Note: DOS_HEADER_SIZE < malloc'ed PE_HEADER_SIZE */
737 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
738 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %d\n",
739 fname, byte_count));
740 goto no_version_info;
743 /* Is this really a DOS header? */
744 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
745 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
746 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
747 goto no_version_info;
750 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
751 if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
752 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
753 fname, errno));
754 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
755 goto no_version_info;
758 if ((byte_count = vfs_read_data(fsp, buf, PE_HEADER_SIZE)) < PE_HEADER_SIZE) {
759 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %d\n",
760 fname, byte_count));
761 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
762 goto no_version_info;
765 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
766 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
767 int num_sections;
768 int section_table_bytes;
770 if (SVAL(buf,PE_HEADER_MACHINE_OFFSET) != PE_HEADER_MACHINE_I386) {
771 DEBUG(3,("get_file_version: PE file [%s] wrong machine = 0x%x\n",
772 fname, SVAL(buf,PE_HEADER_MACHINE_OFFSET)));
773 /* At this point, we assume the file is in error. It still could be somthing
774 * else besides a PE file, but it unlikely at this point.
776 goto error_exit;
779 /* get the section table */
780 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
781 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
782 SAFE_FREE(buf);
783 if ((buf=malloc(section_table_bytes)) == NULL) {
784 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
785 fname, section_table_bytes));
786 goto error_exit;
789 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
790 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %d\n",
791 fname, byte_count));
792 goto error_exit;
795 /* Iterate the section table looking for the resource section ".rsrc" */
796 for (i = 0; i < num_sections; i++) {
797 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
799 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
800 int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
801 int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
803 SAFE_FREE(buf);
804 if ((buf=malloc(section_bytes)) == NULL) {
805 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
806 fname, section_bytes));
807 goto error_exit;
810 /* Seek to the start of the .rsrc section info */
811 if (fsp->conn->vfs_ops.lseek(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
812 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
813 fname, errno));
814 goto error_exit;
817 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
818 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %d\n",
819 fname, byte_count));
820 goto error_exit;
823 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
824 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
825 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
826 /* Align to next long address */
827 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
829 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
830 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
831 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
833 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
834 fname, *major, *minor,
835 (*major>>16)&0xffff, *major&0xffff,
836 (*minor>>16)&0xffff, *minor&0xffff));
837 SAFE_FREE(buf);
838 return 1;
845 /* Version info not found, fall back to origin date/time */
846 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
847 SAFE_FREE(buf);
848 return 0;
850 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
851 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
852 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
853 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
854 /* At this point, we assume the file is in error. It still could be somthing
855 * else besides a NE file, but it unlikely at this point. */
856 goto error_exit;
859 /* Allocate a bit more space to speed up things */
860 SAFE_FREE(buf);
861 if ((buf=malloc(VS_NE_BUF_SIZE)) == NULL) {
862 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
863 fname, PE_HEADER_SIZE));
864 goto error_exit;
867 /* This is a HACK! I got tired of trying to sort through the messy
868 * 'NE' file format. If anyone wants to clean this up please have at
869 * it, but this works. 'NE' files will eventually fade away. JRR */
870 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
871 /* Cover case that should not occur in a well formed 'NE' .dll file */
872 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
874 for(i=0; i<byte_count; i++) {
875 /* Fast skip past data that can't possibly match */
876 if (buf[i] != 'V') continue;
878 /* Potential match data crosses buf boundry, move it to beginning
879 * of buf, and fill the buf with as much as it will hold. */
880 if (i>byte_count-VS_VERSION_INFO_SIZE) {
881 int bc;
883 memcpy(buf, &buf[i], byte_count-i);
884 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
885 (byte_count-i))) < 0) {
887 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
888 fname, errno));
889 goto error_exit;
892 byte_count = bc + (byte_count - i);
893 if (byte_count<VS_VERSION_INFO_SIZE) break;
895 i = 0;
898 /* Check that the full signature string and the magic number that
899 * follows exist (not a perfect solution, but the chances that this
900 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
901 * twice, as it is simpler to read the code. */
902 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
903 /* Compute skip alignment to next long address */
904 int skip = -(fsp->conn->vfs_ops.lseek(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) +
905 sizeof(VS_SIGNATURE)) & 3;
906 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
908 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
909 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
910 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
911 fname, *major, *minor,
912 (*major>>16)&0xffff, *major&0xffff,
913 (*minor>>16)&0xffff, *minor&0xffff));
914 SAFE_FREE(buf);
915 return 1;
920 /* Version info not found, fall back to origin date/time */
921 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
922 SAFE_FREE(buf);
923 return 0;
925 } else
926 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
927 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
928 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
930 no_version_info:
931 SAFE_FREE(buf);
932 return 0;
934 error_exit:
935 SAFE_FREE(buf);
936 return -1;
939 /****************************************************************************
940 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
941 share one or more files. During the MS installation process files are checked
942 to insure that only a newer version of a shared file is installed over an
943 older version. There are several possibilities for this comparison. If there
944 is no previous version, the new one is newer (obviously). If either file is
945 missing the version info structure, compare the creation date (on Unix use
946 the modification date). Otherwise chose the numerically larger version number.
947 ****************************************************************************/
948 static int file_version_is_newer(connection_struct *conn, fstring new_file,
949 fstring old_file)
951 BOOL use_version = True;
952 pstring filepath;
954 uint32 new_major;
955 uint32 new_minor;
956 time_t new_create_time;
958 uint32 old_major;
959 uint32 old_minor;
960 time_t old_create_time;
962 int access_mode;
963 int action;
964 files_struct *fsp = NULL;
965 SMB_STRUCT_STAT st;
966 SMB_STRUCT_STAT stat_buf;
967 BOOL bad_path;
969 ZERO_STRUCT(st);
970 ZERO_STRUCT(stat_buf);
971 new_create_time = (time_t)0;
972 old_create_time = (time_t)0;
974 /* Get file version info (if available) for previous file (if it exists) */
975 pstrcpy(filepath, old_file);
977 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
979 fsp = open_file_shared(conn, filepath, &stat_buf,
980 SET_OPEN_MODE(DOS_OPEN_RDONLY),
981 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
982 0, 0, &access_mode, &action);
983 if (!fsp) {
984 /* Old file not found, so by definition new file is in fact newer */
985 DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
986 filepath, errno));
987 return True;
989 } else {
990 int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
991 if (ret == -1) goto error_exit;
993 if (!ret) {
994 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
995 old_file));
996 use_version = False;
997 if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
998 old_create_time = st.st_mtime;
999 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time));
1002 close_file(fsp, True);
1004 /* Get file version info (if available) for new file */
1005 pstrcpy(filepath, new_file);
1006 unix_convert(filepath,conn,NULL,&bad_path,&stat_buf);
1008 fsp = open_file_shared(conn, filepath, &stat_buf,
1009 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1010 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1011 0, 0, &access_mode, &action);
1012 if (!fsp) {
1013 /* New file not found, this shouldn't occur if the caller did its job */
1014 DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
1015 filepath, errno));
1016 goto error_exit;
1018 } else {
1019 int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
1020 if (ret == -1) goto error_exit;
1022 if (!ret) {
1023 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
1024 new_file));
1025 use_version = False;
1026 if (fsp->conn->vfs_ops.fstat(fsp, fsp->fd, &st) == -1) goto error_exit;
1027 new_create_time = st.st_mtime;
1028 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time));
1031 close_file(fsp, True);
1033 if (use_version && (new_major != old_major || new_minor != old_minor)) {
1034 /* Compare versions and choose the larger version number */
1035 if (new_major > old_major ||
1036 (new_major == old_major && new_minor > old_minor)) {
1038 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1039 return True;
1041 else {
1042 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1043 return False;
1046 } else {
1047 /* Compare modification time/dates and choose the newest time/date */
1048 if (new_create_time > old_create_time) {
1049 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
1050 return True;
1052 else {
1053 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
1054 return False;
1058 error_exit:
1059 if(fsp)
1060 close_file(fsp, True);
1061 return -1;
1064 /****************************************************************************
1065 Determine the correct cVersion associated with an architecture and driver
1066 ****************************************************************************/
1067 static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
1068 struct current_user *user, WERROR *perr)
1070 int cversion;
1071 int access_mode;
1072 int action;
1073 NTSTATUS nt_status;
1074 pstring driverpath;
1075 DATA_BLOB null_pw;
1076 files_struct *fsp = NULL;
1077 BOOL bad_path;
1078 SMB_STRUCT_STAT st;
1079 connection_struct *conn;
1081 ZERO_STRUCT(st);
1083 *perr = WERR_INVALID_PARAM;
1085 /* If architecture is Windows 95/98/ME, the version is always 0. */
1086 if (strcmp(architecture, "WIN40") == 0) {
1087 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1088 *perr = WERR_OK;
1089 return 0;
1093 * Connect to the print$ share under the same account as the user connected
1094 * to the rpc pipe. Note we must still be root to do this.
1097 /* Null password is ok - we are already an authenticated user... */
1098 null_pw = data_blob(NULL, 0);
1099 become_root();
1100 conn = make_connection_with_chdir("print$", null_pw, "A:", user->vuid, &nt_status);
1101 unbecome_root();
1103 if (conn == NULL) {
1104 DEBUG(0,("get_correct_cversion: Unable to connect\n"));
1105 *perr = ntstatus_to_werror(nt_status);
1106 return -1;
1109 /* We are temporarily becoming the connection user. */
1110 if (!become_user(conn, conn->vuid)) {
1111 DEBUG(0,("get_correct_cversion: Can't become user!\n"));
1112 *perr = WERR_ACCESS_DENIED;
1113 return -1;
1116 /* Open the driver file (Portable Executable format) and determine the
1117 * deriver the cversion. */
1118 slprintf(driverpath, sizeof(driverpath)-1, "%s/%s", architecture, driverpath_in);
1120 unix_convert(driverpath,conn,NULL,&bad_path,&st);
1122 fsp = open_file_shared(conn, driverpath, &st,
1123 SET_OPEN_MODE(DOS_OPEN_RDONLY),
1124 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1125 0, 0, &access_mode, &action);
1126 if (!fsp) {
1127 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
1128 driverpath, errno));
1129 *perr = WERR_ACCESS_DENIED;
1130 goto error_exit;
1132 else {
1133 uint32 major;
1134 uint32 minor;
1135 int ret = get_file_version(fsp, driverpath, &major, &minor);
1136 if (ret == -1) goto error_exit;
1138 if (!ret) {
1139 DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
1140 goto error_exit;
1144 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1145 * for more details. Version in this case is not just the version of the
1146 * file, but the version in the sense of kernal mode (2) vs. user mode
1147 * (3) drivers. Other bits of the version fields are the version info.
1148 * JRR 010716
1150 cversion = major & 0x0000ffff;
1151 switch (cversion) {
1152 case 2: /* WinNT drivers */
1153 case 3: /* Win2K drivers */
1154 break;
1156 default:
1157 DEBUG(6,("get_correct_cversion: cversion invalid [%s] cversion = %d\n",
1158 driverpath, cversion));
1159 goto error_exit;
1162 DEBUG(10,("get_correct_cversion: Version info found [%s] major = 0x%x minor = 0x%x\n",
1163 driverpath, major, minor));
1166 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1167 driverpath, cversion));
1169 close_file(fsp, True);
1170 close_cnum(conn, user->vuid);
1171 unbecome_user();
1172 *perr = WERR_OK;
1173 return cversion;
1176 error_exit:
1178 if(fsp)
1179 close_file(fsp, True);
1181 close_cnum(conn, user->vuid);
1182 unbecome_user();
1183 return -1;
1186 /****************************************************************************
1187 ****************************************************************************/
1188 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
1189 struct current_user *user)
1191 fstring architecture;
1192 fstring new_name;
1193 char *p;
1194 int i;
1195 WERROR err;
1197 /* clean up the driver name.
1198 * we can get .\driver.dll
1199 * or worse c:\windows\system\driver.dll !
1201 /* using an intermediate string to not have overlaping memcpy()'s */
1202 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1203 fstrcpy(new_name, p+1);
1204 fstrcpy(driver->driverpath, new_name);
1207 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1208 fstrcpy(new_name, p+1);
1209 fstrcpy(driver->datafile, new_name);
1212 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1213 fstrcpy(new_name, p+1);
1214 fstrcpy(driver->configfile, new_name);
1217 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1218 fstrcpy(new_name, p+1);
1219 fstrcpy(driver->helpfile, new_name);
1222 if (driver->dependentfiles) {
1223 for (i=0; *driver->dependentfiles[i]; i++) {
1224 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1225 fstrcpy(new_name, p+1);
1226 fstrcpy(driver->dependentfiles[i], new_name);
1231 get_short_archi(architecture, driver->environment);
1233 /* jfm:7/16/2000 the client always sends the cversion=0.
1234 * The server should check which version the driver is by reading
1235 * the PE header of driver->driverpath.
1237 * For Windows 95/98 the version is 0 (so the value sent is correct)
1238 * For Windows NT (the architecture doesn't matter)
1239 * NT 3.1: cversion=0
1240 * NT 3.5/3.51: cversion=1
1241 * NT 4: cversion=2
1242 * NT2K: cversion=3
1244 if ((driver->cversion = get_correct_cversion( architecture,
1245 driver->driverpath, user, &err)) == -1)
1246 return err;
1248 return WERR_OK;
1251 /****************************************************************************
1252 ****************************************************************************/
1253 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver, struct current_user *user)
1255 fstring architecture;
1256 fstring new_name;
1257 char *p;
1258 int i;
1259 WERROR err;
1261 /* clean up the driver name.
1262 * we can get .\driver.dll
1263 * or worse c:\windows\system\driver.dll !
1265 /* using an intermediate string to not have overlaping memcpy()'s */
1266 if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
1267 fstrcpy(new_name, p+1);
1268 fstrcpy(driver->driverpath, new_name);
1271 if ((p = strrchr(driver->datafile,'\\')) != NULL) {
1272 fstrcpy(new_name, p+1);
1273 fstrcpy(driver->datafile, new_name);
1276 if ((p = strrchr(driver->configfile,'\\')) != NULL) {
1277 fstrcpy(new_name, p+1);
1278 fstrcpy(driver->configfile, new_name);
1281 if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
1282 fstrcpy(new_name, p+1);
1283 fstrcpy(driver->helpfile, new_name);
1286 if (driver->dependentfiles) {
1287 for (i=0; *driver->dependentfiles[i]; i++) {
1288 if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
1289 fstrcpy(new_name, p+1);
1290 fstrcpy(driver->dependentfiles[i], new_name);
1295 get_short_archi(architecture, driver->environment);
1297 /* jfm:7/16/2000 the client always sends the cversion=0.
1298 * The server should check which version the driver is by reading
1299 * the PE header of driver->driverpath.
1301 * For Windows 95/98 the version is 0 (so the value sent is correct)
1302 * For Windows NT (the architecture doesn't matter)
1303 * NT 3.1: cversion=0
1304 * NT 3.5/3.51: cversion=1
1305 * NT 4: cversion=2
1306 * NT2K: cversion=3
1308 if ((driver->version = get_correct_cversion(architecture, driver->driverpath, user, &err)) == -1)
1309 return err;
1311 return WERR_OK;
1314 /****************************************************************************
1315 ****************************************************************************/
1316 WERROR clean_up_driver_struct(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
1317 uint32 level, struct current_user *user)
1319 switch (level) {
1320 case 3:
1322 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1323 driver=driver_abstract.info_3;
1324 return clean_up_driver_struct_level_3(driver, user);
1326 case 6:
1328 NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
1329 driver=driver_abstract.info_6;
1330 return clean_up_driver_struct_level_6(driver, user);
1332 default:
1333 return WERR_INVALID_PARAM;
1337 /****************************************************************************
1338 This function sucks and should be replaced. JRA.
1339 ****************************************************************************/
1341 static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
1343 dst->cversion = src->version;
1345 fstrcpy( dst->name, src->name);
1346 fstrcpy( dst->environment, src->environment);
1347 fstrcpy( dst->driverpath, src->driverpath);
1348 fstrcpy( dst->datafile, src->datafile);
1349 fstrcpy( dst->configfile, src->configfile);
1350 fstrcpy( dst->helpfile, src->helpfile);
1351 fstrcpy( dst->monitorname, src->monitorname);
1352 fstrcpy( dst->defaultdatatype, src->defaultdatatype);
1353 dst->dependentfiles = src->dependentfiles;
1356 #if 0 /* Debugging function */
1358 static char* ffmt(unsigned char *c){
1359 int i;
1360 static char ffmt_str[17];
1362 for (i=0; i<16; i++) {
1363 if ((c[i] < ' ') || (c[i] > '~'))
1364 ffmt_str[i]='.';
1365 else
1366 ffmt_str[i]=c[i];
1368 ffmt_str[16]='\0';
1369 return ffmt_str;
1372 #endif
1374 /****************************************************************************
1375 ****************************************************************************/
1376 BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract, uint32 level,
1377 struct current_user *user, WERROR *perr)
1379 NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
1380 NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
1381 fstring architecture;
1382 pstring new_dir;
1383 pstring old_name;
1384 pstring new_name;
1385 DATA_BLOB null_pw;
1386 connection_struct *conn;
1387 NTSTATUS nt_status;
1388 pstring inbuf;
1389 pstring outbuf;
1390 int ver = 0;
1391 int i;
1393 memset(inbuf, '\0', sizeof(inbuf));
1394 memset(outbuf, '\0', sizeof(outbuf));
1395 *perr = WERR_OK;
1397 if (level==3)
1398 driver=driver_abstract.info_3;
1399 else if (level==6) {
1400 convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
1401 driver = &converted_driver;
1402 } else {
1403 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
1404 return False;
1407 get_short_archi(architecture, driver->environment);
1410 * Connect to the print$ share under the same account as the user connected to the rpc pipe.
1411 * Note we must be root to do this.
1414 become_root();
1415 null_pw = data_blob(NULL, 0);
1416 conn = make_connection_with_chdir("print$", null_pw, "A:", user->vuid, &nt_status);
1417 unbecome_root();
1419 if (conn == NULL) {
1420 DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
1421 *perr = ntstatus_to_werror(nt_status);
1422 return False;
1426 * Save who we are - we are temporarily becoming the connection user.
1429 if (!become_user(conn, conn->vuid)) {
1430 DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
1431 return False;
1435 * make the directories version and version\driver_name
1436 * under the architecture directory.
1438 DEBUG(5,("Creating first directory\n"));
1439 slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
1440 mkdir_internal(conn, new_dir);
1442 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1443 * listed for this driver which has already been moved, skip it (note:
1444 * drivers may list the same file name several times. Then check if the
1445 * file already exists in archi\cversion\, if so, check that the version
1446 * info (or time stamps if version info is unavailable) is newer (or the
1447 * date is later). If it is, move it to archi\cversion\filexxx.yyy.
1448 * Otherwise, delete the file.
1450 * If a file is not moved to archi\cversion\ because of an error, all the
1451 * rest of the 'unmoved' driver files are removed from archi\. If one or
1452 * more of the driver's files was already moved to archi\cversion\, it
1453 * potentially leaves the driver in a partially updated state. Version
1454 * trauma will most likely occur if an client attempts to use any printer
1455 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1456 * done is appropriate... later JRR
1459 DEBUG(5,("Moving files now !\n"));
1461 if (driver->driverpath && strlen(driver->driverpath)) {
1462 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->driverpath);
1463 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath);
1464 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1465 NTSTATUS status;
1466 status = rename_internals(conn, new_name, old_name, True);
1467 if (!NT_STATUS_IS_OK(status)) {
1468 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1469 new_name, old_name));
1470 *perr = ntstatus_to_werror(status);
1471 unlink_internals(conn, 0, new_name);
1472 ver = -1;
1475 else
1476 unlink_internals(conn, 0, new_name);
1479 if (driver->datafile && strlen(driver->datafile)) {
1480 if (!strequal(driver->datafile, driver->driverpath)) {
1481 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->datafile);
1482 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile);
1483 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1484 NTSTATUS status;
1485 status = rename_internals(conn, new_name, old_name, True);
1486 if (!NT_STATUS_IS_OK(status)) {
1487 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1488 new_name, old_name));
1489 *perr = ntstatus_to_werror(status);
1490 unlink_internals(conn, 0, new_name);
1491 ver = -1;
1494 else
1495 unlink_internals(conn, 0, new_name);
1499 if (driver->configfile && strlen(driver->configfile)) {
1500 if (!strequal(driver->configfile, driver->driverpath) &&
1501 !strequal(driver->configfile, driver->datafile)) {
1502 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->configfile);
1503 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile);
1504 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1505 NTSTATUS status;
1506 status = rename_internals(conn, new_name, old_name, True);
1507 if (!NT_STATUS_IS_OK(status)) {
1508 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1509 new_name, old_name));
1510 *perr = ntstatus_to_werror(status);
1511 unlink_internals(conn, 0, new_name);
1512 ver = -1;
1515 else
1516 unlink_internals(conn, 0, new_name);
1520 if (driver->helpfile && strlen(driver->helpfile)) {
1521 if (!strequal(driver->helpfile, driver->driverpath) &&
1522 !strequal(driver->helpfile, driver->datafile) &&
1523 !strequal(driver->helpfile, driver->configfile)) {
1524 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->helpfile);
1525 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile);
1526 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1527 NTSTATUS status;
1528 status = rename_internals(conn, new_name, old_name, True);
1529 if (!NT_STATUS_IS_OK(status)) {
1530 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1531 new_name, old_name));
1532 *perr = ntstatus_to_werror(status);
1533 unlink_internals(conn, 0, new_name);
1534 ver = -1;
1537 else
1538 unlink_internals(conn, 0, new_name);
1542 if (driver->dependentfiles) {
1543 for (i=0; *driver->dependentfiles[i]; i++) {
1544 if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
1545 !strequal(driver->dependentfiles[i], driver->datafile) &&
1546 !strequal(driver->dependentfiles[i], driver->configfile) &&
1547 !strequal(driver->dependentfiles[i], driver->helpfile)) {
1548 int j;
1549 for (j=0; j < i; j++) {
1550 if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
1551 goto NextDriver;
1555 slprintf(new_name, sizeof(new_name)-1, "%s/%s", architecture, driver->dependentfiles[i]);
1556 slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]);
1557 if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
1558 NTSTATUS status;
1559 status = rename_internals(conn, new_name, old_name, True);
1560 if (!NT_STATUS_IS_OK(status)) {
1561 DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
1562 new_name, old_name));
1563 *perr = ntstatus_to_werror(status);
1564 unlink_internals(conn, 0, new_name);
1565 ver = -1;
1568 else
1569 unlink_internals(conn, 0, new_name);
1571 NextDriver: ;
1575 close_cnum(conn, user->vuid);
1576 unbecome_user();
1578 return ver == -1 ? False : True;
1581 /****************************************************************************
1582 ****************************************************************************/
1583 static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
1585 int len, buflen;
1586 fstring architecture;
1587 pstring directory;
1588 fstring temp_name;
1589 pstring key;
1590 char *buf;
1591 int i, ret;
1592 TDB_DATA kbuf, dbuf;
1594 get_short_archi(architecture, driver->environment);
1596 /* The names are relative. We store them in the form: \print$\arch\version\driver.xxx
1597 * \\server is added in the rpc server layer.
1598 * It does make sense to NOT store the server's name in the printer TDB.
1601 slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
1603 /* .inf files do not always list a file for each of the four standard files.
1604 * Don't prepend a path to a null filename, or client claims:
1605 * "The server on which the printer resides does not have a suitable
1606 * <printer driver name> printer driver installed. Click OK if you
1607 * wish to install the driver on your local machine."
1609 if (strlen(driver->driverpath)) {
1610 fstrcpy(temp_name, driver->driverpath);
1611 slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
1614 if (strlen(driver->datafile)) {
1615 fstrcpy(temp_name, driver->datafile);
1616 slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
1619 if (strlen(driver->configfile)) {
1620 fstrcpy(temp_name, driver->configfile);
1621 slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
1624 if (strlen(driver->helpfile)) {
1625 fstrcpy(temp_name, driver->helpfile);
1626 slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
1629 if (driver->dependentfiles) {
1630 for (i=0; *driver->dependentfiles[i]; i++) {
1631 fstrcpy(temp_name, driver->dependentfiles[i]);
1632 slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
1636 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, driver->cversion, driver->name);
1638 DEBUG(5,("add_a_printer_driver_3: Adding driver with key %s\n", key ));
1640 buf = NULL;
1641 len = buflen = 0;
1643 again:
1644 len = 0;
1645 len += tdb_pack(buf+len, buflen-len, "dffffffff",
1646 driver->cversion,
1647 driver->name,
1648 driver->environment,
1649 driver->driverpath,
1650 driver->datafile,
1651 driver->configfile,
1652 driver->helpfile,
1653 driver->monitorname,
1654 driver->defaultdatatype);
1656 if (driver->dependentfiles) {
1657 for (i=0; *driver->dependentfiles[i]; i++) {
1658 len += tdb_pack(buf+len, buflen-len, "f",
1659 driver->dependentfiles[i]);
1663 if (len != buflen) {
1664 char *tb;
1666 tb = (char *)Realloc(buf, len);
1667 if (!tb) {
1668 DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
1669 ret = -1;
1670 goto done;
1672 else buf = tb;
1673 buflen = len;
1674 goto again;
1678 kbuf.dptr = key;
1679 kbuf.dsize = strlen(key)+1;
1680 dbuf.dptr = buf;
1681 dbuf.dsize = len;
1683 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
1685 done:
1686 if (ret)
1687 DEBUG(0,("add_a_printer_driver_3: Adding driver with key %s failed.\n", key ));
1689 SAFE_FREE(buf);
1690 return ret;
1693 /****************************************************************************
1694 ****************************************************************************/
1695 static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
1697 NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
1699 ZERO_STRUCT(info3);
1700 info3.cversion = driver->version;
1701 fstrcpy(info3.name,driver->name);
1702 fstrcpy(info3.environment,driver->environment);
1703 fstrcpy(info3.driverpath,driver->driverpath);
1704 fstrcpy(info3.datafile,driver->datafile);
1705 fstrcpy(info3.configfile,driver->configfile);
1706 fstrcpy(info3.helpfile,driver->helpfile);
1707 fstrcpy(info3.monitorname,driver->monitorname);
1708 fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
1709 info3.dependentfiles = driver->dependentfiles;
1711 return add_a_printer_driver_3(&info3);
1715 /****************************************************************************
1716 ****************************************************************************/
1717 static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
1719 NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
1721 ZERO_STRUCT(info);
1723 fstrcpy(info.name, driver);
1724 fstrcpy(info.defaultdatatype, "RAW");
1726 fstrcpy(info.driverpath, "");
1727 fstrcpy(info.datafile, "");
1728 fstrcpy(info.configfile, "");
1729 fstrcpy(info.helpfile, "");
1731 if ((info.dependentfiles=(fstring *)malloc(2*sizeof(fstring))) == NULL)
1732 return WERR_NOMEM;
1734 memset(info.dependentfiles, '\0', 2*sizeof(fstring));
1735 fstrcpy(info.dependentfiles[0], "");
1737 *info_ptr = memdup(&info, sizeof(info));
1739 return WERR_OK;
1742 /****************************************************************************
1743 ****************************************************************************/
1744 static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
1746 NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
1747 TDB_DATA kbuf, dbuf;
1748 fstring architecture;
1749 int len = 0;
1750 int i;
1751 pstring key;
1753 ZERO_STRUCT(driver);
1755 get_short_archi(architecture, arch);
1757 DEBUG(8,("get_a_printer_driver_3: [%s%s/%d/%s]\n", DRIVERS_PREFIX, architecture, version, drivername));
1759 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX, architecture, version, drivername);
1761 kbuf.dptr = key;
1762 kbuf.dsize = strlen(key)+1;
1764 dbuf = tdb_fetch(tdb_drivers, kbuf);
1765 if (!dbuf.dptr)
1766 return WERR_UNKNOWN_PRINTER_DRIVER;
1768 len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
1769 &driver.cversion,
1770 driver.name,
1771 driver.environment,
1772 driver.driverpath,
1773 driver.datafile,
1774 driver.configfile,
1775 driver.helpfile,
1776 driver.monitorname,
1777 driver.defaultdatatype);
1779 i=0;
1780 while (len < dbuf.dsize) {
1781 fstring *tddfs;
1783 tddfs = (fstring *)Realloc(driver.dependentfiles,
1784 sizeof(fstring)*(i+2));
1785 if (tddfs == NULL) {
1786 DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
1787 break;
1789 else driver.dependentfiles = tddfs;
1791 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
1792 &driver.dependentfiles[i]);
1793 i++;
1796 if (driver.dependentfiles != NULL)
1797 fstrcpy(driver.dependentfiles[i], "");
1799 SAFE_FREE(dbuf.dptr);
1801 if (len != dbuf.dsize) {
1802 SAFE_FREE(driver.dependentfiles);
1804 return get_a_printer_driver_3_default(info_ptr, drivername, arch);
1807 *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
1809 return WERR_OK;
1812 /****************************************************************************
1813 Debugging function, dump at level 6 the struct in the logs.
1814 ****************************************************************************/
1816 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
1818 uint32 result;
1819 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
1820 int i;
1822 DEBUG(20,("Dumping printer driver at level [%d]\n", level));
1824 switch (level)
1826 case 3:
1828 if (driver.info_3 == NULL)
1829 result=5;
1830 else {
1831 info3=driver.info_3;
1833 DEBUGADD(20,("version:[%d]\n", info3->cversion));
1834 DEBUGADD(20,("name:[%s]\n", info3->name));
1835 DEBUGADD(20,("environment:[%s]\n", info3->environment));
1836 DEBUGADD(20,("driverpath:[%s]\n", info3->driverpath));
1837 DEBUGADD(20,("datafile:[%s]\n", info3->datafile));
1838 DEBUGADD(20,("configfile:[%s]\n", info3->configfile));
1839 DEBUGADD(20,("helpfile:[%s]\n", info3->helpfile));
1840 DEBUGADD(20,("monitorname:[%s]\n", info3->monitorname));
1841 DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
1843 for (i=0; info3->dependentfiles &&
1844 *info3->dependentfiles[i]; i++) {
1845 DEBUGADD(20,("dependentfile:[%s]\n",
1846 info3->dependentfiles[i]));
1848 result=0;
1850 break;
1852 default:
1853 DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
1854 result=1;
1855 break;
1858 return result;
1861 /****************************************************************************
1862 ****************************************************************************/
1863 int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
1865 int len = 0;
1867 len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
1869 if (!nt_devmode) return len;
1871 len += tdb_pack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
1872 nt_devmode->devicename,
1873 nt_devmode->formname,
1875 nt_devmode->specversion,
1876 nt_devmode->driverversion,
1877 nt_devmode->size,
1878 nt_devmode->driverextra,
1879 nt_devmode->orientation,
1880 nt_devmode->papersize,
1881 nt_devmode->paperlength,
1882 nt_devmode->paperwidth,
1883 nt_devmode->scale,
1884 nt_devmode->copies,
1885 nt_devmode->defaultsource,
1886 nt_devmode->printquality,
1887 nt_devmode->color,
1888 nt_devmode->duplex,
1889 nt_devmode->yresolution,
1890 nt_devmode->ttoption,
1891 nt_devmode->collate,
1892 nt_devmode->logpixels,
1894 nt_devmode->fields,
1895 nt_devmode->bitsperpel,
1896 nt_devmode->pelswidth,
1897 nt_devmode->pelsheight,
1898 nt_devmode->displayflags,
1899 nt_devmode->displayfrequency,
1900 nt_devmode->icmmethod,
1901 nt_devmode->icmintent,
1902 nt_devmode->mediatype,
1903 nt_devmode->dithertype,
1904 nt_devmode->reserved1,
1905 nt_devmode->reserved2,
1906 nt_devmode->panningwidth,
1907 nt_devmode->panningheight,
1908 nt_devmode->private);
1911 if (nt_devmode->private) {
1912 len += tdb_pack(buf+len, buflen-len, "B",
1913 nt_devmode->driverextra,
1914 nt_devmode->private);
1917 DEBUG(8,("Packed devicemode [%s]\n", nt_devmode->formname));
1919 return len;
1922 /****************************************************************************
1923 Pack all values in all printer keys
1924 ***************************************************************************/
1926 static int pack_values(NT_PRINTER_DATA *data, char *buf, int buflen)
1928 int len = 0;
1929 int i, j;
1930 REGISTRY_VALUE *val;
1931 REGVAL_CTR *val_ctr;
1932 pstring path;
1933 int num_values;
1935 if ( !data )
1936 return 0;
1938 /* loop over all keys */
1940 for ( i=0; i<data->num_keys; i++ )
1942 val_ctr = &data->keys[i].values;
1943 num_values = regval_ctr_numvals( val_ctr );
1945 /* loop over all values */
1947 for ( j=0; j<num_values; j++ )
1949 /* pathname should be stored as <key>\<value> */
1951 val = regval_ctr_specific_value( val_ctr, j );
1952 pstrcpy( path, data->keys[i].name );
1953 pstrcat( path, "\\" );
1954 pstrcat( path, regval_name(val) );
1956 len += tdb_pack(buf+len, buflen-len, "pPdB",
1957 val,
1958 path,
1959 regval_type(val),
1960 regval_size(val),
1961 regval_data_p(val) );
1966 /* terminator */
1968 len += tdb_pack(buf+len, buflen-len, "p", NULL);
1970 return len;
1974 /****************************************************************************
1975 Delete a printer - this just deletes the printer info file, any open
1976 handles are not affected.
1977 ****************************************************************************/
1979 uint32 del_a_printer(char *sharename)
1981 pstring key;
1982 TDB_DATA kbuf;
1984 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
1986 kbuf.dptr=key;
1987 kbuf.dsize=strlen(key)+1;
1989 tdb_delete(tdb_printers, kbuf);
1990 return 0;
1993 /* FIXME!!! Reorder so this forward declaration is not necessary --jerry */
1994 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **, fstring);
1995 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **);
1996 /****************************************************************************
1997 ****************************************************************************/
1998 static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
2000 pstring key;
2001 char *buf;
2002 int buflen, len;
2003 WERROR ret;
2004 TDB_DATA kbuf, dbuf;
2007 * in addprinter: no servername and the printer is the name
2008 * in setprinter: servername is \\server
2009 * and printer is \\server\\printer
2011 * Samba manages only local printers.
2012 * we currently don't support things like path=\\other_server\printer
2015 if (info->servername[0]!='\0') {
2016 trim_string(info->printername, info->servername, NULL);
2017 trim_string(info->printername, "\\", NULL);
2018 info->servername[0]='\0';
2022 * JFM: one day I'll forget.
2023 * below that's info->portname because that's the SAMBA sharename
2024 * and I made NT 'thinks' it's the portname
2025 * the info->sharename is the thing you can name when you add a printer
2026 * that's the short-name when you create shared printer for 95/98
2027 * So I've made a limitation in SAMBA: you can only have 1 printer model
2028 * behind a SAMBA share.
2031 buf = NULL;
2032 buflen = 0;
2034 again:
2035 len = 0;
2036 len += tdb_pack(buf+len, buflen-len, "dddddddddddfffffPfffff",
2037 info->attributes,
2038 info->priority,
2039 info->default_priority,
2040 info->starttime,
2041 info->untiltime,
2042 info->status,
2043 info->cjobs,
2044 info->averageppm,
2045 info->changeid,
2046 info->c_setprinter,
2047 info->setuptime,
2048 info->servername,
2049 info->printername,
2050 info->sharename,
2051 info->portname,
2052 info->drivername,
2053 info->comment,
2054 info->location,
2055 info->sepfile,
2056 info->printprocessor,
2057 info->datatype,
2058 info->parameters);
2060 len += pack_devicemode(info->devmode, buf+len, buflen-len);
2062 len += pack_values( &info->data, buf+len, buflen-len );
2064 if (buflen != len) {
2065 char *tb;
2067 tb = (char *)Realloc(buf, len);
2068 if (!tb) {
2069 DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
2070 ret = WERR_NOMEM;
2071 goto done;
2073 else buf = tb;
2074 buflen = len;
2075 goto again;
2079 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, info->sharename);
2081 kbuf.dptr = key;
2082 kbuf.dsize = strlen(key)+1;
2083 dbuf.dptr = buf;
2084 dbuf.dsize = len;
2086 ret = (tdb_store(tdb_printers, kbuf, dbuf, TDB_REPLACE) == 0? WERR_OK : WERR_NOMEM);
2088 done:
2089 if (!W_ERROR_IS_OK(ret))
2090 DEBUG(8, ("error updating printer to tdb on disk\n"));
2092 SAFE_FREE(buf);
2094 DEBUG(8,("packed printer [%s] with driver [%s] portname=[%s] len=%d\n",
2095 info->sharename, info->drivername, info->portname, len));
2097 return ret;
2101 /****************************************************************************
2102 Malloc and return an NT devicemode.
2103 ****************************************************************************/
2105 NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
2108 char adevice[32];
2109 NT_DEVICEMODE *nt_devmode = (NT_DEVICEMODE *)malloc(sizeof(NT_DEVICEMODE));
2111 if (nt_devmode == NULL) {
2112 DEBUG(0,("construct_nt_devicemode: malloc fail.\n"));
2113 return NULL;
2116 ZERO_STRUCTP(nt_devmode);
2118 safe_strcpy(adevice, default_devicename, sizeof(adevice));
2119 fstrcpy(nt_devmode->devicename, adevice);
2121 fstrcpy(nt_devmode->formname, "Letter");
2123 nt_devmode->specversion = 0x0401;
2124 nt_devmode->driverversion = 0x0400;
2125 nt_devmode->size = 0x00DC;
2126 nt_devmode->driverextra = 0x0000;
2127 nt_devmode->fields = FORMNAME | TTOPTION | PRINTQUALITY |
2128 DEFAULTSOURCE | COPIES | SCALE |
2129 PAPERSIZE | ORIENTATION;
2130 nt_devmode->orientation = 1;
2131 nt_devmode->papersize = PAPER_LETTER;
2132 nt_devmode->paperlength = 0;
2133 nt_devmode->paperwidth = 0;
2134 nt_devmode->scale = 0x64;
2135 nt_devmode->copies = 1;
2136 nt_devmode->defaultsource = BIN_FORMSOURCE;
2137 nt_devmode->printquality = RES_HIGH; /* 0x0258 */
2138 nt_devmode->color = COLOR_MONOCHROME;
2139 nt_devmode->duplex = DUP_SIMPLEX;
2140 nt_devmode->yresolution = 0;
2141 nt_devmode->ttoption = TT_SUBDEV;
2142 nt_devmode->collate = COLLATE_FALSE;
2143 nt_devmode->icmmethod = 0;
2144 nt_devmode->icmintent = 0;
2145 nt_devmode->mediatype = 0;
2146 nt_devmode->dithertype = 0;
2148 /* non utilisés par un driver d'imprimante */
2149 nt_devmode->logpixels = 0;
2150 nt_devmode->bitsperpel = 0;
2151 nt_devmode->pelswidth = 0;
2152 nt_devmode->pelsheight = 0;
2153 nt_devmode->displayflags = 0;
2154 nt_devmode->displayfrequency = 0;
2155 nt_devmode->reserved1 = 0;
2156 nt_devmode->reserved2 = 0;
2157 nt_devmode->panningwidth = 0;
2158 nt_devmode->panningheight = 0;
2160 nt_devmode->private = NULL;
2161 return nt_devmode;
2164 /****************************************************************************
2165 Deepcopy an NT devicemode.
2166 ****************************************************************************/
2168 NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
2170 NT_DEVICEMODE *new_nt_devicemode = NULL;
2172 if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
2173 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2174 return NULL;
2177 new_nt_devicemode->private = NULL;
2178 if (nt_devicemode->private != NULL) {
2179 if ((new_nt_devicemode->private = memdup(nt_devicemode->private, nt_devicemode->driverextra)) == NULL) {
2180 SAFE_FREE(new_nt_devicemode);
2181 DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
2182 return NULL;
2186 return new_nt_devicemode;
2189 /****************************************************************************
2190 Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
2191 ****************************************************************************/
2193 void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
2195 NT_DEVICEMODE *nt_devmode = *devmode_ptr;
2197 if(nt_devmode == NULL)
2198 return;
2200 DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
2202 SAFE_FREE(nt_devmode->private);
2203 SAFE_FREE(*devmode_ptr);
2206 /****************************************************************************
2207 Clean up and deallocate a (maybe partially) allocated NT_PRINTER_INFO_LEVEL_2.
2208 ****************************************************************************/
2209 static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
2211 NT_PRINTER_INFO_LEVEL_2 *info = *info_ptr;
2212 NT_PRINTER_DATA *data;
2213 int i;
2215 if ( !info )
2216 return;
2218 DEBUG(106,("free_nt_printer_info_level_2: deleting info\n"));
2220 free_nt_devicemode(&info->devmode);
2222 /* clean up all registry keys */
2224 data = &info->data;
2225 for ( i=0; i<data->num_keys; i++ )
2227 SAFE_FREE( data->keys[i].name );
2228 regval_ctr_destroy( &data->keys[i].values );
2230 SAFE_FREE( data->keys );
2232 /* finally the top level structure */
2234 SAFE_FREE( *info_ptr );
2238 /****************************************************************************
2239 ****************************************************************************/
2240 int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
2242 int len = 0;
2243 int extra_len = 0;
2244 NT_DEVICEMODE devmode;
2246 ZERO_STRUCT(devmode);
2248 len += tdb_unpack(buf+len, buflen-len, "p", nt_devmode);
2250 if (!*nt_devmode) return len;
2252 len += tdb_unpack(buf+len, buflen-len, "ffwwwwwwwwwwwwwwwwwwddddddddddddddp",
2253 devmode.devicename,
2254 devmode.formname,
2256 &devmode.specversion,
2257 &devmode.driverversion,
2258 &devmode.size,
2259 &devmode.driverextra,
2260 &devmode.orientation,
2261 &devmode.papersize,
2262 &devmode.paperlength,
2263 &devmode.paperwidth,
2264 &devmode.scale,
2265 &devmode.copies,
2266 &devmode.defaultsource,
2267 &devmode.printquality,
2268 &devmode.color,
2269 &devmode.duplex,
2270 &devmode.yresolution,
2271 &devmode.ttoption,
2272 &devmode.collate,
2273 &devmode.logpixels,
2275 &devmode.fields,
2276 &devmode.bitsperpel,
2277 &devmode.pelswidth,
2278 &devmode.pelsheight,
2279 &devmode.displayflags,
2280 &devmode.displayfrequency,
2281 &devmode.icmmethod,
2282 &devmode.icmintent,
2283 &devmode.mediatype,
2284 &devmode.dithertype,
2285 &devmode.reserved1,
2286 &devmode.reserved2,
2287 &devmode.panningwidth,
2288 &devmode.panningheight,
2289 &devmode.private);
2291 if (devmode.private) {
2292 /* the len in tdb_unpack is an int value and
2293 * devmode.driverextra is only a short
2295 len += tdb_unpack(buf+len, buflen-len, "B", &extra_len, &devmode.private);
2296 devmode.driverextra=(uint16)extra_len;
2298 /* check to catch an invalid TDB entry so we don't segfault */
2299 if (devmode.driverextra == 0) {
2300 devmode.private = NULL;
2304 *nt_devmode = (NT_DEVICEMODE *)memdup(&devmode, sizeof(devmode));
2306 DEBUG(8,("Unpacked devicemode [%s](%s)\n", devmode.devicename, devmode.formname));
2307 if (devmode.private)
2308 DEBUG(8,("with a private section of %d bytes\n", devmode.driverextra));
2310 return len;
2313 /****************************************************************************
2314 allocate and initialize a new slot in
2315 ***************************************************************************/
2317 static int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
2319 NT_PRINTER_KEY *d;
2320 int key_index;
2322 if ( !data || !name )
2323 return -1;
2325 /* allocate another slot in the NT_PRINTER_KEY array */
2327 d = Realloc( data->keys, sizeof(NT_PRINTER_KEY)*(data->num_keys+1) );
2328 if ( d )
2329 data->keys = d;
2331 key_index = data->num_keys;
2333 /* initialze new key */
2335 data->num_keys++;
2336 data->keys[key_index].name = strdup( name );
2338 ZERO_STRUCTP( &data->keys[key_index].values );
2340 regval_ctr_init( &data->keys[key_index].values );
2342 DEBUG(10,("add_new_printer_key: Inserted new data key [%s]\n", name ));
2344 return key_index;
2347 /****************************************************************************
2348 search for a registry key name in the existing printer data
2349 ***************************************************************************/
2351 int lookup_printerkey( NT_PRINTER_DATA *data, const char *name )
2353 int key_index = -1;
2354 int i;
2356 if ( !data || !name )
2357 return -1;
2359 DEBUG(12,("lookup_printerkey: Looking for [%s]\n", name));
2361 /* loop over all existing keys */
2363 for ( i=0; i<data->num_keys; i++ )
2365 if ( strequal(data->keys[i].name, name) ) {
2366 DEBUG(12,("lookup_printerkey: Found [%s]!\n", name));
2367 key_index = i;
2368 break;
2373 return key_index;
2376 /****************************************************************************
2377 ***************************************************************************/
2379 uint32 get_printer_subkeys( NT_PRINTER_DATA *data, const char* key, fstring **subkeys )
2381 int i, j;
2382 int key_len;
2383 int num_subkeys = 0;
2384 char *p;
2385 fstring *ptr, *subkeys_ptr = NULL;
2386 fstring subkeyname;
2388 if ( !data )
2389 return 0;
2391 for ( i=0; i<data->num_keys; i++ )
2393 if ( StrnCaseCmp(data->keys[i].name, key, strlen(key)) == 0 )
2395 /* match sure it is a subkey and not the key itself */
2397 key_len = strlen( key );
2398 if ( strlen(data->keys[i].name) == key_len )
2399 continue;
2401 /* get subkey path */
2403 p = data->keys[i].name + key_len;
2404 if ( *p == '\\' )
2405 p++;
2406 fstrcpy( subkeyname, p );
2407 if ( (p = strchr( subkeyname, '\\' )) )
2408 *p = '\0';
2410 /* don't add a key more than once */
2412 for ( j=0; j<num_subkeys; j++ ) {
2413 if ( strequal( subkeys_ptr[j], subkeyname ) )
2414 break;
2417 if ( j != num_subkeys )
2418 continue;
2420 /* found a match, so allocate space and copy the name */
2422 if ( !(ptr = Realloc( subkeys_ptr, (num_subkeys+2)*sizeof(fstring))) ) {
2423 DEBUG(0,("get_printer_subkeys: Realloc failed for [%d] entries!\n",
2424 num_subkeys+1));
2425 SAFE_FREE( subkeys );
2426 return 0;
2429 subkeys_ptr = ptr;
2430 fstrcpy( subkeys_ptr[num_subkeys], subkeyname );
2431 num_subkeys++;
2436 /* tag of the end */
2438 if (num_subkeys)
2439 fstrcpy( subkeys_ptr[num_subkeys], "" );
2441 *subkeys = subkeys_ptr;
2443 return num_subkeys;
2446 static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2447 const char *sz)
2449 smb_ucs2_t conv_str[1024];
2450 size_t str_size;
2452 regval_ctr_delvalue(ctr, val_name);
2453 str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
2454 STR_TERMINATE | STR_NOALIGN);
2455 regval_ctr_addvalue(ctr, val_name, REG_SZ,
2456 (char *) conv_str, str_size);
2459 static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2460 uint32 dword)
2462 regval_ctr_delvalue(ctr, val_name);
2463 regval_ctr_addvalue(ctr, val_name, REG_DWORD,
2464 (char *) &dword, sizeof(dword));
2467 static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2468 BOOL bool)
2470 uint8 bin_bool = (bool ? 1 : 0);
2471 regval_ctr_delvalue(ctr, val_name);
2472 regval_ctr_addvalue(ctr, val_name, REG_BINARY,
2473 (char *) &bin_bool, sizeof(bin_bool));
2476 static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
2477 const char *multi_sz)
2479 smb_ucs2_t *conv_strs = NULL;
2480 size_t str_size;
2482 /* a multi-sz has to have a null string terminator, i.e., the last
2483 string must be followed by two nulls */
2484 str_size = (strlen(multi_sz) + 2) * sizeof(smb_ucs2_t);
2485 conv_strs = calloc(str_size, 1);
2487 push_ucs2(NULL, conv_strs, multi_sz, str_size,
2488 STR_TERMINATE | STR_NOALIGN);
2490 regval_ctr_delvalue(ctr, val_name);
2491 regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
2492 (char *) conv_strs, str_size);
2493 safe_free(conv_strs);
2497 /****************************************************************************
2498 * Map the NT_PRINTER_INFO_LEVEL_2 data into DsSpooler keys for publishing.
2500 * @param info2 NT_PRINTER_INFO_LEVEL_2 describing printer - gets modified
2501 * @return BOOL indicating success or failure
2502 ***************************************************************************/
2504 static BOOL map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
2506 REGVAL_CTR *ctr = NULL;
2507 fstring longname;
2508 char *allocated_string = NULL;
2509 const char *ascii_str;
2510 int i;
2512 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2513 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2514 ctr = &info2->data.keys[i].values;
2516 map_sz_into_ctr(ctr, SPOOL_REG_PRINTERNAME, info2->sharename);
2517 map_sz_into_ctr(ctr, SPOOL_REG_SHORTSERVERNAME, global_myname());
2519 get_myfullname(longname);
2520 map_sz_into_ctr(ctr, SPOOL_REG_SERVERNAME, longname);
2522 asprintf(&allocated_string, "\\\\%s\\%s", longname, info2->sharename);
2523 map_sz_into_ctr(ctr, SPOOL_REG_UNCNAME, allocated_string);
2524 SAFE_FREE(allocated_string);
2526 map_dword_into_ctr(ctr, SPOOL_REG_VERSIONNUMBER, 4);
2527 map_sz_into_ctr(ctr, SPOOL_REG_DRIVERNAME, info2->drivername);
2528 map_sz_into_ctr(ctr, SPOOL_REG_LOCATION, info2->location);
2529 map_sz_into_ctr(ctr, SPOOL_REG_DESCRIPTION, info2->comment);
2530 map_single_multi_sz_into_ctr(ctr, SPOOL_REG_PORTNAME, info2->portname);
2531 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSEPARATORFILE, info2->sepfile);
2532 map_dword_into_ctr(ctr, SPOOL_REG_PRINTSTARTTIME, info2->starttime);
2533 map_dword_into_ctr(ctr, SPOOL_REG_PRINTENDTIME, info2->untiltime);
2534 map_dword_into_ctr(ctr, SPOOL_REG_PRIORITY, info2->priority);
2536 map_bool_into_ctr(ctr, SPOOL_REG_PRINTKEEPPRINTEDJOBS,
2537 (info2->attributes &
2538 PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS));
2540 switch (info2->attributes & 0x3) {
2541 case 0:
2542 ascii_str = SPOOL_REGVAL_PRINTWHILESPOOLING;
2543 break;
2544 case 1:
2545 ascii_str = SPOOL_REGVAL_PRINTAFTERSPOOLED;
2546 break;
2547 case 2:
2548 ascii_str = SPOOL_REGVAL_PRINTDIRECT;
2549 break;
2550 default:
2551 ascii_str = "unknown";
2553 map_sz_into_ctr(ctr, SPOOL_REG_PRINTSPOOLING, ascii_str);
2555 return True;
2558 #ifdef HAVE_ADS
2559 static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2, GUID guid)
2561 int i;
2562 REGVAL_CTR *ctr=NULL;
2564 /* find the DsSpooler key */
2565 if ((i = lookup_printerkey(&info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
2566 i = add_new_printer_key(&info2->data, SPOOL_DSSPOOLER_KEY);
2567 ctr = &info2->data.keys[i].values;
2569 regval_ctr_delvalue(ctr, "objectGUID");
2570 regval_ctr_addvalue(ctr, "objectGUID", REG_BINARY,
2571 (char *) &guid, sizeof(GUID));
2574 static WERROR publish_it(NT_PRINTER_INFO_LEVEL *printer)
2576 ADS_STATUS ads_rc;
2577 TALLOC_CTX *ctx = talloc_init("publish_it");
2578 ADS_MODLIST mods = ads_init_mods(ctx);
2579 char *prt_dn = NULL, *srv_dn, **srv_cn;
2580 void *res = NULL;
2581 ADS_STRUCT *ads;
2582 const char *attrs[] = {"objectGUID", NULL};
2583 GUID guid;
2584 WERROR win_rc = WERR_OK;
2586 ZERO_STRUCT(guid);
2587 /* set the DsSpooler info and attributes */
2588 if (!(map_nt_printer_info2_to_dsspooler(printer->info_2)))
2589 return WERR_NOMEM;
2590 printer->info_2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
2591 win_rc = mod_a_printer(*printer, 2);
2592 if (!W_ERROR_IS_OK(win_rc)) {
2593 DEBUG(3, ("err %d saving data\n",
2594 W_ERROR_V(win_rc)));
2595 return win_rc;
2598 /* Build the ads mods */
2599 get_local_printer_publishing_data(ctx, &mods,
2600 &printer->info_2->data);
2601 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME,
2602 printer->info_2->sharename);
2604 /* connect to the ADS server */
2605 ads = ads_init(NULL, NULL, lp_ads_server());
2606 if (!ads) {
2607 DEBUG(3, ("ads_init() failed\n"));
2608 return WERR_SERVER_UNAVAILABLE;
2610 ads_rc = ads_connect(ads);
2611 if (!ADS_ERR_OK(ads_rc)) {
2612 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2613 ads_destroy(&ads);
2614 return WERR_ACCESS_DENIED;
2617 /* figure out where to publish */
2618 ads_find_machine_acct(ads, &res, global_myname());
2619 srv_dn = ldap_get_dn(ads->ld, res);
2620 ads_msgfree(ads, res);
2621 srv_cn = ldap_explode_dn(srv_dn, 1);
2622 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0],
2623 printer->info_2->sharename, srv_dn);
2624 ads_memfree(ads, srv_dn);
2626 /* publish it */
2627 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
2628 if (LDAP_ALREADY_EXISTS == ads_rc.err.rc)
2629 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx,&mods);
2631 /* retreive the guid and store it locally */
2632 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
2633 ads_memfree(ads, prt_dn);
2634 ads_pull_guid(ads, res, &guid);
2635 ads_msgfree(ads, res);
2636 store_printer_guid(printer->info_2, guid);
2637 win_rc = mod_a_printer(*printer, 2);
2640 safe_free(prt_dn);
2641 ads_destroy(&ads);
2643 return WERR_OK;
2646 WERROR unpublish_it(NT_PRINTER_INFO_LEVEL *printer)
2648 ADS_STATUS ads_rc;
2649 ADS_STRUCT *ads;
2650 void *res;
2651 char *prt_dn = NULL;
2652 WERROR win_rc;
2654 printer->info_2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
2655 win_rc = mod_a_printer(*printer, 2);
2656 if (!W_ERROR_IS_OK(win_rc)) {
2657 DEBUG(3, ("err %d saving data\n",
2658 W_ERROR_V(win_rc)));
2659 return win_rc;
2662 ads = ads_init(NULL, NULL, lp_ads_server());
2663 if (!ads) {
2664 DEBUG(3, ("ads_init() failed\n"));
2665 return WERR_SERVER_UNAVAILABLE;
2667 ads_rc = ads_connect(ads);
2668 if (!ADS_ERR_OK(ads_rc)) {
2669 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
2670 ads_destroy(&ads);
2671 return WERR_ACCESS_DENIED;
2674 /* remove the printer from the directory */
2675 ads_rc = ads_find_printer_on_server(ads, &res,
2676 printer->info_2->sharename, global_myname());
2677 if (ADS_ERR_OK(ads_rc) && ads_count_replies(ads, res)) {
2678 prt_dn = ads_get_dn(ads, res);
2679 ads_msgfree(ads, res);
2680 ads_rc = ads_del_dn(ads, prt_dn);
2681 ads_memfree(ads, prt_dn);
2684 ads_destroy(&ads);
2685 return WERR_OK;
2688 /****************************************************************************
2689 * Publish a printer in the directory
2691 * @param snum describing printer service
2692 * @return WERROR indicating status of publishing
2693 ***************************************************************************/
2695 WERROR nt_printer_publish(int snum, int action)
2697 NT_PRINTER_INFO_LEVEL *printer = NULL;
2698 WERROR win_rc;
2700 win_rc = get_a_printer(&printer, 2, lp_servicename(snum));
2701 if (!W_ERROR_IS_OK(win_rc))
2702 return win_rc;
2704 switch(action) {
2705 case SPOOL_DS_PUBLISH:
2706 case SPOOL_DS_UPDATE:
2707 win_rc = publish_it(printer);
2708 break;
2709 case SPOOL_DS_UNPUBLISH:
2710 win_rc = unpublish_it(printer);
2711 break;
2712 default:
2713 win_rc = WERR_NOT_SUPPORTED;
2717 free_a_printer(&printer, 2);
2718 return win_rc;
2721 BOOL is_printer_published(int snum, GUID *guid)
2723 NT_PRINTER_INFO_LEVEL *printer = NULL;
2724 REGVAL_CTR *ctr;
2725 REGISTRY_VALUE *guid_val;
2726 WERROR win_rc;
2727 int i;
2730 win_rc = get_a_printer(&printer, 2, lp_servicename(snum));
2731 if (!W_ERROR_IS_OK(win_rc))
2732 return False;
2734 if (!(printer->info_2->attributes & PRINTER_ATTRIBUTE_PUBLISHED))
2735 return False;
2737 if ((i = lookup_printerkey(&printer->info_2->data,
2738 SPOOL_DSSPOOLER_KEY)) < 0)
2739 return False;
2741 if (!(ctr = &printer->info_2->data.keys[i].values)) {
2742 return False;
2745 if (!(guid_val = regval_ctr_getvalue(ctr, "objectGUID"))) {
2746 return False;
2749 if (regval_size(guid_val) == sizeof(GUID))
2750 memcpy(guid, regval_data_p(guid_val), sizeof(GUID));
2752 return True;
2755 #else
2756 WERROR nt_printer_publish(int snum, int action)
2758 return WERR_OK;
2760 BOOL is_printer_published(int snum, GUID *guid)
2762 return False;
2764 #endif
2765 /****************************************************************************
2766 ***************************************************************************/
2768 WERROR delete_all_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key )
2770 NT_PRINTER_DATA *data;
2771 int i;
2772 int removed_keys = 0;
2773 int empty_slot;
2775 data = &p2->data;
2776 empty_slot = data->num_keys;
2778 if ( !key )
2779 return WERR_INVALID_PARAM;
2781 /* remove all keys */
2783 if ( !strlen(key) )
2785 for ( i=0; i<data->num_keys; i++ )
2787 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2788 data->keys[i].name));
2790 SAFE_FREE( data->keys[i].name );
2791 regval_ctr_destroy( &data->keys[i].values );
2794 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from printer [%s]\n",
2795 p2->printername ));
2797 SAFE_FREE( data->keys );
2798 ZERO_STRUCTP( data );
2800 return WERR_OK;
2803 /* remove a specific key (and all subkeys) */
2805 for ( i=0; i<data->num_keys; i++ )
2807 if ( StrnCaseCmp( data->keys[i].name, key, strlen(key)) == 0 )
2809 DEBUG(8,("delete_all_printer_data: Removed all Printer Data from key [%s]\n",
2810 data->keys[i].name));
2812 SAFE_FREE( data->keys[i].name );
2813 regval_ctr_destroy( &data->keys[i].values );
2815 /* mark the slot as empty */
2817 ZERO_STRUCTP( &data->keys[i] );
2821 /* find the first empty slot */
2823 for ( i=0; i<data->num_keys; i++ ) {
2824 if ( !data->keys[i].name ) {
2825 empty_slot = i;
2826 removed_keys++;
2827 break;
2831 if ( i == data->num_keys )
2832 /* nothing was removed */
2833 return WERR_INVALID_PARAM;
2835 /* move everything down */
2837 for ( i=empty_slot+1; i<data->num_keys; i++ ) {
2838 if ( data->keys[i].name ) {
2839 memcpy( &data->keys[empty_slot], &data->keys[i], sizeof(NT_PRINTER_KEY) );
2840 ZERO_STRUCTP( &data->keys[i] );
2841 empty_slot++;
2842 removed_keys++;
2846 /* update count */
2848 data->num_keys -= removed_keys;
2850 /* sanity check to see if anything is left */
2852 if ( !data->num_keys )
2854 DEBUG(8,("delete_all_printer_data: No keys left for printer [%s]\n", p2->printername ));
2856 SAFE_FREE( data->keys );
2857 ZERO_STRUCTP( data );
2860 return WERR_OK;
2863 /****************************************************************************
2864 ***************************************************************************/
2866 WERROR delete_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2868 WERROR result = WERR_OK;
2869 int key_index;
2871 /* we must have names on non-zero length */
2873 if ( !key || !*key|| !value || !*value )
2874 return WERR_INVALID_NAME;
2876 /* find the printer key first */
2878 key_index = lookup_printerkey( &p2->data, key );
2879 if ( key_index == -1 )
2880 return WERR_OK;
2882 regval_ctr_delvalue( &p2->data.keys[key_index].values, value );
2884 DEBUG(8,("delete_printer_data: Removed key => [%s], value => [%s]\n",
2885 key, value ));
2887 return result;
2890 /****************************************************************************
2891 ***************************************************************************/
2893 WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value,
2894 uint32 type, uint8 *data, int real_len )
2896 WERROR result = WERR_OK;
2897 int key_index;
2899 /* we must have names on non-zero length */
2901 if ( !key || !*key|| !value || !*value )
2902 return WERR_INVALID_NAME;
2904 /* find the printer key first */
2906 key_index = lookup_printerkey( &p2->data, key );
2907 if ( key_index == -1 )
2908 key_index = add_new_printer_key( &p2->data, key );
2910 if ( key_index == -1 )
2911 return WERR_NOMEM;
2913 regval_ctr_addvalue( &p2->data.keys[key_index].values, value,
2914 type, data, real_len );
2916 DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
2917 key, value, type, real_len ));
2919 return result;
2922 /****************************************************************************
2923 ***************************************************************************/
2925 REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
2927 int key_index;
2929 if ( (key_index = lookup_printerkey( &p2->data, key )) == -1 )
2930 return NULL;
2932 DEBUG(8,("get_printer_data: Attempting to lookup key => [%s], value => [%s]\n",
2933 key, value ));
2935 return regval_ctr_getvalue( &p2->data.keys[key_index].values, value );
2938 /****************************************************************************
2939 Unpack a list of registry values frem the TDB
2940 ***************************************************************************/
2942 static int unpack_values(NT_PRINTER_DATA *printer_data, char *buf, int buflen)
2944 int len = 0;
2945 uint32 type;
2946 pstring string, valuename, keyname;
2947 char *str;
2948 int size;
2949 uint8 *data_p;
2950 REGISTRY_VALUE *regval_p;
2951 int key_index;
2953 /* add the "PrinterDriverData" key first for performance reasons */
2955 add_new_printer_key( printer_data, SPOOL_PRINTERDATA_KEY );
2957 /* loop and unpack the rest of the registry values */
2959 while ( True )
2962 /* check to see if there are any more registry values */
2964 len += tdb_unpack(buf+len, buflen-len, "p", &regval_p);
2965 if ( !regval_p )
2966 break;
2968 /* unpack the next regval */
2970 len += tdb_unpack(buf+len, buflen-len, "fdB",
2971 string,
2972 &type,
2973 &size,
2974 &data_p);
2977 * break of the keyname from the value name.
2978 * Should only be one '\' in the string returned.
2981 str = strrchr( string, '\\');
2983 /* Put in "PrinterDriverData" is no key specified */
2985 if ( !str ) {
2986 pstrcpy( keyname, SPOOL_PRINTERDATA_KEY );
2987 pstrcpy( valuename, string );
2989 else {
2990 *str = '\0';
2991 pstrcpy( keyname, string );
2992 pstrcpy( valuename, str+1 );
2995 /* see if we need a new key */
2997 if ( (key_index=lookup_printerkey( printer_data, keyname )) == -1 )
2998 key_index = add_new_printer_key( printer_data, keyname );
3000 if ( key_index == -1 ) {
3001 DEBUG(0,("unpack_values: Failed to allocate a new key [%s]!\n",
3002 keyname));
3003 break;
3006 /* add the new value */
3008 regval_ctr_addvalue( &printer_data->keys[key_index].values, valuename, type, data_p, size );
3010 SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
3011 DEBUG(8,("specific: [%s:%s], len: %d\n", keyname, valuename, size));
3014 return len;
3017 /****************************************************************************
3018 ***************************************************************************/
3020 static void map_to_os2_driver(fstring drivername)
3022 static BOOL initialised=False;
3023 static fstring last_from,last_to;
3024 char *mapfile = lp_os2_driver_map();
3025 char **lines = NULL;
3026 int numlines = 0;
3027 int i;
3029 if (!strlen(drivername))
3030 return;
3032 if (!*mapfile)
3033 return;
3035 if (!initialised) {
3036 *last_from = *last_to = 0;
3037 initialised = True;
3040 if (strequal(drivername,last_from)) {
3041 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,last_to));
3042 fstrcpy(drivername,last_to);
3043 return;
3046 lines = file_lines_load(mapfile, &numlines);
3047 if (numlines == 0) {
3048 DEBUG(0,("No entries in OS/2 driver map %s\n",mapfile));
3049 return;
3052 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
3054 for( i = 0; i < numlines; i++) {
3055 char *nt_name = lines[i];
3056 char *os2_name = strchr(nt_name,'=');
3058 if (!os2_name)
3059 continue;
3061 *os2_name++ = 0;
3063 while (isspace(*nt_name))
3064 nt_name++;
3066 if (!*nt_name || strchr("#;",*nt_name))
3067 continue;
3070 int l = strlen(nt_name);
3071 while (l && isspace(nt_name[l-1])) {
3072 nt_name[l-1] = 0;
3073 l--;
3077 while (isspace(*os2_name))
3078 os2_name++;
3081 int l = strlen(os2_name);
3082 while (l && isspace(os2_name[l-1])) {
3083 os2_name[l-1] = 0;
3084 l--;
3088 if (strequal(nt_name,drivername)) {
3089 DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
3090 fstrcpy(last_from,drivername);
3091 fstrcpy(last_to,os2_name);
3092 fstrcpy(drivername,os2_name);
3093 file_lines_free(lines);
3094 return;
3098 file_lines_free(lines);
3101 /****************************************************************************
3102 get a default printer info 2 struct
3103 ****************************************************************************/
3104 static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
3106 int snum;
3107 NT_PRINTER_INFO_LEVEL_2 info;
3109 ZERO_STRUCT(info);
3111 snum = lp_servicenumber(sharename);
3113 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3114 slprintf(info.printername, sizeof(info.printername)-1, "\\\\%s\\%s",
3115 get_called_name(), sharename);
3116 fstrcpy(info.sharename, sharename);
3117 fstrcpy(info.portname, SAMBA_PRINTER_PORT_NAME);
3119 /* by setting the driver name to an empty string, a local NT admin
3120 can now run the **local** APW to install a local printer driver
3121 for a Samba shared printer in 2.2. Without this, drivers **must** be
3122 installed on the Samba server for NT clients --jerry */
3123 #if 0 /* JERRY --do not uncomment-- */
3124 if (!*info.drivername)
3125 fstrcpy(info.drivername, "NO DRIVER AVAILABLE FOR THIS PRINTER");
3126 #endif
3129 DEBUG(10,("get_a_printer_2_default: driver name set to [%s]\n", info.drivername));
3131 pstrcpy(info.comment, "");
3132 fstrcpy(info.printprocessor, "winprint");
3133 fstrcpy(info.datatype, "RAW");
3135 info.attributes = PRINTER_ATTRIBUTE_SAMBA;
3137 info.starttime = 0; /* Minutes since 12:00am GMT */
3138 info.untiltime = 0; /* Minutes since 12:00am GMT */
3139 info.priority = 1;
3140 info.default_priority = 1;
3141 info.setuptime = (uint32)time(NULL);
3144 * I changed this as I think it is better to have a generic
3145 * DEVMODE than to crash Win2k explorer.exe --jerry
3146 * See the HP Deskjet 990c Win2k drivers for an example.
3148 * However the default devmode appears to cause problems
3149 * with the HP CLJ 8500 PCL driver. Hence the addition of
3150 * the "default devmode" parameter --jerry 22/01/2002
3153 if (lp_default_devmode(snum)) {
3154 if ((info.devmode = construct_nt_devicemode(info.printername)) == NULL)
3155 goto fail;
3157 else {
3158 info.devmode = NULL;
3161 /* This will get the current RPC talloc context, but we should be
3162 passing this as a parameter... fixme... JRA ! */
3164 if (!nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf))
3165 goto fail;
3167 *info_ptr = (NT_PRINTER_INFO_LEVEL_2 *)memdup(&info, sizeof(info));
3168 if (! *info_ptr) {
3169 DEBUG(0,("get_a_printer_2_default: malloc fail.\n"));
3170 goto fail;
3173 return WERR_OK;
3175 fail:
3176 if (info.devmode)
3177 free_nt_devicemode(&info.devmode);
3178 return WERR_ACCESS_DENIED;
3181 /****************************************************************************
3182 ****************************************************************************/
3183 static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstring sharename)
3185 pstring key;
3186 NT_PRINTER_INFO_LEVEL_2 info;
3187 int len = 0;
3188 TDB_DATA kbuf, dbuf;
3189 fstring printername;
3191 ZERO_STRUCT(info);
3193 slprintf(key, sizeof(key)-1, "%s%s", PRINTERS_PREFIX, sharename);
3195 kbuf.dptr = key;
3196 kbuf.dsize = strlen(key)+1;
3198 dbuf = tdb_fetch(tdb_printers, kbuf);
3199 if (!dbuf.dptr)
3200 return get_a_printer_2_default(info_ptr, sharename);
3202 len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "dddddddddddfffffPfffff",
3203 &info.attributes,
3204 &info.priority,
3205 &info.default_priority,
3206 &info.starttime,
3207 &info.untiltime,
3208 &info.status,
3209 &info.cjobs,
3210 &info.averageppm,
3211 &info.changeid,
3212 &info.c_setprinter,
3213 &info.setuptime,
3214 info.servername,
3215 info.printername,
3216 info.sharename,
3217 info.portname,
3218 info.drivername,
3219 info.comment,
3220 info.location,
3221 info.sepfile,
3222 info.printprocessor,
3223 info.datatype,
3224 info.parameters);
3226 /* Samba has to have shared raw drivers. */
3227 info.attributes |= PRINTER_ATTRIBUTE_SAMBA;
3229 /* Restore the stripped strings. */
3230 slprintf(info.servername, sizeof(info.servername)-1, "\\\\%s", get_called_name());
3231 slprintf(printername, sizeof(printername)-1, "\\\\%s\\%s", get_called_name(),
3232 info.printername);
3233 fstrcpy(info.printername, printername);
3235 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3238 * Some client drivers freak out if there is a NULL devmode
3239 * (probably the driver is not checking before accessing
3240 * the devmode pointer) --jerry
3242 * See comments in get_a_printer_2_default()
3245 if (lp_default_devmode(lp_servicenumber(sharename)) && !info.devmode) {
3246 DEBUG(8,("get_a_printer_2: Constructing a default device mode for [%s]\n",
3247 printername));
3248 info.devmode = construct_nt_devicemode(printername);
3251 len += unpack_values( &info.data, dbuf.dptr+len, dbuf.dsize-len );
3253 /* This will get the current RPC talloc context, but we should be
3254 passing this as a parameter... fixme... JRA ! */
3256 nt_printing_getsec(get_talloc_ctx(), sharename, &info.secdesc_buf);
3258 /* Fix for OS/2 drivers. */
3260 if (get_remote_arch() == RA_OS2)
3261 map_to_os2_driver(info.drivername);
3263 SAFE_FREE(dbuf.dptr);
3264 *info_ptr=memdup(&info, sizeof(info));
3266 DEBUG(9,("Unpacked printer [%s] name [%s] running driver [%s]\n",
3267 sharename, info.printername, info.drivername));
3269 return WERR_OK;
3272 /****************************************************************************
3273 debugging function, dump at level 6 the struct in the logs
3274 ****************************************************************************/
3275 static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3277 uint32 result;
3278 NT_PRINTER_INFO_LEVEL_2 *info2;
3280 DEBUG(106,("Dumping printer at level [%d]\n", level));
3282 switch (level)
3284 case 2:
3286 if (printer.info_2 == NULL)
3287 result=5;
3288 else
3290 info2=printer.info_2;
3292 DEBUGADD(106,("attributes:[%d]\n", info2->attributes));
3293 DEBUGADD(106,("priority:[%d]\n", info2->priority));
3294 DEBUGADD(106,("default_priority:[%d]\n", info2->default_priority));
3295 DEBUGADD(106,("starttime:[%d]\n", info2->starttime));
3296 DEBUGADD(106,("untiltime:[%d]\n", info2->untiltime));
3297 DEBUGADD(106,("status:[%d]\n", info2->status));
3298 DEBUGADD(106,("cjobs:[%d]\n", info2->cjobs));
3299 DEBUGADD(106,("averageppm:[%d]\n", info2->averageppm));
3300 DEBUGADD(106,("changeid:[%d]\n", info2->changeid));
3301 DEBUGADD(106,("c_setprinter:[%d]\n", info2->c_setprinter));
3302 DEBUGADD(106,("setuptime:[%d]\n", info2->setuptime));
3304 DEBUGADD(106,("servername:[%s]\n", info2->servername));
3305 DEBUGADD(106,("printername:[%s]\n", info2->printername));
3306 DEBUGADD(106,("sharename:[%s]\n", info2->sharename));
3307 DEBUGADD(106,("portname:[%s]\n", info2->portname));
3308 DEBUGADD(106,("drivername:[%s]\n", info2->drivername));
3309 DEBUGADD(106,("comment:[%s]\n", info2->comment));
3310 DEBUGADD(106,("location:[%s]\n", info2->location));
3311 DEBUGADD(106,("sepfile:[%s]\n", info2->sepfile));
3312 DEBUGADD(106,("printprocessor:[%s]\n", info2->printprocessor));
3313 DEBUGADD(106,("datatype:[%s]\n", info2->datatype));
3314 DEBUGADD(106,("parameters:[%s]\n", info2->parameters));
3315 result=0;
3317 break;
3319 default:
3320 DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
3321 result=1;
3322 break;
3325 return result;
3328 /****************************************************************************
3329 Get the parameters we can substitute in an NT print job.
3330 ****************************************************************************/
3332 void get_printer_subst_params(int snum, fstring *printername, fstring *sharename, fstring *portname)
3334 NT_PRINTER_INFO_LEVEL *printer = NULL;
3336 **printername = **sharename = **portname = '\0';
3338 if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
3339 return;
3341 fstrcpy(*printername, printer->info_2->printername);
3342 fstrcpy(*sharename, printer->info_2->sharename);
3343 fstrcpy(*portname, printer->info_2->portname);
3345 free_a_printer(&printer, 2);
3348 /****************************************************************************
3349 Update the changeid time.
3350 This is SO NASTY as some drivers need this to change, others need it
3351 static. This value will change every second, and I must hope that this
3352 is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF
3353 UTAH ! JRA.
3354 ****************************************************************************/
3356 static uint32 rev_changeid(void)
3358 struct timeval tv;
3360 get_process_uptime(&tv);
3362 #if 1 /* JERRY */
3363 /* Return changeid as msec since spooler restart */
3364 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
3365 #else
3367 * This setting seems to work well but is too untested
3368 * to replace the above calculation. Left in for experiementation
3369 * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002)
3371 return tv.tv_sec * 10 + tv.tv_usec / 100000;
3372 #endif
3376 * The function below are the high level ones.
3377 * only those ones must be called from the spoolss code.
3378 * JFM.
3381 /****************************************************************************
3382 Modify a printer. This is called from SETPRINTERDATA/DELETEPRINTERDATA.
3383 ****************************************************************************/
3385 WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3387 WERROR result;
3389 dump_a_printer(printer, level);
3391 switch (level)
3393 case 2:
3396 * Update the changestamp. Emperical tests show that the
3397 * ChangeID is always updated,but c_setprinter is
3398 * global spooler variable (not per printer).
3401 /* ChangeID **must** be increasing over the lifetime
3402 of client's spoolss service in order for the
3403 client's cache to show updates */
3405 printer.info_2->changeid = rev_changeid();
3408 * Because one day someone will ask:
3409 * NT->NT An admin connection to a remote
3410 * printer show changes imeediately in
3411 * the properities dialog
3413 * A non-admin connection will only show the
3414 * changes after viewing the properites page
3415 * 2 times. Seems to be related to a
3416 * race condition in the client between the spooler
3417 * updating the local cache and the Explorer.exe GUI
3418 * actually displaying the properties.
3420 * This is fixed in Win2k. admin/non-admin
3421 * connections both display changes immediately.
3423 * 14/12/01 --jerry
3426 result=update_a_printer_2(printer.info_2);
3427 break;
3429 default:
3430 result=WERR_UNKNOWN_LEVEL;
3431 break;
3434 return result;
3437 /****************************************************************************
3438 Initialize printer devmode & data with previously saved driver init values.
3439 ****************************************************************************/
3441 static BOOL set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
3443 int len = 0;
3444 pstring key;
3445 TDB_DATA kbuf, dbuf;
3446 NT_PRINTER_INFO_LEVEL_2 info;
3449 ZERO_STRUCT(info);
3452 * Delete any printer data 'values' already set. When called for driver
3453 * replace, there will generally be some, but during an add printer, there
3454 * should not be any (if there are delete them).
3457 delete_all_printer_data( info_ptr, "" );
3459 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
3461 kbuf.dptr = key;
3462 kbuf.dsize = strlen(key)+1;
3464 dbuf = tdb_fetch(tdb_drivers, kbuf);
3465 if (!dbuf.dptr) {
3467 * When changing to a driver that has no init info in the tdb, remove
3468 * the previous drivers init info and leave the new on blank.
3470 free_nt_devicemode(&info_ptr->devmode);
3471 return False;
3475 * Get the saved DEVMODE..
3478 len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
3481 * The saved DEVMODE contains the devicename from the printer used during
3482 * the initialization save. Change it to reflect the new printer.
3485 if ( info.devmode ) {
3486 ZERO_STRUCT(info.devmode->devicename);
3487 fstrcpy(info.devmode->devicename, info_ptr->printername);
3491 * NT/2k does not change out the entire DeviceMode of a printer
3492 * when changing the driver. Only the driverextra, private, &
3493 * driverversion fields. --jerry (Thu Mar 14 08:58:43 CST 2002)
3495 * Later examination revealed that Windows NT/2k does reset the
3496 * the printer's device mode, bit **only** when you change a
3497 * property of the device mode such as the page orientation.
3498 * --jerry
3502 /* Bind the saved DEVMODE to the new the printer */
3504 free_nt_devicemode(&info_ptr->devmode);
3505 info_ptr->devmode = info.devmode;
3507 DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
3508 info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
3510 /* Add the printer data 'values' to the new printer */
3512 len += unpack_values( &info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
3515 SAFE_FREE(dbuf.dptr);
3517 return True;
3520 /****************************************************************************
3521 Initialize printer devmode & data with previously saved driver init values.
3522 When a printer is created using AddPrinter, the drivername bound to the
3523 printer is used to lookup previously saved driver initialization info, which
3524 is bound to the new printer.
3525 ****************************************************************************/
3527 BOOL set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
3529 BOOL result = False;
3531 switch (level)
3533 case 2:
3534 result = set_driver_init_2(printer->info_2);
3535 break;
3537 default:
3538 DEBUG(0,("set_driver_init: Programmer's error! Unknown driver_init level [%d]\n",
3539 level));
3540 break;
3543 return result;
3546 /****************************************************************************
3547 Delete driver init data stored for a specified driver
3548 ****************************************************************************/
3550 BOOL del_driver_init(char *drivername)
3552 pstring key;
3553 TDB_DATA kbuf;
3555 if (!drivername || !*drivername) {
3556 DEBUG(3,("del_driver_init: No drivername specified!\n"));
3557 return False;
3560 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, drivername);
3562 kbuf.dptr = key;
3563 kbuf.dsize = strlen(key)+1;
3565 DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n", drivername));
3567 return (tdb_delete(tdb_drivers, kbuf) == 0);
3570 /****************************************************************************
3571 Pack up the DEVMODE and values for a printer into a 'driver init' entry
3572 in the tdb. Note: this is different from the driver entry and the printer
3573 entry. There should be a single driver init entry for each driver regardless
3574 of whether it was installed from NT or 2K. Technically, they should be
3575 different, but they work out to the same struct.
3576 ****************************************************************************/
3578 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
3580 pstring key;
3581 char *buf;
3582 int buflen, len, ret;
3583 TDB_DATA kbuf, dbuf;
3585 buf = NULL;
3586 buflen = 0;
3588 again:
3589 len = 0;
3590 len += pack_devicemode(info->devmode, buf+len, buflen-len);
3592 len += pack_values( &info->data, buf+len, buflen-len );
3594 if (buflen != len) {
3595 char *tb;
3597 tb = (char *)Realloc(buf, len);
3598 if (!tb) {
3599 DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
3600 ret = -1;
3601 goto done;
3603 else buf = tb;
3604 buflen = len;
3605 goto again;
3608 slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info->drivername);
3610 kbuf.dptr = key;
3611 kbuf.dsize = strlen(key)+1;
3612 dbuf.dptr = buf;
3613 dbuf.dsize = len;
3615 ret = tdb_store(tdb_drivers, kbuf, dbuf, TDB_REPLACE);
3617 done:
3618 if (ret == -1)
3619 DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
3621 SAFE_FREE(buf);
3623 DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
3624 info->sharename, info->drivername));
3626 return ret;
3629 /****************************************************************************
3630 Update (i.e. save) the driver init info (DEVMODE and values) for a printer
3631 ****************************************************************************/
3633 uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
3635 uint32 result;
3637 dump_a_printer(printer, level);
3639 switch (level)
3641 case 2:
3643 result = update_driver_init_2(printer.info_2);
3644 break;
3646 default:
3647 result = 1;
3648 break;
3651 return result;
3654 /****************************************************************************
3655 Convert the printer data value, a REG_BINARY array, into an initialization
3656 DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
3657 got to keep the endians happy :).
3658 ****************************************************************************/
3660 static BOOL convert_driver_init( TALLOC_CTX *ctx, NT_DEVICEMODE *nt_devmode, uint8 *data, uint32 data_len )
3662 BOOL result = False;
3663 prs_struct ps;
3664 DEVICEMODE devmode;
3666 ZERO_STRUCT(devmode);
3668 prs_init(&ps, 0, ctx, UNMARSHALL);
3669 ps.data_p = (char *)data;
3670 ps.buffer_size = data_len;
3672 if (spoolss_io_devmode("phantom DEVMODE", &ps, 0, &devmode))
3673 result = convert_devicemode("", &devmode, &nt_devmode);
3674 else
3675 DEBUG(10,("convert_driver_init: error parsing DEVMODE\n"));
3677 return result;
3680 /****************************************************************************
3681 Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
3683 1. Use the driver's config DLL to this UNC printername and:
3684 a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
3685 b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
3686 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
3688 The last step triggers saving the "driver initialization" information for
3689 this printer into the tdb. Later, new printers that use this driver will
3690 have this initialization information bound to them. This simulates the
3691 driver initialization, as if it had run on the Samba server (as it would
3692 have done on NT).
3694 The Win32 client side code requirement sucks! But until we can run arbitrary
3695 Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
3697 It would have been easier to use SetPrinter because all the UNMARSHALLING of
3698 the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
3699 about it and you will realize why. JRR 010720
3700 ****************************************************************************/
3702 static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
3704 WERROR status = WERR_OK;
3705 TALLOC_CTX *ctx = NULL;
3706 NT_DEVICEMODE *nt_devmode = NULL;
3707 NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
3710 * When the DEVMODE is already set on the printer, don't try to unpack it.
3712 DEBUG(8,("save_driver_init_2: Enter...\n"));
3714 if ( !printer->info_2->devmode && data_len )
3717 * Set devmode on printer info, so entire printer initialization can be
3718 * saved to tdb.
3721 if ((ctx = talloc_init("save_driver_init_2")) == NULL)
3722 return WERR_NOMEM;
3724 if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
3725 status = WERR_NOMEM;
3726 goto done;
3729 ZERO_STRUCTP(nt_devmode);
3732 * The DEVMODE is held in the 'data' component of the param in raw binary.
3733 * Convert it to to a devmode structure
3735 if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
3736 DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
3737 status = WERR_INVALID_PARAM;
3738 goto done;
3741 printer->info_2->devmode = nt_devmode;
3745 * Pack up and add (or update) the DEVMODE and any current printer data to
3746 * a 'driver init' element in the tdb
3750 if ( update_driver_init(*printer, 2) != 0 ) {
3751 DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
3752 status = WERR_NOMEM;
3753 goto done;
3757 * If driver initialization info was successfully saved, set the current
3758 * printer to match it. This allows initialization of the current printer
3759 * as well as the driver.
3761 status = mod_a_printer(*printer, 2);
3762 if (!W_ERROR_IS_OK(status)) {
3763 DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
3764 printer->info_2->printername));
3767 done:
3768 talloc_destroy(ctx);
3769 free_nt_devicemode( &nt_devmode );
3771 printer->info_2->devmode = tmp_devmode;
3773 return status;
3776 /****************************************************************************
3777 Update the driver init info (DEVMODE and specifics) for a printer
3778 ****************************************************************************/
3780 WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
3782 WERROR status = WERR_OK;
3784 switch (level)
3786 case 2:
3788 status = save_driver_init_2( printer, data, data_len );
3789 break;
3791 default:
3792 status = WERR_UNKNOWN_LEVEL;
3793 break;
3796 return status;
3799 /****************************************************************************
3800 Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
3801 ****************************************************************************/
3803 WERROR get_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level, fstring sharename)
3805 WERROR result;
3806 NT_PRINTER_INFO_LEVEL *printer = NULL;
3808 *pp_printer = NULL;
3810 DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
3812 switch (level)
3814 case 2:
3816 if ((printer = (NT_PRINTER_INFO_LEVEL *)malloc(sizeof(NT_PRINTER_INFO_LEVEL))) == NULL) {
3817 DEBUG(0,("get_a_printer: malloc fail.\n"));
3818 return WERR_NOMEM;
3820 ZERO_STRUCTP(printer);
3821 result=get_a_printer_2(&printer->info_2, sharename);
3822 if (W_ERROR_IS_OK(result)) {
3823 dump_a_printer(*printer, level);
3824 *pp_printer = printer;
3825 } else {
3826 SAFE_FREE(printer);
3828 break;
3830 default:
3831 result=WERR_UNKNOWN_LEVEL;
3832 break;
3835 DEBUG(10,("get_a_printer: [%s] level %u returning %s\n", sharename, (unsigned int)level, dos_errstr(result)));
3837 return result;
3840 /****************************************************************************
3841 Deletes a NT_PRINTER_INFO_LEVEL struct.
3842 ****************************************************************************/
3844 uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
3846 uint32 result;
3847 NT_PRINTER_INFO_LEVEL *printer = *pp_printer;
3849 DEBUG(104,("freeing a printer at level [%d]\n", level));
3851 if (printer == NULL)
3852 return 0;
3854 switch (level)
3856 case 2:
3858 if (printer->info_2 != NULL)
3860 free_nt_printer_info_level_2(&printer->info_2);
3861 result=0;
3863 else
3865 result=4;
3867 break;
3869 default:
3870 result=1;
3871 break;
3874 SAFE_FREE(*pp_printer);
3875 return result;
3878 /****************************************************************************
3879 ****************************************************************************/
3880 uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
3882 uint32 result;
3883 DEBUG(104,("adding a printer at level [%d]\n", level));
3884 dump_a_printer_driver(driver, level);
3886 switch (level)
3888 case 3:
3890 result=add_a_printer_driver_3(driver.info_3);
3891 break;
3894 case 6:
3896 result=add_a_printer_driver_6(driver.info_6);
3897 break;
3899 default:
3900 result=1;
3901 break;
3904 return result;
3906 /****************************************************************************
3907 ****************************************************************************/
3908 WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
3909 fstring drivername, const char *architecture, uint32 version)
3911 WERROR result;
3913 switch (level)
3915 case 3:
3916 /* Sometime we just want any version of the driver */
3918 if ( version == DRIVER_ANY_VERSION ) {
3919 /* look for Win2k first and then for NT4 */
3920 result = get_a_printer_driver_3(&driver->info_3, drivername,
3921 architecture, 3);
3923 if ( !W_ERROR_IS_OK(result) ) {
3924 result = get_a_printer_driver_3( &driver->info_3,
3925 drivername, architecture, 2 );
3928 else {
3929 result = get_a_printer_driver_3(&driver->info_3, drivername,
3930 architecture, version);
3932 break;
3934 default:
3935 result=W_ERROR(1);
3936 break;
3939 if (W_ERROR_IS_OK(result))
3940 dump_a_printer_driver(*driver, level);
3942 return result;
3945 /****************************************************************************
3946 ****************************************************************************/
3947 uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
3949 uint32 result;
3951 switch (level)
3953 case 3:
3955 NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
3956 if (driver.info_3 != NULL)
3958 info3=driver.info_3;
3959 SAFE_FREE(info3->dependentfiles);
3960 ZERO_STRUCTP(info3);
3961 SAFE_FREE(info3);
3962 result=0;
3964 else
3966 result=4;
3968 break;
3970 case 6:
3972 NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
3973 if (driver.info_6 != NULL)
3975 info6=driver.info_6;
3976 SAFE_FREE(info6->dependentfiles);
3977 SAFE_FREE(info6->previousnames);
3978 ZERO_STRUCTP(info6);
3979 SAFE_FREE(info6);
3980 result=0;
3982 else
3984 result=4;
3986 break;
3988 default:
3989 result=1;
3990 break;
3992 return result;
3996 /****************************************************************************
3997 Determine whether or not a particular driver is currently assigned
3998 to a printer
3999 ****************************************************************************/
4001 BOOL printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
4003 int snum;
4004 int n_services = lp_numservices();
4005 NT_PRINTER_INFO_LEVEL *printer = NULL;
4007 if ( !info_3 )
4008 return False;
4010 DEBUG(5,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
4012 /* loop through the printers.tdb and check for the drivername */
4014 for (snum=0; snum<n_services; snum++)
4016 if ( !(lp_snum_ok(snum) && lp_print_ok(snum) ) )
4017 continue;
4019 if ( !W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))) )
4020 continue;
4022 if ( !StrCaseCmp(info_3->name, printer->info_2->drivername) ) {
4023 free_a_printer( &printer, 2 );
4024 return True;
4027 free_a_printer( &printer, 2 );
4030 DEBUG(5,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
4032 /* report that the driver is not in use by default */
4034 return False;
4038 /**********************************************************************
4039 Check to see if a ogiven file is in use by *info
4040 *********************************************************************/
4042 static BOOL drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4044 int i = 0;
4046 if ( !info )
4047 return False;
4049 if ( strequal(file, info->driverpath) )
4050 return True;
4052 if ( strequal(file, info->datafile) )
4053 return True;
4055 if ( strequal(file, info->configfile) )
4056 return True;
4058 if ( strequal(file, info->helpfile) )
4059 return True;
4061 /* see of there are any dependent files to examine */
4063 if ( !info->dependentfiles )
4064 return False;
4066 while ( *info->dependentfiles[i] )
4068 if ( strequal(file, info->dependentfiles[i]) )
4069 return True;
4071 i++;
4074 return False;
4078 /**********************************************************************
4079 Utility function to remove the dependent file pointed to by the
4080 input parameter from the list
4081 *********************************************************************/
4083 static void trim_dependent_file( fstring files[], int idx )
4086 /* bump everything down a slot */
4088 while( *files[idx+1] )
4090 fstrcpy( files[idx], files[idx+1] );
4091 idx++;
4094 *files[idx] = '\0';
4096 return;
4099 /**********************************************************************
4100 Check if any of the files used by src are also used by drv
4101 *********************************************************************/
4103 static BOOL trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
4104 NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
4106 BOOL in_use = False;
4107 int i = 0;
4109 if ( !src || !drv )
4110 return False;
4112 /* check each file. Remove it from the src structure if it overlaps */
4114 if ( drv_file_in_use(src->driverpath, drv) ) {
4115 in_use = True;
4116 DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
4117 fstrcpy( src->driverpath, "" );
4120 if ( drv_file_in_use(src->datafile, drv) ) {
4121 in_use = True;
4122 DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
4123 fstrcpy( src->datafile, "" );
4126 if ( drv_file_in_use(src->configfile, drv) ) {
4127 in_use = True;
4128 DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
4129 fstrcpy( src->configfile, "" );
4132 if ( drv_file_in_use(src->helpfile, drv) ) {
4133 in_use = True;
4134 DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
4135 fstrcpy( src->helpfile, "" );
4138 /* are there any dependentfiles to examine? */
4140 if ( !src->dependentfiles )
4141 return in_use;
4143 while ( *src->dependentfiles[i] )
4145 if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
4146 in_use = True;
4147 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
4148 trim_dependent_file( src->dependentfiles, i );
4150 else
4151 i++;
4154 return in_use;
4157 /****************************************************************************
4158 Determine whether or not a particular driver files are currently being
4159 used by any other driver.
4161 Return value is True if any files were in use by other drivers
4162 and False otherwise.
4164 Upon return, *info has been modified to only contain the driver files
4165 which are not in use
4166 ****************************************************************************/
4168 BOOL printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
4170 int i;
4171 int ndrivers;
4172 uint32 version;
4173 fstring *list = NULL;
4174 NT_PRINTER_DRIVER_INFO_LEVEL driver;
4176 if ( !info )
4177 return False;
4179 version = info->cversion;
4181 /* loop over all driver versions */
4183 DEBUG(5,("printer_driver_files_in_use: Beginning search through ntdrivers.tdb...\n"));
4185 /* get the list of drivers */
4187 list = NULL;
4188 ndrivers = get_ntdrivers(&list, info->environment, version);
4190 DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
4191 ndrivers, info->environment, version));
4193 /* check each driver for overlap in files */
4195 for (i=0; i<ndrivers; i++)
4197 DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
4199 ZERO_STRUCT(driver);
4201 if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i],
4202 info->environment, version)) )
4204 SAFE_FREE(list);
4205 return True;
4208 /* check if d2 uses any files from d1 */
4209 /* only if this is a different driver than the one being deleted */
4211 if ( !strequal(info->name, driver.info_3->name) )
4213 if ( trim_overlap_drv_files(info, driver.info_3) ) {
4214 free_a_printer_driver(driver, 3);
4215 SAFE_FREE( list );
4216 return True;
4220 free_a_printer_driver(driver, 3);
4223 SAFE_FREE(list);
4225 DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
4227 driver.info_3 = info;
4229 if ( DEBUGLEVEL >= 20 )
4230 dump_a_printer_driver( driver, 3 );
4232 return False;
4235 /****************************************************************************
4236 Actually delete the driver files. Make sure that
4237 printer_driver_files_in_use() return False before calling
4238 this.
4239 ****************************************************************************/
4241 static BOOL delete_driver_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user )
4243 int i = 0;
4244 char *s;
4245 connection_struct *conn;
4246 DATA_BLOB null_pw;
4247 NTSTATUS nt_status;
4249 if ( !info_3 )
4250 return False;
4252 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
4255 * Connect to the print$ share under the same account as the
4256 * user connected to the rpc pipe. Note we must be root to
4257 * do this.
4260 become_root();
4261 null_pw = data_blob( NULL, 0 );
4262 conn = make_connection_with_chdir( "print$", null_pw, "A:", user->vuid, &nt_status );
4263 unbecome_root();
4265 if ( !conn ) {
4266 DEBUG(0,("delete_driver_files: Unable to connect\n"));
4267 return False;
4270 /* Save who we are - we are temporarily becoming the connection user. */
4272 if ( !become_user(conn, conn->vuid) ) {
4273 DEBUG(0,("delete_driver_files: Can't become user!\n"));
4274 return False;
4277 /* now delete the files; must strip the '\print$' string from
4278 fron of path */
4280 if ( *info_3->driverpath ) {
4281 if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
4282 DEBUG(10,("deleting driverfile [%s]\n", s));
4283 unlink_internals(conn, 0, s);
4287 if ( *info_3->configfile ) {
4288 if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
4289 DEBUG(10,("deleting configfile [%s]\n", s));
4290 unlink_internals(conn, 0, s);
4294 if ( *info_3->datafile ) {
4295 if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
4296 DEBUG(10,("deleting datafile [%s]\n", s));
4297 unlink_internals(conn, 0, s);
4301 if ( *info_3->helpfile ) {
4302 if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
4303 DEBUG(10,("deleting helpfile [%s]\n", s));
4304 unlink_internals(conn, 0, s);
4308 /* check if we are done removing files */
4310 if ( info_3->dependentfiles )
4312 while ( *info_3->dependentfiles[i] ) {
4313 char *file;
4315 /* bypass the "\print$" portion of the path */
4317 if ( (file = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL )
4319 DEBUG(10,("deleting dependent file [%s]\n", file));
4320 unlink_internals(conn, 0, file );
4323 i++;
4327 unbecome_user();
4329 return True;
4332 /****************************************************************************
4333 Remove a printer driver from the TDB. This assumes that the the driver was
4334 previously looked up.
4335 ***************************************************************************/
4337 WERROR delete_printer_driver( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3, struct current_user *user,
4338 uint32 version, BOOL delete_files )
4340 pstring key;
4341 fstring arch;
4342 TDB_DATA kbuf, dbuf;
4343 NT_PRINTER_DRIVER_INFO_LEVEL ctr;
4345 /* delete the tdb data first */
4347 get_short_archi(arch, info_3->environment);
4348 slprintf(key, sizeof(key)-1, "%s%s/%d/%s", DRIVERS_PREFIX,
4349 arch, version, info_3->name);
4351 DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
4352 key, delete_files ? "TRUE" : "FALSE" ));
4354 ctr.info_3 = info_3;
4355 dump_a_printer_driver( ctr, 3 );
4357 kbuf.dptr=key;
4358 kbuf.dsize=strlen(key)+1;
4360 /* check if the driver actually exists for this environment */
4362 dbuf = tdb_fetch( tdb_drivers, kbuf );
4363 if ( !dbuf.dptr ) {
4364 DEBUG(8,("delete_printer_driver: Driver unknown [%s]\n", key));
4365 return WERR_UNKNOWN_PRINTER_DRIVER;
4368 SAFE_FREE( dbuf.dptr );
4370 /* ok... the driver exists so the delete should return success */
4372 if (tdb_delete(tdb_drivers, kbuf) == -1) {
4373 DEBUG (0,("delete_printer_driver: fail to delete %s!\n", key));
4374 return WERR_ACCESS_DENIED;
4378 * now delete any associated files if delete_files == True
4379 * even if this part failes, we return succes because the
4380 * driver doesn not exist any more
4383 if ( delete_files )
4384 delete_driver_files( info_3, user );
4387 DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
4389 return WERR_OK;
4392 /****************************************************************************
4393 Store a security desc for a printer.
4394 ****************************************************************************/
4396 WERROR nt_printing_setsec(const char *printername, SEC_DESC_BUF *secdesc_ctr)
4398 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4399 SEC_DESC_BUF *old_secdesc_ctr = NULL;
4400 prs_struct ps;
4401 TALLOC_CTX *mem_ctx = NULL;
4402 fstring key;
4403 WERROR status;
4405 mem_ctx = talloc_init("nt_printing_setsec");
4406 if (mem_ctx == NULL)
4407 return WERR_NOMEM;
4409 /* The old owner and group sids of the security descriptor are not
4410 present when new ACEs are added or removed by changing printer
4411 permissions through NT. If they are NULL in the new security
4412 descriptor then copy them over from the old one. */
4414 if (!secdesc_ctr->sec->owner_sid || !secdesc_ctr->sec->grp_sid) {
4415 DOM_SID *owner_sid, *group_sid;
4416 SEC_ACL *dacl, *sacl;
4417 SEC_DESC *psd = NULL;
4418 size_t size;
4420 nt_printing_getsec(mem_ctx, printername, &old_secdesc_ctr);
4422 /* Pick out correct owner and group sids */
4424 owner_sid = secdesc_ctr->sec->owner_sid ?
4425 secdesc_ctr->sec->owner_sid :
4426 old_secdesc_ctr->sec->owner_sid;
4428 group_sid = secdesc_ctr->sec->grp_sid ?
4429 secdesc_ctr->sec->grp_sid :
4430 old_secdesc_ctr->sec->grp_sid;
4432 dacl = secdesc_ctr->sec->dacl ?
4433 secdesc_ctr->sec->dacl :
4434 old_secdesc_ctr->sec->dacl;
4436 sacl = secdesc_ctr->sec->sacl ?
4437 secdesc_ctr->sec->sacl :
4438 old_secdesc_ctr->sec->sacl;
4440 /* Make a deep copy of the security descriptor */
4442 psd = make_sec_desc(mem_ctx, secdesc_ctr->sec->revision,
4443 owner_sid, group_sid,
4444 sacl,
4445 dacl,
4446 &size);
4448 new_secdesc_ctr = make_sec_desc_buf(mem_ctx, size, psd);
4451 if (!new_secdesc_ctr) {
4452 new_secdesc_ctr = secdesc_ctr;
4455 /* Store the security descriptor in a tdb */
4457 prs_init(&ps, (uint32)sec_desc_size(new_secdesc_ctr->sec) +
4458 sizeof(SEC_DESC_BUF), mem_ctx, MARSHALL);
4460 if (!sec_io_desc_buf("nt_printing_setsec", &new_secdesc_ctr,
4461 &ps, 1)) {
4462 status = WERR_BADFUNC;
4463 goto out;
4466 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4468 if (tdb_prs_store(tdb_printers, key, &ps)==0) {
4469 status = WERR_OK;
4470 } else {
4471 DEBUG(1,("Failed to store secdesc for %s\n", printername));
4472 status = WERR_BADFUNC;
4475 /* Free malloc'ed memory */
4477 out:
4479 prs_mem_free(&ps);
4480 if (mem_ctx)
4481 talloc_destroy(mem_ctx);
4482 return status;
4485 /****************************************************************************
4486 Construct a default security descriptor buffer for a printer.
4487 ****************************************************************************/
4489 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
4491 SEC_ACE ace[3];
4492 SEC_ACCESS sa;
4493 SEC_ACL *psa = NULL;
4494 SEC_DESC_BUF *sdb = NULL;
4495 SEC_DESC *psd = NULL;
4496 DOM_SID owner_sid;
4497 size_t sd_size;
4499 /* Create an ACE where Everyone is allowed to print */
4501 init_sec_access(&sa, PRINTER_ACE_PRINT);
4502 init_sec_ace(&ace[0], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
4503 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4505 /* Make the security descriptor owned by the Administrators group
4506 on the PDC of the domain. */
4508 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4509 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4510 } else {
4512 /* Backup plan - make printer owned by admins.
4513 This should emulate a lanman printer as security
4514 settings can't be changed. */
4516 sid_copy(&owner_sid, get_global_sam_sid());
4517 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4520 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4521 init_sec_ace(&ace[1], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4522 sa, SEC_ACE_FLAG_OBJECT_INHERIT |
4523 SEC_ACE_FLAG_INHERIT_ONLY);
4525 init_sec_access(&sa, PRINTER_ACE_FULL_CONTROL);
4526 init_sec_ace(&ace[2], &owner_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
4527 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
4529 /* The ACL revision number in rpc_secdesc.h differs from the one
4530 created by NT when setting ACE entries in printer
4531 descriptors. NT4 complains about the property being edited by a
4532 NT5 machine. */
4534 if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, 3, ace)) != NULL) {
4535 psd = make_sec_desc(ctx, SEC_DESC_REVISION,
4536 &owner_sid, NULL,
4537 NULL, psa, &sd_size);
4540 if (!psd) {
4541 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
4542 return NULL;
4545 sdb = make_sec_desc_buf(ctx, sd_size, psd);
4547 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
4548 (unsigned int)sd_size));
4550 return sdb;
4553 /****************************************************************************
4554 Get a security desc for a printer.
4555 ****************************************************************************/
4557 BOOL nt_printing_getsec(TALLOC_CTX *ctx, const char *printername, SEC_DESC_BUF **secdesc_ctr)
4559 prs_struct ps;
4560 fstring key;
4561 char *temp;
4563 if (strlen(printername) > 2 && (temp = strchr(printername + 2, '\\')))
4564 printername = temp + 1;
4566 /* Fetch security descriptor from tdb */
4568 slprintf(key, sizeof(key)-1, "SECDESC/%s", printername);
4570 if (tdb_prs_fetch(tdb_printers, key, &ps, ctx)!=0 ||
4571 !sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1)) {
4573 DEBUG(4,("using default secdesc for %s\n", printername));
4575 if (!(*secdesc_ctr = construct_default_printer_sdb(ctx))) {
4576 return False;
4579 /* Save default security descriptor for later */
4581 prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
4582 sizeof(SEC_DESC_BUF), ctx, MARSHALL);
4584 if (sec_io_desc_buf("nt_printing_getsec", secdesc_ctr, &ps, 1))
4585 tdb_prs_store(tdb_printers, key, &ps);
4587 prs_mem_free(&ps);
4589 return True;
4592 /* If security descriptor is owned by S-1-1-0 and winbindd is up,
4593 this security descriptor has been created when winbindd was
4594 down. Take ownership of security descriptor. */
4596 if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
4597 DOM_SID owner_sid;
4599 /* Change sd owner to workgroup administrator */
4601 if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
4602 SEC_DESC_BUF *new_secdesc_ctr = NULL;
4603 SEC_DESC *psd = NULL;
4604 size_t size;
4606 /* Create new sd */
4608 sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
4610 psd = make_sec_desc(ctx, (*secdesc_ctr)->sec->revision,
4611 &owner_sid,
4612 (*secdesc_ctr)->sec->grp_sid,
4613 (*secdesc_ctr)->sec->sacl,
4614 (*secdesc_ctr)->sec->dacl,
4615 &size);
4617 new_secdesc_ctr = make_sec_desc_buf(ctx, size, psd);
4619 /* Swap with other one */
4621 *secdesc_ctr = new_secdesc_ctr;
4623 /* Set it */
4625 nt_printing_setsec(printername, *secdesc_ctr);
4629 if (DEBUGLEVEL >= 10) {
4630 SEC_ACL *the_acl = (*secdesc_ctr)->sec->dacl;
4631 int i;
4633 DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
4634 printername, the_acl->num_aces));
4636 for (i = 0; i < the_acl->num_aces; i++) {
4637 fstring sid_str;
4639 sid_to_string(sid_str, &the_acl->ace[i].trustee);
4641 DEBUG(10, ("%s %d %d 0x%08x\n", sid_str,
4642 the_acl->ace[i].type, the_acl->ace[i].flags,
4643 the_acl->ace[i].info.mask));
4647 prs_mem_free(&ps);
4648 return True;
4651 /* error code:
4652 0: everything OK
4653 1: level not implemented
4654 2: file doesn't exist
4655 3: can't allocate memory
4656 4: can't free memory
4657 5: non existant struct
4661 A printer and a printer driver are 2 different things.
4662 NT manages them separatelly, Samba does the same.
4663 Why ? Simply because it's easier and it makes sense !
4665 Now explanation: You have 3 printers behind your samba server,
4666 2 of them are the same make and model (laser A and B). But laser B
4667 has an 3000 sheet feeder and laser A doesn't such an option.
4668 Your third printer is an old dot-matrix model for the accounting :-).
4670 If the /usr/local/samba/lib directory (default dir), you will have
4671 5 files to describe all of this.
4673 3 files for the printers (1 by printer):
4674 NTprinter_laser A
4675 NTprinter_laser B
4676 NTprinter_accounting
4677 2 files for the drivers (1 for the laser and 1 for the dot matrix)
4678 NTdriver_printer model X
4679 NTdriver_printer model Y
4681 jfm: I should use this comment for the text file to explain
4682 same thing for the forms BTW.
4683 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
4687 /* Convert generic access rights to printer object specific access rights.
4688 It turns out that NT4 security descriptors use generic access rights and
4689 NT5 the object specific ones. */
4691 void map_printer_permissions(SEC_DESC *sd)
4693 int i;
4695 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
4696 se_map_generic(&sd->dacl->ace[i].info.mask,
4697 &printer_generic_mapping);
4701 /****************************************************************************
4702 Check a user has permissions to perform the given operation. We use the
4703 permission constants defined in include/rpc_spoolss.h to check the various
4704 actions we perform when checking printer access.
4706 PRINTER_ACCESS_ADMINISTER:
4707 print_queue_pause, print_queue_resume, update_printer_sec,
4708 update_printer, spoolss_addprinterex_level_2,
4709 _spoolss_setprinterdata
4711 PRINTER_ACCESS_USE:
4712 print_job_start
4714 JOB_ACCESS_ADMINISTER:
4715 print_job_delete, print_job_pause, print_job_resume,
4716 print_queue_purge
4718 ****************************************************************************/
4719 BOOL print_access_check(struct current_user *user, int snum, int access_type)
4721 SEC_DESC_BUF *secdesc = NULL;
4722 uint32 access_granted;
4723 NTSTATUS status;
4724 BOOL result;
4725 const char *pname;
4726 TALLOC_CTX *mem_ctx = NULL;
4727 extern struct current_user current_user;
4729 /* If user is NULL then use the current_user structure */
4731 if (!user)
4732 user = &current_user;
4734 /* Always allow root or printer admins to do anything */
4736 if (user->uid == 0 ||
4737 user_in_list(uidtoname(user->uid), lp_printer_admin(snum))) {
4738 return True;
4741 /* Get printer name */
4743 pname = PRINTERNAME(snum);
4745 if (!pname || !*pname) {
4746 errno = EACCES;
4747 return False;
4750 /* Get printer security descriptor */
4752 if(!(mem_ctx = talloc_init("print_access_check"))) {
4753 errno = ENOMEM;
4754 return False;
4757 nt_printing_getsec(mem_ctx, pname, &secdesc);
4759 if (access_type == JOB_ACCESS_ADMINISTER) {
4760 SEC_DESC_BUF *parent_secdesc = secdesc;
4762 /* Create a child security descriptor to check permissions
4763 against. This is because print jobs are child objects
4764 objects of a printer. */
4766 secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sec, False);
4768 /* Now this is the bit that really confuses me. The access
4769 type needs to be changed from JOB_ACCESS_ADMINISTER to
4770 PRINTER_ACCESS_ADMINISTER for this to work. Something
4771 to do with the child (job) object becoming like a
4772 printer?? -tpot */
4774 access_type = PRINTER_ACCESS_ADMINISTER;
4777 /* Check access */
4779 map_printer_permissions(secdesc->sec);
4781 result = se_access_check(secdesc->sec, user->nt_user_token, access_type,
4782 &access_granted, &status);
4784 DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
4786 talloc_destroy(mem_ctx);
4788 if (!result)
4789 errno = EACCES;
4791 return result;
4794 /****************************************************************************
4795 Check the time parameters allow a print operation.
4796 *****************************************************************************/
4798 BOOL print_time_access_check(int snum)
4800 NT_PRINTER_INFO_LEVEL *printer = NULL;
4801 BOOL ok = False;
4802 time_t now = time(NULL);
4803 struct tm *t;
4804 uint32 mins;
4806 if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
4807 return False;
4809 if (printer->info_2->starttime == 0 && printer->info_2->untiltime == 0)
4810 ok = True;
4812 t = gmtime(&now);
4813 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
4815 if (mins >= printer->info_2->starttime && mins <= printer->info_2->untiltime)
4816 ok = True;
4818 free_a_printer(&printer, 2);
4820 if (!ok)
4821 errno = EACCES;
4823 return ok;