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();
84 service
= lp_servicenumber("print$");
86 /* We don't have a print$ share */
87 DEBUG(5, ("No print$ share has been configured.\n"));
92 driver_path
= lp_path(mem_ctx
, service
);
93 if (driver_path
== NULL
) {
98 ok
= directory_create_or_exist(driver_path
, sec_initial_uid(), 0755);
100 DEBUG(1, ("Failed to create printer driver directory %s\n",
102 talloc_free(mem_ctx
);
106 for (i
= 0; archi_table
[i
].long_archi
!= NULL
; i
++) {
107 const char *arch_path
;
109 arch_path
= talloc_asprintf(mem_ctx
,
112 archi_table
[i
].short_archi
);
113 if (arch_path
== NULL
) {
114 talloc_free(mem_ctx
);
118 ok
= directory_create_or_exist(arch_path
,
122 DEBUG(1, ("Failed to create printer driver "
123 "architecture directory %s\n",
125 talloc_free(mem_ctx
);
130 talloc_free(mem_ctx
);
134 /****************************************************************************
135 Open the NT printing tdbs. Done once before fork().
136 ****************************************************************************/
138 bool nt_printing_init(struct messaging_context
*msg_ctx
)
142 if (!print_driver_directories_init()) {
146 if (!nt_printing_tdb_upgrade()) {
151 * register callback to handle updating printers as new
152 * drivers are installed
154 messaging_register(msg_ctx
, NULL
, MSG_PRINTER_DRVUPGRADE
,
155 do_drv_upgrade_printer
);
157 /* of course, none of the message callbacks matter if you don't
158 tell messages.c that you interested in receiving PRINT_GENERAL
159 msgs. This is done in serverid_register() */
161 if ( lp_security() == SEC_ADS
) {
162 win_rc
= check_published_printers(msg_ctx
);
163 if (!W_ERROR_IS_OK(win_rc
))
164 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc
)));
170 /*******************************************************************
171 Function to allow filename parsing "the old way".
172 ********************************************************************/
174 static NTSTATUS
driver_unix_convert(connection_struct
*conn
,
175 const char *old_name
,
176 struct smb_filename
**smb_fname
)
179 TALLOC_CTX
*ctx
= talloc_tos();
180 char *name
= talloc_strdup(ctx
, old_name
);
183 return NT_STATUS_NO_MEMORY
;
186 name
= unix_clean_name(ctx
, name
);
188 return NT_STATUS_NO_MEMORY
;
190 trim_string(name
,"/","/");
192 status
= unix_convert(ctx
, conn
, name
, smb_fname
, 0);
193 if (!NT_STATUS_IS_OK(status
)) {
194 return NT_STATUS_NO_MEMORY
;
200 /****************************************************************************
201 Function to do the mapping between the long architecture name and
203 ****************************************************************************/
205 const char *get_short_archi(const char *long_archi
)
209 DEBUG(107,("Getting architecture dependent directory\n"));
212 } while ( (archi_table
[i
].long_archi
!=NULL
) &&
213 strcasecmp_m(long_archi
, archi_table
[i
].long_archi
) );
215 if (archi_table
[i
].long_archi
==NULL
) {
216 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi
));
220 /* this might be client code - but shouldn't this be an fstrcpy etc? */
222 DEBUGADD(108,("index: [%d]\n", i
));
223 DEBUGADD(108,("long architecture: [%s]\n", archi_table
[i
].long_archi
));
224 DEBUGADD(108,("short architecture: [%s]\n", archi_table
[i
].short_archi
));
226 return archi_table
[i
].short_archi
;
229 /****************************************************************************
230 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
231 There are two case to be covered here: PE (Portable Executable) and NE (New
232 Executable) files. Both files support the same INFO structure, but PE files
233 store the signature in unicode, and NE files store it as !unicode.
234 returns -1 on error, 1 on version info found, and 0 on no version info found.
235 ****************************************************************************/
237 static int get_file_version(files_struct
*fsp
, char *fname
,uint32
*major
, uint32
*minor
)
243 if ((buf
=(char *)SMB_MALLOC(DOS_HEADER_SIZE
)) == NULL
) {
244 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
245 fname
, DOS_HEADER_SIZE
));
249 if ((byte_count
= vfs_read_data(fsp
, buf
, DOS_HEADER_SIZE
)) < DOS_HEADER_SIZE
) {
250 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
251 fname
, (unsigned long)byte_count
));
252 goto no_version_info
;
255 /* Is this really a DOS header? */
256 if (SVAL(buf
,DOS_HEADER_MAGIC_OFFSET
) != DOS_HEADER_MAGIC
) {
257 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
258 fname
, SVAL(buf
,DOS_HEADER_MAGIC_OFFSET
)));
259 goto no_version_info
;
262 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
263 if (SMB_VFS_LSEEK(fsp
, SVAL(buf
,DOS_HEADER_LFANEW_OFFSET
), SEEK_SET
) == (off_t
)-1) {
264 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
266 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
267 goto no_version_info
;
270 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
271 if ((byte_count
= vfs_read_data(fsp
, buf
, NE_HEADER_SIZE
)) < NE_HEADER_SIZE
) {
272 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
273 fname
, (unsigned long)byte_count
));
274 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
275 goto no_version_info
;
278 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
279 if (IVAL(buf
,PE_HEADER_SIGNATURE_OFFSET
) == PE_HEADER_SIGNATURE
) {
280 unsigned int num_sections
;
281 unsigned int section_table_bytes
;
283 /* Just skip over optional header to get to section table */
284 if (SMB_VFS_LSEEK(fsp
,
285 SVAL(buf
,PE_HEADER_OPTIONAL_HEADER_SIZE
)-(NE_HEADER_SIZE
-PE_HEADER_SIZE
),
286 SEEK_CUR
) == (off_t
)-1) {
287 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
292 /* get the section table */
293 num_sections
= SVAL(buf
,PE_HEADER_NUMBER_OF_SECTIONS
);
294 section_table_bytes
= num_sections
* PE_HEADER_SECT_HEADER_SIZE
;
295 if (section_table_bytes
== 0)
299 if ((buf
=(char *)SMB_MALLOC(section_table_bytes
)) == NULL
) {
300 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
301 fname
, section_table_bytes
));
305 if ((byte_count
= vfs_read_data(fsp
, buf
, section_table_bytes
)) < section_table_bytes
) {
306 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
307 fname
, (unsigned long)byte_count
));
311 /* Iterate the section table looking for the resource section ".rsrc" */
312 for (i
= 0; i
< num_sections
; i
++) {
313 int sec_offset
= i
* PE_HEADER_SECT_HEADER_SIZE
;
315 if (strcmp(".rsrc", &buf
[sec_offset
+PE_HEADER_SECT_NAME_OFFSET
]) == 0) {
316 unsigned int section_pos
= IVAL(buf
,sec_offset
+PE_HEADER_SECT_PTR_DATA_OFFSET
);
317 unsigned int section_bytes
= IVAL(buf
,sec_offset
+PE_HEADER_SECT_SIZE_DATA_OFFSET
);
319 if (section_bytes
== 0)
323 if ((buf
=(char *)SMB_MALLOC(section_bytes
)) == NULL
) {
324 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
325 fname
, section_bytes
));
329 /* Seek to the start of the .rsrc section info */
330 if (SMB_VFS_LSEEK(fsp
, section_pos
, SEEK_SET
) == (off_t
)-1) {
331 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
336 if ((byte_count
= vfs_read_data(fsp
, buf
, section_bytes
)) < section_bytes
) {
337 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
338 fname
, (unsigned long)byte_count
));
342 if (section_bytes
< VS_VERSION_INFO_UNICODE_SIZE
)
345 for (i
=0; i
<section_bytes
-VS_VERSION_INFO_UNICODE_SIZE
; i
++) {
346 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
347 if (buf
[i
] == 'V' && buf
[i
+1] == '\0' && buf
[i
+2] == 'S') {
348 /* Align to next long address */
349 int pos
= (i
+ sizeof(VS_SIGNATURE
)*2 + 3) & 0xfffffffc;
351 if (IVAL(buf
,pos
) == VS_MAGIC_VALUE
) {
352 *major
= IVAL(buf
,pos
+VS_MAJOR_OFFSET
);
353 *minor
= IVAL(buf
,pos
+VS_MINOR_OFFSET
);
355 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
356 fname
, *major
, *minor
,
357 (*major
>>16)&0xffff, *major
&0xffff,
358 (*minor
>>16)&0xffff, *minor
&0xffff));
367 /* Version info not found, fall back to origin date/time */
368 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname
));
372 } else if (SVAL(buf
,NE_HEADER_SIGNATURE_OFFSET
) == NE_HEADER_SIGNATURE
) {
373 if (CVAL(buf
,NE_HEADER_TARGET_OS_OFFSET
) != NE_HEADER_TARGOS_WIN
) {
374 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
375 fname
, CVAL(buf
,NE_HEADER_TARGET_OS_OFFSET
)));
376 /* At this point, we assume the file is in error. It still could be somthing
377 * else besides a NE file, but it unlikely at this point. */
381 /* Allocate a bit more space to speed up things */
383 if ((buf
=(char *)SMB_MALLOC(VS_NE_BUF_SIZE
)) == NULL
) {
384 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
385 fname
, PE_HEADER_SIZE
));
389 /* This is a HACK! I got tired of trying to sort through the messy
390 * 'NE' file format. If anyone wants to clean this up please have at
391 * it, but this works. 'NE' files will eventually fade away. JRR */
392 while((byte_count
= vfs_read_data(fsp
, buf
, VS_NE_BUF_SIZE
)) > 0) {
393 /* Cover case that should not occur in a well formed 'NE' .dll file */
394 if (byte_count
-VS_VERSION_INFO_SIZE
<= 0) break;
396 for(i
=0; i
<byte_count
; i
++) {
397 /* Fast skip past data that can't possibly match */
398 if (buf
[i
] != 'V') continue;
400 /* Potential match data crosses buf boundry, move it to beginning
401 * of buf, and fill the buf with as much as it will hold. */
402 if (i
>byte_count
-VS_VERSION_INFO_SIZE
) {
405 memcpy(buf
, &buf
[i
], byte_count
-i
);
406 if ((bc
= vfs_read_data(fsp
, &buf
[byte_count
-i
], VS_NE_BUF_SIZE
-
407 (byte_count
-i
))) < 0) {
409 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
414 byte_count
= bc
+ (byte_count
- i
);
415 if (byte_count
<VS_VERSION_INFO_SIZE
) break;
420 /* Check that the full signature string and the magic number that
421 * follows exist (not a perfect solution, but the chances that this
422 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
423 * twice, as it is simpler to read the code. */
424 if (strcmp(&buf
[i
], VS_SIGNATURE
) == 0) {
425 /* Compute skip alignment to next long address */
426 int skip
= -(SMB_VFS_LSEEK(fsp
, 0, SEEK_CUR
) - (byte_count
- i
) +
427 sizeof(VS_SIGNATURE
)) & 3;
428 if (IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
) != 0xfeef04bd) continue;
430 *major
= IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
+VS_MAJOR_OFFSET
);
431 *minor
= IVAL(buf
,i
+sizeof(VS_SIGNATURE
)+skip
+VS_MINOR_OFFSET
);
432 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
433 fname
, *major
, *minor
,
434 (*major
>>16)&0xffff, *major
&0xffff,
435 (*minor
>>16)&0xffff, *minor
&0xffff));
442 /* Version info not found, fall back to origin date/time */
443 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname
));
448 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
449 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
450 fname
, IVAL(buf
,PE_HEADER_SIGNATURE_OFFSET
)));
461 /****************************************************************************
462 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
463 share one or more files. During the MS installation process files are checked
464 to insure that only a newer version of a shared file is installed over an
465 older version. There are several possibilities for this comparison. If there
466 is no previous version, the new one is newer (obviously). If either file is
467 missing the version info structure, compare the creation date (on Unix use
468 the modification date). Otherwise chose the numerically larger version number.
469 ****************************************************************************/
471 static int file_version_is_newer(connection_struct
*conn
, fstring new_file
, fstring old_file
)
473 bool use_version
= true;
477 time_t new_create_time
;
481 time_t old_create_time
;
483 struct smb_filename
*smb_fname
= NULL
;
484 files_struct
*fsp
= NULL
;
490 SET_STAT_INVALID(st
);
491 new_create_time
= (time_t)0;
492 old_create_time
= (time_t)0;
494 /* Get file version info (if available) for previous file (if it exists) */
495 status
= driver_unix_convert(conn
, old_file
, &smb_fname
);
496 if (!NT_STATUS_IS_OK(status
)) {
500 status
= SMB_VFS_CREATE_FILE(
503 0, /* root_dir_fid */
504 smb_fname
, /* fname */
505 FILE_GENERIC_READ
, /* access_mask */
506 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
507 FILE_OPEN
, /* create_disposition*/
508 0, /* create_options */
509 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
510 INTERNAL_OPEN_ONLY
, /* oplock_request */
511 0, /* allocation_size */
512 0, /* private_flags */
518 if (!NT_STATUS_IS_OK(status
)) {
519 /* Old file not found, so by definition new file is in fact newer */
520 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
521 "errno = %d\n", smb_fname_str_dbg(smb_fname
),
527 ret
= get_file_version(fsp
, old_file
, &old_major
, &old_minor
);
533 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
536 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
539 old_create_time
= convert_timespec_to_time_t(st
.st_ex_mtime
);
540 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
541 (long)old_create_time
));
544 close_file(NULL
, fsp
, NORMAL_CLOSE
);
547 /* Get file version info (if available) for new file */
548 status
= driver_unix_convert(conn
, new_file
, &smb_fname
);
549 if (!NT_STATUS_IS_OK(status
)) {
553 status
= SMB_VFS_CREATE_FILE(
556 0, /* root_dir_fid */
557 smb_fname
, /* fname */
558 FILE_GENERIC_READ
, /* access_mask */
559 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
560 FILE_OPEN
, /* create_disposition*/
561 0, /* create_options */
562 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
563 INTERNAL_OPEN_ONLY
, /* oplock_request */
564 0, /* allocation_size */
565 0, /* private_flags */
571 if (!NT_STATUS_IS_OK(status
)) {
572 /* New file not found, this shouldn't occur if the caller did its job */
573 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
574 "errno = %d\n", smb_fname_str_dbg(smb_fname
), errno
));
578 ret
= get_file_version(fsp
, new_file
, &new_major
, &new_minor
);
584 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
587 if (SMB_VFS_FSTAT(fsp
, &st
) == -1) {
590 new_create_time
= convert_timespec_to_time_t(st
.st_ex_mtime
);
591 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
592 (long)new_create_time
));
595 close_file(NULL
, fsp
, NORMAL_CLOSE
);
598 if (use_version
&& (new_major
!= old_major
|| new_minor
!= old_minor
)) {
599 /* Compare versions and choose the larger version number */
600 if (new_major
> old_major
||
601 (new_major
== old_major
&& new_minor
> old_minor
)) {
603 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file
, new_file
));
608 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file
));
614 /* Compare modification time/dates and choose the newest time/date */
615 if (new_create_time
> old_create_time
) {
616 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file
, new_file
));
621 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file
));
629 close_file(NULL
, fsp
, NORMAL_CLOSE
);
632 TALLOC_FREE(smb_fname
);
636 /****************************************************************************
637 Determine the correct cVersion associated with an architecture and driver
638 ****************************************************************************/
639 static uint32
get_correct_cversion(struct auth_session_info
*session_info
,
640 const char *architecture
,
641 const char *driverpath_in
,
646 struct smb_filename
*smb_fname
= NULL
;
647 char *driverpath
= NULL
;
648 files_struct
*fsp
= NULL
;
649 connection_struct
*conn
= NULL
;
651 char *printdollar
= NULL
;
652 int printdollar_snum
;
654 *perr
= WERR_INVALID_PARAM
;
656 /* If architecture is Windows 95/98/ME, the version is always 0. */
657 if (strcmp(architecture
, SPL_ARCH_WIN40
) == 0) {
658 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
663 /* If architecture is Windows x64, the version is always 3. */
664 if (strcmp(architecture
, SPL_ARCH_X64
) == 0) {
665 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
670 printdollar_snum
= find_service(talloc_tos(), "print$", &printdollar
);
675 if (printdollar_snum
== -1) {
676 *perr
= WERR_NO_SUCH_SHARE
;
680 nt_status
= create_conn_struct_cwd(talloc_tos(),
681 server_event_context(),
682 server_messaging_context(),
685 lp_path(talloc_tos(), printdollar_snum
),
686 session_info
, &oldcwd
);
687 if (!NT_STATUS_IS_OK(nt_status
)) {
688 DEBUG(0,("get_correct_cversion: create_conn_struct "
689 "returned %s\n", nt_errstr(nt_status
)));
690 *perr
= ntstatus_to_werror(nt_status
);
694 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
695 if (!NT_STATUS_IS_OK(nt_status
)) {
696 DEBUG(0, ("failed set force user / group\n"));
697 *perr
= ntstatus_to_werror(nt_status
);
698 goto error_free_conn
;
701 if (!become_user_by_session(conn
, session_info
)) {
702 DEBUG(0, ("failed to become user\n"));
703 *perr
= WERR_ACCESS_DENIED
;
704 goto error_free_conn
;
707 /* Open the driver file (Portable Executable format) and determine the
708 * deriver the cversion. */
709 driverpath
= talloc_asprintf(talloc_tos(),
718 nt_status
= driver_unix_convert(conn
, driverpath
, &smb_fname
);
719 if (!NT_STATUS_IS_OK(nt_status
)) {
720 *perr
= ntstatus_to_werror(nt_status
);
724 nt_status
= vfs_file_exist(conn
, smb_fname
);
725 if (!NT_STATUS_IS_OK(nt_status
)) {
726 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
727 *perr
= WERR_BADFILE
;
731 nt_status
= SMB_VFS_CREATE_FILE(
734 0, /* root_dir_fid */
735 smb_fname
, /* fname */
736 FILE_GENERIC_READ
, /* access_mask */
737 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
738 FILE_OPEN
, /* create_disposition*/
739 0, /* create_options */
740 FILE_ATTRIBUTE_NORMAL
, /* file_attributes */
741 INTERNAL_OPEN_ONLY
, /* oplock_request */
742 0, /* private_flags */
743 0, /* allocation_size */
749 if (!NT_STATUS_IS_OK(nt_status
)) {
750 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
751 "%d\n", smb_fname_str_dbg(smb_fname
), errno
));
752 *perr
= WERR_ACCESS_DENIED
;
759 ret
= get_file_version(fsp
, smb_fname
->base_name
, &major
, &minor
);
761 *perr
= WERR_INVALID_PARAM
;
764 DEBUG(6,("get_correct_cversion: Version info not "
766 smb_fname_str_dbg(smb_fname
)));
767 *perr
= WERR_INVALID_PARAM
;
772 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
773 * for more details. Version in this case is not just the version of the
774 * file, but the version in the sense of kernal mode (2) vs. user mode
775 * (3) drivers. Other bits of the version fields are the version info.
778 cversion
= major
& 0x0000ffff;
780 case 2: /* WinNT drivers */
781 case 3: /* Win2K drivers */
785 DEBUG(6,("get_correct_cversion: cversion "
786 "invalid [%s] cversion = %d\n",
787 smb_fname_str_dbg(smb_fname
),
792 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
793 " = 0x%x minor = 0x%x\n",
794 smb_fname_str_dbg(smb_fname
), major
, minor
));
797 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
798 smb_fname_str_dbg(smb_fname
), cversion
));
804 TALLOC_FREE(smb_fname
);
806 close_file(NULL
, fsp
, NORMAL_CLOSE
);
809 vfs_ChDir(conn
, oldcwd
);
810 SMB_VFS_DISCONNECT(conn
);
813 if (!W_ERROR_IS_OK(*perr
)) {
820 /****************************************************************************
821 ****************************************************************************/
823 #define strip_driver_path(_mem_ctx, _element) do { \
824 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
825 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
826 W_ERROR_HAVE_NO_MEMORY((_element)); \
830 static WERROR
clean_up_driver_struct_level(TALLOC_CTX
*mem_ctx
,
831 struct auth_session_info
*session_info
,
832 const char *architecture
,
833 const char **driver_path
,
834 const char **data_file
,
835 const char **config_file
,
836 const char **help_file
,
837 struct spoolss_StringArray
*dependent_files
,
838 enum spoolss_DriverOSVersion
*version
)
840 const char *short_architecture
;
845 if (!*driver_path
|| !*data_file
) {
846 return WERR_INVALID_PARAM
;
849 if (!strequal(architecture
, SPOOLSS_ARCHITECTURE_4_0
) && !*config_file
) {
850 return WERR_INVALID_PARAM
;
853 /* clean up the driver name.
854 * we can get .\driver.dll
855 * or worse c:\windows\system\driver.dll !
857 /* using an intermediate string to not have overlaping memcpy()'s */
859 strip_driver_path(mem_ctx
, *driver_path
);
860 strip_driver_path(mem_ctx
, *data_file
);
862 strip_driver_path(mem_ctx
, *config_file
);
865 strip_driver_path(mem_ctx
, *help_file
);
868 if (dependent_files
&& dependent_files
->string
) {
869 for (i
=0; dependent_files
->string
[i
]; i
++) {
870 strip_driver_path(mem_ctx
, dependent_files
->string
[i
]);
874 short_architecture
= get_short_archi(architecture
);
875 if (!short_architecture
) {
876 return WERR_UNKNOWN_PRINTER_DRIVER
;
879 /* jfm:7/16/2000 the client always sends the cversion=0.
880 * The server should check which version the driver is by reading
881 * the PE header of driver->driverpath.
883 * For Windows 95/98 the version is 0 (so the value sent is correct)
884 * For Windows NT (the architecture doesn't matter)
886 * NT 3.5/3.51: cversion=1
891 *version
= get_correct_cversion(session_info
, short_architecture
,
893 if (*version
== -1) {
900 /****************************************************************************
901 ****************************************************************************/
903 WERROR
clean_up_driver_struct(TALLOC_CTX
*mem_ctx
,
904 struct auth_session_info
*session_info
,
905 struct spoolss_AddDriverInfoCtr
*r
)
909 return clean_up_driver_struct_level(mem_ctx
, session_info
,
910 r
->info
.info3
->architecture
,
911 &r
->info
.info3
->driver_path
,
912 &r
->info
.info3
->data_file
,
913 &r
->info
.info3
->config_file
,
914 &r
->info
.info3
->help_file
,
915 r
->info
.info3
->dependent_files
,
916 &r
->info
.info3
->version
);
918 return clean_up_driver_struct_level(mem_ctx
, session_info
,
919 r
->info
.info6
->architecture
,
920 &r
->info
.info6
->driver_path
,
921 &r
->info
.info6
->data_file
,
922 &r
->info
.info6
->config_file
,
923 &r
->info
.info6
->help_file
,
924 r
->info
.info6
->dependent_files
,
925 &r
->info
.info6
->version
);
927 return WERR_NOT_SUPPORTED
;
931 /****************************************************************************
932 This function sucks and should be replaced. JRA.
933 ****************************************************************************/
935 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3
*dst
,
936 const struct spoolss_AddDriverInfo6
*src
)
938 dst
->version
= src
->version
;
940 dst
->driver_name
= src
->driver_name
;
941 dst
->architecture
= src
->architecture
;
942 dst
->driver_path
= src
->driver_path
;
943 dst
->data_file
= src
->data_file
;
944 dst
->config_file
= src
->config_file
;
945 dst
->help_file
= src
->help_file
;
946 dst
->monitor_name
= src
->monitor_name
;
947 dst
->default_datatype
= src
->default_datatype
;
948 dst
->_ndr_size_dependent_files
= src
->_ndr_size_dependent_files
;
949 dst
->dependent_files
= src
->dependent_files
;
952 /****************************************************************************
953 ****************************************************************************/
955 static WERROR
move_driver_file_to_download_area(TALLOC_CTX
*mem_ctx
,
956 connection_struct
*conn
,
957 const char *driver_file
,
958 const char *short_architecture
,
959 uint32_t driver_version
,
962 struct smb_filename
*smb_fname_old
= NULL
;
963 struct smb_filename
*smb_fname_new
= NULL
;
964 char *old_name
= NULL
;
965 char *new_name
= NULL
;
969 old_name
= talloc_asprintf(mem_ctx
, "%s/%s",
970 short_architecture
, driver_file
);
971 W_ERROR_HAVE_NO_MEMORY(old_name
);
973 new_name
= talloc_asprintf(mem_ctx
, "%s/%d/%s",
974 short_architecture
, driver_version
, driver_file
);
975 if (new_name
== NULL
) {
976 TALLOC_FREE(old_name
);
980 if (version
!= -1 && (version
= file_version_is_newer(conn
, old_name
, new_name
)) > 0) {
982 status
= driver_unix_convert(conn
, old_name
, &smb_fname_old
);
983 if (!NT_STATUS_IS_OK(status
)) {
988 /* Setup a synthetic smb_filename struct */
989 smb_fname_new
= talloc_zero(mem_ctx
, struct smb_filename
);
990 if (!smb_fname_new
) {
995 smb_fname_new
->base_name
= new_name
;
997 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
998 "'%s'\n", smb_fname_old
->base_name
,
999 smb_fname_new
->base_name
));
1001 status
= copy_file(mem_ctx
, conn
, smb_fname_old
, smb_fname_new
,
1002 OPENX_FILE_EXISTS_TRUNCATE
|
1003 OPENX_FILE_CREATE_IF_NOT_EXIST
,
1006 if (!NT_STATUS_IS_OK(status
)) {
1007 DEBUG(0,("move_driver_file_to_download_area: Unable "
1008 "to rename [%s] to [%s]: %s\n",
1009 smb_fname_old
->base_name
, new_name
,
1010 nt_errstr(status
)));
1011 ret
= WERR_ACCESS_DENIED
;
1018 TALLOC_FREE(smb_fname_old
);
1019 TALLOC_FREE(smb_fname_new
);
1023 WERROR
move_driver_to_download_area(struct auth_session_info
*session_info
,
1024 struct spoolss_AddDriverInfoCtr
*r
)
1026 struct spoolss_AddDriverInfo3
*driver
;
1027 struct spoolss_AddDriverInfo3 converted_driver
;
1028 const char *short_architecture
;
1029 struct smb_filename
*smb_dname
= NULL
;
1030 char *new_dir
= NULL
;
1031 connection_struct
*conn
= NULL
;
1034 TALLOC_CTX
*ctx
= talloc_tos();
1037 char *printdollar
= NULL
;
1038 int printdollar_snum
;
1039 WERROR err
= WERR_OK
;
1043 driver
= r
->info
.info3
;
1046 convert_level_6_to_level3(&converted_driver
, r
->info
.info6
);
1047 driver
= &converted_driver
;
1050 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r
->level
));
1051 return WERR_UNKNOWN_LEVEL
;
1054 short_architecture
= get_short_archi(driver
->architecture
);
1055 if (!short_architecture
) {
1056 return WERR_UNKNOWN_PRINTER_DRIVER
;
1059 printdollar_snum
= find_service(ctx
, "print$", &printdollar
);
1063 if (printdollar_snum
== -1) {
1064 return WERR_NO_SUCH_SHARE
;
1067 nt_status
= create_conn_struct_cwd(talloc_tos(),
1068 server_event_context(),
1069 server_messaging_context(),
1072 lp_path(talloc_tos(), printdollar_snum
),
1073 session_info
, &oldcwd
);
1074 if (!NT_STATUS_IS_OK(nt_status
)) {
1075 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1076 "returned %s\n", nt_errstr(nt_status
)));
1077 err
= ntstatus_to_werror(nt_status
);
1081 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
1082 if (!NT_STATUS_IS_OK(nt_status
)) {
1083 DEBUG(0, ("failed set force user / group\n"));
1084 err
= ntstatus_to_werror(nt_status
);
1088 if (!become_user_by_session(conn
, session_info
)) {
1089 DEBUG(0, ("failed to become user\n"));
1090 err
= WERR_ACCESS_DENIED
;
1094 new_dir
= talloc_asprintf(ctx
,
1102 nt_status
= driver_unix_convert(conn
, new_dir
, &smb_dname
);
1103 if (!NT_STATUS_IS_OK(nt_status
)) {
1108 DEBUG(5,("Creating first directory: %s\n", smb_dname
->base_name
));
1110 nt_status
= create_directory(conn
, NULL
, smb_dname
);
1111 if (!NT_STATUS_IS_OK(nt_status
)
1112 && !NT_STATUS_EQUAL(nt_status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
1113 DEBUG(0, ("failed to create driver destination directory: %s\n",
1114 nt_errstr(nt_status
)));
1115 err
= ntstatus_to_werror(nt_status
);
1119 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1120 * listed for this driver which has already been moved, skip it (note:
1121 * drivers may list the same file name several times. Then check if the
1122 * file already exists in archi\version\, if so, check that the version
1123 * info (or time stamps if version info is unavailable) is newer (or the
1124 * date is later). If it is, move it to archi\version\filexxx.yyy.
1125 * Otherwise, delete the file.
1127 * If a file is not moved to archi\version\ because of an error, all the
1128 * rest of the 'unmoved' driver files are removed from archi\. If one or
1129 * more of the driver's files was already moved to archi\version\, it
1130 * potentially leaves the driver in a partially updated state. Version
1131 * trauma will most likely occur if an client attempts to use any printer
1132 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1133 * done is appropriate... later JRR
1136 DEBUG(5,("Moving files now !\n"));
1138 if (driver
->driver_path
&& strlen(driver
->driver_path
)) {
1140 err
= move_driver_file_to_download_area(ctx
,
1142 driver
->driver_path
,
1146 if (!W_ERROR_IS_OK(err
)) {
1151 if (driver
->data_file
&& strlen(driver
->data_file
)) {
1152 if (!strequal(driver
->data_file
, driver
->driver_path
)) {
1154 err
= move_driver_file_to_download_area(ctx
,
1160 if (!W_ERROR_IS_OK(err
)) {
1166 if (driver
->config_file
&& strlen(driver
->config_file
)) {
1167 if (!strequal(driver
->config_file
, driver
->driver_path
) &&
1168 !strequal(driver
->config_file
, driver
->data_file
)) {
1170 err
= move_driver_file_to_download_area(ctx
,
1172 driver
->config_file
,
1176 if (!W_ERROR_IS_OK(err
)) {
1182 if (driver
->help_file
&& strlen(driver
->help_file
)) {
1183 if (!strequal(driver
->help_file
, driver
->driver_path
) &&
1184 !strequal(driver
->help_file
, driver
->data_file
) &&
1185 !strequal(driver
->help_file
, driver
->config_file
)) {
1187 err
= move_driver_file_to_download_area(ctx
,
1193 if (!W_ERROR_IS_OK(err
)) {
1199 if (driver
->dependent_files
&& driver
->dependent_files
->string
) {
1200 for (i
=0; driver
->dependent_files
->string
[i
]; i
++) {
1201 if (!strequal(driver
->dependent_files
->string
[i
], driver
->driver_path
) &&
1202 !strequal(driver
->dependent_files
->string
[i
], driver
->data_file
) &&
1203 !strequal(driver
->dependent_files
->string
[i
], driver
->config_file
) &&
1204 !strequal(driver
->dependent_files
->string
[i
], driver
->help_file
)) {
1206 for (j
=0; j
< i
; j
++) {
1207 if (strequal(driver
->dependent_files
->string
[i
], driver
->dependent_files
->string
[j
])) {
1212 err
= move_driver_file_to_download_area(ctx
,
1214 driver
->dependent_files
->string
[i
],
1218 if (!W_ERROR_IS_OK(err
)) {
1230 TALLOC_FREE(smb_dname
);
1233 vfs_ChDir(conn
, oldcwd
);
1234 SMB_VFS_DISCONNECT(conn
);
1241 /****************************************************************************
1242 Determine whether or not a particular driver is currently assigned
1244 ****************************************************************************/
1246 bool printer_driver_in_use(TALLOC_CTX
*mem_ctx
,
1247 struct dcerpc_binding_handle
*b
,
1248 const struct spoolss_DriverInfo8
*r
)
1251 int n_services
= lp_numservices();
1252 bool in_use
= False
;
1253 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
1260 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1262 /* loop through the printers.tdb and check for the drivername */
1264 for (snum
=0; snum
<n_services
&& !in_use
; snum
++) {
1265 if (!lp_snum_ok(snum
) || !lp_printable(snum
)) {
1269 result
= winreg_get_printer(mem_ctx
, b
,
1270 lp_servicename(talloc_tos(), snum
),
1272 if (!W_ERROR_IS_OK(result
)) {
1273 continue; /* skip */
1276 if (strequal(r
->driver_name
, pinfo2
->drivername
)) {
1280 TALLOC_FREE(pinfo2
);
1283 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1286 struct spoolss_DriverInfo8
*driver
= NULL
;
1289 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r
->driver_name
));
1291 /* we can still remove the driver if there is one of
1292 "Windows NT x86" version 2 or 3 left */
1294 if (!strequal("Windows NT x86", r
->architecture
)) {
1295 werr
= winreg_get_driver(mem_ctx
, b
,
1300 } else if (r
->version
== 2) {
1301 werr
= winreg_get_driver(mem_ctx
, b
,
1305 } else if (r
->version
== 3) {
1306 werr
= winreg_get_driver(mem_ctx
, b
,
1311 DEBUG(0, ("printer_driver_in_use: ERROR!"
1312 " unknown driver version (%d)\n",
1314 werr
= WERR_UNKNOWN_PRINTER_DRIVER
;
1317 /* now check the error code */
1319 if ( W_ERROR_IS_OK(werr
) ) {
1320 /* it's ok to remove the driver, we have other architctures left */
1322 talloc_free(driver
);
1326 /* report that the driver is not in use by default */
1332 /**********************************************************************
1333 Check to see if a ogiven file is in use by *info
1334 *********************************************************************/
1336 static bool drv_file_in_use(const char *file
, const struct spoolss_DriverInfo8
*info
)
1343 /* mz: skip files that are in the list but already deleted */
1344 if (!file
|| !file
[0]) {
1348 if (strequal(file
, info
->driver_path
))
1351 if (strequal(file
, info
->data_file
))
1354 if (strequal(file
, info
->config_file
))
1357 if (strequal(file
, info
->help_file
))
1360 /* see of there are any dependent files to examine */
1362 if (!info
->dependent_files
)
1365 while (info
->dependent_files
[i
] && *info
->dependent_files
[i
]) {
1366 if (strequal(file
, info
->dependent_files
[i
]))
1375 /**********************************************************************
1376 Utility function to remove the dependent file pointed to by the
1377 input parameter from the list
1378 *********************************************************************/
1380 static void trim_dependent_file(TALLOC_CTX
*mem_ctx
, const char **files
, int idx
)
1383 /* bump everything down a slot */
1385 while (files
&& files
[idx
+1]) {
1386 files
[idx
] = talloc_strdup(mem_ctx
, files
[idx
+1]);
1395 /**********************************************************************
1396 Check if any of the files used by src are also used by drv
1397 *********************************************************************/
1399 static bool trim_overlap_drv_files(TALLOC_CTX
*mem_ctx
,
1400 struct spoolss_DriverInfo8
*src
,
1401 const struct spoolss_DriverInfo8
*drv
)
1403 bool in_use
= False
;
1409 /* check each file. Remove it from the src structure if it overlaps */
1411 if (drv_file_in_use(src
->driver_path
, drv
)) {
1413 DEBUG(10,("Removing driverfile [%s] from list\n", src
->driver_path
));
1414 src
->driver_path
= talloc_strdup(mem_ctx
, "");
1415 if (!src
->driver_path
) { return false; }
1418 if (drv_file_in_use(src
->data_file
, drv
)) {
1420 DEBUG(10,("Removing datafile [%s] from list\n", src
->data_file
));
1421 src
->data_file
= talloc_strdup(mem_ctx
, "");
1422 if (!src
->data_file
) { return false; }
1425 if (drv_file_in_use(src
->config_file
, drv
)) {
1427 DEBUG(10,("Removing configfile [%s] from list\n", src
->config_file
));
1428 src
->config_file
= talloc_strdup(mem_ctx
, "");
1429 if (!src
->config_file
) { return false; }
1432 if (drv_file_in_use(src
->help_file
, drv
)) {
1434 DEBUG(10,("Removing helpfile [%s] from list\n", src
->help_file
));
1435 src
->help_file
= talloc_strdup(mem_ctx
, "");
1436 if (!src
->help_file
) { return false; }
1439 /* are there any dependentfiles to examine? */
1441 if (!src
->dependent_files
)
1444 while (src
->dependent_files
[i
] && *src
->dependent_files
[i
]) {
1445 if (drv_file_in_use(src
->dependent_files
[i
], drv
)) {
1447 DEBUG(10,("Removing [%s] from dependent file list\n", src
->dependent_files
[i
]));
1448 trim_dependent_file(mem_ctx
, src
->dependent_files
, i
);
1456 /****************************************************************************
1457 Determine whether or not a particular driver files are currently being
1458 used by any other driver.
1460 Return value is True if any files were in use by other drivers
1461 and False otherwise.
1463 Upon return, *info has been modified to only contain the driver files
1464 which are not in use
1468 This needs to check all drivers to ensure that all files in use
1469 have been removed from *info, not just the ones in the first
1471 ****************************************************************************/
1473 bool printer_driver_files_in_use(TALLOC_CTX
*mem_ctx
,
1474 struct dcerpc_binding_handle
*b
,
1475 struct spoolss_DriverInfo8
*info
)
1479 struct spoolss_DriverInfo8
*driver
;
1480 bool in_use
= false;
1481 uint32_t num_drivers
;
1482 const char **drivers
;
1488 version
= info
->version
;
1490 /* loop over all driver versions */
1492 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1494 /* get the list of drivers */
1496 result
= winreg_get_driver_list(mem_ctx
, b
,
1497 info
->architecture
, version
,
1498 &num_drivers
, &drivers
);
1499 if (!W_ERROR_IS_OK(result
)) {
1503 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1504 num_drivers
, info
->architecture
, version
));
1506 /* check each driver for overlap in files */
1508 for (i
= 0; i
< num_drivers
; i
++) {
1509 DEBUGADD(5,("\tdriver: [%s]\n", drivers
[i
]));
1513 result
= winreg_get_driver(mem_ctx
, b
,
1514 info
->architecture
, drivers
[i
],
1516 if (!W_ERROR_IS_OK(result
)) {
1517 talloc_free(drivers
);
1521 /* check if d2 uses any files from d1 */
1522 /* only if this is a different driver than the one being deleted */
1524 if (!strequal(info
->driver_name
, driver
->driver_name
)) {
1525 if (trim_overlap_drv_files(mem_ctx
, info
, driver
)) {
1526 /* mz: Do not instantly return -
1527 * we need to ensure this file isn't
1528 * also in use by other drivers. */
1533 talloc_free(driver
);
1536 talloc_free(drivers
);
1538 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1543 static NTSTATUS
driver_unlink_internals(connection_struct
*conn
,
1544 const char *short_arch
,
1548 TALLOC_CTX
*tmp_ctx
= talloc_new(conn
);
1549 struct smb_filename
*smb_fname
= NULL
;
1550 char *print_dlr_path
;
1551 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1553 print_dlr_path
= talloc_asprintf(tmp_ctx
, "%s/%d/%s",
1554 short_arch
, vers
, fname
);
1555 if (print_dlr_path
== NULL
) {
1559 smb_fname
= synthetic_smb_fname(tmp_ctx
, print_dlr_path
, NULL
, NULL
);
1560 if (smb_fname
== NULL
) {
1564 status
= unlink_internals(conn
, NULL
, 0, smb_fname
, false);
1566 talloc_free(tmp_ctx
);
1570 /****************************************************************************
1571 Actually delete the driver files. Make sure that
1572 printer_driver_files_in_use() return False before calling
1574 ****************************************************************************/
1576 bool delete_driver_files(const struct auth_session_info
*session_info
,
1577 const struct spoolss_DriverInfo8
*r
)
1579 const char *short_arch
;
1580 connection_struct
*conn
;
1583 char *printdollar
= NULL
;
1584 int printdollar_snum
;
1591 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1592 r
->driver_name
, r
->version
));
1594 printdollar_snum
= find_service(talloc_tos(), "print$", &printdollar
);
1598 if (printdollar_snum
== -1) {
1602 nt_status
= create_conn_struct_cwd(talloc_tos(),
1603 server_event_context(),
1604 server_messaging_context(),
1607 lp_path(talloc_tos(), printdollar_snum
),
1608 session_info
, &oldcwd
);
1609 if (!NT_STATUS_IS_OK(nt_status
)) {
1610 DEBUG(0,("delete_driver_files: create_conn_struct "
1611 "returned %s\n", nt_errstr(nt_status
)));
1615 nt_status
= set_conn_force_user_group(conn
, printdollar_snum
);
1616 if (!NT_STATUS_IS_OK(nt_status
)) {
1617 DEBUG(0, ("failed set force user / group\n"));
1622 if (!become_user_by_session(conn
, session_info
)) {
1623 DEBUG(0, ("failed to become user\n"));
1628 if ( !CAN_WRITE(conn
) ) {
1629 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1634 short_arch
= get_short_archi(r
->architecture
);
1635 if (short_arch
== NULL
) {
1636 DEBUG(0, ("bad architecture %s\n", r
->architecture
));
1641 /* now delete the files */
1643 if (r
->driver_path
&& r
->driver_path
[0]) {
1644 DEBUG(10,("deleting driverfile [%s]\n", r
->driver_path
));
1645 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->driver_path
);
1648 if (r
->config_file
&& r
->config_file
[0]) {
1649 DEBUG(10,("deleting configfile [%s]\n", r
->config_file
));
1650 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->config_file
);
1653 if (r
->data_file
&& r
->data_file
[0]) {
1654 DEBUG(10,("deleting datafile [%s]\n", r
->data_file
));
1655 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->data_file
);
1658 if (r
->help_file
&& r
->help_file
[0]) {
1659 DEBUG(10,("deleting helpfile [%s]\n", r
->help_file
));
1660 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->help_file
);
1663 if (r
->dependent_files
) {
1665 while (r
->dependent_files
[i
] && r
->dependent_files
[i
][0]) {
1666 DEBUG(10,("deleting dependent file [%s]\n", r
->dependent_files
[i
]));
1667 driver_unlink_internals(conn
, short_arch
, r
->version
, r
->dependent_files
[i
]);
1677 vfs_ChDir(conn
, oldcwd
);
1678 SMB_VFS_DISCONNECT(conn
);
1686 1: level not implemented
1687 2: file doesn't exist
1688 3: can't allocate memory
1689 4: can't free memory
1690 5: non existent struct
1694 A printer and a printer driver are 2 different things.
1695 NT manages them separatelly, Samba does the same.
1696 Why ? Simply because it's easier and it makes sense !
1698 Now explanation: You have 3 printers behind your samba server,
1699 2 of them are the same make and model (laser A and B). But laser B
1700 has an 3000 sheet feeder and laser A doesn't such an option.
1701 Your third printer is an old dot-matrix model for the accounting :-).
1703 If the /usr/local/samba/lib directory (default dir), you will have
1704 5 files to describe all of this.
1706 3 files for the printers (1 by printer):
1709 NTprinter_accounting
1710 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1711 NTdriver_printer model X
1712 NTdriver_printer model Y
1714 jfm: I should use this comment for the text file to explain
1715 same thing for the forms BTW.
1716 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1720 /* Convert generic access rights to printer object specific access rights.
1721 It turns out that NT4 security descriptors use generic access rights and
1722 NT5 the object specific ones. */
1724 void map_printer_permissions(struct security_descriptor
*sd
)
1728 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
1729 se_map_generic(&sd
->dacl
->aces
[i
].access_mask
,
1730 &printer_generic_mapping
);
1734 void map_job_permissions(struct security_descriptor
*sd
)
1738 for (i
= 0; sd
->dacl
&& i
< sd
->dacl
->num_aces
; i
++) {
1739 se_map_generic(&sd
->dacl
->aces
[i
].access_mask
,
1740 &job_generic_mapping
);
1745 /****************************************************************************
1746 Check a user has permissions to perform the given operation. We use the
1747 permission constants defined in include/rpc_spoolss.h to check the various
1748 actions we perform when checking printer access.
1750 PRINTER_ACCESS_ADMINISTER:
1751 print_queue_pause, print_queue_resume, update_printer_sec,
1752 update_printer, spoolss_addprinterex_level_2,
1753 _spoolss_setprinterdata
1758 JOB_ACCESS_ADMINISTER:
1759 print_job_delete, print_job_pause, print_job_resume,
1762 Try access control in the following order (for performance reasons):
1763 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1764 2) check security descriptor (bit comparisons in memory)
1765 3) "printer admins" (may result in numerous calls to winbind)
1767 ****************************************************************************/
1768 WERROR
print_access_check(const struct auth_session_info
*session_info
,
1769 struct messaging_context
*msg_ctx
, int snum
,
1772 struct spoolss_security_descriptor
*secdesc
= NULL
;
1773 uint32 access_granted
;
1778 TALLOC_CTX
*mem_ctx
= NULL
;
1780 /* If user is NULL then use the current_user structure */
1782 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1784 if ((session_info
->unix_token
->uid
== sec_initial_uid())
1785 || security_token_has_privilege(session_info
->security_token
,
1786 SEC_PRIV_PRINT_OPERATOR
)) {
1790 /* Get printer name */
1792 pname
= lp_printername(talloc_tos(), snum
);
1794 if (!pname
|| !*pname
) {
1795 return WERR_ACCESS_DENIED
;
1798 /* Get printer security descriptor */
1800 if(!(mem_ctx
= talloc_init("print_access_check"))) {
1804 result
= winreg_get_printer_secdesc_internal(mem_ctx
,
1805 get_session_info_system(),
1809 if (!W_ERROR_IS_OK(result
)) {
1810 talloc_destroy(mem_ctx
);
1814 if (access_type
== JOB_ACCESS_ADMINISTER
) {
1815 struct spoolss_security_descriptor
*parent_secdesc
= secdesc
;
1817 /* Create a child security descriptor to check permissions
1818 against. This is because print jobs are child objects
1819 objects of a printer. */
1820 status
= se_create_child_secdesc(mem_ctx
,
1824 parent_secdesc
->owner_sid
,
1825 parent_secdesc
->group_sid
,
1827 if (!NT_STATUS_IS_OK(status
)) {
1828 talloc_destroy(mem_ctx
);
1829 return ntstatus_to_werror(status
);
1832 map_job_permissions(secdesc
);
1834 map_printer_permissions(secdesc
);
1838 status
= se_access_check(secdesc
, session_info
->security_token
, access_type
,
1841 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status
) ? "SUCCESS" : "FAILURE"));
1843 talloc_destroy(mem_ctx
);
1845 return ntstatus_to_werror(status
);
1848 /****************************************************************************
1849 Check the time parameters allow a print operation.
1850 *****************************************************************************/
1852 bool print_time_access_check(const struct auth_session_info
*session_info
,
1853 struct messaging_context
*msg_ctx
,
1854 const char *servicename
)
1856 struct spoolss_PrinterInfo2
*pinfo2
= NULL
;
1859 time_t now
= time(NULL
);
1863 result
= winreg_get_printer_internal(NULL
, session_info
, msg_ctx
,
1864 servicename
, &pinfo2
);
1865 if (!W_ERROR_IS_OK(result
)) {
1869 if (pinfo2
->starttime
== 0 && pinfo2
->untiltime
== 0) {
1874 mins
= (uint32
)t
->tm_hour
*60 + (uint32
)t
->tm_min
;
1876 if (mins
>= pinfo2
->starttime
&& mins
<= pinfo2
->untiltime
) {
1880 TALLOC_FREE(pinfo2
);
1889 void nt_printer_remove(TALLOC_CTX
*mem_ctx
,
1890 const struct auth_session_info
*session_info
,
1891 struct messaging_context
*msg_ctx
,
1892 const char *printer
)
1896 result
= winreg_delete_printer_key_internal(mem_ctx
, session_info
, msg_ctx
,
1898 if (!W_ERROR_IS_OK(result
)) {
1899 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1900 "%s\n", printer
, win_errstr(result
)));
1904 void nt_printer_add(TALLOC_CTX
*mem_ctx
,
1905 const struct auth_session_info
*session_info
,
1906 struct messaging_context
*msg_ctx
,
1907 const char *printer
)
1911 result
= winreg_create_printer_internal(mem_ctx
, session_info
, msg_ctx
,
1913 if (!W_ERROR_IS_OK(result
)) {
1914 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1915 printer
, win_errstr(result
)));