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"
34 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 /* Map generic permissions to printer object specific permissions */
38 const struct generic_mapping printer_generic_mapping = {
45 /* Map generic permissions to print server object specific permissions */
47 const struct generic_mapping printserver_generic_mapping = {
54 /* Map generic permissions to job object specific permissions */
56 const struct generic_mapping job_generic_mapping = {
63 static const struct print_architecture_table_node archi_table[]= {
65 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
66 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
67 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
68 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
69 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
70 {"Windows IA64", SPL_ARCH_IA64, 3 },
71 {"Windows x64", SPL_ARCH_X64, 3 },
75 /****************************************************************************
76 Open the NT printing tdbs. Done once before fork().
77 ****************************************************************************/
79 bool nt_printing_init(struct messaging_context *msg_ctx)
83 if (!nt_printing_tdb_upgrade()) {
88 * register callback to handle updating printers as new
89 * drivers are installed
91 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
92 do_drv_upgrade_printer);
94 /* of course, none of the message callbacks matter if you don't
95 tell messages.c that you interested in receiving PRINT_GENERAL
96 msgs. This is done in serverid_register() */
98 if ( lp_security() == SEC_ADS ) {
99 win_rc = check_published_printers(msg_ctx);
100 if (!W_ERROR_IS_OK(win_rc))
101 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
107 /*******************************************************************
108 Function to allow filename parsing "the old way".
109 ********************************************************************/
111 static NTSTATUS driver_unix_convert(connection_struct *conn,
112 const char *old_name,
113 struct smb_filename **smb_fname)
116 TALLOC_CTX *ctx = talloc_tos();
117 char *name = talloc_strdup(ctx, old_name);
120 return NT_STATUS_NO_MEMORY;
123 name = unix_clean_name(ctx, name);
125 return NT_STATUS_NO_MEMORY;
127 trim_string(name,"/","/");
129 status = unix_convert(ctx, conn, name, smb_fname, 0);
130 if (!NT_STATUS_IS_OK(status)) {
131 return NT_STATUS_NO_MEMORY;
137 /****************************************************************************
138 Function to do the mapping between the long architecture name and
140 ****************************************************************************/
142 const char *get_short_archi(const char *long_archi)
146 DEBUG(107,("Getting architecture dependent directory\n"));
149 } while ( (archi_table[i].long_archi!=NULL ) &&
150 strcasecmp_m(long_archi, archi_table[i].long_archi) );
152 if (archi_table[i].long_archi==NULL) {
153 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
157 /* this might be client code - but shouldn't this be an fstrcpy etc? */
159 DEBUGADD(108,("index: [%d]\n", i));
160 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
161 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
163 return archi_table[i].short_archi;
166 /****************************************************************************
167 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
168 There are two case to be covered here: PE (Portable Executable) and NE (New
169 Executable) files. Both files support the same INFO structure, but PE files
170 store the signature in unicode, and NE files store it as !unicode.
171 returns -1 on error, 1 on version info found, and 0 on no version info found.
172 ****************************************************************************/
174 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
180 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
181 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
182 fname, DOS_HEADER_SIZE));
186 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
187 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
188 fname, (unsigned long)byte_count));
189 goto no_version_info;
192 /* Is this really a DOS header? */
193 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
194 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
195 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
196 goto no_version_info;
199 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
200 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
201 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
203 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
204 goto no_version_info;
207 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
208 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
209 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
210 fname, (unsigned long)byte_count));
211 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
212 goto no_version_info;
215 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
216 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
217 unsigned int num_sections;
218 unsigned int section_table_bytes;
220 /* Just skip over optional header to get to section table */
221 if (SMB_VFS_LSEEK(fsp,
222 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
223 SEEK_CUR) == (SMB_OFF_T)-1) {
224 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
229 /* get the section table */
230 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
231 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
232 if (section_table_bytes == 0)
236 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
237 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
238 fname, section_table_bytes));
242 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
243 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
244 fname, (unsigned long)byte_count));
248 /* Iterate the section table looking for the resource section ".rsrc" */
249 for (i = 0; i < num_sections; i++) {
250 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
252 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
253 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
254 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
256 if (section_bytes == 0)
260 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
261 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
262 fname, section_bytes));
266 /* Seek to the start of the .rsrc section info */
267 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
268 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
273 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
274 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
275 fname, (unsigned long)byte_count));
279 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
282 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
283 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
284 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
285 /* Align to next long address */
286 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
288 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
289 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
290 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
292 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
293 fname, *major, *minor,
294 (*major>>16)&0xffff, *major&0xffff,
295 (*minor>>16)&0xffff, *minor&0xffff));
304 /* Version info not found, fall back to origin date/time */
305 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
309 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
310 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
311 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
312 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
313 /* At this point, we assume the file is in error. It still could be somthing
314 * else besides a NE file, but it unlikely at this point. */
318 /* Allocate a bit more space to speed up things */
320 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
321 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
322 fname, PE_HEADER_SIZE));
326 /* This is a HACK! I got tired of trying to sort through the messy
327 * 'NE' file format. If anyone wants to clean this up please have at
328 * it, but this works. 'NE' files will eventually fade away. JRR */
329 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
330 /* Cover case that should not occur in a well formed 'NE' .dll file */
331 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
333 for(i=0; i<byte_count; i++) {
334 /* Fast skip past data that can't possibly match */
335 if (buf[i] != 'V') continue;
337 /* Potential match data crosses buf boundry, move it to beginning
338 * of buf, and fill the buf with as much as it will hold. */
339 if (i>byte_count-VS_VERSION_INFO_SIZE) {
342 memcpy(buf, &buf[i], byte_count-i);
343 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
344 (byte_count-i))) < 0) {
346 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
351 byte_count = bc + (byte_count - i);
352 if (byte_count<VS_VERSION_INFO_SIZE) break;
357 /* Check that the full signature string and the magic number that
358 * follows exist (not a perfect solution, but the chances that this
359 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
360 * twice, as it is simpler to read the code. */
361 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
362 /* Compute skip alignment to next long address */
363 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
364 sizeof(VS_SIGNATURE)) & 3;
365 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
367 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
368 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
369 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
370 fname, *major, *minor,
371 (*major>>16)&0xffff, *major&0xffff,
372 (*minor>>16)&0xffff, *minor&0xffff));
379 /* Version info not found, fall back to origin date/time */
380 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
385 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
386 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
387 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
398 /****************************************************************************
399 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
400 share one or more files. During the MS installation process files are checked
401 to insure that only a newer version of a shared file is installed over an
402 older version. There are several possibilities for this comparison. If there
403 is no previous version, the new one is newer (obviously). If either file is
404 missing the version info structure, compare the creation date (on Unix use
405 the modification date). Otherwise chose the numerically larger version number.
406 ****************************************************************************/
408 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
410 bool use_version = true;
414 time_t new_create_time;
418 time_t old_create_time;
420 struct smb_filename *smb_fname = NULL;
421 files_struct *fsp = NULL;
427 SET_STAT_INVALID(st);
428 new_create_time = (time_t)0;
429 old_create_time = (time_t)0;
431 /* Get file version info (if available) for previous file (if it exists) */
432 status = driver_unix_convert(conn, old_file, &smb_fname);
433 if (!NT_STATUS_IS_OK(status)) {
437 status = SMB_VFS_CREATE_FILE(
440 0, /* root_dir_fid */
441 smb_fname, /* fname */
442 FILE_GENERIC_READ, /* access_mask */
443 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
444 FILE_OPEN, /* create_disposition*/
445 0, /* create_options */
446 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
447 INTERNAL_OPEN_ONLY, /* oplock_request */
448 0, /* allocation_size */
449 0, /* private_flags */
455 if (!NT_STATUS_IS_OK(status)) {
456 /* Old file not found, so by definition new file is in fact newer */
457 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
458 "errno = %d\n", smb_fname_str_dbg(smb_fname),
464 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
470 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
473 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
476 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
477 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
478 (long)old_create_time));
481 close_file(NULL, fsp, NORMAL_CLOSE);
484 /* Get file version info (if available) for new file */
485 status = driver_unix_convert(conn, new_file, &smb_fname);
486 if (!NT_STATUS_IS_OK(status)) {
490 status = SMB_VFS_CREATE_FILE(
493 0, /* root_dir_fid */
494 smb_fname, /* fname */
495 FILE_GENERIC_READ, /* access_mask */
496 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
497 FILE_OPEN, /* create_disposition*/
498 0, /* create_options */
499 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
500 INTERNAL_OPEN_ONLY, /* oplock_request */
501 0, /* allocation_size */
502 0, /* private_flags */
508 if (!NT_STATUS_IS_OK(status)) {
509 /* New file not found, this shouldn't occur if the caller did its job */
510 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
511 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
515 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
521 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
524 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
527 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
528 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
529 (long)new_create_time));
532 close_file(NULL, fsp, NORMAL_CLOSE);
535 if (use_version && (new_major != old_major || new_minor != old_minor)) {
536 /* Compare versions and choose the larger version number */
537 if (new_major > old_major ||
538 (new_major == old_major && new_minor > old_minor)) {
540 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
545 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
551 /* Compare modification time/dates and choose the newest time/date */
552 if (new_create_time > old_create_time) {
553 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
558 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
566 close_file(NULL, fsp, NORMAL_CLOSE);
569 TALLOC_FREE(smb_fname);
573 /****************************************************************************
574 Determine the correct cVersion associated with an architecture and driver
575 ****************************************************************************/
576 static uint32 get_correct_cversion(struct auth_serversupplied_info *session_info,
577 const char *architecture,
578 const char *driverpath_in,
583 struct smb_filename *smb_fname = NULL;
584 char *driverpath = NULL;
585 files_struct *fsp = NULL;
586 connection_struct *conn = NULL;
588 char *printdollar = NULL;
589 int printdollar_snum;
591 *perr = WERR_INVALID_PARAM;
593 /* If architecture is Windows 95/98/ME, the version is always 0. */
594 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
595 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
600 /* If architecture is Windows x64, the version is always 3. */
601 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
602 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
607 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
612 if (printdollar_snum == -1) {
613 *perr = WERR_NO_SUCH_SHARE;
617 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
618 lp_pathname(printdollar_snum),
619 session_info, &oldcwd);
620 if (!NT_STATUS_IS_OK(nt_status)) {
621 DEBUG(0,("get_correct_cversion: create_conn_struct "
622 "returned %s\n", nt_errstr(nt_status)));
623 *perr = ntstatus_to_werror(nt_status);
627 nt_status = set_conn_force_user_group(conn, printdollar_snum);
628 if (!NT_STATUS_IS_OK(nt_status)) {
629 DEBUG(0, ("failed set force user / group\n"));
630 *perr = ntstatus_to_werror(nt_status);
631 goto error_free_conn;
634 if (!become_user_by_session(conn, session_info)) {
635 DEBUG(0, ("failed to become user\n"));
636 *perr = WERR_ACCESS_DENIED;
637 goto error_free_conn;
640 /* Open the driver file (Portable Executable format) and determine the
641 * deriver the cversion. */
642 driverpath = talloc_asprintf(talloc_tos(),
651 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
652 if (!NT_STATUS_IS_OK(nt_status)) {
653 *perr = ntstatus_to_werror(nt_status);
657 nt_status = vfs_file_exist(conn, smb_fname);
658 if (!NT_STATUS_IS_OK(nt_status)) {
659 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
660 *perr = WERR_BADFILE;
664 nt_status = SMB_VFS_CREATE_FILE(
667 0, /* root_dir_fid */
668 smb_fname, /* fname */
669 FILE_GENERIC_READ, /* access_mask */
670 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
671 FILE_OPEN, /* create_disposition*/
672 0, /* create_options */
673 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
674 INTERNAL_OPEN_ONLY, /* oplock_request */
675 0, /* private_flags */
676 0, /* allocation_size */
682 if (!NT_STATUS_IS_OK(nt_status)) {
683 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
684 "%d\n", smb_fname_str_dbg(smb_fname), errno));
685 *perr = WERR_ACCESS_DENIED;
692 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
694 *perr = WERR_INVALID_PARAM;
697 DEBUG(6,("get_correct_cversion: Version info not "
699 smb_fname_str_dbg(smb_fname)));
700 *perr = WERR_INVALID_PARAM;
705 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
706 * for more details. Version in this case is not just the version of the
707 * file, but the version in the sense of kernal mode (2) vs. user mode
708 * (3) drivers. Other bits of the version fields are the version info.
711 cversion = major & 0x0000ffff;
713 case 2: /* WinNT drivers */
714 case 3: /* Win2K drivers */
718 DEBUG(6,("get_correct_cversion: cversion "
719 "invalid [%s] cversion = %d\n",
720 smb_fname_str_dbg(smb_fname),
725 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
726 " = 0x%x minor = 0x%x\n",
727 smb_fname_str_dbg(smb_fname), major, minor));
730 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
731 smb_fname_str_dbg(smb_fname), cversion));
737 TALLOC_FREE(smb_fname);
739 close_file(NULL, fsp, NORMAL_CLOSE);
742 vfs_ChDir(conn, oldcwd);
743 SMB_VFS_DISCONNECT(conn);
746 if (!NT_STATUS_IS_OK(*perr)) {
753 /****************************************************************************
754 ****************************************************************************/
756 #define strip_driver_path(_mem_ctx, _element) do { \
757 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
758 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
759 W_ERROR_HAVE_NO_MEMORY((_element)); \
763 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
764 struct auth_serversupplied_info *session_info,
765 const char *architecture,
766 const char **driver_path,
767 const char **data_file,
768 const char **config_file,
769 const char **help_file,
770 struct spoolss_StringArray *dependent_files,
771 enum spoolss_DriverOSVersion *version)
773 const char *short_architecture;
778 if (!*driver_path || !*data_file) {
779 return WERR_INVALID_PARAM;
782 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
783 return WERR_INVALID_PARAM;
786 /* clean up the driver name.
787 * we can get .\driver.dll
788 * or worse c:\windows\system\driver.dll !
790 /* using an intermediate string to not have overlaping memcpy()'s */
792 strip_driver_path(mem_ctx, *driver_path);
793 strip_driver_path(mem_ctx, *data_file);
795 strip_driver_path(mem_ctx, *config_file);
798 strip_driver_path(mem_ctx, *help_file);
801 if (dependent_files && dependent_files->string) {
802 for (i=0; dependent_files->string[i]; i++) {
803 strip_driver_path(mem_ctx, dependent_files->string[i]);
807 short_architecture = get_short_archi(architecture);
808 if (!short_architecture) {
809 return WERR_UNKNOWN_PRINTER_DRIVER;
812 /* jfm:7/16/2000 the client always sends the cversion=0.
813 * The server should check which version the driver is by reading
814 * the PE header of driver->driverpath.
816 * For Windows 95/98 the version is 0 (so the value sent is correct)
817 * For Windows NT (the architecture doesn't matter)
819 * NT 3.5/3.51: cversion=1
824 *version = get_correct_cversion(session_info, short_architecture,
826 if (*version == -1) {
833 /****************************************************************************
834 ****************************************************************************/
836 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
837 struct auth_serversupplied_info *session_info,
838 struct spoolss_AddDriverInfoCtr *r)
842 return clean_up_driver_struct_level(mem_ctx, session_info,
843 r->info.info3->architecture,
844 &r->info.info3->driver_path,
845 &r->info.info3->data_file,
846 &r->info.info3->config_file,
847 &r->info.info3->help_file,
848 r->info.info3->dependent_files,
849 &r->info.info3->version);
851 return clean_up_driver_struct_level(mem_ctx, session_info,
852 r->info.info6->architecture,
853 &r->info.info6->driver_path,
854 &r->info.info6->data_file,
855 &r->info.info6->config_file,
856 &r->info.info6->help_file,
857 r->info.info6->dependent_files,
858 &r->info.info6->version);
860 return WERR_NOT_SUPPORTED;
864 /****************************************************************************
865 This function sucks and should be replaced. JRA.
866 ****************************************************************************/
868 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
869 const struct spoolss_AddDriverInfo6 *src)
871 dst->version = src->version;
873 dst->driver_name = src->driver_name;
874 dst->architecture = src->architecture;
875 dst->driver_path = src->driver_path;
876 dst->data_file = src->data_file;
877 dst->config_file = src->config_file;
878 dst->help_file = src->help_file;
879 dst->monitor_name = src->monitor_name;
880 dst->default_datatype = src->default_datatype;
881 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
882 dst->dependent_files = src->dependent_files;
885 /****************************************************************************
886 ****************************************************************************/
888 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
889 connection_struct *conn,
890 const char *driver_file,
891 const char *short_architecture,
892 uint32_t driver_version,
895 struct smb_filename *smb_fname_old = NULL;
896 struct smb_filename *smb_fname_new = NULL;
897 char *old_name = NULL;
898 char *new_name = NULL;
902 old_name = talloc_asprintf(mem_ctx, "%s/%s",
903 short_architecture, driver_file);
904 W_ERROR_HAVE_NO_MEMORY(old_name);
906 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
907 short_architecture, driver_version, driver_file);
908 if (new_name == NULL) {
909 TALLOC_FREE(old_name);
913 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
915 status = driver_unix_convert(conn, old_name, &smb_fname_old);
916 if (!NT_STATUS_IS_OK(status)) {
921 /* Setup a synthetic smb_filename struct */
922 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
923 if (!smb_fname_new) {
928 smb_fname_new->base_name = new_name;
930 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
931 "'%s'\n", smb_fname_old->base_name,
932 smb_fname_new->base_name));
934 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
935 OPENX_FILE_EXISTS_TRUNCATE |
936 OPENX_FILE_CREATE_IF_NOT_EXIST,
939 if (!NT_STATUS_IS_OK(status)) {
940 DEBUG(0,("move_driver_file_to_download_area: Unable "
941 "to rename [%s] to [%s]: %s\n",
942 smb_fname_old->base_name, new_name,
944 ret = WERR_ACCESS_DENIED;
951 TALLOC_FREE(smb_fname_old);
952 TALLOC_FREE(smb_fname_new);
956 WERROR move_driver_to_download_area(struct auth_serversupplied_info *session_info,
957 struct spoolss_AddDriverInfoCtr *r)
959 struct spoolss_AddDriverInfo3 *driver;
960 struct spoolss_AddDriverInfo3 converted_driver;
961 const char *short_architecture;
962 struct smb_filename *smb_dname = NULL;
963 char *new_dir = NULL;
964 connection_struct *conn = NULL;
967 TALLOC_CTX *ctx = talloc_tos();
970 char *printdollar = NULL;
971 int printdollar_snum;
972 WERROR err = WERR_OK;
976 driver = r->info.info3;
979 convert_level_6_to_level3(&converted_driver, r->info.info6);
980 driver = &converted_driver;
983 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
984 return WERR_UNKNOWN_LEVEL;
987 short_architecture = get_short_archi(driver->architecture);
988 if (!short_architecture) {
989 return WERR_UNKNOWN_PRINTER_DRIVER;
992 printdollar_snum = find_service(ctx, "print$", &printdollar);
996 if (printdollar_snum == -1) {
997 return WERR_NO_SUCH_SHARE;
1000 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1001 lp_pathname(printdollar_snum),
1002 session_info, &oldcwd);
1003 if (!NT_STATUS_IS_OK(nt_status)) {
1004 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1005 "returned %s\n", nt_errstr(nt_status)));
1006 err = ntstatus_to_werror(nt_status);
1010 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1011 if (!NT_STATUS_IS_OK(nt_status)) {
1012 DEBUG(0, ("failed set force user / group\n"));
1013 err = ntstatus_to_werror(nt_status);
1017 if (!become_user_by_session(conn, session_info)) {
1018 DEBUG(0, ("failed to become user\n"));
1019 err = WERR_ACCESS_DENIED;
1023 new_dir = talloc_asprintf(ctx,
1031 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1032 if (!NT_STATUS_IS_OK(nt_status)) {
1037 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1039 nt_status = create_directory(conn, NULL, smb_dname);
1040 if (!NT_STATUS_IS_OK(nt_status)
1041 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1042 DEBUG(0, ("failed to create driver destination directory: %s\n",
1043 nt_errstr(nt_status)));
1044 err = ntstatus_to_werror(nt_status);
1048 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1049 * listed for this driver which has already been moved, skip it (note:
1050 * drivers may list the same file name several times. Then check if the
1051 * file already exists in archi\version\, if so, check that the version
1052 * info (or time stamps if version info is unavailable) is newer (or the
1053 * date is later). If it is, move it to archi\version\filexxx.yyy.
1054 * Otherwise, delete the file.
1056 * If a file is not moved to archi\version\ because of an error, all the
1057 * rest of the 'unmoved' driver files are removed from archi\. If one or
1058 * more of the driver's files was already moved to archi\version\, it
1059 * potentially leaves the driver in a partially updated state. Version
1060 * trauma will most likely occur if an client attempts to use any printer
1061 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1062 * done is appropriate... later JRR
1065 DEBUG(5,("Moving files now !\n"));
1067 if (driver->driver_path && strlen(driver->driver_path)) {
1069 err = move_driver_file_to_download_area(ctx,
1071 driver->driver_path,
1075 if (!W_ERROR_IS_OK(err)) {
1080 if (driver->data_file && strlen(driver->data_file)) {
1081 if (!strequal(driver->data_file, driver->driver_path)) {
1083 err = move_driver_file_to_download_area(ctx,
1089 if (!W_ERROR_IS_OK(err)) {
1095 if (driver->config_file && strlen(driver->config_file)) {
1096 if (!strequal(driver->config_file, driver->driver_path) &&
1097 !strequal(driver->config_file, driver->data_file)) {
1099 err = move_driver_file_to_download_area(ctx,
1101 driver->config_file,
1105 if (!W_ERROR_IS_OK(err)) {
1111 if (driver->help_file && strlen(driver->help_file)) {
1112 if (!strequal(driver->help_file, driver->driver_path) &&
1113 !strequal(driver->help_file, driver->data_file) &&
1114 !strequal(driver->help_file, driver->config_file)) {
1116 err = move_driver_file_to_download_area(ctx,
1122 if (!W_ERROR_IS_OK(err)) {
1128 if (driver->dependent_files && driver->dependent_files->string) {
1129 for (i=0; driver->dependent_files->string[i]; i++) {
1130 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1131 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1132 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1133 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1135 for (j=0; j < i; j++) {
1136 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1141 err = move_driver_file_to_download_area(ctx,
1143 driver->dependent_files->string[i],
1147 if (!W_ERROR_IS_OK(err)) {
1159 TALLOC_FREE(smb_dname);
1162 vfs_ChDir(conn, oldcwd);
1163 SMB_VFS_DISCONNECT(conn);
1170 /****************************************************************************
1171 Determine whether or not a particular driver is currently assigned
1173 ****************************************************************************/
1175 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1176 const struct auth_serversupplied_info *session_info,
1177 struct messaging_context *msg_ctx,
1178 const struct spoolss_DriverInfo8 *r)
1181 int n_services = lp_numservices();
1182 bool in_use = False;
1183 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1190 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1192 /* loop through the printers.tdb and check for the drivername */
1194 for (snum=0; snum<n_services && !in_use; snum++) {
1195 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1199 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
1200 lp_servicename(snum),
1202 if (!W_ERROR_IS_OK(result)) {
1203 continue; /* skip */
1206 if (strequal(r->driver_name, pinfo2->drivername)) {
1210 TALLOC_FREE(pinfo2);
1213 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1216 struct spoolss_DriverInfo8 *driver;
1219 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1221 /* we can still remove the driver if there is one of
1222 "Windows NT x86" version 2 or 3 left */
1224 if (!strequal("Windows NT x86", r->architecture)) {
1225 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1230 } else if (r->version == 2) {
1231 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1235 } else if (r->version == 3) {
1236 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1241 DEBUG(0, ("printer_driver_in_use: ERROR!"
1242 " unknown driver version (%d)\n",
1244 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1247 /* now check the error code */
1249 if ( W_ERROR_IS_OK(werr) ) {
1250 /* it's ok to remove the driver, we have other architctures left */
1252 talloc_free(driver);
1256 /* report that the driver is not in use by default */
1262 /**********************************************************************
1263 Check to see if a ogiven file is in use by *info
1264 *********************************************************************/
1266 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1273 /* mz: skip files that are in the list but already deleted */
1274 if (!file || !file[0]) {
1278 if (strequal(file, info->driver_path))
1281 if (strequal(file, info->data_file))
1284 if (strequal(file, info->config_file))
1287 if (strequal(file, info->help_file))
1290 /* see of there are any dependent files to examine */
1292 if (!info->dependent_files)
1295 while (info->dependent_files[i] && *info->dependent_files[i]) {
1296 if (strequal(file, info->dependent_files[i]))
1305 /**********************************************************************
1306 Utility function to remove the dependent file pointed to by the
1307 input parameter from the list
1308 *********************************************************************/
1310 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1313 /* bump everything down a slot */
1315 while (files && files[idx+1]) {
1316 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1325 /**********************************************************************
1326 Check if any of the files used by src are also used by drv
1327 *********************************************************************/
1329 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1330 struct spoolss_DriverInfo8 *src,
1331 const struct spoolss_DriverInfo8 *drv)
1333 bool in_use = False;
1339 /* check each file. Remove it from the src structure if it overlaps */
1341 if (drv_file_in_use(src->driver_path, drv)) {
1343 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1344 src->driver_path = talloc_strdup(mem_ctx, "");
1345 if (!src->driver_path) { return false; }
1348 if (drv_file_in_use(src->data_file, drv)) {
1350 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1351 src->data_file = talloc_strdup(mem_ctx, "");
1352 if (!src->data_file) { return false; }
1355 if (drv_file_in_use(src->config_file, drv)) {
1357 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1358 src->config_file = talloc_strdup(mem_ctx, "");
1359 if (!src->config_file) { return false; }
1362 if (drv_file_in_use(src->help_file, drv)) {
1364 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1365 src->help_file = talloc_strdup(mem_ctx, "");
1366 if (!src->help_file) { return false; }
1369 /* are there any dependentfiles to examine? */
1371 if (!src->dependent_files)
1374 while (src->dependent_files[i] && *src->dependent_files[i]) {
1375 if (drv_file_in_use(src->dependent_files[i], drv)) {
1377 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1378 trim_dependent_file(mem_ctx, src->dependent_files, i);
1386 /****************************************************************************
1387 Determine whether or not a particular driver files are currently being
1388 used by any other driver.
1390 Return value is True if any files were in use by other drivers
1391 and False otherwise.
1393 Upon return, *info has been modified to only contain the driver files
1394 which are not in use
1398 This needs to check all drivers to ensure that all files in use
1399 have been removed from *info, not just the ones in the first
1401 ****************************************************************************/
1403 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1404 const struct auth_serversupplied_info *session_info,
1405 struct messaging_context *msg_ctx,
1406 struct spoolss_DriverInfo8 *info)
1410 struct spoolss_DriverInfo8 *driver;
1411 bool in_use = false;
1412 uint32_t num_drivers;
1413 const char **drivers;
1419 version = info->version;
1421 /* loop over all driver versions */
1423 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1425 /* get the list of drivers */
1427 result = winreg_get_driver_list(mem_ctx, session_info, msg_ctx,
1428 info->architecture, version,
1429 &num_drivers, &drivers);
1430 if (!W_ERROR_IS_OK(result)) {
1434 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1435 num_drivers, info->architecture, version));
1437 /* check each driver for overlap in files */
1439 for (i = 0; i < num_drivers; i++) {
1440 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1444 result = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1445 info->architecture, drivers[i],
1447 if (!W_ERROR_IS_OK(result)) {
1448 talloc_free(drivers);
1452 /* check if d2 uses any files from d1 */
1453 /* only if this is a different driver than the one being deleted */
1455 if (!strequal(info->driver_name, driver->driver_name)) {
1456 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1457 /* mz: Do not instantly return -
1458 * we need to ensure this file isn't
1459 * also in use by other drivers. */
1464 talloc_free(driver);
1467 talloc_free(drivers);
1469 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1474 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1477 struct smb_filename *smb_fname = NULL;
1480 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1482 if (!NT_STATUS_IS_OK(status)) {
1486 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1488 TALLOC_FREE(smb_fname);
1492 /****************************************************************************
1493 Actually delete the driver files. Make sure that
1494 printer_driver_files_in_use() return False before calling
1496 ****************************************************************************/
1498 bool delete_driver_files(const struct auth_serversupplied_info *session_info,
1499 const struct spoolss_DriverInfo8 *r)
1504 connection_struct *conn;
1507 char *printdollar = NULL;
1508 int printdollar_snum;
1515 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1516 r->driver_name, r->version));
1518 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1522 if (printdollar_snum == -1) {
1526 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1527 lp_pathname(printdollar_snum),
1528 session_info, &oldcwd);
1529 if (!NT_STATUS_IS_OK(nt_status)) {
1530 DEBUG(0,("delete_driver_files: create_conn_struct "
1531 "returned %s\n", nt_errstr(nt_status)));
1535 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1536 if (!NT_STATUS_IS_OK(nt_status)) {
1537 DEBUG(0, ("failed set force user / group\n"));
1542 if (!become_user_by_session(conn, session_info)) {
1543 DEBUG(0, ("failed to become user\n"));
1548 if ( !CAN_WRITE(conn) ) {
1549 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1554 /* now delete the files; must strip the '\print$' string from
1557 if (r->driver_path && r->driver_path[0]) {
1558 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1560 DEBUG(10,("deleting driverfile [%s]\n", s));
1561 driver_unlink_internals(conn, file);
1565 if (r->config_file && r->config_file[0]) {
1566 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1568 DEBUG(10,("deleting configfile [%s]\n", s));
1569 driver_unlink_internals(conn, file);
1573 if (r->data_file && r->data_file[0]) {
1574 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1576 DEBUG(10,("deleting datafile [%s]\n", s));
1577 driver_unlink_internals(conn, file);
1581 if (r->help_file && r->help_file[0]) {
1582 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1584 DEBUG(10,("deleting helpfile [%s]\n", s));
1585 driver_unlink_internals(conn, file);
1589 /* check if we are done removing files */
1591 if (r->dependent_files) {
1592 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1595 /* bypass the "\print$" portion of the path */
1597 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1599 DEBUG(10,("deleting dependent file [%s]\n", file));
1600 driver_unlink_internals(conn, file);
1612 vfs_ChDir(conn, oldcwd);
1613 SMB_VFS_DISCONNECT(conn);
1621 1: level not implemented
1622 2: file doesn't exist
1623 3: can't allocate memory
1624 4: can't free memory
1625 5: non existant struct
1629 A printer and a printer driver are 2 different things.
1630 NT manages them separatelly, Samba does the same.
1631 Why ? Simply because it's easier and it makes sense !
1633 Now explanation: You have 3 printers behind your samba server,
1634 2 of them are the same make and model (laser A and B). But laser B
1635 has an 3000 sheet feeder and laser A doesn't such an option.
1636 Your third printer is an old dot-matrix model for the accounting :-).
1638 If the /usr/local/samba/lib directory (default dir), you will have
1639 5 files to describe all of this.
1641 3 files for the printers (1 by printer):
1644 NTprinter_accounting
1645 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1646 NTdriver_printer model X
1647 NTdriver_printer model Y
1649 jfm: I should use this comment for the text file to explain
1650 same thing for the forms BTW.
1651 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1655 /* Convert generic access rights to printer object specific access rights.
1656 It turns out that NT4 security descriptors use generic access rights and
1657 NT5 the object specific ones. */
1659 void map_printer_permissions(struct security_descriptor *sd)
1663 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1664 se_map_generic(&sd->dacl->aces[i].access_mask,
1665 &printer_generic_mapping);
1669 void map_job_permissions(struct security_descriptor *sd)
1673 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1674 se_map_generic(&sd->dacl->aces[i].access_mask,
1675 &job_generic_mapping);
1680 /****************************************************************************
1681 Check a user has permissions to perform the given operation. We use the
1682 permission constants defined in include/rpc_spoolss.h to check the various
1683 actions we perform when checking printer access.
1685 PRINTER_ACCESS_ADMINISTER:
1686 print_queue_pause, print_queue_resume, update_printer_sec,
1687 update_printer, spoolss_addprinterex_level_2,
1688 _spoolss_setprinterdata
1693 JOB_ACCESS_ADMINISTER:
1694 print_job_delete, print_job_pause, print_job_resume,
1697 Try access control in the following order (for performance reasons):
1698 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1699 2) check security descriptor (bit comparisons in memory)
1700 3) "printer admins" (may result in numerous calls to winbind)
1702 ****************************************************************************/
1703 bool print_access_check(const struct auth_serversupplied_info *session_info,
1704 struct messaging_context *msg_ctx, int snum,
1707 struct spoolss_security_descriptor *secdesc = NULL;
1708 uint32 access_granted;
1713 TALLOC_CTX *mem_ctx = NULL;
1715 /* If user is NULL then use the current_user structure */
1717 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1719 if (session_info->utok.uid == sec_initial_uid()
1720 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1724 /* Get printer name */
1726 pname = lp_printername(snum);
1728 if (!pname || !*pname) {
1733 /* Get printer security descriptor */
1735 if(!(mem_ctx = talloc_init("print_access_check"))) {
1740 result = winreg_get_printer_secdesc(mem_ctx,
1741 get_session_info_system(),
1745 if (!W_ERROR_IS_OK(result)) {
1746 talloc_destroy(mem_ctx);
1751 if (access_type == JOB_ACCESS_ADMINISTER) {
1752 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1754 /* Create a child security descriptor to check permissions
1755 against. This is because print jobs are child objects
1756 objects of a printer. */
1757 status = se_create_child_secdesc(mem_ctx,
1761 parent_secdesc->owner_sid,
1762 parent_secdesc->group_sid,
1764 if (!NT_STATUS_IS_OK(status)) {
1765 talloc_destroy(mem_ctx);
1766 errno = map_errno_from_nt_status(status);
1770 map_job_permissions(secdesc);
1772 map_printer_permissions(secdesc);
1776 status = se_access_check(secdesc, session_info->security_token, access_type,
1779 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1781 /* see if we need to try the printer admin list */
1783 if (!NT_STATUS_IS_OK(status) &&
1784 (token_contains_name_in_list(uidtoname(session_info->utok.uid),
1785 session_info->info3->base.domain.string,
1786 NULL, session_info->security_token,
1787 lp_printer_admin(snum)))) {
1788 talloc_destroy(mem_ctx);
1792 talloc_destroy(mem_ctx);
1794 if (!NT_STATUS_IS_OK(status)) {
1798 return NT_STATUS_IS_OK(status);
1801 /****************************************************************************
1802 Check the time parameters allow a print operation.
1803 *****************************************************************************/
1805 bool print_time_access_check(const struct auth_serversupplied_info *session_info,
1806 struct messaging_context *msg_ctx,
1807 const char *servicename)
1809 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1812 time_t now = time(NULL);
1816 result = winreg_get_printer(NULL, session_info, msg_ctx,
1817 servicename, &pinfo2);
1818 if (!W_ERROR_IS_OK(result)) {
1822 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1827 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1829 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1833 TALLOC_FREE(pinfo2);
1842 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1843 const struct auth_serversupplied_info *session_info,
1844 struct messaging_context *msg_ctx,
1845 const char *printer)
1849 result = winreg_delete_printer_key(mem_ctx, session_info, msg_ctx,
1851 if (!W_ERROR_IS_OK(result)) {
1852 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",