libcli/smb: move smb2cli_close.c from source3 to the toplevel
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blob96947f199bc05198c9dfdd4da4c05aecf3da0bc9
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 /****************************************************************************
78 Open the NT printing tdbs. Done once before fork().
79 ****************************************************************************/
81 bool nt_printing_init(struct messaging_context *msg_ctx)
83 WERROR win_rc;
85 if (!nt_printing_tdb_upgrade()) {
86 return false;
90 * register callback to handle updating printers as new
91 * drivers are installed
93 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
94 do_drv_upgrade_printer);
96 /* of course, none of the message callbacks matter if you don't
97 tell messages.c that you interested in receiving PRINT_GENERAL
98 msgs. This is done in serverid_register() */
100 if ( lp_security() == SEC_ADS ) {
101 win_rc = check_published_printers(msg_ctx);
102 if (!W_ERROR_IS_OK(win_rc))
103 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
106 return true;
109 /*******************************************************************
110 Function to allow filename parsing "the old way".
111 ********************************************************************/
113 static NTSTATUS driver_unix_convert(connection_struct *conn,
114 const char *old_name,
115 struct smb_filename **smb_fname)
117 NTSTATUS status;
118 TALLOC_CTX *ctx = talloc_tos();
119 char *name = talloc_strdup(ctx, old_name);
121 if (!name) {
122 return NT_STATUS_NO_MEMORY;
124 unix_format(name);
125 name = unix_clean_name(ctx, name);
126 if (!name) {
127 return NT_STATUS_NO_MEMORY;
129 trim_string(name,"/","/");
131 status = unix_convert(ctx, conn, name, smb_fname, 0);
132 if (!NT_STATUS_IS_OK(status)) {
133 return NT_STATUS_NO_MEMORY;
136 return NT_STATUS_OK;
139 /****************************************************************************
140 Function to do the mapping between the long architecture name and
141 the short one.
142 ****************************************************************************/
144 const char *get_short_archi(const char *long_archi)
146 int i=-1;
148 DEBUG(107,("Getting architecture dependent directory\n"));
149 do {
150 i++;
151 } while ( (archi_table[i].long_archi!=NULL ) &&
152 strcasecmp_m(long_archi, archi_table[i].long_archi) );
154 if (archi_table[i].long_archi==NULL) {
155 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
156 return NULL;
159 /* this might be client code - but shouldn't this be an fstrcpy etc? */
161 DEBUGADD(108,("index: [%d]\n", i));
162 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
163 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
165 return archi_table[i].short_archi;
168 /****************************************************************************
169 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
170 There are two case to be covered here: PE (Portable Executable) and NE (New
171 Executable) files. Both files support the same INFO structure, but PE files
172 store the signature in unicode, and NE files store it as !unicode.
173 returns -1 on error, 1 on version info found, and 0 on no version info found.
174 ****************************************************************************/
176 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
178 int i;
179 char *buf = NULL;
180 ssize_t byte_count;
182 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
183 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
184 fname, DOS_HEADER_SIZE));
185 goto error_exit;
188 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
189 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
190 fname, (unsigned long)byte_count));
191 goto no_version_info;
194 /* Is this really a DOS header? */
195 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
196 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
197 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
198 goto no_version_info;
201 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
202 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
203 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
204 fname, errno));
205 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
206 goto no_version_info;
209 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
210 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
211 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
212 fname, (unsigned long)byte_count));
213 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
214 goto no_version_info;
217 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
218 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
219 unsigned int num_sections;
220 unsigned int section_table_bytes;
222 /* Just skip over optional header to get to section table */
223 if (SMB_VFS_LSEEK(fsp,
224 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
225 SEEK_CUR) == (off_t)-1) {
226 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
227 fname, errno));
228 goto error_exit;
231 /* get the section table */
232 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
233 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
234 if (section_table_bytes == 0)
235 goto error_exit;
237 SAFE_FREE(buf);
238 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
239 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
240 fname, section_table_bytes));
241 goto error_exit;
244 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
245 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
246 fname, (unsigned long)byte_count));
247 goto error_exit;
250 /* Iterate the section table looking for the resource section ".rsrc" */
251 for (i = 0; i < num_sections; i++) {
252 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
254 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
255 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
256 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
258 if (section_bytes == 0)
259 goto error_exit;
261 SAFE_FREE(buf);
262 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
263 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
264 fname, section_bytes));
265 goto error_exit;
268 /* Seek to the start of the .rsrc section info */
269 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
270 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
271 fname, errno));
272 goto error_exit;
275 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
276 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
277 fname, (unsigned long)byte_count));
278 goto error_exit;
281 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
282 goto error_exit;
284 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
285 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
286 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
287 /* Align to next long address */
288 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
290 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
291 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
292 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
294 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
295 fname, *major, *minor,
296 (*major>>16)&0xffff, *major&0xffff,
297 (*minor>>16)&0xffff, *minor&0xffff));
298 SAFE_FREE(buf);
299 return 1;
306 /* Version info not found, fall back to origin date/time */
307 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
308 SAFE_FREE(buf);
309 return 0;
311 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
312 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
313 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
314 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
315 /* At this point, we assume the file is in error. It still could be somthing
316 * else besides a NE file, but it unlikely at this point. */
317 goto error_exit;
320 /* Allocate a bit more space to speed up things */
321 SAFE_FREE(buf);
322 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
323 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
324 fname, PE_HEADER_SIZE));
325 goto error_exit;
328 /* This is a HACK! I got tired of trying to sort through the messy
329 * 'NE' file format. If anyone wants to clean this up please have at
330 * it, but this works. 'NE' files will eventually fade away. JRR */
331 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
332 /* Cover case that should not occur in a well formed 'NE' .dll file */
333 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
335 for(i=0; i<byte_count; i++) {
336 /* Fast skip past data that can't possibly match */
337 if (buf[i] != 'V') continue;
339 /* Potential match data crosses buf boundry, move it to beginning
340 * of buf, and fill the buf with as much as it will hold. */
341 if (i>byte_count-VS_VERSION_INFO_SIZE) {
342 int bc;
344 memcpy(buf, &buf[i], byte_count-i);
345 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
346 (byte_count-i))) < 0) {
348 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
349 fname, errno));
350 goto error_exit;
353 byte_count = bc + (byte_count - i);
354 if (byte_count<VS_VERSION_INFO_SIZE) break;
356 i = 0;
359 /* Check that the full signature string and the magic number that
360 * follows exist (not a perfect solution, but the chances that this
361 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
362 * twice, as it is simpler to read the code. */
363 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
364 /* Compute skip alignment to next long address */
365 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
366 sizeof(VS_SIGNATURE)) & 3;
367 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
369 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
370 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
371 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
372 fname, *major, *minor,
373 (*major>>16)&0xffff, *major&0xffff,
374 (*minor>>16)&0xffff, *minor&0xffff));
375 SAFE_FREE(buf);
376 return 1;
381 /* Version info not found, fall back to origin date/time */
382 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
383 SAFE_FREE(buf);
384 return 0;
386 } else
387 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
388 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
389 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
391 no_version_info:
392 SAFE_FREE(buf);
393 return 0;
395 error_exit:
396 SAFE_FREE(buf);
397 return -1;
400 /****************************************************************************
401 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
402 share one or more files. During the MS installation process files are checked
403 to insure that only a newer version of a shared file is installed over an
404 older version. There are several possibilities for this comparison. If there
405 is no previous version, the new one is newer (obviously). If either file is
406 missing the version info structure, compare the creation date (on Unix use
407 the modification date). Otherwise chose the numerically larger version number.
408 ****************************************************************************/
410 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
412 bool use_version = true;
414 uint32 new_major;
415 uint32 new_minor;
416 time_t new_create_time;
418 uint32 old_major;
419 uint32 old_minor;
420 time_t old_create_time;
422 struct smb_filename *smb_fname = NULL;
423 files_struct *fsp = NULL;
424 SMB_STRUCT_STAT st;
426 NTSTATUS status;
427 int ret;
429 SET_STAT_INVALID(st);
430 new_create_time = (time_t)0;
431 old_create_time = (time_t)0;
433 /* Get file version info (if available) for previous file (if it exists) */
434 status = driver_unix_convert(conn, old_file, &smb_fname);
435 if (!NT_STATUS_IS_OK(status)) {
436 goto error_exit;
439 status = SMB_VFS_CREATE_FILE(
440 conn, /* conn */
441 NULL, /* req */
442 0, /* root_dir_fid */
443 smb_fname, /* fname */
444 FILE_GENERIC_READ, /* access_mask */
445 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
446 FILE_OPEN, /* create_disposition*/
447 0, /* create_options */
448 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
449 INTERNAL_OPEN_ONLY, /* oplock_request */
450 0, /* allocation_size */
451 0, /* private_flags */
452 NULL, /* sd */
453 NULL, /* ea_list */
454 &fsp, /* result */
455 NULL); /* pinfo */
457 if (!NT_STATUS_IS_OK(status)) {
458 /* Old file not found, so by definition new file is in fact newer */
459 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
460 "errno = %d\n", smb_fname_str_dbg(smb_fname),
461 errno));
462 ret = 1;
463 goto done;
465 } else {
466 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
467 if (ret == -1) {
468 goto error_exit;
471 if (!ret) {
472 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
473 old_file));
474 use_version = false;
475 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
476 goto error_exit;
478 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
479 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
480 (long)old_create_time));
483 close_file(NULL, fsp, NORMAL_CLOSE);
484 fsp = NULL;
486 /* Get file version info (if available) for new file */
487 status = driver_unix_convert(conn, new_file, &smb_fname);
488 if (!NT_STATUS_IS_OK(status)) {
489 goto error_exit;
492 status = SMB_VFS_CREATE_FILE(
493 conn, /* conn */
494 NULL, /* req */
495 0, /* root_dir_fid */
496 smb_fname, /* fname */
497 FILE_GENERIC_READ, /* access_mask */
498 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
499 FILE_OPEN, /* create_disposition*/
500 0, /* create_options */
501 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
502 INTERNAL_OPEN_ONLY, /* oplock_request */
503 0, /* allocation_size */
504 0, /* private_flags */
505 NULL, /* sd */
506 NULL, /* ea_list */
507 &fsp, /* result */
508 NULL); /* pinfo */
510 if (!NT_STATUS_IS_OK(status)) {
511 /* New file not found, this shouldn't occur if the caller did its job */
512 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
513 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
514 goto error_exit;
516 } else {
517 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
518 if (ret == -1) {
519 goto error_exit;
522 if (!ret) {
523 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
524 new_file));
525 use_version = false;
526 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
527 goto error_exit;
529 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
530 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
531 (long)new_create_time));
534 close_file(NULL, fsp, NORMAL_CLOSE);
535 fsp = NULL;
537 if (use_version && (new_major != old_major || new_minor != old_minor)) {
538 /* Compare versions and choose the larger version number */
539 if (new_major > old_major ||
540 (new_major == old_major && new_minor > old_minor)) {
542 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
543 ret = 1;
544 goto done;
546 else {
547 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
548 ret = 0;
549 goto done;
552 } else {
553 /* Compare modification time/dates and choose the newest time/date */
554 if (new_create_time > old_create_time) {
555 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
556 ret = 1;
557 goto done;
559 else {
560 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
561 ret = 0;
562 goto done;
566 error_exit:
567 if(fsp)
568 close_file(NULL, fsp, NORMAL_CLOSE);
569 ret = -1;
570 done:
571 TALLOC_FREE(smb_fname);
572 return ret;
575 /****************************************************************************
576 Determine the correct cVersion associated with an architecture and driver
577 ****************************************************************************/
578 static uint32 get_correct_cversion(struct auth_session_info *session_info,
579 const char *architecture,
580 const char *driverpath_in,
581 WERROR *perr)
583 int cversion = -1;
584 NTSTATUS nt_status;
585 struct smb_filename *smb_fname = NULL;
586 char *driverpath = NULL;
587 files_struct *fsp = NULL;
588 connection_struct *conn = NULL;
589 char *oldcwd;
590 char *printdollar = NULL;
591 int printdollar_snum;
593 *perr = WERR_INVALID_PARAM;
595 /* If architecture is Windows 95/98/ME, the version is always 0. */
596 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
597 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
598 *perr = WERR_OK;
599 return 0;
602 /* If architecture is Windows x64, the version is always 3. */
603 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
604 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
605 *perr = WERR_OK;
606 return 3;
609 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
610 if (!printdollar) {
611 *perr = WERR_NOMEM;
612 return -1;
614 if (printdollar_snum == -1) {
615 *perr = WERR_NO_SUCH_SHARE;
616 return -1;
619 nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
620 printdollar_snum,
621 lp_pathname(printdollar_snum),
622 session_info, &oldcwd);
623 if (!NT_STATUS_IS_OK(nt_status)) {
624 DEBUG(0,("get_correct_cversion: create_conn_struct "
625 "returned %s\n", nt_errstr(nt_status)));
626 *perr = ntstatus_to_werror(nt_status);
627 return -1;
630 nt_status = set_conn_force_user_group(conn, printdollar_snum);
631 if (!NT_STATUS_IS_OK(nt_status)) {
632 DEBUG(0, ("failed set force user / group\n"));
633 *perr = ntstatus_to_werror(nt_status);
634 goto error_free_conn;
637 if (!become_user_by_session(conn, session_info)) {
638 DEBUG(0, ("failed to become user\n"));
639 *perr = WERR_ACCESS_DENIED;
640 goto error_free_conn;
643 /* Open the driver file (Portable Executable format) and determine the
644 * deriver the cversion. */
645 driverpath = talloc_asprintf(talloc_tos(),
646 "%s/%s",
647 architecture,
648 driverpath_in);
649 if (!driverpath) {
650 *perr = WERR_NOMEM;
651 goto error_exit;
654 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
655 if (!NT_STATUS_IS_OK(nt_status)) {
656 *perr = ntstatus_to_werror(nt_status);
657 goto error_exit;
660 nt_status = vfs_file_exist(conn, smb_fname);
661 if (!NT_STATUS_IS_OK(nt_status)) {
662 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
663 *perr = WERR_BADFILE;
664 goto error_exit;
667 nt_status = SMB_VFS_CREATE_FILE(
668 conn, /* conn */
669 NULL, /* req */
670 0, /* root_dir_fid */
671 smb_fname, /* fname */
672 FILE_GENERIC_READ, /* access_mask */
673 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
674 FILE_OPEN, /* create_disposition*/
675 0, /* create_options */
676 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
677 INTERNAL_OPEN_ONLY, /* oplock_request */
678 0, /* private_flags */
679 0, /* allocation_size */
680 NULL, /* sd */
681 NULL, /* ea_list */
682 &fsp, /* result */
683 NULL); /* pinfo */
685 if (!NT_STATUS_IS_OK(nt_status)) {
686 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
687 "%d\n", smb_fname_str_dbg(smb_fname), errno));
688 *perr = WERR_ACCESS_DENIED;
689 goto error_exit;
690 } else {
691 uint32 major;
692 uint32 minor;
693 int ret;
695 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
696 if (ret == -1) {
697 *perr = WERR_INVALID_PARAM;
698 goto error_exit;
699 } else if (!ret) {
700 DEBUG(6,("get_correct_cversion: Version info not "
701 "found [%s]\n",
702 smb_fname_str_dbg(smb_fname)));
703 *perr = WERR_INVALID_PARAM;
704 goto error_exit;
708 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
709 * for more details. Version in this case is not just the version of the
710 * file, but the version in the sense of kernal mode (2) vs. user mode
711 * (3) drivers. Other bits of the version fields are the version info.
712 * JRR 010716
714 cversion = major & 0x0000ffff;
715 switch (cversion) {
716 case 2: /* WinNT drivers */
717 case 3: /* Win2K drivers */
718 break;
720 default:
721 DEBUG(6,("get_correct_cversion: cversion "
722 "invalid [%s] cversion = %d\n",
723 smb_fname_str_dbg(smb_fname),
724 cversion));
725 goto error_exit;
728 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
729 " = 0x%x minor = 0x%x\n",
730 smb_fname_str_dbg(smb_fname), major, minor));
733 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
734 smb_fname_str_dbg(smb_fname), cversion));
735 *perr = WERR_OK;
737 error_exit:
738 unbecome_user();
739 error_free_conn:
740 TALLOC_FREE(smb_fname);
741 if (fsp != NULL) {
742 close_file(NULL, fsp, NORMAL_CLOSE);
744 if (conn != NULL) {
745 vfs_ChDir(conn, oldcwd);
746 SMB_VFS_DISCONNECT(conn);
747 conn_free(conn);
749 if (!W_ERROR_IS_OK(*perr)) {
750 cversion = -1;
753 return cversion;
756 /****************************************************************************
757 ****************************************************************************/
759 #define strip_driver_path(_mem_ctx, _element) do { \
760 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
761 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
762 W_ERROR_HAVE_NO_MEMORY((_element)); \
764 } while (0);
766 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
767 struct auth_session_info *session_info,
768 const char *architecture,
769 const char **driver_path,
770 const char **data_file,
771 const char **config_file,
772 const char **help_file,
773 struct spoolss_StringArray *dependent_files,
774 enum spoolss_DriverOSVersion *version)
776 const char *short_architecture;
777 int i;
778 WERROR err;
779 char *_p;
781 if (!*driver_path || !*data_file) {
782 return WERR_INVALID_PARAM;
785 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
786 return WERR_INVALID_PARAM;
789 /* clean up the driver name.
790 * we can get .\driver.dll
791 * or worse c:\windows\system\driver.dll !
793 /* using an intermediate string to not have overlaping memcpy()'s */
795 strip_driver_path(mem_ctx, *driver_path);
796 strip_driver_path(mem_ctx, *data_file);
797 if (*config_file) {
798 strip_driver_path(mem_ctx, *config_file);
800 if (help_file) {
801 strip_driver_path(mem_ctx, *help_file);
804 if (dependent_files && dependent_files->string) {
805 for (i=0; dependent_files->string[i]; i++) {
806 strip_driver_path(mem_ctx, dependent_files->string[i]);
810 short_architecture = get_short_archi(architecture);
811 if (!short_architecture) {
812 return WERR_UNKNOWN_PRINTER_DRIVER;
815 /* jfm:7/16/2000 the client always sends the cversion=0.
816 * The server should check which version the driver is by reading
817 * the PE header of driver->driverpath.
819 * For Windows 95/98 the version is 0 (so the value sent is correct)
820 * For Windows NT (the architecture doesn't matter)
821 * NT 3.1: cversion=0
822 * NT 3.5/3.51: cversion=1
823 * NT 4: cversion=2
824 * NT2K: cversion=3
827 *version = get_correct_cversion(session_info, short_architecture,
828 *driver_path, &err);
829 if (*version == -1) {
830 return err;
833 return WERR_OK;
836 /****************************************************************************
837 ****************************************************************************/
839 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
840 struct auth_session_info *session_info,
841 struct spoolss_AddDriverInfoCtr *r)
843 switch (r->level) {
844 case 3:
845 return clean_up_driver_struct_level(mem_ctx, session_info,
846 r->info.info3->architecture,
847 &r->info.info3->driver_path,
848 &r->info.info3->data_file,
849 &r->info.info3->config_file,
850 &r->info.info3->help_file,
851 r->info.info3->dependent_files,
852 &r->info.info3->version);
853 case 6:
854 return clean_up_driver_struct_level(mem_ctx, session_info,
855 r->info.info6->architecture,
856 &r->info.info6->driver_path,
857 &r->info.info6->data_file,
858 &r->info.info6->config_file,
859 &r->info.info6->help_file,
860 r->info.info6->dependent_files,
861 &r->info.info6->version);
862 default:
863 return WERR_NOT_SUPPORTED;
867 /****************************************************************************
868 This function sucks and should be replaced. JRA.
869 ****************************************************************************/
871 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
872 const struct spoolss_AddDriverInfo6 *src)
874 dst->version = src->version;
876 dst->driver_name = src->driver_name;
877 dst->architecture = src->architecture;
878 dst->driver_path = src->driver_path;
879 dst->data_file = src->data_file;
880 dst->config_file = src->config_file;
881 dst->help_file = src->help_file;
882 dst->monitor_name = src->monitor_name;
883 dst->default_datatype = src->default_datatype;
884 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
885 dst->dependent_files = src->dependent_files;
888 /****************************************************************************
889 ****************************************************************************/
891 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
892 connection_struct *conn,
893 const char *driver_file,
894 const char *short_architecture,
895 uint32_t driver_version,
896 uint32_t version)
898 struct smb_filename *smb_fname_old = NULL;
899 struct smb_filename *smb_fname_new = NULL;
900 char *old_name = NULL;
901 char *new_name = NULL;
902 NTSTATUS status;
903 WERROR ret;
905 old_name = talloc_asprintf(mem_ctx, "%s/%s",
906 short_architecture, driver_file);
907 W_ERROR_HAVE_NO_MEMORY(old_name);
909 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
910 short_architecture, driver_version, driver_file);
911 if (new_name == NULL) {
912 TALLOC_FREE(old_name);
913 return WERR_NOMEM;
916 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
918 status = driver_unix_convert(conn, old_name, &smb_fname_old);
919 if (!NT_STATUS_IS_OK(status)) {
920 ret = WERR_NOMEM;
921 goto out;
924 /* Setup a synthetic smb_filename struct */
925 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
926 if (!smb_fname_new) {
927 ret = WERR_NOMEM;
928 goto out;
931 smb_fname_new->base_name = new_name;
933 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
934 "'%s'\n", smb_fname_old->base_name,
935 smb_fname_new->base_name));
937 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
938 OPENX_FILE_EXISTS_TRUNCATE |
939 OPENX_FILE_CREATE_IF_NOT_EXIST,
940 0, false);
942 if (!NT_STATUS_IS_OK(status)) {
943 DEBUG(0,("move_driver_file_to_download_area: Unable "
944 "to rename [%s] to [%s]: %s\n",
945 smb_fname_old->base_name, new_name,
946 nt_errstr(status)));
947 ret = WERR_ACCESS_DENIED;
948 goto out;
952 ret = WERR_OK;
953 out:
954 TALLOC_FREE(smb_fname_old);
955 TALLOC_FREE(smb_fname_new);
956 return ret;
959 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
960 struct spoolss_AddDriverInfoCtr *r)
962 struct spoolss_AddDriverInfo3 *driver;
963 struct spoolss_AddDriverInfo3 converted_driver;
964 const char *short_architecture;
965 struct smb_filename *smb_dname = NULL;
966 char *new_dir = NULL;
967 connection_struct *conn = NULL;
968 NTSTATUS nt_status;
969 int i;
970 TALLOC_CTX *ctx = talloc_tos();
971 int ver = 0;
972 char *oldcwd;
973 char *printdollar = NULL;
974 int printdollar_snum;
975 WERROR err = WERR_OK;
977 switch (r->level) {
978 case 3:
979 driver = r->info.info3;
980 break;
981 case 6:
982 convert_level_6_to_level3(&converted_driver, r->info.info6);
983 driver = &converted_driver;
984 break;
985 default:
986 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
987 return WERR_UNKNOWN_LEVEL;
990 short_architecture = get_short_archi(driver->architecture);
991 if (!short_architecture) {
992 return WERR_UNKNOWN_PRINTER_DRIVER;
995 printdollar_snum = find_service(ctx, "print$", &printdollar);
996 if (!printdollar) {
997 return WERR_NOMEM;
999 if (printdollar_snum == -1) {
1000 return WERR_NO_SUCH_SHARE;
1003 nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1004 printdollar_snum,
1005 lp_pathname(printdollar_snum),
1006 session_info, &oldcwd);
1007 if (!NT_STATUS_IS_OK(nt_status)) {
1008 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1009 "returned %s\n", nt_errstr(nt_status)));
1010 err = ntstatus_to_werror(nt_status);
1011 return err;
1014 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1015 if (!NT_STATUS_IS_OK(nt_status)) {
1016 DEBUG(0, ("failed set force user / group\n"));
1017 err = ntstatus_to_werror(nt_status);
1018 goto err_free_conn;
1021 if (!become_user_by_session(conn, session_info)) {
1022 DEBUG(0, ("failed to become user\n"));
1023 err = WERR_ACCESS_DENIED;
1024 goto err_free_conn;
1027 new_dir = talloc_asprintf(ctx,
1028 "%s/%d",
1029 short_architecture,
1030 driver->version);
1031 if (!new_dir) {
1032 err = WERR_NOMEM;
1033 goto err_exit;
1035 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1036 if (!NT_STATUS_IS_OK(nt_status)) {
1037 err = WERR_NOMEM;
1038 goto err_exit;
1041 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1043 nt_status = create_directory(conn, NULL, smb_dname);
1044 if (!NT_STATUS_IS_OK(nt_status)
1045 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1046 DEBUG(0, ("failed to create driver destination directory: %s\n",
1047 nt_errstr(nt_status)));
1048 err = ntstatus_to_werror(nt_status);
1049 goto err_exit;
1052 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1053 * listed for this driver which has already been moved, skip it (note:
1054 * drivers may list the same file name several times. Then check if the
1055 * file already exists in archi\version\, if so, check that the version
1056 * info (or time stamps if version info is unavailable) is newer (or the
1057 * date is later). If it is, move it to archi\version\filexxx.yyy.
1058 * Otherwise, delete the file.
1060 * If a file is not moved to archi\version\ because of an error, all the
1061 * rest of the 'unmoved' driver files are removed from archi\. If one or
1062 * more of the driver's files was already moved to archi\version\, it
1063 * potentially leaves the driver in a partially updated state. Version
1064 * trauma will most likely occur if an client attempts to use any printer
1065 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1066 * done is appropriate... later JRR
1069 DEBUG(5,("Moving files now !\n"));
1071 if (driver->driver_path && strlen(driver->driver_path)) {
1073 err = move_driver_file_to_download_area(ctx,
1074 conn,
1075 driver->driver_path,
1076 short_architecture,
1077 driver->version,
1078 ver);
1079 if (!W_ERROR_IS_OK(err)) {
1080 goto err_exit;
1084 if (driver->data_file && strlen(driver->data_file)) {
1085 if (!strequal(driver->data_file, driver->driver_path)) {
1087 err = move_driver_file_to_download_area(ctx,
1088 conn,
1089 driver->data_file,
1090 short_architecture,
1091 driver->version,
1092 ver);
1093 if (!W_ERROR_IS_OK(err)) {
1094 goto err_exit;
1099 if (driver->config_file && strlen(driver->config_file)) {
1100 if (!strequal(driver->config_file, driver->driver_path) &&
1101 !strequal(driver->config_file, driver->data_file)) {
1103 err = move_driver_file_to_download_area(ctx,
1104 conn,
1105 driver->config_file,
1106 short_architecture,
1107 driver->version,
1108 ver);
1109 if (!W_ERROR_IS_OK(err)) {
1110 goto err_exit;
1115 if (driver->help_file && strlen(driver->help_file)) {
1116 if (!strequal(driver->help_file, driver->driver_path) &&
1117 !strequal(driver->help_file, driver->data_file) &&
1118 !strequal(driver->help_file, driver->config_file)) {
1120 err = move_driver_file_to_download_area(ctx,
1121 conn,
1122 driver->help_file,
1123 short_architecture,
1124 driver->version,
1125 ver);
1126 if (!W_ERROR_IS_OK(err)) {
1127 goto err_exit;
1132 if (driver->dependent_files && driver->dependent_files->string) {
1133 for (i=0; driver->dependent_files->string[i]; i++) {
1134 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1135 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1136 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1137 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1138 int j;
1139 for (j=0; j < i; j++) {
1140 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1141 goto NextDriver;
1145 err = move_driver_file_to_download_area(ctx,
1146 conn,
1147 driver->dependent_files->string[i],
1148 short_architecture,
1149 driver->version,
1150 ver);
1151 if (!W_ERROR_IS_OK(err)) {
1152 goto err_exit;
1155 NextDriver: ;
1159 err = WERR_OK;
1160 err_exit:
1161 unbecome_user();
1162 err_free_conn:
1163 TALLOC_FREE(smb_dname);
1165 if (conn != NULL) {
1166 vfs_ChDir(conn, oldcwd);
1167 SMB_VFS_DISCONNECT(conn);
1168 conn_free(conn);
1171 return err;
1174 /****************************************************************************
1175 Determine whether or not a particular driver is currently assigned
1176 to a printer
1177 ****************************************************************************/
1179 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1180 struct dcerpc_binding_handle *b,
1181 const struct spoolss_DriverInfo8 *r)
1183 int snum;
1184 int n_services = lp_numservices();
1185 bool in_use = False;
1186 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1187 WERROR result;
1189 if (!r) {
1190 return false;
1193 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1195 /* loop through the printers.tdb and check for the drivername */
1197 for (snum=0; snum<n_services && !in_use; snum++) {
1198 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1199 continue;
1202 result = winreg_get_printer(mem_ctx, b,
1203 lp_servicename(snum),
1204 &pinfo2);
1205 if (!W_ERROR_IS_OK(result)) {
1206 continue; /* skip */
1209 if (strequal(r->driver_name, pinfo2->drivername)) {
1210 in_use = True;
1213 TALLOC_FREE(pinfo2);
1216 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1218 if ( in_use ) {
1219 struct spoolss_DriverInfo8 *driver;
1220 WERROR werr;
1222 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1224 /* we can still remove the driver if there is one of
1225 "Windows NT x86" version 2 or 3 left */
1227 if (!strequal("Windows NT x86", r->architecture)) {
1228 werr = winreg_get_driver(mem_ctx, b,
1229 "Windows NT x86",
1230 r->driver_name,
1231 DRIVER_ANY_VERSION,
1232 &driver);
1233 } else if (r->version == 2) {
1234 werr = winreg_get_driver(mem_ctx, b,
1235 "Windows NT x86",
1236 r->driver_name,
1237 3, &driver);
1238 } else if (r->version == 3) {
1239 werr = winreg_get_driver(mem_ctx, b,
1240 "Windows NT x86",
1241 r->driver_name,
1242 2, &driver);
1243 } else {
1244 DEBUG(0, ("printer_driver_in_use: ERROR!"
1245 " unknown driver version (%d)\n",
1246 r->version));
1247 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1250 /* now check the error code */
1252 if ( W_ERROR_IS_OK(werr) ) {
1253 /* it's ok to remove the driver, we have other architctures left */
1254 in_use = False;
1255 talloc_free(driver);
1259 /* report that the driver is not in use by default */
1261 return in_use;
1265 /**********************************************************************
1266 Check to see if a ogiven file is in use by *info
1267 *********************************************************************/
1269 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1271 int i = 0;
1273 if ( !info )
1274 return False;
1276 /* mz: skip files that are in the list but already deleted */
1277 if (!file || !file[0]) {
1278 return false;
1281 if (strequal(file, info->driver_path))
1282 return True;
1284 if (strequal(file, info->data_file))
1285 return True;
1287 if (strequal(file, info->config_file))
1288 return True;
1290 if (strequal(file, info->help_file))
1291 return True;
1293 /* see of there are any dependent files to examine */
1295 if (!info->dependent_files)
1296 return False;
1298 while (info->dependent_files[i] && *info->dependent_files[i]) {
1299 if (strequal(file, info->dependent_files[i]))
1300 return True;
1301 i++;
1304 return False;
1308 /**********************************************************************
1309 Utility function to remove the dependent file pointed to by the
1310 input parameter from the list
1311 *********************************************************************/
1313 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1316 /* bump everything down a slot */
1318 while (files && files[idx+1]) {
1319 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1320 idx++;
1323 files[idx] = NULL;
1325 return;
1328 /**********************************************************************
1329 Check if any of the files used by src are also used by drv
1330 *********************************************************************/
1332 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1333 struct spoolss_DriverInfo8 *src,
1334 const struct spoolss_DriverInfo8 *drv)
1336 bool in_use = False;
1337 int i = 0;
1339 if ( !src || !drv )
1340 return False;
1342 /* check each file. Remove it from the src structure if it overlaps */
1344 if (drv_file_in_use(src->driver_path, drv)) {
1345 in_use = True;
1346 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1347 src->driver_path = talloc_strdup(mem_ctx, "");
1348 if (!src->driver_path) { return false; }
1351 if (drv_file_in_use(src->data_file, drv)) {
1352 in_use = True;
1353 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1354 src->data_file = talloc_strdup(mem_ctx, "");
1355 if (!src->data_file) { return false; }
1358 if (drv_file_in_use(src->config_file, drv)) {
1359 in_use = True;
1360 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1361 src->config_file = talloc_strdup(mem_ctx, "");
1362 if (!src->config_file) { return false; }
1365 if (drv_file_in_use(src->help_file, drv)) {
1366 in_use = True;
1367 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1368 src->help_file = talloc_strdup(mem_ctx, "");
1369 if (!src->help_file) { return false; }
1372 /* are there any dependentfiles to examine? */
1374 if (!src->dependent_files)
1375 return in_use;
1377 while (src->dependent_files[i] && *src->dependent_files[i]) {
1378 if (drv_file_in_use(src->dependent_files[i], drv)) {
1379 in_use = True;
1380 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1381 trim_dependent_file(mem_ctx, src->dependent_files, i);
1382 } else
1383 i++;
1386 return in_use;
1389 /****************************************************************************
1390 Determine whether or not a particular driver files are currently being
1391 used by any other driver.
1393 Return value is True if any files were in use by other drivers
1394 and False otherwise.
1396 Upon return, *info has been modified to only contain the driver files
1397 which are not in use
1399 Fix from mz:
1401 This needs to check all drivers to ensure that all files in use
1402 have been removed from *info, not just the ones in the first
1403 match.
1404 ****************************************************************************/
1406 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1407 struct dcerpc_binding_handle *b,
1408 struct spoolss_DriverInfo8 *info)
1410 int i;
1411 uint32 version;
1412 struct spoolss_DriverInfo8 *driver;
1413 bool in_use = false;
1414 uint32_t num_drivers;
1415 const char **drivers;
1416 WERROR result;
1418 if ( !info )
1419 return False;
1421 version = info->version;
1423 /* loop over all driver versions */
1425 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1427 /* get the list of drivers */
1429 result = winreg_get_driver_list(mem_ctx, b,
1430 info->architecture, version,
1431 &num_drivers, &drivers);
1432 if (!W_ERROR_IS_OK(result)) {
1433 return true;
1436 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1437 num_drivers, info->architecture, version));
1439 /* check each driver for overlap in files */
1441 for (i = 0; i < num_drivers; i++) {
1442 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1444 driver = NULL;
1446 result = winreg_get_driver(mem_ctx, b,
1447 info->architecture, drivers[i],
1448 version, &driver);
1449 if (!W_ERROR_IS_OK(result)) {
1450 talloc_free(drivers);
1451 return True;
1454 /* check if d2 uses any files from d1 */
1455 /* only if this is a different driver than the one being deleted */
1457 if (!strequal(info->driver_name, driver->driver_name)) {
1458 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1459 /* mz: Do not instantly return -
1460 * we need to ensure this file isn't
1461 * also in use by other drivers. */
1462 in_use = true;
1466 talloc_free(driver);
1469 talloc_free(drivers);
1471 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1473 return in_use;
1476 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1477 const char *short_arch,
1478 int vers,
1479 const char *fname)
1481 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1482 struct smb_filename *smb_fname = NULL;
1483 char *print_dlr_path;
1484 NTSTATUS status = NT_STATUS_NO_MEMORY;
1486 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1487 short_arch, vers, fname);
1488 if (print_dlr_path == NULL) {
1489 goto err_out;
1492 status = create_synthetic_smb_fname(tmp_ctx, print_dlr_path,
1493 NULL, NULL, &smb_fname);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 goto err_out;
1498 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1499 err_out:
1500 talloc_free(tmp_ctx);
1501 return status;
1504 /****************************************************************************
1505 Actually delete the driver files. Make sure that
1506 printer_driver_files_in_use() return False before calling
1507 this.
1508 ****************************************************************************/
1510 bool delete_driver_files(const struct auth_session_info *session_info,
1511 const struct spoolss_DriverInfo8 *r)
1513 const char *short_arch;
1514 connection_struct *conn;
1515 NTSTATUS nt_status;
1516 char *oldcwd;
1517 char *printdollar = NULL;
1518 int printdollar_snum;
1519 bool ret = false;
1521 if (!r) {
1522 return false;
1525 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1526 r->driver_name, r->version));
1528 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1529 if (!printdollar) {
1530 return false;
1532 if (printdollar_snum == -1) {
1533 return false;
1536 nt_status = create_conn_struct(talloc_tos(), smbd_server_conn, &conn,
1537 printdollar_snum,
1538 lp_pathname(printdollar_snum),
1539 session_info, &oldcwd);
1540 if (!NT_STATUS_IS_OK(nt_status)) {
1541 DEBUG(0,("delete_driver_files: create_conn_struct "
1542 "returned %s\n", nt_errstr(nt_status)));
1543 return false;
1546 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1547 if (!NT_STATUS_IS_OK(nt_status)) {
1548 DEBUG(0, ("failed set force user / group\n"));
1549 ret = false;
1550 goto err_free_conn;
1553 if (!become_user_by_session(conn, session_info)) {
1554 DEBUG(0, ("failed to become user\n"));
1555 ret = false;
1556 goto err_free_conn;
1559 if ( !CAN_WRITE(conn) ) {
1560 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1561 ret = false;
1562 goto err_out;
1565 short_arch = get_short_archi(r->architecture);
1566 if (short_arch == NULL) {
1567 DEBUG(0, ("bad architecture %s\n", r->architecture));
1568 ret = false;
1569 goto err_out;
1572 /* now delete the files */
1574 if (r->driver_path && r->driver_path[0]) {
1575 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1576 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1579 if (r->config_file && r->config_file[0]) {
1580 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1581 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1584 if (r->data_file && r->data_file[0]) {
1585 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1586 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1589 if (r->help_file && r->help_file[0]) {
1590 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1591 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1594 if (r->dependent_files) {
1595 int i = 0;
1596 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1597 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1598 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1599 i++;
1603 ret = true;
1604 err_out:
1605 unbecome_user();
1606 err_free_conn:
1607 if (conn != NULL) {
1608 vfs_ChDir(conn, oldcwd);
1609 SMB_VFS_DISCONNECT(conn);
1610 conn_free(conn);
1612 return ret;
1615 /* error code:
1616 0: everything OK
1617 1: level not implemented
1618 2: file doesn't exist
1619 3: can't allocate memory
1620 4: can't free memory
1621 5: non existant struct
1625 A printer and a printer driver are 2 different things.
1626 NT manages them separatelly, Samba does the same.
1627 Why ? Simply because it's easier and it makes sense !
1629 Now explanation: You have 3 printers behind your samba server,
1630 2 of them are the same make and model (laser A and B). But laser B
1631 has an 3000 sheet feeder and laser A doesn't such an option.
1632 Your third printer is an old dot-matrix model for the accounting :-).
1634 If the /usr/local/samba/lib directory (default dir), you will have
1635 5 files to describe all of this.
1637 3 files for the printers (1 by printer):
1638 NTprinter_laser A
1639 NTprinter_laser B
1640 NTprinter_accounting
1641 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1642 NTdriver_printer model X
1643 NTdriver_printer model Y
1645 jfm: I should use this comment for the text file to explain
1646 same thing for the forms BTW.
1647 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1651 /* Convert generic access rights to printer object specific access rights.
1652 It turns out that NT4 security descriptors use generic access rights and
1653 NT5 the object specific ones. */
1655 void map_printer_permissions(struct security_descriptor *sd)
1657 int i;
1659 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1660 se_map_generic(&sd->dacl->aces[i].access_mask,
1661 &printer_generic_mapping);
1665 void map_job_permissions(struct security_descriptor *sd)
1667 int i;
1669 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1670 se_map_generic(&sd->dacl->aces[i].access_mask,
1671 &job_generic_mapping);
1676 /****************************************************************************
1677 Check a user has permissions to perform the given operation. We use the
1678 permission constants defined in include/rpc_spoolss.h to check the various
1679 actions we perform when checking printer access.
1681 PRINTER_ACCESS_ADMINISTER:
1682 print_queue_pause, print_queue_resume, update_printer_sec,
1683 update_printer, spoolss_addprinterex_level_2,
1684 _spoolss_setprinterdata
1686 PRINTER_ACCESS_USE:
1687 print_job_start
1689 JOB_ACCESS_ADMINISTER:
1690 print_job_delete, print_job_pause, print_job_resume,
1691 print_queue_purge
1693 Try access control in the following order (for performance reasons):
1694 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1695 2) check security descriptor (bit comparisons in memory)
1696 3) "printer admins" (may result in numerous calls to winbind)
1698 ****************************************************************************/
1699 bool print_access_check(const struct auth_session_info *session_info,
1700 struct messaging_context *msg_ctx, int snum,
1701 int access_type)
1703 struct spoolss_security_descriptor *secdesc = NULL;
1704 uint32 access_granted;
1705 size_t sd_size;
1706 NTSTATUS status;
1707 WERROR result;
1708 const char *pname;
1709 TALLOC_CTX *mem_ctx = NULL;
1711 /* If user is NULL then use the current_user structure */
1713 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1715 if (session_info->unix_token->uid == sec_initial_uid()
1716 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1717 return True;
1720 /* Get printer name */
1722 pname = lp_printername(snum);
1724 if (!pname || !*pname) {
1725 errno = EACCES;
1726 return False;
1729 /* Get printer security descriptor */
1731 if(!(mem_ctx = talloc_init("print_access_check"))) {
1732 errno = ENOMEM;
1733 return False;
1736 result = winreg_get_printer_secdesc_internal(mem_ctx,
1737 get_session_info_system(),
1738 msg_ctx,
1739 pname,
1740 &secdesc);
1741 if (!W_ERROR_IS_OK(result)) {
1742 talloc_destroy(mem_ctx);
1743 errno = ENOMEM;
1744 return False;
1747 if (access_type == JOB_ACCESS_ADMINISTER) {
1748 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1750 /* Create a child security descriptor to check permissions
1751 against. This is because print jobs are child objects
1752 objects of a printer. */
1753 status = se_create_child_secdesc(mem_ctx,
1754 &secdesc,
1755 &sd_size,
1756 parent_secdesc,
1757 parent_secdesc->owner_sid,
1758 parent_secdesc->group_sid,
1759 false);
1760 if (!NT_STATUS_IS_OK(status)) {
1761 talloc_destroy(mem_ctx);
1762 errno = map_errno_from_nt_status(status);
1763 return False;
1766 map_job_permissions(secdesc);
1767 } else {
1768 map_printer_permissions(secdesc);
1771 /* Check access */
1772 status = se_access_check(secdesc, session_info->security_token, access_type,
1773 &access_granted);
1775 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1777 /* see if we need to try the printer admin list */
1779 if (!NT_STATUS_IS_OK(status) &&
1780 (token_contains_name_in_list(uidtoname(session_info->unix_token->uid),
1781 session_info->info->domain_name,
1782 NULL, session_info->security_token,
1783 lp_printer_admin(snum)))) {
1784 talloc_destroy(mem_ctx);
1785 return True;
1788 talloc_destroy(mem_ctx);
1790 if (!NT_STATUS_IS_OK(status)) {
1791 errno = EACCES;
1794 return NT_STATUS_IS_OK(status);
1797 /****************************************************************************
1798 Check the time parameters allow a print operation.
1799 *****************************************************************************/
1801 bool print_time_access_check(const struct auth_session_info *session_info,
1802 struct messaging_context *msg_ctx,
1803 const char *servicename)
1805 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1806 WERROR result;
1807 bool ok = False;
1808 time_t now = time(NULL);
1809 struct tm *t;
1810 uint32 mins;
1812 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1813 servicename, &pinfo2);
1814 if (!W_ERROR_IS_OK(result)) {
1815 return False;
1818 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1819 ok = True;
1822 t = gmtime(&now);
1823 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1825 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1826 ok = True;
1829 TALLOC_FREE(pinfo2);
1831 if (!ok) {
1832 errno = EACCES;
1835 return ok;
1838 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1839 const struct auth_session_info *session_info,
1840 struct messaging_context *msg_ctx,
1841 const char *printer)
1843 WERROR result;
1845 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1846 printer, "");
1847 if (!W_ERROR_IS_OK(result)) {
1848 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1849 "%s\n", printer, win_errstr(result)));
1853 void nt_printer_add(TALLOC_CTX *mem_ctx,
1854 const struct auth_session_info *session_info,
1855 struct messaging_context *msg_ctx,
1856 const char *printer)
1858 WERROR result;
1860 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1861 printer);
1862 if (!W_ERROR_IS_OK(result)) {
1863 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1864 printer, win_errstr(result)));