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/>.
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"
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"
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
= {
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping
= {
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping
= {
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 },
77 static bool print_driver_directories_init(void)
82 TALLOC_CTX
*mem_ctx
= talloc_stackframe();
83 const char *dir_list
[] = {
89 service
= lp_servicenumber("print$");
91 /* We don't have a print$ share */
92 DEBUG(5, ("No print$ share has been configured.\n"));
97 driver_path
= lp_path(mem_ctx
, service
);
98 if (driver_path
== NULL
) {
103 ok
= directory_create_or_exist(driver_path
, 0755);
105 DEBUG(1, ("Failed to create printer driver directory %s\n",
107 talloc_free(mem_ctx
);
111 for (i
= 0; archi_table
[i
].long_archi
!= NULL
; i
++) {
112 const char *arch_path
;
114 arch_path
= talloc_asprintf(mem_ctx
,
117 archi_table
[i
].short_archi
);
118 if (arch_path
== NULL
) {
119 talloc_free(mem_ctx
);
123 ok
= directory_create_or_exist(arch_path
, 0755);
125 DEBUG(1, ("Failed to create printer driver "
126 "architecture directory %s\n",
128 talloc_free(mem_ctx
);
133 for (i
= 0; i
< ARRAY_SIZE(dir_list
); i
++) {
136 path
= talloc_asprintf(mem_ctx
,
141 talloc_free(mem_ctx
);
145 ok
= directory_create_or_exist(path
, 0755);
147 DEBUG(1, ("Failed to create printer driver "
148 "architecture directory %s\n",
150 talloc_free(mem_ctx
);
155 driver_path
= state_path("DriverStore");
156 if (driver_path
== NULL
) {
157 talloc_free(mem_ctx
);
161 ok
= directory_create_or_exist(driver_path
, 0755);
163 DEBUG(1,("failed to create path %s\n", driver_path
));
164 talloc_free(mem_ctx
);
168 driver_path
= state_path("DriverStore/FileRepository");
169 if (driver_path
== NULL
) {
170 talloc_free(mem_ctx
);
174 ok
= directory_create_or_exist(driver_path
, 0755);
176 DEBUG(1,("failed to create path %s\n", driver_path
));
177 talloc_free(mem_ctx
);
181 driver_path
= state_path("DriverStore/Temp");
182 if (driver_path
== NULL
) {
183 talloc_free(mem_ctx
);
187 ok
= directory_create_or_exist(driver_path
, 0755);
189 DEBUG(1,("failed to create path %s\n", driver_path
));
190 talloc_free(mem_ctx
);
194 talloc_free(mem_ctx
);
198 /****************************************************************************
199 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
200 background lpq updater.
201 ****************************************************************************/
203 static void forward_drv_upgrade_printer_msg(struct messaging_context
*msg
,
206 struct server_id server_id
,
209 extern pid_t background_lpq_updater_pid
;
211 if (background_lpq_updater_pid
== -1) {
212 DEBUG(3,("no background lpq queue updater\n"));
216 messaging_send_buf(msg
,
217 pid_to_procid(background_lpq_updater_pid
),
218 MSG_PRINTER_DRVUPGRADE
,
223 /****************************************************************************
224 Open the NT printing tdbs. Done once before fork().
225 ****************************************************************************/
227 bool nt_printing_init(struct messaging_context
*msg_ctx
)
231 if (!print_driver_directories_init()) {
235 if (!nt_printing_tdb_upgrade()) {
240 * register callback to handle updating printers as new
241 * drivers are installed. Forwards to background lpq updater.
243 messaging_register(msg_ctx
, NULL
, MSG_PRINTER_DRVUPGRADE
,
244 forward_drv_upgrade_printer_msg
);
246 if ( lp_security() == SEC_ADS
) {
247 win_rc
= check_published_printers(msg_ctx
);
248 if (!W_ERROR_IS_OK(win_rc
))
249 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc
)));
255 /*******************************************************************
256 Function to allow filename parsing "the old way".
257 ********************************************************************/
259 static NTSTATUS
driver_unix_convert(connection_struct
*conn
,
260 const char *old_name
,
261 struct smb_filename
**smb_fname
)
264 TALLOC_CTX
*ctx
= talloc_tos();
265 char *name
= talloc_strdup(ctx
, old_name
);
268 return NT_STATUS_NO_MEMORY
;
271 name
= unix_clean_name(ctx
, name
);
273 return NT_STATUS_NO_MEMORY
;
275 trim_string(name
,"/","/");
277 status
= unix_convert(ctx
, conn
, name
, smb_fname
, 0);
278 if (!NT_STATUS_IS_OK(status
)) {
279 return NT_STATUS_NO_MEMORY
;
285 /****************************************************************************
286 Function to do the mapping between the long architecture name and
288 ****************************************************************************/
290 const char *get_short_archi(const char *long_archi
)
294 DEBUG(107,("Getting architecture dependent directory\n"));
297 } while ( (archi_table
[i
].long_archi
!=NULL
) &&
298 strcasecmp_m(long_archi
, archi_table
[i
].long_archi
) );
300 if (archi_table
[i
].long_archi
==NULL
) {
301 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi
));
305 /* this might be client code - but shouldn't this be an fstrcpy etc? */
307 DEBUGADD(108,("index: [%d]\n", i
));
308 DEBUGADD(108,("long architecture: [%s]\n", archi_table
[i
].long_archi
));
309 DEBUGADD(108,("short architecture: [%s]\n", archi_table
[i
].short_archi
));
311 return archi_table
[i
].short_archi
;
314 /****************************************************************************
315 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
316 There are two case to be covered here: PE (Portable Executable) and NE (New
317 Executable) files. Both files support the same INFO structure, but PE files
318 store the signature in unicode, and NE files store it as !unicode.
319 returns -1 on error, 1 on version info found, and 0 on no version info found.
320 ****************************************************************************/
322 static int get_file_version(files_struct
*fsp
, char *fname
,uint32_t *major
, uint32_t *minor
)
328 if ((buf
=(char *)SMB_MALLOC(DOS_HEADER_SIZE
)) == NULL
) {
329 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
330 fname
, DOS_HEADER_SIZE
));
334 if ((byte_count
= vfs_read_data(fsp
, buf
, DOS_HEADER_SIZE
)) < DOS_HEADER_SIZE
) {
335 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
336 fname
, (unsigned long)byte_count
));
337 goto no_version_info
;
340 /* Is this really a DOS header? */
341 if (SVAL(buf
,DOS_HEADER_MAGIC_OFFSET
) != DOS_HEADER_MAGIC
) {
342 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
343 fname
, SVAL(buf
,DOS_HEADER_MAGIC_OFFSET
)));
344 goto no_version_info
;
347 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
348 if (SMB_VFS_LSEEK(fsp
, SVAL(buf
,DOS_HEADER_LFANEW_OFFSET
), SEEK_SET
) == (off_t
)-1) {
349 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
351 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
352 goto no_version_info
;
355 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
356 if ((byte_count
= vfs_read_data(fsp
, buf
, NE_HEADER_SIZE
)) < NE_HEADER_SIZE
) {
357 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
358 fname
, (unsigned long)byte_count
));
359 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
360 goto no_version_info
;
363 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
364 if (IVAL(buf
,PE_HEADER_SIGNATURE_OFFSET
) == PE_HEADER_SIGNATURE
) {
365 unsigned int num_sections
;
366 unsigned int section_table_bytes
;
368 /* Just skip over optional header to get to section table */
369 if (SMB_VFS_LSEEK(fsp
,
370 SVAL(buf
,PE_HEADER_OPTIONAL_HEADER_SIZE
)-(NE_HEADER_SIZE
-PE_HEADER_SIZE
),
371 SEEK_CUR
) == (off_t
)-1) {
372 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
377 /* get the section table */
378 num_sections
= SVAL(buf
,PE_HEADER_NUMBER_OF_SECTIONS
);
379 section_table_bytes
= num_sections
* PE_HEADER_SECT_HEADER_SIZE
;
380 if (section_table_bytes
== 0)
384 if ((buf
=(char *)SMB_MALLOC(section_table_bytes
)) == NULL
) {
385 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
386 fname
, section_table_bytes
));
390 if ((byte_count
= vfs_read_data(fsp
, buf
, section_table_bytes
)) < section_table_bytes
) {
391 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
392 fname
, (unsigned long)byte_count
));
396 /* Iterate the section table looking for the resource section ".rsrc" */
397 for (i
= 0; i
< num_sections
; i
++) {
398 int sec_offset
= i
* PE_HEADER_SECT_HEADER_SIZE
;
400 if (strcmp(".rsrc", &buf
[sec_offset
+PE_HEADER_SECT_NAME_OFFSET
]) == 0) {
401 unsigned int section_pos
= IVAL(buf
,sec_offset
+PE_HEADER_SECT_PTR_DATA_OFFSET
);
402 unsigned int section_bytes
= IVAL(buf
,sec_offset
+PE_HEADER_SECT_SIZE_DATA_OFFSET
);
404 if (section_bytes
== 0)
408 if ((buf
=(char *)SMB_MALLOC(section_bytes
)) == NULL
) {
409 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
410 fname
, section_bytes
));
414 /* Seek to the start of the .rsrc section info */
415 if (SMB_VFS_LSEEK(fsp
, section_pos
, SEEK_SET
) == (off_t
)-1) {
416 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
421 if ((byte_count
= vfs_read_data(fsp
, buf
, section_bytes
)) < section_bytes
) {
422 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
423 fname
, (unsigned long)byte_count
));
427 if (section_bytes
< VS_VERSION_INFO_UNICODE_SIZE
)
430 for (i
=0; i
<section_bytes
-VS_VERSION_INFO_UNICODE_SIZE
; i
++) {
431 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
432 if (buf
[i
] == 'V' && buf
[i
+1] == '\0' && buf
[i
+2] == 'S') {
433 /* Align to next long address */
434 int pos
= (i
+ sizeof(VS_SIGNATURE
)*2 + 3) & 0xfffffffc;
436 if (IVAL(buf
,pos
) == VS_MAGIC_VALUE
) {
437 *major
= IVAL(buf
,pos
+VS_MAJOR_OFFSET
);
438 *minor
= IVAL(buf
,pos
+VS_MINOR_OFFSET
);
440 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
441 fname
, *major
, *minor
,
442 (*major
>>16)&0xffff, *major
&0xffff,
443 (*minor
>>16)&0xffff, *minor
&0xffff));
452 /* Version info not found, fall back to origin date/time */
453 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname
));
457 } else if (SVAL(buf
,NE_HEADER_SIGNATURE_OFFSET
) == NE_HEADER_SIGNATURE
) {
458 if (CVAL(buf
,NE_HEADER_TARGET_OS_OFFSET
) != NE_HEADER_TARGOS_WIN
) {
459 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
460 fname
, CVAL(buf
,NE_HEADER_TARGET_OS_OFFSET
)));
461 /* At this point, we assume the file is in error. It still could be something
462 * else besides a NE file, but it unlikely at this point. */
466 /* Allocate a bit more space to speed up things */
468 if ((buf
=(char *)SMB_MALLOC(VS_NE_BUF_SIZE
)) == NULL
) {
469 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
470 fname
, PE_HEADER_SIZE
));
474 /* This is a HACK! I got tired of trying to sort through the messy
475 * 'NE' file format. If anyone wants to clean this up please have at
476 * it, but this works. 'NE' files will eventually fade away. JRR */
477 while((byte_count
= vfs_read_data(fsp
, buf
, VS_NE_BUF_SIZE
)) > 0) {
478 /* Cover case that should not occur in a well formed 'NE' .dll file */
479 if (byte_count
-VS_VERSION_INFO_SIZE
<= 0) break;
481 for(i
=0; i
<byte_count
; i
++) {
482 /* Fast skip past data that can't possibly match */
483 if (buf
[i
] != 'V') continue;
485 /* Potential match data crosses buf boundry, move it to beginning
486 * of buf, and fill the buf with as much as it will hold. */
487 if (i
>byte_count
-VS_VERSION_INFO_SIZE
) {
490 memcpy(buf
, &buf
[i
], byte_count
-i
);
491 if ((bc
= vfs_read_data(fsp
, &buf
[byte_count
-i
], VS_NE_BUF_SIZE
-
492 (byte_count
-i
))) < 0) {
494 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
499 byte_count
= bc
+ (byte_count
- i
);
500 if (byte_count
<VS_VERSION_INFO_SIZE
) break;
505 /* Check that the full signature string and the magic number that
506 * follows exist (not a perfect solution, but the chances that this
507 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
508 * twice, as it is simpler to read the code. */
509 if (strcmp(&buf
[i
], VS_SIGNATURE
) == 0) {
510 /* Compute skip alignment to next long address */
511 int skip
= -(SMB_VFS_LSEEK(fsp
, 0, SEEK_CUR
) - (byte_count
- i
) +
512 sizeof(VS_SIGNATURE
)) & 3;
513 if (IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
) != 0xfeef04bd) continue;
515 *major
= IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
+VS_MAJOR_OFFSET
);
516 *minor
= IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
+VS_MINOR_OFFSET
);
517 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
518 fname
, *major
, *minor
,
519 (*major
>>16)&0xffff, *major
&0xffff,
520 (*minor
>>16)&0xffff, *minor
&0xffff));
527 /* Version info not found, fall back to origin date/time */
528 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname
));
533 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
534 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
535 fname
, IVAL(buf
,PE_HEADER_SIGNATURE_OFFSET
)));
546 /****************************************************************************
547 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
548 share one or more files. During the MS installation process files are checked
549 to insure that only a newer version of a shared file is installed over an
550 older version. There are several possibilities for this comparison. If there
551 is no previous version, the new one is newer (obviously). If either file is
552 missing the version info structure, compare the creation date (on Unix use
553 the modification date). Otherwise chose the numerically larger version number.
554 ****************************************************************************/
556 static int file_version_is_newer(connection_struct
*conn
, fstring new_file
, fstring old_file
)
558 bool use_version
= true;
562 time_t new_create_time
;
566 time_t old_create_time
;
568 struct smb_filename
*smb_fname
= NULL
;
569 files_struct
*fsp
= NULL
;
575 SET_STAT_INVALID(st
);
576 new_create_time
= (time_t)0;
577 old_create_time
= (time_t)0;
579 /* Get file version info (if available) for previous file (if it exists) */
580 status
= driver_unix_convert(conn
, old_file
, &smb_fname
);
581 if (!NT_STATUS_IS_OK(status
)) {
585 status
= SMB_VFS_CREATE_FILE(
588 0, /* root_dir_fid */
589 smb_fname
, /* fname */
590 FILE_GENERIC_READ
, /* access_mask */
591 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
592 FILE_OPEN
, /* create_disposition*/
593 0, /* create_options */
594 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
595 INTERNAL_OPEN_ONLY
, /* oplock_request */
597 0, /* allocation_size */
598 0, /* private_flags */
603 NULL
, NULL
); /* create context */
605 if (!NT_STATUS_IS_OK(status
)) {
606 /* Old file not found, so by definition new file is in fact newer */
607 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
608 "errno = %d\n", smb_fname_str_dbg(smb_fname
),
614 ret
= get_file_version(fsp
, old_file
, &old_major
, &old_minor
);
620 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
623 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
626 old_create_time
= convert_timespec_to_time_t(st
.st_ex_mtime
);
627 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
628 (long)old_create_time
));
631 close_file(NULL
, fsp
, NORMAL_CLOSE
);
634 /* Get file version info (if available) for new file */
635 status
= driver_unix_convert(conn
, new_file
, &smb_fname
);
636 if (!NT_STATUS_IS_OK(status
)) {
640 status
= SMB_VFS_CREATE_FILE(
643 0, /* root_dir_fid */
644 smb_fname
, /* fname */
645 FILE_GENERIC_READ
, /* access_mask */
646 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
647 FILE_OPEN
, /* create_disposition*/
648 0, /* create_options */
649 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
650 INTERNAL_OPEN_ONLY
, /* oplock_request */
652 0, /* allocation_size */
653 0, /* private_flags */
658 NULL
, NULL
); /* create context */
660 if (!NT_STATUS_IS_OK(status
)) {
661 /* New file not found, this shouldn't occur if the caller did its job */
662 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
663 "errno = %d\n", smb_fname_str_dbg(smb_fname
), errno
));
667 ret
= get_file_version(fsp
, new_file
, &new_major
, &new_minor
);
673 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
676 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
679 new_create_time
= convert_timespec_to_time_t(st
.st_ex_mtime
);
680 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
681 (long)new_create_time
));
684 close_file(NULL
, fsp
, NORMAL_CLOSE
);
687 if (use_version
&& (new_major
!= old_major
|| new_minor
!= old_minor
)) {
688 /* Compare versions and choose the larger version number */
689 if (new_major
> old_major
||
690 (new_major
== old_major
&& new_minor
> old_minor
)) {
692 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file
, new_file
));
697 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file
));
703 /* Compare modification time/dates and choose the newest time/date */
704 if (new_create_time
> old_create_time
) {
705 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file
, new_file
));
710 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file
));
718 close_file(NULL
, fsp
, NORMAL_CLOSE
);
721 TALLOC_FREE(smb_fname
);
725 /****************************************************************************
726 Determine the correct cVersion associated with an architecture and driver
727 ****************************************************************************/
728 static uint32_t get_correct_cversion(struct auth_session_info
*session_info
,
729 const char *architecture
,
730 const char *driverpath_in
,
731 const char *driver_directory
,
736 struct smb_filename
*smb_fname
= NULL
;
737 files_struct
*fsp
= NULL
;
738 connection_struct
*conn
= NULL
;
739 struct smb_filename
*oldcwd_fname
= NULL
;
740 char *printdollar
= NULL
;
741 char *printdollar_path
= NULL
;
742 char *working_dir
= NULL
;
743 int printdollar_snum
;
745 *perr
= WERR_INVALID_PARAMETER
;
747 /* If architecture is Windows 95/98/ME, the version is always 0. */
748 if (strcmp(architecture
, SPL_ARCH_WIN40
) == 0) {
749 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
754 /* If architecture is Windows x64, the version is always 3. */
755 if (strcmp(architecture
, SPL_ARCH_X64
) == 0) {
756 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
761 printdollar_snum
= find_service(talloc_tos(), "print$", &printdollar
);
763 *perr
= WERR_NOT_ENOUGH_MEMORY
;
766 if (printdollar_snum
== -1) {
767 *perr
= WERR_BAD_NET_NAME
;
771 printdollar_path
= lp_path(talloc_tos(), printdollar_snum
);
772 if (printdollar_path
== NULL
) {
773 *perr
= WERR_NOT_ENOUGH_MEMORY
;
777 working_dir
= talloc_asprintf(talloc_tos(),
782 * If the driver has been uploaded into a temorpary driver
783 * directory, switch to the driver directory.
785 if (driver_directory
!= NULL
) {
786 working_dir
= talloc_asprintf(talloc_tos(), "%s/%s/%s",
792 nt_status
= create_conn_struct_cwd(talloc_tos(),
793 server_event_context(),
794 server_messaging_context(),
798 session_info
, &oldcwd_fname
);
799 if (!NT_STATUS_IS_OK(nt_status
)) {
800 DEBUG(0,("get_correct_cversion: create_conn_struct "
801 "returned %s\n", nt_errstr(nt_status
)));
802 *perr
= ntstatus_to_werror(nt_status
);
806 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
807 if (!NT_STATUS_IS_OK(nt_status
)) {
808 DEBUG(0, ("failed set force user / group\n"));
809 *perr
= ntstatus_to_werror(nt_status
);
810 goto error_free_conn
;
813 if (!become_user_by_session(conn
, session_info
)) {
814 DEBUG(0, ("failed to become user\n"));
815 *perr
= WERR_ACCESS_DENIED
;
816 goto error_free_conn
;
820 * We switch to the directory where the driver files are located,
821 * so only work on the file names
823 nt_status
= driver_unix_convert(conn
, driverpath_in
, &smb_fname
);
824 if (!NT_STATUS_IS_OK(nt_status
)) {
825 *perr
= ntstatus_to_werror(nt_status
);
829 nt_status
= vfs_file_exist(conn
, smb_fname
);
830 if (!NT_STATUS_IS_OK(nt_status
)) {
831 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
832 *perr
= WERR_FILE_NOT_FOUND
;
836 nt_status
= SMB_VFS_CREATE_FILE(
839 0, /* root_dir_fid */
840 smb_fname
, /* fname */
841 FILE_GENERIC_READ
, /* access_mask */
842 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
843 FILE_OPEN
, /* create_disposition*/
844 0, /* create_options */
845 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
846 INTERNAL_OPEN_ONLY
, /* oplock_request */
848 0, /* private_flags */
849 0, /* allocation_size */
854 NULL
, NULL
); /* create context */
856 if (!NT_STATUS_IS_OK(nt_status
)) {
857 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
858 "%d\n", smb_fname_str_dbg(smb_fname
), errno
));
859 *perr
= WERR_ACCESS_DENIED
;
866 ret
= get_file_version(fsp
, smb_fname
->base_name
, &major
, &minor
);
868 *perr
= WERR_INVALID_PARAMETER
;
871 DEBUG(6,("get_correct_cversion: Version info not "
873 smb_fname_str_dbg(smb_fname
)));
874 *perr
= WERR_INVALID_PARAMETER
;
879 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
880 * for more details. Version in this case is not just the version of the
881 * file, but the version in the sense of kernal mode (2) vs. user mode
882 * (3) drivers. Other bits of the version fields are the version info.
885 cversion
= major
& 0x0000ffff;
887 case 2: /* WinNT drivers */
888 case 3: /* Win2K drivers */
892 DEBUG(6,("get_correct_cversion: cversion "
893 "invalid [%s] cversion = %d\n",
894 smb_fname_str_dbg(smb_fname
),
899 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
900 " = 0x%x minor = 0x%x\n",
901 smb_fname_str_dbg(smb_fname
), major
, minor
));
904 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
905 smb_fname_str_dbg(smb_fname
), cversion
));
911 TALLOC_FREE(smb_fname
);
913 close_file(NULL
, fsp
, NORMAL_CLOSE
);
916 vfs_ChDir(conn
, oldcwd_fname
);
917 TALLOC_FREE(oldcwd_fname
);
918 SMB_VFS_DISCONNECT(conn
);
921 if (!W_ERROR_IS_OK(*perr
)) {
928 /****************************************************************************
929 ****************************************************************************/
931 #define strip_driver_path(_mem_ctx, _element) do { \
932 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
933 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
934 W_ERROR_HAVE_NO_MEMORY((_element)); \
938 static WERROR
clean_up_driver_struct_level(TALLOC_CTX
*mem_ctx
,
939 struct auth_session_info
*session_info
,
940 const char *architecture
,
941 const char **driver_path
,
942 const char **data_file
,
943 const char **config_file
,
944 const char **help_file
,
945 struct spoolss_StringArray
*dependent_files
,
946 enum spoolss_DriverOSVersion
*version
,
948 const char **driver_directory
)
950 const char *short_architecture
;
955 if (!*driver_path
|| !*data_file
) {
956 return WERR_INVALID_PARAMETER
;
959 if (!strequal(architecture
, SPOOLSS_ARCHITECTURE_4_0
) && !*config_file
) {
960 return WERR_INVALID_PARAMETER
;
963 if (flags
& APD_COPY_FROM_DIRECTORY
) {
968 * driver_path is set to:
970 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
972 path
= talloc_strdup(mem_ctx
, *driver_path
);
974 return WERR_NOT_ENOUGH_MEMORY
;
977 /* Remove pscript5.dll */
978 q
= strrchr_m(path
, '\\');
980 return WERR_INVALID_PARAMETER
;
984 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
985 q
= strrchr_m(path
, '\\');
987 return WERR_INVALID_PARAMETER
;
991 * Set driver_directory to:
993 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
995 * This is the directory where all the files have been uploaded
997 *driver_directory
= q
+ 1;
1000 /* clean up the driver name.
1001 * we can get .\driver.dll
1002 * or worse c:\windows\system\driver.dll !
1004 /* using an intermediate string to not have overlaping memcpy()'s */
1006 strip_driver_path(mem_ctx
, *driver_path
);
1007 strip_driver_path(mem_ctx
, *data_file
);
1009 strip_driver_path(mem_ctx
, *config_file
);
1012 strip_driver_path(mem_ctx
, *help_file
);
1015 if (dependent_files
&& dependent_files
->string
) {
1016 for (i
=0; dependent_files
->string
[i
]; i
++) {
1017 strip_driver_path(mem_ctx
, dependent_files
->string
[i
]);
1021 short_architecture
= get_short_archi(architecture
);
1022 if (!short_architecture
) {
1023 return WERR_UNKNOWN_PRINTER_DRIVER
;
1026 /* jfm:7/16/2000 the client always sends the cversion=0.
1027 * The server should check which version the driver is by reading
1028 * the PE header of driver->driverpath.
1030 * For Windows 95/98 the version is 0 (so the value sent is correct)
1031 * For Windows NT (the architecture doesn't matter)
1032 * NT 3.1: cversion=0
1033 * NT 3.5/3.51: cversion=1
1038 *version
= get_correct_cversion(session_info
,
1043 if (*version
== -1) {
1050 /****************************************************************************
1051 ****************************************************************************/
1053 WERROR
clean_up_driver_struct(TALLOC_CTX
*mem_ctx
,
1054 struct auth_session_info
*session_info
,
1055 struct spoolss_AddDriverInfoCtr
*r
,
1057 const char **driver_directory
)
1061 return clean_up_driver_struct_level(mem_ctx
, session_info
,
1062 r
->info
.info3
->architecture
,
1063 &r
->info
.info3
->driver_path
,
1064 &r
->info
.info3
->data_file
,
1065 &r
->info
.info3
->config_file
,
1066 &r
->info
.info3
->help_file
,
1067 r
->info
.info3
->dependent_files
,
1068 &r
->info
.info3
->version
,
1072 return clean_up_driver_struct_level(mem_ctx
, session_info
,
1073 r
->info
.info6
->architecture
,
1074 &r
->info
.info6
->driver_path
,
1075 &r
->info
.info6
->data_file
,
1076 &r
->info
.info6
->config_file
,
1077 &r
->info
.info6
->help_file
,
1078 r
->info
.info6
->dependent_files
,
1079 &r
->info
.info6
->version
,
1083 return clean_up_driver_struct_level(mem_ctx
, session_info
,
1084 r
->info
.info8
->architecture
,
1085 &r
->info
.info8
->driver_path
,
1086 &r
->info
.info8
->data_file
,
1087 &r
->info
.info8
->config_file
,
1088 &r
->info
.info8
->help_file
,
1089 r
->info
.info8
->dependent_files
,
1090 &r
->info
.info8
->version
,
1094 return WERR_NOT_SUPPORTED
;
1098 /****************************************************************************
1099 This function sucks and should be replaced. JRA.
1100 ****************************************************************************/
1102 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3
*dst
,
1103 const struct spoolss_AddDriverInfo6
*src
)
1105 dst
->version
= src
->version
;
1107 dst
->driver_name
= src
->driver_name
;
1108 dst
->architecture
= src
->architecture
;
1109 dst
->driver_path
= src
->driver_path
;
1110 dst
->data_file
= src
->data_file
;
1111 dst
->config_file
= src
->config_file
;
1112 dst
->help_file
= src
->help_file
;
1113 dst
->monitor_name
= src
->monitor_name
;
1114 dst
->default_datatype
= src
->default_datatype
;
1115 dst
->_ndr_size_dependent_files
= src
->_ndr_size_dependent_files
;
1116 dst
->dependent_files
= src
->dependent_files
;
1119 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3
*dst
,
1120 const struct spoolss_AddDriverInfo8
*src
)
1122 dst
->version
= src
->version
;
1124 dst
->driver_name
= src
->driver_name
;
1125 dst
->architecture
= src
->architecture
;
1126 dst
->driver_path
= src
->driver_path
;
1127 dst
->data_file
= src
->data_file
;
1128 dst
->config_file
= src
->config_file
;
1129 dst
->help_file
= src
->help_file
;
1130 dst
->monitor_name
= src
->monitor_name
;
1131 dst
->default_datatype
= src
->default_datatype
;
1132 dst
->_ndr_size_dependent_files
= src
->_ndr_size_dependent_files
;
1133 dst
->dependent_files
= src
->dependent_files
;
1136 /****************************************************************************
1137 ****************************************************************************/
1139 static WERROR
move_driver_file_to_download_area(TALLOC_CTX
*mem_ctx
,
1140 connection_struct
*conn
,
1141 const char *driver_file
,
1142 const char *short_architecture
,
1143 uint32_t driver_version
,
1145 const char *driver_directory
)
1147 struct smb_filename
*smb_fname_old
= NULL
;
1148 struct smb_filename
*smb_fname_new
= NULL
;
1149 char *old_name
= NULL
;
1150 char *new_name
= NULL
;
1154 if (driver_directory
!= NULL
) {
1155 old_name
= talloc_asprintf(mem_ctx
,
1161 old_name
= talloc_asprintf(mem_ctx
,
1166 if (old_name
== NULL
) {
1167 return WERR_NOT_ENOUGH_MEMORY
;
1170 new_name
= talloc_asprintf(mem_ctx
, "%s/%d/%s",
1171 short_architecture
, driver_version
, driver_file
);
1172 if (new_name
== NULL
) {
1173 TALLOC_FREE(old_name
);
1174 return WERR_NOT_ENOUGH_MEMORY
;
1177 if (version
!= -1 && (version
= file_version_is_newer(conn
, old_name
, new_name
)) > 0) {
1179 status
= driver_unix_convert(conn
, old_name
, &smb_fname_old
);
1180 if (!NT_STATUS_IS_OK(status
)) {
1181 ret
= WERR_NOT_ENOUGH_MEMORY
;
1185 /* Setup a synthetic smb_filename struct */
1186 smb_fname_new
= talloc_zero(mem_ctx
, struct smb_filename
);
1187 if (!smb_fname_new
) {
1188 ret
= WERR_NOT_ENOUGH_MEMORY
;
1192 smb_fname_new
->base_name
= new_name
;
1194 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1195 "'%s'\n", smb_fname_old
->base_name
,
1196 smb_fname_new
->base_name
));
1198 status
= copy_file(mem_ctx
, conn
, smb_fname_old
, smb_fname_new
,
1199 OPENX_FILE_EXISTS_TRUNCATE
|
1200 OPENX_FILE_CREATE_IF_NOT_EXIST
,
1203 if (!NT_STATUS_IS_OK(status
)) {
1204 DEBUG(0,("move_driver_file_to_download_area: Unable "
1205 "to rename [%s] to [%s]: %s\n",
1206 smb_fname_old
->base_name
, new_name
,
1207 nt_errstr(status
)));
1208 ret
= WERR_ACCESS_DENIED
;
1215 TALLOC_FREE(smb_fname_old
);
1216 TALLOC_FREE(smb_fname_new
);
1220 WERROR
move_driver_to_download_area(struct auth_session_info
*session_info
,
1221 struct spoolss_AddDriverInfoCtr
*r
,
1222 const char *driver_directory
)
1224 struct spoolss_AddDriverInfo3
*driver
;
1225 struct spoolss_AddDriverInfo3 converted_driver
;
1226 const char *short_architecture
;
1227 struct smb_filename
*smb_dname
= NULL
;
1228 char *new_dir
= NULL
;
1229 connection_struct
*conn
= NULL
;
1232 TALLOC_CTX
*ctx
= talloc_tos();
1234 struct smb_filename
*oldcwd_fname
= NULL
;
1235 char *printdollar
= NULL
;
1236 int printdollar_snum
;
1237 WERROR err
= WERR_OK
;
1241 driver
= r
->info
.info3
;
1244 convert_level_6_to_level3(&converted_driver
, r
->info
.info6
);
1245 driver
= &converted_driver
;
1248 convert_level_8_to_level3(&converted_driver
, r
->info
.info8
);
1249 driver
= &converted_driver
;
1252 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r
->level
));
1253 return WERR_INVALID_LEVEL
;
1256 short_architecture
= get_short_archi(driver
->architecture
);
1257 if (!short_architecture
) {
1258 return WERR_UNKNOWN_PRINTER_DRIVER
;
1261 printdollar_snum
= find_service(ctx
, "print$", &printdollar
);
1263 return WERR_NOT_ENOUGH_MEMORY
;
1265 if (printdollar_snum
== -1) {
1266 return WERR_BAD_NET_NAME
;
1269 nt_status
= create_conn_struct_cwd(talloc_tos(),
1270 server_event_context(),
1271 server_messaging_context(),
1274 lp_path(talloc_tos(), printdollar_snum
),
1275 session_info
, &oldcwd_fname
);
1276 if (!NT_STATUS_IS_OK(nt_status
)) {
1277 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1278 "returned %s\n", nt_errstr(nt_status
)));
1279 err
= ntstatus_to_werror(nt_status
);
1283 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
1284 if (!NT_STATUS_IS_OK(nt_status
)) {
1285 DEBUG(0, ("failed set force user / group\n"));
1286 err
= ntstatus_to_werror(nt_status
);
1290 if (!become_user_by_session(conn
, session_info
)) {
1291 DEBUG(0, ("failed to become user\n"));
1292 err
= WERR_ACCESS_DENIED
;
1296 new_dir
= talloc_asprintf(ctx
,
1301 err
= WERR_NOT_ENOUGH_MEMORY
;
1304 nt_status
= driver_unix_convert(conn
, new_dir
, &smb_dname
);
1305 if (!NT_STATUS_IS_OK(nt_status
)) {
1306 err
= WERR_NOT_ENOUGH_MEMORY
;
1310 DEBUG(5,("Creating first directory: %s\n", smb_dname
->base_name
));
1312 nt_status
= create_directory(conn
, NULL
, smb_dname
);
1313 if (!NT_STATUS_IS_OK(nt_status
)
1314 && !NT_STATUS_EQUAL(nt_status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
1315 DEBUG(0, ("failed to create driver destination directory: %s\n",
1316 nt_errstr(nt_status
)));
1317 err
= ntstatus_to_werror(nt_status
);
1321 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1322 * listed for this driver which has already been moved, skip it (note:
1323 * drivers may list the same file name several times. Then check if the
1324 * file already exists in archi\version\, if so, check that the version
1325 * info (or time stamps if version info is unavailable) is newer (or the
1326 * date is later). If it is, move it to archi\version\filexxx.yyy.
1327 * Otherwise, delete the file.
1329 * If a file is not moved to archi\version\ because of an error, all the
1330 * rest of the 'unmoved' driver files are removed from archi\. If one or
1331 * more of the driver's files was already moved to archi\version\, it
1332 * potentially leaves the driver in a partially updated state. Version
1333 * trauma will most likely occur if an client attempts to use any printer
1334 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1335 * done is appropriate... later JRR
1338 DEBUG(5,("Moving files now !\n"));
1340 if (driver
->driver_path
&& strlen(driver
->driver_path
)) {
1342 err
= move_driver_file_to_download_area(ctx
,
1344 driver
->driver_path
,
1349 if (!W_ERROR_IS_OK(err
)) {
1354 if (driver
->data_file
&& strlen(driver
->data_file
)) {
1355 if (!strequal(driver
->data_file
, driver
->driver_path
)) {
1357 err
= move_driver_file_to_download_area(ctx
,
1364 if (!W_ERROR_IS_OK(err
)) {
1370 if (driver
->config_file
&& strlen(driver
->config_file
)) {
1371 if (!strequal(driver
->config_file
, driver
->driver_path
) &&
1372 !strequal(driver
->config_file
, driver
->data_file
)) {
1374 err
= move_driver_file_to_download_area(ctx
,
1376 driver
->config_file
,
1381 if (!W_ERROR_IS_OK(err
)) {
1387 if (driver
->help_file
&& strlen(driver
->help_file
)) {
1388 if (!strequal(driver
->help_file
, driver
->driver_path
) &&
1389 !strequal(driver
->help_file
, driver
->data_file
) &&
1390 !strequal(driver
->help_file
, driver
->config_file
)) {
1392 err
= move_driver_file_to_download_area(ctx
,
1399 if (!W_ERROR_IS_OK(err
)) {
1405 if (driver
->dependent_files
&& driver
->dependent_files
->string
) {
1406 for (i
=0; driver
->dependent_files
->string
[i
]; i
++) {
1407 if (!strequal(driver
->dependent_files
->string
[i
], driver
->driver_path
) &&
1408 !strequal(driver
->dependent_files
->string
[i
], driver
->data_file
) &&
1409 !strequal(driver
->dependent_files
->string
[i
], driver
->config_file
) &&
1410 !strequal(driver
->dependent_files
->string
[i
], driver
->help_file
)) {
1412 for (j
=0; j
< i
; j
++) {
1413 if (strequal(driver
->dependent_files
->string
[i
], driver
->dependent_files
->string
[j
])) {
1418 err
= move_driver_file_to_download_area(ctx
,
1420 driver
->dependent_files
->string
[i
],
1425 if (!W_ERROR_IS_OK(err
)) {
1437 TALLOC_FREE(smb_dname
);
1440 vfs_ChDir(conn
, oldcwd_fname
);
1441 TALLOC_FREE(oldcwd_fname
);
1442 SMB_VFS_DISCONNECT(conn
);
1449 /****************************************************************************
1450 Determine whether or not a particular driver is currently assigned
1452 ****************************************************************************/
1454 bool printer_driver_in_use(TALLOC_CTX
*mem_ctx
,
1455 struct dcerpc_binding_handle
*b
,
1456 const struct spoolss_DriverInfo8
*r
)
1459 int n_services
= lp_numservices();
1460 bool in_use
= false;
1461 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
1468 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1470 /* loop through the printers.tdb and check for the drivername */
1472 for (snum
=0; snum
<n_services
&& !in_use
; snum
++) {
1473 if (!lp_snum_ok(snum
) || !lp_printable(snum
)) {
1477 result
= winreg_get_printer(mem_ctx
, b
,
1478 lp_servicename(talloc_tos(), snum
),
1480 if (!W_ERROR_IS_OK(result
)) {
1481 continue; /* skip */
1484 if (strequal(r
->driver_name
, pinfo2
->drivername
)) {
1488 TALLOC_FREE(pinfo2
);
1491 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1494 struct spoolss_DriverInfo8
*driver
= NULL
;
1497 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r
->driver_name
));
1499 /* we can still remove the driver if there is one of
1500 "Windows NT x86" version 2 or 3 left */
1502 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86
, r
->architecture
)) {
1503 if (r
->version
== 2) {
1504 werr
= winreg_get_driver(mem_ctx
, b
,
1508 } else if (r
->version
== 3) {
1509 werr
= winreg_get_driver(mem_ctx
, b
,
1514 DBG_ERR("Unknown driver version (%d)\n",
1516 werr
= WERR_UNKNOWN_PRINTER_DRIVER
;
1518 } else if (strequal(SPOOLSS_ARCHITECTURE_x64
, r
->architecture
)) {
1519 werr
= winreg_get_driver(mem_ctx
, b
,
1520 SPOOLSS_ARCHITECTURE_NT_X86
,
1525 DBG_ERR("Unknown driver architecture: %s\n",
1527 werr
= WERR_UNKNOWN_PRINTER_DRIVER
;
1530 /* now check the error code */
1532 if ( W_ERROR_IS_OK(werr
) ) {
1533 /* it's ok to remove the driver, we have other architctures left */
1535 talloc_free(driver
);
1539 /* report that the driver is not in use by default */
1545 /**********************************************************************
1546 Check to see if a ogiven file is in use by *info
1547 *********************************************************************/
1549 static bool drv_file_in_use(const char *file
, const struct spoolss_DriverInfo8
*info
)
1556 /* mz: skip files that are in the list but already deleted */
1557 if (!file
|| !file
[0]) {
1561 if (strequal(file
, info
->driver_path
))
1564 if (strequal(file
, info
->data_file
))
1567 if (strequal(file
, info
->config_file
))
1570 if (strequal(file
, info
->help_file
))
1573 /* see of there are any dependent files to examine */
1575 if (!info
->dependent_files
)
1578 while (info
->dependent_files
[i
] && *info
->dependent_files
[i
]) {
1579 if (strequal(file
, info
->dependent_files
[i
]))
1588 /**********************************************************************
1589 Utility function to remove the dependent file pointed to by the
1590 input parameter from the list
1591 *********************************************************************/
1593 static void trim_dependent_file(TALLOC_CTX
*mem_ctx
, const char **files
, int idx
)
1596 /* bump everything down a slot */
1598 while (files
&& files
[idx
+1]) {
1599 files
[idx
] = talloc_strdup(mem_ctx
, files
[idx
+1]);
1608 /**********************************************************************
1609 Check if any of the files used by src are also used by drv
1610 *********************************************************************/
1612 static bool trim_overlap_drv_files(TALLOC_CTX
*mem_ctx
,
1613 struct spoolss_DriverInfo8
*src
,
1614 const struct spoolss_DriverInfo8
*drv
)
1616 bool in_use
= False
;
1622 /* check each file. Remove it from the src structure if it overlaps */
1624 if (drv_file_in_use(src
->driver_path
, drv
)) {
1626 DEBUG(10,("Removing driverfile [%s] from list\n", src
->driver_path
));
1627 src
->driver_path
= talloc_strdup(mem_ctx
, "");
1628 if (!src
->driver_path
) { return false; }
1631 if (drv_file_in_use(src
->data_file
, drv
)) {
1633 DEBUG(10,("Removing datafile [%s] from list\n", src
->data_file
));
1634 src
->data_file
= talloc_strdup(mem_ctx
, "");
1635 if (!src
->data_file
) { return false; }
1638 if (drv_file_in_use(src
->config_file
, drv
)) {
1640 DEBUG(10,("Removing configfile [%s] from list\n", src
->config_file
));
1641 src
->config_file
= talloc_strdup(mem_ctx
, "");
1642 if (!src
->config_file
) { return false; }
1645 if (drv_file_in_use(src
->help_file
, drv
)) {
1647 DEBUG(10,("Removing helpfile [%s] from list\n", src
->help_file
));
1648 src
->help_file
= talloc_strdup(mem_ctx
, "");
1649 if (!src
->help_file
) { return false; }
1652 /* are there any dependentfiles to examine? */
1654 if (!src
->dependent_files
)
1657 while (src
->dependent_files
[i
] && *src
->dependent_files
[i
]) {
1658 if (drv_file_in_use(src
->dependent_files
[i
], drv
)) {
1660 DEBUG(10,("Removing [%s] from dependent file list\n", src
->dependent_files
[i
]));
1661 trim_dependent_file(mem_ctx
, src
->dependent_files
, i
);
1669 /****************************************************************************
1670 Determine whether or not a particular driver files are currently being
1671 used by any other driver.
1673 Return value is True if any files were in use by other drivers
1674 and False otherwise.
1676 Upon return, *info has been modified to only contain the driver files
1677 which are not in use
1681 This needs to check all drivers to ensure that all files in use
1682 have been removed from *info, not just the ones in the first
1684 ****************************************************************************/
1686 bool printer_driver_files_in_use(TALLOC_CTX
*mem_ctx
,
1687 struct dcerpc_binding_handle
*b
,
1688 struct spoolss_DriverInfo8
*info
)
1692 struct spoolss_DriverInfo8
*driver
;
1693 bool in_use
= false;
1694 uint32_t num_drivers
;
1695 const char **drivers
;
1701 version
= info
->version
;
1703 /* loop over all driver versions */
1705 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1707 /* get the list of drivers */
1709 result
= winreg_get_driver_list(mem_ctx
, b
,
1710 info
->architecture
, version
,
1711 &num_drivers
, &drivers
);
1712 if (!W_ERROR_IS_OK(result
)) {
1716 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1717 num_drivers
, info
->architecture
, version
));
1719 /* check each driver for overlap in files */
1721 for (i
= 0; i
< num_drivers
; i
++) {
1722 DEBUGADD(5,("\tdriver: [%s]\n", drivers
[i
]));
1726 result
= winreg_get_driver(mem_ctx
, b
,
1727 info
->architecture
, drivers
[i
],
1729 if (!W_ERROR_IS_OK(result
)) {
1730 talloc_free(drivers
);
1734 /* check if d2 uses any files from d1 */
1735 /* only if this is a different driver than the one being deleted */
1737 if (!strequal(info
->driver_name
, driver
->driver_name
)) {
1738 if (trim_overlap_drv_files(mem_ctx
, info
, driver
)) {
1739 /* mz: Do not instantly return -
1740 * we need to ensure this file isn't
1741 * also in use by other drivers. */
1746 talloc_free(driver
);
1749 talloc_free(drivers
);
1751 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1756 static NTSTATUS
driver_unlink_internals(connection_struct
*conn
,
1757 const char *short_arch
,
1761 TALLOC_CTX
*tmp_ctx
= talloc_new(conn
);
1762 struct smb_filename
*smb_fname
= NULL
;
1763 char *print_dlr_path
;
1764 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1766 print_dlr_path
= talloc_asprintf(tmp_ctx
, "%s/%d/%s",
1767 short_arch
, vers
, fname
);
1768 if (print_dlr_path
== NULL
) {
1772 smb_fname
= synthetic_smb_fname(tmp_ctx
, print_dlr_path
, NULL
, NULL
, 0);
1773 if (smb_fname
== NULL
) {
1777 status
= unlink_internals(conn
, NULL
, 0, smb_fname
, false);
1779 talloc_free(tmp_ctx
);
1783 /****************************************************************************
1784 Actually delete the driver files. Make sure that
1785 printer_driver_files_in_use() return False before calling
1787 ****************************************************************************/
1789 bool delete_driver_files(const struct auth_session_info
*session_info
,
1790 const struct spoolss_DriverInfo8
*r
)
1792 const char *short_arch
;
1793 connection_struct
*conn
;
1795 struct smb_filename
*oldcwd_fname
= NULL
;
1796 char *printdollar
= NULL
;
1797 int printdollar_snum
;
1804 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1805 r
->driver_name
, r
->version
));
1807 printdollar_snum
= find_service(talloc_tos(), "print$", &printdollar
);
1811 if (printdollar_snum
== -1) {
1815 nt_status
= create_conn_struct_cwd(talloc_tos(),
1816 server_event_context(),
1817 server_messaging_context(),
1820 lp_path(talloc_tos(), printdollar_snum
),
1821 session_info
, &oldcwd_fname
);
1822 if (!NT_STATUS_IS_OK(nt_status
)) {
1823 DEBUG(0,("delete_driver_files: create_conn_struct "
1824 "returned %s\n", nt_errstr(nt_status
)));
1828 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
1829 if (!NT_STATUS_IS_OK(nt_status
)) {
1830 DEBUG(0, ("failed set force user / group\n"));
1835 if (!become_user_by_session(conn
, session_info
)) {
1836 DEBUG(0, ("failed to become user\n"));
1841 if ( !CAN_WRITE(conn
) ) {
1842 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1847 short_arch
= get_short_archi(r
->architecture
);
1848 if (short_arch
== NULL
) {
1849 DEBUG(0, ("bad architecture %s\n", r
->architecture
));
1854 /* now delete the files */
1856 if (r
->driver_path
&& r
->driver_path
[0]) {
1857 DEBUG(10,("deleting driverfile [%s]\n", r
->driver_path
));
1858 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->driver_path
);
1861 if (r
->config_file
&& r
->config_file
[0]) {
1862 DEBUG(10,("deleting configfile [%s]\n", r
->config_file
));
1863 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->config_file
);
1866 if (r
->data_file
&& r
->data_file
[0]) {
1867 DEBUG(10,("deleting datafile [%s]\n", r
->data_file
));
1868 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->data_file
);
1871 if (r
->help_file
&& r
->help_file
[0]) {
1872 DEBUG(10,("deleting helpfile [%s]\n", r
->help_file
));
1873 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->help_file
);
1876 if (r
->dependent_files
) {
1878 while (r
->dependent_files
[i
] && r
->dependent_files
[i
][0]) {
1879 DEBUG(10,("deleting dependent file [%s]\n", r
->dependent_files
[i
]));
1880 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->dependent_files
[i
]);
1890 vfs_ChDir(conn
, oldcwd_fname
);
1891 TALLOC_FREE(oldcwd_fname
);
1892 SMB_VFS_DISCONNECT(conn
);
1900 1: level not implemented
1901 2: file doesn't exist
1902 3: can't allocate memory
1903 4: can't free memory
1904 5: non existent struct
1908 A printer and a printer driver are 2 different things.
1909 NT manages them separatelly, Samba does the same.
1910 Why ? Simply because it's easier and it makes sense !
1912 Now explanation: You have 3 printers behind your samba server,
1913 2 of them are the same make and model (laser A and B). But laser B
1914 has an 3000 sheet feeder and laser A doesn't such an option.
1915 Your third printer is an old dot-matrix model for the accounting :-).
1917 If the /usr/local/samba/lib directory (default dir), you will have
1918 5 files to describe all of this.
1920 3 files for the printers (1 by printer):
1923 NTprinter_accounting
1924 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1925 NTdriver_printer model X
1926 NTdriver_printer model Y
1928 jfm: I should use this comment for the text file to explain
1929 same thing for the forms BTW.
1930 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1934 /* Convert generic access rights to printer object specific access rights.
1935 It turns out that NT4 security descriptors use generic access rights and
1936 NT5 the object specific ones. */
1938 void map_printer_permissions(struct security_descriptor
*sd
)
1942 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
1943 se_map_generic(&sd
->dacl
->aces
[i
].access_mask
,
1944 &printer_generic_mapping
);
1948 void map_job_permissions(struct security_descriptor
*sd
)
1952 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
1953 se_map_generic(&sd
->dacl
->aces
[i
].access_mask
,
1954 &job_generic_mapping
);
1959 /****************************************************************************
1960 Check a user has permissions to perform the given operation. We use the
1961 permission constants defined in include/rpc_spoolss.h to check the various
1962 actions we perform when checking printer access.
1964 PRINTER_ACCESS_ADMINISTER:
1965 print_queue_pause, print_queue_resume, update_printer_sec,
1966 update_printer, spoolss_addprinterex_level_2,
1967 _spoolss_setprinterdata
1972 JOB_ACCESS_ADMINISTER:
1973 print_job_delete, print_job_pause, print_job_resume,
1976 Try access control in the following order (for performance reasons):
1977 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1978 2) check security descriptor (bit comparisons in memory)
1979 3) "printer admins" (may result in numerous calls to winbind)
1981 ****************************************************************************/
1982 WERROR
print_access_check(const struct auth_session_info
*session_info
,
1983 struct messaging_context
*msg_ctx
, int snum
,
1986 struct spoolss_security_descriptor
*secdesc
= NULL
;
1987 uint32_t access_granted
;
1992 TALLOC_CTX
*mem_ctx
= NULL
;
1994 /* If user is NULL then use the current_user structure */
1996 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1998 if ((session_info
->unix_token
->uid
== sec_initial_uid())
1999 || security_token_has_privilege(session_info
->security_token
,
2000 SEC_PRIV_PRINT_OPERATOR
)) {
2004 /* Get printer name */
2006 pname
= lp_printername(talloc_tos(), snum
);
2008 if (!pname
|| !*pname
) {
2009 return WERR_ACCESS_DENIED
;
2012 /* Get printer security descriptor */
2014 if(!(mem_ctx
= talloc_init("print_access_check"))) {
2015 return WERR_NOT_ENOUGH_MEMORY
;
2018 result
= winreg_get_printer_secdesc_internal(mem_ctx
,
2019 get_session_info_system(),
2023 if (!W_ERROR_IS_OK(result
)) {
2024 talloc_destroy(mem_ctx
);
2025 return WERR_NOT_ENOUGH_MEMORY
;
2028 if (access_type
== JOB_ACCESS_ADMINISTER
) {
2029 struct spoolss_security_descriptor
*parent_secdesc
= secdesc
;
2031 /* Create a child security descriptor to check permissions
2032 against. This is because print jobs are child objects
2033 objects of a printer. */
2034 status
= se_create_child_secdesc(mem_ctx
,
2038 parent_secdesc
->owner_sid
,
2039 parent_secdesc
->group_sid
,
2041 if (!NT_STATUS_IS_OK(status
)) {
2042 talloc_destroy(mem_ctx
);
2043 return ntstatus_to_werror(status
);
2046 map_job_permissions(secdesc
);
2048 map_printer_permissions(secdesc
);
2052 status
= se_access_check(secdesc
, session_info
->security_token
, access_type
,
2055 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status
) ? "SUCCESS" : "FAILURE"));
2057 talloc_destroy(mem_ctx
);
2059 return ntstatus_to_werror(status
);
2062 /****************************************************************************
2063 Check the time parameters allow a print operation.
2064 *****************************************************************************/
2066 bool print_time_access_check(const struct auth_session_info
*session_info
,
2067 struct messaging_context
*msg_ctx
,
2068 const char *servicename
)
2070 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
2073 time_t now
= time(NULL
);
2077 result
= winreg_get_printer_internal(NULL
, session_info
, msg_ctx
,
2078 servicename
, &pinfo2
);
2079 if (!W_ERROR_IS_OK(result
)) {
2083 if (pinfo2
->starttime
== 0 && pinfo2
->untiltime
== 0) {
2088 mins
= (uint32_t)t
->tm_hour
*60 + (uint32_t)t
->tm_min
;
2090 if (mins
>= pinfo2
->starttime
&& mins
<= pinfo2
->untiltime
) {
2094 TALLOC_FREE(pinfo2
);
2103 void nt_printer_remove(TALLOC_CTX
*mem_ctx
,
2104 const struct auth_session_info
*session_info
,
2105 struct messaging_context
*msg_ctx
,
2106 const char *printer
)
2110 result
= winreg_delete_printer_key_internal(mem_ctx
, session_info
, msg_ctx
,
2112 if (!W_ERROR_IS_OK(result
)) {
2113 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2114 "%s\n", printer
, win_errstr(result
)));
2118 void nt_printer_add(TALLOC_CTX
*mem_ctx
,
2119 const struct auth_session_info
*session_info
,
2120 struct messaging_context
*msg_ctx
,
2121 const char *printer
)
2125 result
= winreg_create_printer_internal(mem_ctx
, session_info
, msg_ctx
,
2127 if (!W_ERROR_IS_OK(result
)) {
2128 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2129 printer
, win_errstr(result
)));