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, 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, 0755);
120 DEBUG(1, ("Failed to create printer driver "
121 "architecture directory %s\n",
123 talloc_free(mem_ctx);
128 talloc_free(mem_ctx);
132 /****************************************************************************
133 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
134 background lpq updater.
135 ****************************************************************************/
137 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
140 struct server_id server_id,
143 extern pid_t background_lpq_updater_pid;
145 if (background_lpq_updater_pid == -1) {
146 DEBUG(3,("no background lpq queue updater\n"));
150 messaging_send_buf(msg,
151 pid_to_procid(background_lpq_updater_pid),
152 MSG_PRINTER_DRVUPGRADE,
157 /****************************************************************************
158 Open the NT printing tdbs. Done once before fork().
159 ****************************************************************************/
161 bool nt_printing_init(struct messaging_context *msg_ctx)
165 if (!print_driver_directories_init()) {
169 if (!nt_printing_tdb_upgrade()) {
174 * register callback to handle updating printers as new
175 * drivers are installed. Forwards to background lpq updater.
177 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
178 forward_drv_upgrade_printer_msg);
180 /* of course, none of the message callbacks matter if you don't
181 tell messages.c that you interested in receiving PRINT_GENERAL
182 msgs. This is done in serverid_register() */
184 if ( lp_security() == SEC_ADS ) {
185 win_rc = check_published_printers(msg_ctx);
186 if (!W_ERROR_IS_OK(win_rc))
187 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
193 /*******************************************************************
194 Function to allow filename parsing "the old way".
195 ********************************************************************/
197 static NTSTATUS driver_unix_convert(connection_struct *conn,
198 const char *old_name,
199 struct smb_filename **smb_fname)
202 TALLOC_CTX *ctx = talloc_tos();
203 char *name = talloc_strdup(ctx, old_name);
206 return NT_STATUS_NO_MEMORY;
209 name = unix_clean_name(ctx, name);
211 return NT_STATUS_NO_MEMORY;
213 trim_string(name,"/","/");
215 status = unix_convert(ctx, conn, name, smb_fname, 0);
216 if (!NT_STATUS_IS_OK(status)) {
217 return NT_STATUS_NO_MEMORY;
223 /****************************************************************************
224 Function to do the mapping between the long architecture name and
226 ****************************************************************************/
228 const char *get_short_archi(const char *long_archi)
232 DEBUG(107,("Getting architecture dependent directory\n"));
235 } while ( (archi_table[i].long_archi!=NULL ) &&
236 strcasecmp_m(long_archi, archi_table[i].long_archi) );
238 if (archi_table[i].long_archi==NULL) {
239 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
243 /* this might be client code - but shouldn't this be an fstrcpy etc? */
245 DEBUGADD(108,("index: [%d]\n", i));
246 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
247 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
249 return archi_table[i].short_archi;
252 /****************************************************************************
253 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
254 There are two case to be covered here: PE (Portable Executable) and NE (New
255 Executable) files. Both files support the same INFO structure, but PE files
256 store the signature in unicode, and NE files store it as !unicode.
257 returns -1 on error, 1 on version info found, and 0 on no version info found.
258 ****************************************************************************/
260 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
266 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
267 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
268 fname, DOS_HEADER_SIZE));
272 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
273 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
274 fname, (unsigned long)byte_count));
275 goto no_version_info;
278 /* Is this really a DOS header? */
279 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
280 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
281 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
282 goto no_version_info;
285 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
286 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
287 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
289 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
290 goto no_version_info;
293 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
294 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
295 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
296 fname, (unsigned long)byte_count));
297 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
298 goto no_version_info;
301 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
302 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
303 unsigned int num_sections;
304 unsigned int section_table_bytes;
306 /* Just skip over optional header to get to section table */
307 if (SMB_VFS_LSEEK(fsp,
308 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
309 SEEK_CUR) == (off_t)-1) {
310 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
315 /* get the section table */
316 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
317 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
318 if (section_table_bytes == 0)
322 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
323 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
324 fname, section_table_bytes));
328 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
329 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
330 fname, (unsigned long)byte_count));
334 /* Iterate the section table looking for the resource section ".rsrc" */
335 for (i = 0; i < num_sections; i++) {
336 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
338 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
339 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
340 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
342 if (section_bytes == 0)
346 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
347 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
348 fname, section_bytes));
352 /* Seek to the start of the .rsrc section info */
353 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
354 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
359 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
360 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
361 fname, (unsigned long)byte_count));
365 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
368 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
369 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
370 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
371 /* Align to next long address */
372 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
374 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
375 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
376 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
378 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
379 fname, *major, *minor,
380 (*major>>16)&0xffff, *major&0xffff,
381 (*minor>>16)&0xffff, *minor&0xffff));
390 /* Version info not found, fall back to origin date/time */
391 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
395 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
396 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
397 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
398 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
399 /* At this point, we assume the file is in error. It still could be somthing
400 * else besides a NE file, but it unlikely at this point. */
404 /* Allocate a bit more space to speed up things */
406 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
407 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
408 fname, PE_HEADER_SIZE));
412 /* This is a HACK! I got tired of trying to sort through the messy
413 * 'NE' file format. If anyone wants to clean this up please have at
414 * it, but this works. 'NE' files will eventually fade away. JRR */
415 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
416 /* Cover case that should not occur in a well formed 'NE' .dll file */
417 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
419 for(i=0; i<byte_count; i++) {
420 /* Fast skip past data that can't possibly match */
421 if (buf[i] != 'V') continue;
423 /* Potential match data crosses buf boundry, move it to beginning
424 * of buf, and fill the buf with as much as it will hold. */
425 if (i>byte_count-VS_VERSION_INFO_SIZE) {
428 memcpy(buf, &buf[i], byte_count-i);
429 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
430 (byte_count-i))) < 0) {
432 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
437 byte_count = bc + (byte_count - i);
438 if (byte_count<VS_VERSION_INFO_SIZE) break;
443 /* Check that the full signature string and the magic number that
444 * follows exist (not a perfect solution, but the chances that this
445 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
446 * twice, as it is simpler to read the code. */
447 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
448 /* Compute skip alignment to next long address */
449 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
450 sizeof(VS_SIGNATURE)) & 3;
451 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
453 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
454 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
455 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
456 fname, *major, *minor,
457 (*major>>16)&0xffff, *major&0xffff,
458 (*minor>>16)&0xffff, *minor&0xffff));
465 /* Version info not found, fall back to origin date/time */
466 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
471 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
472 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
473 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
484 /****************************************************************************
485 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
486 share one or more files. During the MS installation process files are checked
487 to insure that only a newer version of a shared file is installed over an
488 older version. There are several possibilities for this comparison. If there
489 is no previous version, the new one is newer (obviously). If either file is
490 missing the version info structure, compare the creation date (on Unix use
491 the modification date). Otherwise chose the numerically larger version number.
492 ****************************************************************************/
494 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
496 bool use_version = true;
500 time_t new_create_time;
504 time_t old_create_time;
506 struct smb_filename *smb_fname = NULL;
507 files_struct *fsp = NULL;
513 SET_STAT_INVALID(st);
514 new_create_time = (time_t)0;
515 old_create_time = (time_t)0;
517 /* Get file version info (if available) for previous file (if it exists) */
518 status = driver_unix_convert(conn, old_file, &smb_fname);
519 if (!NT_STATUS_IS_OK(status)) {
523 status = SMB_VFS_CREATE_FILE(
526 0, /* root_dir_fid */
527 smb_fname, /* fname */
528 FILE_GENERIC_READ, /* access_mask */
529 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
530 FILE_OPEN, /* create_disposition*/
531 0, /* create_options */
532 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
533 INTERNAL_OPEN_ONLY, /* oplock_request */
535 0, /* allocation_size */
536 0, /* private_flags */
542 if (!NT_STATUS_IS_OK(status)) {
543 /* Old file not found, so by definition new file is in fact newer */
544 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
545 "errno = %d\n", smb_fname_str_dbg(smb_fname),
551 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
557 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
560 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
563 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
564 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
565 (long)old_create_time));
568 close_file(NULL, fsp, NORMAL_CLOSE);
571 /* Get file version info (if available) for new file */
572 status = driver_unix_convert(conn, new_file, &smb_fname);
573 if (!NT_STATUS_IS_OK(status)) {
577 status = SMB_VFS_CREATE_FILE(
580 0, /* root_dir_fid */
581 smb_fname, /* fname */
582 FILE_GENERIC_READ, /* access_mask */
583 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
584 FILE_OPEN, /* create_disposition*/
585 0, /* create_options */
586 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
587 INTERNAL_OPEN_ONLY, /* oplock_request */
589 0, /* allocation_size */
590 0, /* private_flags */
596 if (!NT_STATUS_IS_OK(status)) {
597 /* New file not found, this shouldn't occur if the caller did its job */
598 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
599 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
603 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
609 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
612 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
615 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
616 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
617 (long)new_create_time));
620 close_file(NULL, fsp, NORMAL_CLOSE);
623 if (use_version && (new_major != old_major || new_minor != old_minor)) {
624 /* Compare versions and choose the larger version number */
625 if (new_major > old_major ||
626 (new_major == old_major && new_minor > old_minor)) {
628 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
633 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
639 /* Compare modification time/dates and choose the newest time/date */
640 if (new_create_time > old_create_time) {
641 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
646 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
654 close_file(NULL, fsp, NORMAL_CLOSE);
657 TALLOC_FREE(smb_fname);
661 /****************************************************************************
662 Determine the correct cVersion associated with an architecture and driver
663 ****************************************************************************/
664 static uint32 get_correct_cversion(struct auth_session_info *session_info,
665 const char *architecture,
666 const char *driverpath_in,
671 struct smb_filename *smb_fname = NULL;
672 char *driverpath = NULL;
673 files_struct *fsp = NULL;
674 connection_struct *conn = NULL;
676 char *printdollar = NULL;
677 int printdollar_snum;
679 *perr = WERR_INVALID_PARAM;
681 /* If architecture is Windows 95/98/ME, the version is always 0. */
682 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
683 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
688 /* If architecture is Windows x64, the version is always 3. */
689 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
690 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
695 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
700 if (printdollar_snum == -1) {
701 *perr = WERR_NO_SUCH_SHARE;
705 nt_status = create_conn_struct_cwd(talloc_tos(),
706 server_event_context(),
707 server_messaging_context(),
710 lp_path(talloc_tos(), printdollar_snum),
711 session_info, &oldcwd);
712 if (!NT_STATUS_IS_OK(nt_status)) {
713 DEBUG(0,("get_correct_cversion: create_conn_struct "
714 "returned %s\n", nt_errstr(nt_status)));
715 *perr = ntstatus_to_werror(nt_status);
719 nt_status = set_conn_force_user_group(conn, printdollar_snum);
720 if (!NT_STATUS_IS_OK(nt_status)) {
721 DEBUG(0, ("failed set force user / group\n"));
722 *perr = ntstatus_to_werror(nt_status);
723 goto error_free_conn;
726 if (!become_user_by_session(conn, session_info)) {
727 DEBUG(0, ("failed to become user\n"));
728 *perr = WERR_ACCESS_DENIED;
729 goto error_free_conn;
732 /* Open the driver file (Portable Executable format) and determine the
733 * deriver the cversion. */
734 driverpath = talloc_asprintf(talloc_tos(),
743 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
744 if (!NT_STATUS_IS_OK(nt_status)) {
745 *perr = ntstatus_to_werror(nt_status);
749 nt_status = vfs_file_exist(conn, smb_fname);
750 if (!NT_STATUS_IS_OK(nt_status)) {
751 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
752 *perr = WERR_BADFILE;
756 nt_status = SMB_VFS_CREATE_FILE(
759 0, /* root_dir_fid */
760 smb_fname, /* fname */
761 FILE_GENERIC_READ, /* access_mask */
762 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
763 FILE_OPEN, /* create_disposition*/
764 0, /* create_options */
765 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
766 INTERNAL_OPEN_ONLY, /* oplock_request */
768 0, /* private_flags */
769 0, /* allocation_size */
775 if (!NT_STATUS_IS_OK(nt_status)) {
776 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
777 "%d\n", smb_fname_str_dbg(smb_fname), errno));
778 *perr = WERR_ACCESS_DENIED;
785 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
787 *perr = WERR_INVALID_PARAM;
790 DEBUG(6,("get_correct_cversion: Version info not "
792 smb_fname_str_dbg(smb_fname)));
793 *perr = WERR_INVALID_PARAM;
798 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
799 * for more details. Version in this case is not just the version of the
800 * file, but the version in the sense of kernal mode (2) vs. user mode
801 * (3) drivers. Other bits of the version fields are the version info.
804 cversion = major & 0x0000ffff;
806 case 2: /* WinNT drivers */
807 case 3: /* Win2K drivers */
811 DEBUG(6,("get_correct_cversion: cversion "
812 "invalid [%s] cversion = %d\n",
813 smb_fname_str_dbg(smb_fname),
818 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
819 " = 0x%x minor = 0x%x\n",
820 smb_fname_str_dbg(smb_fname), major, minor));
823 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
824 smb_fname_str_dbg(smb_fname), cversion));
830 TALLOC_FREE(smb_fname);
832 close_file(NULL, fsp, NORMAL_CLOSE);
835 vfs_ChDir(conn, oldcwd);
836 SMB_VFS_DISCONNECT(conn);
839 if (!W_ERROR_IS_OK(*perr)) {
846 /****************************************************************************
847 ****************************************************************************/
849 #define strip_driver_path(_mem_ctx, _element) do { \
850 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
851 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
852 W_ERROR_HAVE_NO_MEMORY((_element)); \
856 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
857 struct auth_session_info *session_info,
858 const char *architecture,
859 const char **driver_path,
860 const char **data_file,
861 const char **config_file,
862 const char **help_file,
863 struct spoolss_StringArray *dependent_files,
864 enum spoolss_DriverOSVersion *version)
866 const char *short_architecture;
871 if (!*driver_path || !*data_file) {
872 return WERR_INVALID_PARAM;
875 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
876 return WERR_INVALID_PARAM;
879 /* clean up the driver name.
880 * we can get .\driver.dll
881 * or worse c:\windows\system\driver.dll !
883 /* using an intermediate string to not have overlaping memcpy()'s */
885 strip_driver_path(mem_ctx, *driver_path);
886 strip_driver_path(mem_ctx, *data_file);
888 strip_driver_path(mem_ctx, *config_file);
891 strip_driver_path(mem_ctx, *help_file);
894 if (dependent_files && dependent_files->string) {
895 for (i=0; dependent_files->string[i]; i++) {
896 strip_driver_path(mem_ctx, dependent_files->string[i]);
900 short_architecture = get_short_archi(architecture);
901 if (!short_architecture) {
902 return WERR_UNKNOWN_PRINTER_DRIVER;
905 /* jfm:7/16/2000 the client always sends the cversion=0.
906 * The server should check which version the driver is by reading
907 * the PE header of driver->driverpath.
909 * For Windows 95/98 the version is 0 (so the value sent is correct)
910 * For Windows NT (the architecture doesn't matter)
912 * NT 3.5/3.51: cversion=1
917 *version = get_correct_cversion(session_info, short_architecture,
919 if (*version == -1) {
926 /****************************************************************************
927 ****************************************************************************/
929 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
930 struct auth_session_info *session_info,
931 struct spoolss_AddDriverInfoCtr *r)
935 return clean_up_driver_struct_level(mem_ctx, session_info,
936 r->info.info3->architecture,
937 &r->info.info3->driver_path,
938 &r->info.info3->data_file,
939 &r->info.info3->config_file,
940 &r->info.info3->help_file,
941 r->info.info3->dependent_files,
942 &r->info.info3->version);
944 return clean_up_driver_struct_level(mem_ctx, session_info,
945 r->info.info6->architecture,
946 &r->info.info6->driver_path,
947 &r->info.info6->data_file,
948 &r->info.info6->config_file,
949 &r->info.info6->help_file,
950 r->info.info6->dependent_files,
951 &r->info.info6->version);
953 return WERR_NOT_SUPPORTED;
957 /****************************************************************************
958 This function sucks and should be replaced. JRA.
959 ****************************************************************************/
961 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
962 const struct spoolss_AddDriverInfo6 *src)
964 dst->version = src->version;
966 dst->driver_name = src->driver_name;
967 dst->architecture = src->architecture;
968 dst->driver_path = src->driver_path;
969 dst->data_file = src->data_file;
970 dst->config_file = src->config_file;
971 dst->help_file = src->help_file;
972 dst->monitor_name = src->monitor_name;
973 dst->default_datatype = src->default_datatype;
974 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
975 dst->dependent_files = src->dependent_files;
978 /****************************************************************************
979 ****************************************************************************/
981 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
982 connection_struct *conn,
983 const char *driver_file,
984 const char *short_architecture,
985 uint32_t driver_version,
988 struct smb_filename *smb_fname_old = NULL;
989 struct smb_filename *smb_fname_new = NULL;
990 char *old_name = NULL;
991 char *new_name = NULL;
995 old_name = talloc_asprintf(mem_ctx, "%s/%s",
996 short_architecture, driver_file);
997 W_ERROR_HAVE_NO_MEMORY(old_name);
999 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1000 short_architecture, driver_version, driver_file);
1001 if (new_name == NULL) {
1002 TALLOC_FREE(old_name);
1006 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1008 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1009 if (!NT_STATUS_IS_OK(status)) {
1014 /* Setup a synthetic smb_filename struct */
1015 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1016 if (!smb_fname_new) {
1021 smb_fname_new->base_name = new_name;
1023 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1024 "'%s'\n", smb_fname_old->base_name,
1025 smb_fname_new->base_name));
1027 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1028 OPENX_FILE_EXISTS_TRUNCATE |
1029 OPENX_FILE_CREATE_IF_NOT_EXIST,
1032 if (!NT_STATUS_IS_OK(status)) {
1033 DEBUG(0,("move_driver_file_to_download_area: Unable "
1034 "to rename [%s] to [%s]: %s\n",
1035 smb_fname_old->base_name, new_name,
1036 nt_errstr(status)));
1037 ret = WERR_ACCESS_DENIED;
1044 TALLOC_FREE(smb_fname_old);
1045 TALLOC_FREE(smb_fname_new);
1049 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1050 struct spoolss_AddDriverInfoCtr *r)
1052 struct spoolss_AddDriverInfo3 *driver;
1053 struct spoolss_AddDriverInfo3 converted_driver;
1054 const char *short_architecture;
1055 struct smb_filename *smb_dname = NULL;
1056 char *new_dir = NULL;
1057 connection_struct *conn = NULL;
1060 TALLOC_CTX *ctx = talloc_tos();
1063 char *printdollar = NULL;
1064 int printdollar_snum;
1065 WERROR err = WERR_OK;
1069 driver = r->info.info3;
1072 convert_level_6_to_level3(&converted_driver, r->info.info6);
1073 driver = &converted_driver;
1076 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1077 return WERR_UNKNOWN_LEVEL;
1080 short_architecture = get_short_archi(driver->architecture);
1081 if (!short_architecture) {
1082 return WERR_UNKNOWN_PRINTER_DRIVER;
1085 printdollar_snum = find_service(ctx, "print$", &printdollar);
1089 if (printdollar_snum == -1) {
1090 return WERR_NO_SUCH_SHARE;
1093 nt_status = create_conn_struct_cwd(talloc_tos(),
1094 server_event_context(),
1095 server_messaging_context(),
1098 lp_path(talloc_tos(), printdollar_snum),
1099 session_info, &oldcwd);
1100 if (!NT_STATUS_IS_OK(nt_status)) {
1101 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1102 "returned %s\n", nt_errstr(nt_status)));
1103 err = ntstatus_to_werror(nt_status);
1107 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1108 if (!NT_STATUS_IS_OK(nt_status)) {
1109 DEBUG(0, ("failed set force user / group\n"));
1110 err = ntstatus_to_werror(nt_status);
1114 if (!become_user_by_session(conn, session_info)) {
1115 DEBUG(0, ("failed to become user\n"));
1116 err = WERR_ACCESS_DENIED;
1120 new_dir = talloc_asprintf(ctx,
1128 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1129 if (!NT_STATUS_IS_OK(nt_status)) {
1134 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1136 nt_status = create_directory(conn, NULL, smb_dname);
1137 if (!NT_STATUS_IS_OK(nt_status)
1138 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1139 DEBUG(0, ("failed to create driver destination directory: %s\n",
1140 nt_errstr(nt_status)));
1141 err = ntstatus_to_werror(nt_status);
1145 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1146 * listed for this driver which has already been moved, skip it (note:
1147 * drivers may list the same file name several times. Then check if the
1148 * file already exists in archi\version\, if so, check that the version
1149 * info (or time stamps if version info is unavailable) is newer (or the
1150 * date is later). If it is, move it to archi\version\filexxx.yyy.
1151 * Otherwise, delete the file.
1153 * If a file is not moved to archi\version\ because of an error, all the
1154 * rest of the 'unmoved' driver files are removed from archi\. If one or
1155 * more of the driver's files was already moved to archi\version\, it
1156 * potentially leaves the driver in a partially updated state. Version
1157 * trauma will most likely occur if an client attempts to use any printer
1158 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1159 * done is appropriate... later JRR
1162 DEBUG(5,("Moving files now !\n"));
1164 if (driver->driver_path && strlen(driver->driver_path)) {
1166 err = move_driver_file_to_download_area(ctx,
1168 driver->driver_path,
1172 if (!W_ERROR_IS_OK(err)) {
1177 if (driver->data_file && strlen(driver->data_file)) {
1178 if (!strequal(driver->data_file, driver->driver_path)) {
1180 err = move_driver_file_to_download_area(ctx,
1186 if (!W_ERROR_IS_OK(err)) {
1192 if (driver->config_file && strlen(driver->config_file)) {
1193 if (!strequal(driver->config_file, driver->driver_path) &&
1194 !strequal(driver->config_file, driver->data_file)) {
1196 err = move_driver_file_to_download_area(ctx,
1198 driver->config_file,
1202 if (!W_ERROR_IS_OK(err)) {
1208 if (driver->help_file && strlen(driver->help_file)) {
1209 if (!strequal(driver->help_file, driver->driver_path) &&
1210 !strequal(driver->help_file, driver->data_file) &&
1211 !strequal(driver->help_file, driver->config_file)) {
1213 err = move_driver_file_to_download_area(ctx,
1219 if (!W_ERROR_IS_OK(err)) {
1225 if (driver->dependent_files && driver->dependent_files->string) {
1226 for (i=0; driver->dependent_files->string[i]; i++) {
1227 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1228 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1229 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1230 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1232 for (j=0; j < i; j++) {
1233 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1238 err = move_driver_file_to_download_area(ctx,
1240 driver->dependent_files->string[i],
1244 if (!W_ERROR_IS_OK(err)) {
1256 TALLOC_FREE(smb_dname);
1259 vfs_ChDir(conn, oldcwd);
1260 SMB_VFS_DISCONNECT(conn);
1267 /****************************************************************************
1268 Determine whether or not a particular driver is currently assigned
1270 ****************************************************************************/
1272 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1273 struct dcerpc_binding_handle *b,
1274 const struct spoolss_DriverInfo8 *r)
1277 int n_services = lp_numservices();
1278 bool in_use = False;
1279 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1286 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1288 /* loop through the printers.tdb and check for the drivername */
1290 for (snum=0; snum<n_services && !in_use; snum++) {
1291 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1295 result = winreg_get_printer(mem_ctx, b,
1296 lp_servicename(talloc_tos(), snum),
1298 if (!W_ERROR_IS_OK(result)) {
1299 continue; /* skip */
1302 if (strequal(r->driver_name, pinfo2->drivername)) {
1306 TALLOC_FREE(pinfo2);
1309 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1312 struct spoolss_DriverInfo8 *driver = NULL;
1315 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1317 /* we can still remove the driver if there is one of
1318 "Windows NT x86" version 2 or 3 left */
1320 if (!strequal("Windows NT x86", r->architecture)) {
1321 werr = winreg_get_driver(mem_ctx, b,
1326 } else if (r->version == 2) {
1327 werr = winreg_get_driver(mem_ctx, b,
1331 } else if (r->version == 3) {
1332 werr = winreg_get_driver(mem_ctx, b,
1337 DEBUG(0, ("printer_driver_in_use: ERROR!"
1338 " unknown driver version (%d)\n",
1340 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1343 /* now check the error code */
1345 if ( W_ERROR_IS_OK(werr) ) {
1346 /* it's ok to remove the driver, we have other architctures left */
1348 talloc_free(driver);
1352 /* report that the driver is not in use by default */
1358 /**********************************************************************
1359 Check to see if a ogiven file is in use by *info
1360 *********************************************************************/
1362 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1369 /* mz: skip files that are in the list but already deleted */
1370 if (!file || !file[0]) {
1374 if (strequal(file, info->driver_path))
1377 if (strequal(file, info->data_file))
1380 if (strequal(file, info->config_file))
1383 if (strequal(file, info->help_file))
1386 /* see of there are any dependent files to examine */
1388 if (!info->dependent_files)
1391 while (info->dependent_files[i] && *info->dependent_files[i]) {
1392 if (strequal(file, info->dependent_files[i]))
1401 /**********************************************************************
1402 Utility function to remove the dependent file pointed to by the
1403 input parameter from the list
1404 *********************************************************************/
1406 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1409 /* bump everything down a slot */
1411 while (files && files[idx+1]) {
1412 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1421 /**********************************************************************
1422 Check if any of the files used by src are also used by drv
1423 *********************************************************************/
1425 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1426 struct spoolss_DriverInfo8 *src,
1427 const struct spoolss_DriverInfo8 *drv)
1429 bool in_use = False;
1435 /* check each file. Remove it from the src structure if it overlaps */
1437 if (drv_file_in_use(src->driver_path, drv)) {
1439 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1440 src->driver_path = talloc_strdup(mem_ctx, "");
1441 if (!src->driver_path) { return false; }
1444 if (drv_file_in_use(src->data_file, drv)) {
1446 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1447 src->data_file = talloc_strdup(mem_ctx, "");
1448 if (!src->data_file) { return false; }
1451 if (drv_file_in_use(src->config_file, drv)) {
1453 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1454 src->config_file = talloc_strdup(mem_ctx, "");
1455 if (!src->config_file) { return false; }
1458 if (drv_file_in_use(src->help_file, drv)) {
1460 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1461 src->help_file = talloc_strdup(mem_ctx, "");
1462 if (!src->help_file) { return false; }
1465 /* are there any dependentfiles to examine? */
1467 if (!src->dependent_files)
1470 while (src->dependent_files[i] && *src->dependent_files[i]) {
1471 if (drv_file_in_use(src->dependent_files[i], drv)) {
1473 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1474 trim_dependent_file(mem_ctx, src->dependent_files, i);
1482 /****************************************************************************
1483 Determine whether or not a particular driver files are currently being
1484 used by any other driver.
1486 Return value is True if any files were in use by other drivers
1487 and False otherwise.
1489 Upon return, *info has been modified to only contain the driver files
1490 which are not in use
1494 This needs to check all drivers to ensure that all files in use
1495 have been removed from *info, not just the ones in the first
1497 ****************************************************************************/
1499 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1500 struct dcerpc_binding_handle *b,
1501 struct spoolss_DriverInfo8 *info)
1505 struct spoolss_DriverInfo8 *driver;
1506 bool in_use = false;
1507 uint32_t num_drivers;
1508 const char **drivers;
1514 version = info->version;
1516 /* loop over all driver versions */
1518 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1520 /* get the list of drivers */
1522 result = winreg_get_driver_list(mem_ctx, b,
1523 info->architecture, version,
1524 &num_drivers, &drivers);
1525 if (!W_ERROR_IS_OK(result)) {
1529 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1530 num_drivers, info->architecture, version));
1532 /* check each driver for overlap in files */
1534 for (i = 0; i < num_drivers; i++) {
1535 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1539 result = winreg_get_driver(mem_ctx, b,
1540 info->architecture, drivers[i],
1542 if (!W_ERROR_IS_OK(result)) {
1543 talloc_free(drivers);
1547 /* check if d2 uses any files from d1 */
1548 /* only if this is a different driver than the one being deleted */
1550 if (!strequal(info->driver_name, driver->driver_name)) {
1551 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1552 /* mz: Do not instantly return -
1553 * we need to ensure this file isn't
1554 * also in use by other drivers. */
1559 talloc_free(driver);
1562 talloc_free(drivers);
1564 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1569 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1570 const char *short_arch,
1574 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1575 struct smb_filename *smb_fname = NULL;
1576 char *print_dlr_path;
1577 NTSTATUS status = NT_STATUS_NO_MEMORY;
1579 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1580 short_arch, vers, fname);
1581 if (print_dlr_path == NULL) {
1585 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL);
1586 if (smb_fname == NULL) {
1590 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1592 talloc_free(tmp_ctx);
1596 /****************************************************************************
1597 Actually delete the driver files. Make sure that
1598 printer_driver_files_in_use() return False before calling
1600 ****************************************************************************/
1602 bool delete_driver_files(const struct auth_session_info *session_info,
1603 const struct spoolss_DriverInfo8 *r)
1605 const char *short_arch;
1606 connection_struct *conn;
1609 char *printdollar = NULL;
1610 int printdollar_snum;
1617 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1618 r->driver_name, r->version));
1620 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1624 if (printdollar_snum == -1) {
1628 nt_status = create_conn_struct_cwd(talloc_tos(),
1629 server_event_context(),
1630 server_messaging_context(),
1633 lp_path(talloc_tos(), printdollar_snum),
1634 session_info, &oldcwd);
1635 if (!NT_STATUS_IS_OK(nt_status)) {
1636 DEBUG(0,("delete_driver_files: create_conn_struct "
1637 "returned %s\n", nt_errstr(nt_status)));
1641 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1642 if (!NT_STATUS_IS_OK(nt_status)) {
1643 DEBUG(0, ("failed set force user / group\n"));
1648 if (!become_user_by_session(conn, session_info)) {
1649 DEBUG(0, ("failed to become user\n"));
1654 if ( !CAN_WRITE(conn) ) {
1655 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1660 short_arch = get_short_archi(r->architecture);
1661 if (short_arch == NULL) {
1662 DEBUG(0, ("bad architecture %s\n", r->architecture));
1667 /* now delete the files */
1669 if (r->driver_path && r->driver_path[0]) {
1670 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1671 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1674 if (r->config_file && r->config_file[0]) {
1675 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1676 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1679 if (r->data_file && r->data_file[0]) {
1680 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1681 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1684 if (r->help_file && r->help_file[0]) {
1685 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1686 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1689 if (r->dependent_files) {
1691 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1692 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1693 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1703 vfs_ChDir(conn, oldcwd);
1704 SMB_VFS_DISCONNECT(conn);
1712 1: level not implemented
1713 2: file doesn't exist
1714 3: can't allocate memory
1715 4: can't free memory
1716 5: non existent struct
1720 A printer and a printer driver are 2 different things.
1721 NT manages them separatelly, Samba does the same.
1722 Why ? Simply because it's easier and it makes sense !
1724 Now explanation: You have 3 printers behind your samba server,
1725 2 of them are the same make and model (laser A and B). But laser B
1726 has an 3000 sheet feeder and laser A doesn't such an option.
1727 Your third printer is an old dot-matrix model for the accounting :-).
1729 If the /usr/local/samba/lib directory (default dir), you will have
1730 5 files to describe all of this.
1732 3 files for the printers (1 by printer):
1735 NTprinter_accounting
1736 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1737 NTdriver_printer model X
1738 NTdriver_printer model Y
1740 jfm: I should use this comment for the text file to explain
1741 same thing for the forms BTW.
1742 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1746 /* Convert generic access rights to printer object specific access rights.
1747 It turns out that NT4 security descriptors use generic access rights and
1748 NT5 the object specific ones. */
1750 void map_printer_permissions(struct security_descriptor *sd)
1754 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1755 se_map_generic(&sd->dacl->aces[i].access_mask,
1756 &printer_generic_mapping);
1760 void map_job_permissions(struct security_descriptor *sd)
1764 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1765 se_map_generic(&sd->dacl->aces[i].access_mask,
1766 &job_generic_mapping);
1771 /****************************************************************************
1772 Check a user has permissions to perform the given operation. We use the
1773 permission constants defined in include/rpc_spoolss.h to check the various
1774 actions we perform when checking printer access.
1776 PRINTER_ACCESS_ADMINISTER:
1777 print_queue_pause, print_queue_resume, update_printer_sec,
1778 update_printer, spoolss_addprinterex_level_2,
1779 _spoolss_setprinterdata
1784 JOB_ACCESS_ADMINISTER:
1785 print_job_delete, print_job_pause, print_job_resume,
1788 Try access control in the following order (for performance reasons):
1789 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1790 2) check security descriptor (bit comparisons in memory)
1791 3) "printer admins" (may result in numerous calls to winbind)
1793 ****************************************************************************/
1794 WERROR print_access_check(const struct auth_session_info *session_info,
1795 struct messaging_context *msg_ctx, int snum,
1798 struct spoolss_security_descriptor *secdesc = NULL;
1799 uint32 access_granted;
1804 TALLOC_CTX *mem_ctx = NULL;
1806 /* If user is NULL then use the current_user structure */
1808 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1810 if ((session_info->unix_token->uid == sec_initial_uid())
1811 || security_token_has_privilege(session_info->security_token,
1812 SEC_PRIV_PRINT_OPERATOR)) {
1816 /* Get printer name */
1818 pname = lp_printername(talloc_tos(), snum);
1820 if (!pname || !*pname) {
1821 return WERR_ACCESS_DENIED;
1824 /* Get printer security descriptor */
1826 if(!(mem_ctx = talloc_init("print_access_check"))) {
1830 result = winreg_get_printer_secdesc_internal(mem_ctx,
1831 get_session_info_system(),
1835 if (!W_ERROR_IS_OK(result)) {
1836 talloc_destroy(mem_ctx);
1840 if (access_type == JOB_ACCESS_ADMINISTER) {
1841 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1843 /* Create a child security descriptor to check permissions
1844 against. This is because print jobs are child objects
1845 objects of a printer. */
1846 status = se_create_child_secdesc(mem_ctx,
1850 parent_secdesc->owner_sid,
1851 parent_secdesc->group_sid,
1853 if (!NT_STATUS_IS_OK(status)) {
1854 talloc_destroy(mem_ctx);
1855 return ntstatus_to_werror(status);
1858 map_job_permissions(secdesc);
1860 map_printer_permissions(secdesc);
1864 status = se_access_check(secdesc, session_info->security_token, access_type,
1867 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1869 talloc_destroy(mem_ctx);
1871 return ntstatus_to_werror(status);
1874 /****************************************************************************
1875 Check the time parameters allow a print operation.
1876 *****************************************************************************/
1878 bool print_time_access_check(const struct auth_session_info *session_info,
1879 struct messaging_context *msg_ctx,
1880 const char *servicename)
1882 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1885 time_t now = time(NULL);
1889 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1890 servicename, &pinfo2);
1891 if (!W_ERROR_IS_OK(result)) {
1895 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1900 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1902 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1906 TALLOC_FREE(pinfo2);
1915 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1916 const struct auth_session_info *session_info,
1917 struct messaging_context *msg_ctx,
1918 const char *printer)
1922 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1924 if (!W_ERROR_IS_OK(result)) {
1925 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1926 "%s\n", printer, win_errstr(result)));
1930 void nt_printer_add(TALLOC_CTX *mem_ctx,
1931 const struct auth_session_info *session_info,
1932 struct messaging_context *msg_ctx,
1933 const char *printer)
1937 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1939 if (!W_ERROR_IS_OK(result)) {
1940 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1941 printer, win_errstr(result)));