lib: Use close_low_fd in close_low_fds
[Samba.git] / source3 / printing / nt_printing.c
blobb76badf3f02053cac382df4d25291e9aae6e4da5
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 static bool print_driver_directories_init(void)
79 int service, i;
80 char *driver_path;
81 bool ok;
82 TALLOC_CTX *mem_ctx = talloc_stackframe();
84 service = lp_servicenumber("print$");
85 if (service < 0) {
86 /* We don't have a print$ share */
87 DEBUG(5, ("No print$ share has been configured.\n"));
88 talloc_free(mem_ctx);
89 return true;
92 driver_path = lp_path(mem_ctx, service);
93 if (driver_path == NULL) {
94 talloc_free(mem_ctx);
95 return false;
98 ok = directory_create_or_exist(driver_path, 0755);
99 if (!ok) {
100 DEBUG(1, ("Failed to create printer driver directory %s\n",
101 driver_path));
102 talloc_free(mem_ctx);
103 return false;
106 for (i = 0; archi_table[i].long_archi != NULL; i++) {
107 const char *arch_path;
109 arch_path = talloc_asprintf(mem_ctx,
110 "%s/%s",
111 driver_path,
112 archi_table[i].short_archi);
113 if (arch_path == NULL) {
114 talloc_free(mem_ctx);
115 return false;
118 ok = directory_create_or_exist(arch_path, 0755);
119 if (!ok) {
120 DEBUG(1, ("Failed to create printer driver "
121 "architecture directory %s\n",
122 arch_path));
123 talloc_free(mem_ctx);
124 return false;
128 talloc_free(mem_ctx);
129 return true;
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,
138 void *private_data,
139 uint32_t msg_type,
140 struct server_id server_id,
141 DATA_BLOB *data)
143 extern pid_t background_lpq_updater_pid;
145 if (background_lpq_updater_pid == -1) {
146 DEBUG(3,("no background lpq queue updater\n"));
147 return;
150 messaging_send_buf(msg,
151 pid_to_procid(background_lpq_updater_pid),
152 MSG_PRINTER_DRVUPGRADE,
153 data->data,
154 data->length);
157 /****************************************************************************
158 Open the NT printing tdbs. Done once before fork().
159 ****************************************************************************/
161 bool nt_printing_init(struct messaging_context *msg_ctx)
163 WERROR win_rc;
165 if (!print_driver_directories_init()) {
166 return false;
169 if (!nt_printing_tdb_upgrade()) {
170 return false;
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)));
190 return true;
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)
201 NTSTATUS status;
202 TALLOC_CTX *ctx = talloc_tos();
203 char *name = talloc_strdup(ctx, old_name);
205 if (!name) {
206 return NT_STATUS_NO_MEMORY;
208 unix_format(name);
209 name = unix_clean_name(ctx, name);
210 if (!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;
220 return NT_STATUS_OK;
223 /****************************************************************************
224 Function to do the mapping between the long architecture name and
225 the short one.
226 ****************************************************************************/
228 const char *get_short_archi(const char *long_archi)
230 int i=-1;
232 DEBUG(107,("Getting architecture dependent directory\n"));
233 do {
234 i++;
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));
240 return NULL;
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)
262 int i;
263 char *buf = NULL;
264 ssize_t byte_count;
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));
269 goto error_exit;
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",
288 fname, errno));
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",
311 fname, errno));
312 goto error_exit;
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)
319 goto error_exit;
321 SAFE_FREE(buf);
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));
325 goto error_exit;
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));
331 goto error_exit;
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)
343 goto error_exit;
345 SAFE_FREE(buf);
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));
349 goto error_exit;
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",
355 fname, errno));
356 goto error_exit;
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));
362 goto error_exit;
365 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
366 goto error_exit;
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));
382 SAFE_FREE(buf);
383 return 1;
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));
392 SAFE_FREE(buf);
393 return 0;
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. */
401 goto error_exit;
404 /* Allocate a bit more space to speed up things */
405 SAFE_FREE(buf);
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));
409 goto error_exit;
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) {
426 int bc;
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",
433 fname, errno));
434 goto error_exit;
437 byte_count = bc + (byte_count - i);
438 if (byte_count<VS_VERSION_INFO_SIZE) break;
440 i = 0;
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));
459 SAFE_FREE(buf);
460 return 1;
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));
467 SAFE_FREE(buf);
468 return 0;
470 } else
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)));
475 no_version_info:
476 SAFE_FREE(buf);
477 return 0;
479 error_exit:
480 SAFE_FREE(buf);
481 return -1;
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;
498 uint32 new_major;
499 uint32 new_minor;
500 time_t new_create_time;
502 uint32 old_major;
503 uint32 old_minor;
504 time_t old_create_time;
506 struct smb_filename *smb_fname = NULL;
507 files_struct *fsp = NULL;
508 SMB_STRUCT_STAT st;
510 NTSTATUS status;
511 int ret;
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)) {
520 goto error_exit;
523 status = SMB_VFS_CREATE_FILE(
524 conn, /* conn */
525 NULL, /* req */
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 */
534 0, /* allocation_size */
535 0, /* private_flags */
536 NULL, /* sd */
537 NULL, /* ea_list */
538 &fsp, /* result */
539 NULL); /* pinfo */
541 if (!NT_STATUS_IS_OK(status)) {
542 /* Old file not found, so by definition new file is in fact newer */
543 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
544 "errno = %d\n", smb_fname_str_dbg(smb_fname),
545 errno));
546 ret = 1;
547 goto done;
549 } else {
550 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
551 if (ret == -1) {
552 goto error_exit;
555 if (!ret) {
556 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
557 old_file));
558 use_version = false;
559 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
560 goto error_exit;
562 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
563 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
564 (long)old_create_time));
567 close_file(NULL, fsp, NORMAL_CLOSE);
568 fsp = NULL;
570 /* Get file version info (if available) for new file */
571 status = driver_unix_convert(conn, new_file, &smb_fname);
572 if (!NT_STATUS_IS_OK(status)) {
573 goto error_exit;
576 status = SMB_VFS_CREATE_FILE(
577 conn, /* conn */
578 NULL, /* req */
579 0, /* root_dir_fid */
580 smb_fname, /* fname */
581 FILE_GENERIC_READ, /* access_mask */
582 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
583 FILE_OPEN, /* create_disposition*/
584 0, /* create_options */
585 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
586 INTERNAL_OPEN_ONLY, /* oplock_request */
587 0, /* allocation_size */
588 0, /* private_flags */
589 NULL, /* sd */
590 NULL, /* ea_list */
591 &fsp, /* result */
592 NULL); /* pinfo */
594 if (!NT_STATUS_IS_OK(status)) {
595 /* New file not found, this shouldn't occur if the caller did its job */
596 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
597 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
598 goto error_exit;
600 } else {
601 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
602 if (ret == -1) {
603 goto error_exit;
606 if (!ret) {
607 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
608 new_file));
609 use_version = false;
610 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
611 goto error_exit;
613 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
614 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
615 (long)new_create_time));
618 close_file(NULL, fsp, NORMAL_CLOSE);
619 fsp = NULL;
621 if (use_version && (new_major != old_major || new_minor != old_minor)) {
622 /* Compare versions and choose the larger version number */
623 if (new_major > old_major ||
624 (new_major == old_major && new_minor > old_minor)) {
626 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
627 ret = 1;
628 goto done;
630 else {
631 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
632 ret = 0;
633 goto done;
636 } else {
637 /* Compare modification time/dates and choose the newest time/date */
638 if (new_create_time > old_create_time) {
639 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
640 ret = 1;
641 goto done;
643 else {
644 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
645 ret = 0;
646 goto done;
650 error_exit:
651 if(fsp)
652 close_file(NULL, fsp, NORMAL_CLOSE);
653 ret = -1;
654 done:
655 TALLOC_FREE(smb_fname);
656 return ret;
659 /****************************************************************************
660 Determine the correct cVersion associated with an architecture and driver
661 ****************************************************************************/
662 static uint32 get_correct_cversion(struct auth_session_info *session_info,
663 const char *architecture,
664 const char *driverpath_in,
665 WERROR *perr)
667 int cversion = -1;
668 NTSTATUS nt_status;
669 struct smb_filename *smb_fname = NULL;
670 char *driverpath = NULL;
671 files_struct *fsp = NULL;
672 connection_struct *conn = NULL;
673 char *oldcwd;
674 char *printdollar = NULL;
675 int printdollar_snum;
677 *perr = WERR_INVALID_PARAM;
679 /* If architecture is Windows 95/98/ME, the version is always 0. */
680 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
681 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
682 *perr = WERR_OK;
683 return 0;
686 /* If architecture is Windows x64, the version is always 3. */
687 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
688 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
689 *perr = WERR_OK;
690 return 3;
693 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
694 if (!printdollar) {
695 *perr = WERR_NOMEM;
696 return -1;
698 if (printdollar_snum == -1) {
699 *perr = WERR_NO_SUCH_SHARE;
700 return -1;
703 nt_status = create_conn_struct_cwd(talloc_tos(),
704 server_event_context(),
705 server_messaging_context(),
706 &conn,
707 printdollar_snum,
708 lp_path(talloc_tos(), printdollar_snum),
709 session_info, &oldcwd);
710 if (!NT_STATUS_IS_OK(nt_status)) {
711 DEBUG(0,("get_correct_cversion: create_conn_struct "
712 "returned %s\n", nt_errstr(nt_status)));
713 *perr = ntstatus_to_werror(nt_status);
714 return -1;
717 nt_status = set_conn_force_user_group(conn, printdollar_snum);
718 if (!NT_STATUS_IS_OK(nt_status)) {
719 DEBUG(0, ("failed set force user / group\n"));
720 *perr = ntstatus_to_werror(nt_status);
721 goto error_free_conn;
724 if (!become_user_by_session(conn, session_info)) {
725 DEBUG(0, ("failed to become user\n"));
726 *perr = WERR_ACCESS_DENIED;
727 goto error_free_conn;
730 /* Open the driver file (Portable Executable format) and determine the
731 * deriver the cversion. */
732 driverpath = talloc_asprintf(talloc_tos(),
733 "%s/%s",
734 architecture,
735 driverpath_in);
736 if (!driverpath) {
737 *perr = WERR_NOMEM;
738 goto error_exit;
741 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
742 if (!NT_STATUS_IS_OK(nt_status)) {
743 *perr = ntstatus_to_werror(nt_status);
744 goto error_exit;
747 nt_status = vfs_file_exist(conn, smb_fname);
748 if (!NT_STATUS_IS_OK(nt_status)) {
749 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
750 *perr = WERR_BADFILE;
751 goto error_exit;
754 nt_status = SMB_VFS_CREATE_FILE(
755 conn, /* conn */
756 NULL, /* req */
757 0, /* root_dir_fid */
758 smb_fname, /* fname */
759 FILE_GENERIC_READ, /* access_mask */
760 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
761 FILE_OPEN, /* create_disposition*/
762 0, /* create_options */
763 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
764 INTERNAL_OPEN_ONLY, /* oplock_request */
765 0, /* private_flags */
766 0, /* allocation_size */
767 NULL, /* sd */
768 NULL, /* ea_list */
769 &fsp, /* result */
770 NULL); /* pinfo */
772 if (!NT_STATUS_IS_OK(nt_status)) {
773 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
774 "%d\n", smb_fname_str_dbg(smb_fname), errno));
775 *perr = WERR_ACCESS_DENIED;
776 goto error_exit;
777 } else {
778 uint32 major;
779 uint32 minor;
780 int ret;
782 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
783 if (ret == -1) {
784 *perr = WERR_INVALID_PARAM;
785 goto error_exit;
786 } else if (!ret) {
787 DEBUG(6,("get_correct_cversion: Version info not "
788 "found [%s]\n",
789 smb_fname_str_dbg(smb_fname)));
790 *perr = WERR_INVALID_PARAM;
791 goto error_exit;
795 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
796 * for more details. Version in this case is not just the version of the
797 * file, but the version in the sense of kernal mode (2) vs. user mode
798 * (3) drivers. Other bits of the version fields are the version info.
799 * JRR 010716
801 cversion = major & 0x0000ffff;
802 switch (cversion) {
803 case 2: /* WinNT drivers */
804 case 3: /* Win2K drivers */
805 break;
807 default:
808 DEBUG(6,("get_correct_cversion: cversion "
809 "invalid [%s] cversion = %d\n",
810 smb_fname_str_dbg(smb_fname),
811 cversion));
812 goto error_exit;
815 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
816 " = 0x%x minor = 0x%x\n",
817 smb_fname_str_dbg(smb_fname), major, minor));
820 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
821 smb_fname_str_dbg(smb_fname), cversion));
822 *perr = WERR_OK;
824 error_exit:
825 unbecome_user();
826 error_free_conn:
827 TALLOC_FREE(smb_fname);
828 if (fsp != NULL) {
829 close_file(NULL, fsp, NORMAL_CLOSE);
831 if (conn != NULL) {
832 vfs_ChDir(conn, oldcwd);
833 SMB_VFS_DISCONNECT(conn);
834 conn_free(conn);
836 if (!W_ERROR_IS_OK(*perr)) {
837 cversion = -1;
840 return cversion;
843 /****************************************************************************
844 ****************************************************************************/
846 #define strip_driver_path(_mem_ctx, _element) do { \
847 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
848 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
849 W_ERROR_HAVE_NO_MEMORY((_element)); \
851 } while (0);
853 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
854 struct auth_session_info *session_info,
855 const char *architecture,
856 const char **driver_path,
857 const char **data_file,
858 const char **config_file,
859 const char **help_file,
860 struct spoolss_StringArray *dependent_files,
861 enum spoolss_DriverOSVersion *version)
863 const char *short_architecture;
864 int i;
865 WERROR err;
866 char *_p;
868 if (!*driver_path || !*data_file) {
869 return WERR_INVALID_PARAM;
872 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
873 return WERR_INVALID_PARAM;
876 /* clean up the driver name.
877 * we can get .\driver.dll
878 * or worse c:\windows\system\driver.dll !
880 /* using an intermediate string to not have overlaping memcpy()'s */
882 strip_driver_path(mem_ctx, *driver_path);
883 strip_driver_path(mem_ctx, *data_file);
884 if (*config_file) {
885 strip_driver_path(mem_ctx, *config_file);
887 if (help_file) {
888 strip_driver_path(mem_ctx, *help_file);
891 if (dependent_files && dependent_files->string) {
892 for (i=0; dependent_files->string[i]; i++) {
893 strip_driver_path(mem_ctx, dependent_files->string[i]);
897 short_architecture = get_short_archi(architecture);
898 if (!short_architecture) {
899 return WERR_UNKNOWN_PRINTER_DRIVER;
902 /* jfm:7/16/2000 the client always sends the cversion=0.
903 * The server should check which version the driver is by reading
904 * the PE header of driver->driverpath.
906 * For Windows 95/98 the version is 0 (so the value sent is correct)
907 * For Windows NT (the architecture doesn't matter)
908 * NT 3.1: cversion=0
909 * NT 3.5/3.51: cversion=1
910 * NT 4: cversion=2
911 * NT2K: cversion=3
914 *version = get_correct_cversion(session_info, short_architecture,
915 *driver_path, &err);
916 if (*version == -1) {
917 return err;
920 return WERR_OK;
923 /****************************************************************************
924 ****************************************************************************/
926 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
927 struct auth_session_info *session_info,
928 struct spoolss_AddDriverInfoCtr *r)
930 switch (r->level) {
931 case 3:
932 return clean_up_driver_struct_level(mem_ctx, session_info,
933 r->info.info3->architecture,
934 &r->info.info3->driver_path,
935 &r->info.info3->data_file,
936 &r->info.info3->config_file,
937 &r->info.info3->help_file,
938 r->info.info3->dependent_files,
939 &r->info.info3->version);
940 case 6:
941 return clean_up_driver_struct_level(mem_ctx, session_info,
942 r->info.info6->architecture,
943 &r->info.info6->driver_path,
944 &r->info.info6->data_file,
945 &r->info.info6->config_file,
946 &r->info.info6->help_file,
947 r->info.info6->dependent_files,
948 &r->info.info6->version);
949 default:
950 return WERR_NOT_SUPPORTED;
954 /****************************************************************************
955 This function sucks and should be replaced. JRA.
956 ****************************************************************************/
958 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
959 const struct spoolss_AddDriverInfo6 *src)
961 dst->version = src->version;
963 dst->driver_name = src->driver_name;
964 dst->architecture = src->architecture;
965 dst->driver_path = src->driver_path;
966 dst->data_file = src->data_file;
967 dst->config_file = src->config_file;
968 dst->help_file = src->help_file;
969 dst->monitor_name = src->monitor_name;
970 dst->default_datatype = src->default_datatype;
971 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
972 dst->dependent_files = src->dependent_files;
975 /****************************************************************************
976 ****************************************************************************/
978 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
979 connection_struct *conn,
980 const char *driver_file,
981 const char *short_architecture,
982 uint32_t driver_version,
983 uint32_t version)
985 struct smb_filename *smb_fname_old = NULL;
986 struct smb_filename *smb_fname_new = NULL;
987 char *old_name = NULL;
988 char *new_name = NULL;
989 NTSTATUS status;
990 WERROR ret;
992 old_name = talloc_asprintf(mem_ctx, "%s/%s",
993 short_architecture, driver_file);
994 W_ERROR_HAVE_NO_MEMORY(old_name);
996 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
997 short_architecture, driver_version, driver_file);
998 if (new_name == NULL) {
999 TALLOC_FREE(old_name);
1000 return WERR_NOMEM;
1003 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1005 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 ret = WERR_NOMEM;
1008 goto out;
1011 /* Setup a synthetic smb_filename struct */
1012 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1013 if (!smb_fname_new) {
1014 ret = WERR_NOMEM;
1015 goto out;
1018 smb_fname_new->base_name = new_name;
1020 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1021 "'%s'\n", smb_fname_old->base_name,
1022 smb_fname_new->base_name));
1024 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1025 OPENX_FILE_EXISTS_TRUNCATE |
1026 OPENX_FILE_CREATE_IF_NOT_EXIST,
1027 0, false);
1029 if (!NT_STATUS_IS_OK(status)) {
1030 DEBUG(0,("move_driver_file_to_download_area: Unable "
1031 "to rename [%s] to [%s]: %s\n",
1032 smb_fname_old->base_name, new_name,
1033 nt_errstr(status)));
1034 ret = WERR_ACCESS_DENIED;
1035 goto out;
1039 ret = WERR_OK;
1040 out:
1041 TALLOC_FREE(smb_fname_old);
1042 TALLOC_FREE(smb_fname_new);
1043 return ret;
1046 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1047 struct spoolss_AddDriverInfoCtr *r)
1049 struct spoolss_AddDriverInfo3 *driver;
1050 struct spoolss_AddDriverInfo3 converted_driver;
1051 const char *short_architecture;
1052 struct smb_filename *smb_dname = NULL;
1053 char *new_dir = NULL;
1054 connection_struct *conn = NULL;
1055 NTSTATUS nt_status;
1056 int i;
1057 TALLOC_CTX *ctx = talloc_tos();
1058 int ver = 0;
1059 char *oldcwd;
1060 char *printdollar = NULL;
1061 int printdollar_snum;
1062 WERROR err = WERR_OK;
1064 switch (r->level) {
1065 case 3:
1066 driver = r->info.info3;
1067 break;
1068 case 6:
1069 convert_level_6_to_level3(&converted_driver, r->info.info6);
1070 driver = &converted_driver;
1071 break;
1072 default:
1073 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1074 return WERR_UNKNOWN_LEVEL;
1077 short_architecture = get_short_archi(driver->architecture);
1078 if (!short_architecture) {
1079 return WERR_UNKNOWN_PRINTER_DRIVER;
1082 printdollar_snum = find_service(ctx, "print$", &printdollar);
1083 if (!printdollar) {
1084 return WERR_NOMEM;
1086 if (printdollar_snum == -1) {
1087 return WERR_NO_SUCH_SHARE;
1090 nt_status = create_conn_struct_cwd(talloc_tos(),
1091 server_event_context(),
1092 server_messaging_context(),
1093 &conn,
1094 printdollar_snum,
1095 lp_path(talloc_tos(), printdollar_snum),
1096 session_info, &oldcwd);
1097 if (!NT_STATUS_IS_OK(nt_status)) {
1098 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1099 "returned %s\n", nt_errstr(nt_status)));
1100 err = ntstatus_to_werror(nt_status);
1101 return err;
1104 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1105 if (!NT_STATUS_IS_OK(nt_status)) {
1106 DEBUG(0, ("failed set force user / group\n"));
1107 err = ntstatus_to_werror(nt_status);
1108 goto err_free_conn;
1111 if (!become_user_by_session(conn, session_info)) {
1112 DEBUG(0, ("failed to become user\n"));
1113 err = WERR_ACCESS_DENIED;
1114 goto err_free_conn;
1117 new_dir = talloc_asprintf(ctx,
1118 "%s/%d",
1119 short_architecture,
1120 driver->version);
1121 if (!new_dir) {
1122 err = WERR_NOMEM;
1123 goto err_exit;
1125 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1126 if (!NT_STATUS_IS_OK(nt_status)) {
1127 err = WERR_NOMEM;
1128 goto err_exit;
1131 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1133 nt_status = create_directory(conn, NULL, smb_dname);
1134 if (!NT_STATUS_IS_OK(nt_status)
1135 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1136 DEBUG(0, ("failed to create driver destination directory: %s\n",
1137 nt_errstr(nt_status)));
1138 err = ntstatus_to_werror(nt_status);
1139 goto err_exit;
1142 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1143 * listed for this driver which has already been moved, skip it (note:
1144 * drivers may list the same file name several times. Then check if the
1145 * file already exists in archi\version\, if so, check that the version
1146 * info (or time stamps if version info is unavailable) is newer (or the
1147 * date is later). If it is, move it to archi\version\filexxx.yyy.
1148 * Otherwise, delete the file.
1150 * If a file is not moved to archi\version\ because of an error, all the
1151 * rest of the 'unmoved' driver files are removed from archi\. If one or
1152 * more of the driver's files was already moved to archi\version\, it
1153 * potentially leaves the driver in a partially updated state. Version
1154 * trauma will most likely occur if an client attempts to use any printer
1155 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1156 * done is appropriate... later JRR
1159 DEBUG(5,("Moving files now !\n"));
1161 if (driver->driver_path && strlen(driver->driver_path)) {
1163 err = move_driver_file_to_download_area(ctx,
1164 conn,
1165 driver->driver_path,
1166 short_architecture,
1167 driver->version,
1168 ver);
1169 if (!W_ERROR_IS_OK(err)) {
1170 goto err_exit;
1174 if (driver->data_file && strlen(driver->data_file)) {
1175 if (!strequal(driver->data_file, driver->driver_path)) {
1177 err = move_driver_file_to_download_area(ctx,
1178 conn,
1179 driver->data_file,
1180 short_architecture,
1181 driver->version,
1182 ver);
1183 if (!W_ERROR_IS_OK(err)) {
1184 goto err_exit;
1189 if (driver->config_file && strlen(driver->config_file)) {
1190 if (!strequal(driver->config_file, driver->driver_path) &&
1191 !strequal(driver->config_file, driver->data_file)) {
1193 err = move_driver_file_to_download_area(ctx,
1194 conn,
1195 driver->config_file,
1196 short_architecture,
1197 driver->version,
1198 ver);
1199 if (!W_ERROR_IS_OK(err)) {
1200 goto err_exit;
1205 if (driver->help_file && strlen(driver->help_file)) {
1206 if (!strequal(driver->help_file, driver->driver_path) &&
1207 !strequal(driver->help_file, driver->data_file) &&
1208 !strequal(driver->help_file, driver->config_file)) {
1210 err = move_driver_file_to_download_area(ctx,
1211 conn,
1212 driver->help_file,
1213 short_architecture,
1214 driver->version,
1215 ver);
1216 if (!W_ERROR_IS_OK(err)) {
1217 goto err_exit;
1222 if (driver->dependent_files && driver->dependent_files->string) {
1223 for (i=0; driver->dependent_files->string[i]; i++) {
1224 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1225 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1226 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1227 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1228 int j;
1229 for (j=0; j < i; j++) {
1230 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1231 goto NextDriver;
1235 err = move_driver_file_to_download_area(ctx,
1236 conn,
1237 driver->dependent_files->string[i],
1238 short_architecture,
1239 driver->version,
1240 ver);
1241 if (!W_ERROR_IS_OK(err)) {
1242 goto err_exit;
1245 NextDriver: ;
1249 err = WERR_OK;
1250 err_exit:
1251 unbecome_user();
1252 err_free_conn:
1253 TALLOC_FREE(smb_dname);
1255 if (conn != NULL) {
1256 vfs_ChDir(conn, oldcwd);
1257 SMB_VFS_DISCONNECT(conn);
1258 conn_free(conn);
1261 return err;
1264 /****************************************************************************
1265 Determine whether or not a particular driver is currently assigned
1266 to a printer
1267 ****************************************************************************/
1269 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1270 struct dcerpc_binding_handle *b,
1271 const struct spoolss_DriverInfo8 *r)
1273 int snum;
1274 int n_services = lp_numservices();
1275 bool in_use = False;
1276 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1277 WERROR result;
1279 if (!r) {
1280 return false;
1283 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1285 /* loop through the printers.tdb and check for the drivername */
1287 for (snum=0; snum<n_services && !in_use; snum++) {
1288 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1289 continue;
1292 result = winreg_get_printer(mem_ctx, b,
1293 lp_servicename(talloc_tos(), snum),
1294 &pinfo2);
1295 if (!W_ERROR_IS_OK(result)) {
1296 continue; /* skip */
1299 if (strequal(r->driver_name, pinfo2->drivername)) {
1300 in_use = True;
1303 TALLOC_FREE(pinfo2);
1306 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1308 if ( in_use ) {
1309 struct spoolss_DriverInfo8 *driver = NULL;
1310 WERROR werr;
1312 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1314 /* we can still remove the driver if there is one of
1315 "Windows NT x86" version 2 or 3 left */
1317 if (!strequal("Windows NT x86", r->architecture)) {
1318 werr = winreg_get_driver(mem_ctx, b,
1319 "Windows NT x86",
1320 r->driver_name,
1321 DRIVER_ANY_VERSION,
1322 &driver);
1323 } else if (r->version == 2) {
1324 werr = winreg_get_driver(mem_ctx, b,
1325 "Windows NT x86",
1326 r->driver_name,
1327 3, &driver);
1328 } else if (r->version == 3) {
1329 werr = winreg_get_driver(mem_ctx, b,
1330 "Windows NT x86",
1331 r->driver_name,
1332 2, &driver);
1333 } else {
1334 DEBUG(0, ("printer_driver_in_use: ERROR!"
1335 " unknown driver version (%d)\n",
1336 r->version));
1337 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1340 /* now check the error code */
1342 if ( W_ERROR_IS_OK(werr) ) {
1343 /* it's ok to remove the driver, we have other architctures left */
1344 in_use = False;
1345 talloc_free(driver);
1349 /* report that the driver is not in use by default */
1351 return in_use;
1355 /**********************************************************************
1356 Check to see if a ogiven file is in use by *info
1357 *********************************************************************/
1359 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1361 int i = 0;
1363 if ( !info )
1364 return False;
1366 /* mz: skip files that are in the list but already deleted */
1367 if (!file || !file[0]) {
1368 return false;
1371 if (strequal(file, info->driver_path))
1372 return True;
1374 if (strequal(file, info->data_file))
1375 return True;
1377 if (strequal(file, info->config_file))
1378 return True;
1380 if (strequal(file, info->help_file))
1381 return True;
1383 /* see of there are any dependent files to examine */
1385 if (!info->dependent_files)
1386 return False;
1388 while (info->dependent_files[i] && *info->dependent_files[i]) {
1389 if (strequal(file, info->dependent_files[i]))
1390 return True;
1391 i++;
1394 return False;
1398 /**********************************************************************
1399 Utility function to remove the dependent file pointed to by the
1400 input parameter from the list
1401 *********************************************************************/
1403 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1406 /* bump everything down a slot */
1408 while (files && files[idx+1]) {
1409 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1410 idx++;
1413 files[idx] = NULL;
1415 return;
1418 /**********************************************************************
1419 Check if any of the files used by src are also used by drv
1420 *********************************************************************/
1422 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1423 struct spoolss_DriverInfo8 *src,
1424 const struct spoolss_DriverInfo8 *drv)
1426 bool in_use = False;
1427 int i = 0;
1429 if ( !src || !drv )
1430 return False;
1432 /* check each file. Remove it from the src structure if it overlaps */
1434 if (drv_file_in_use(src->driver_path, drv)) {
1435 in_use = True;
1436 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1437 src->driver_path = talloc_strdup(mem_ctx, "");
1438 if (!src->driver_path) { return false; }
1441 if (drv_file_in_use(src->data_file, drv)) {
1442 in_use = True;
1443 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1444 src->data_file = talloc_strdup(mem_ctx, "");
1445 if (!src->data_file) { return false; }
1448 if (drv_file_in_use(src->config_file, drv)) {
1449 in_use = True;
1450 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1451 src->config_file = talloc_strdup(mem_ctx, "");
1452 if (!src->config_file) { return false; }
1455 if (drv_file_in_use(src->help_file, drv)) {
1456 in_use = True;
1457 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1458 src->help_file = talloc_strdup(mem_ctx, "");
1459 if (!src->help_file) { return false; }
1462 /* are there any dependentfiles to examine? */
1464 if (!src->dependent_files)
1465 return in_use;
1467 while (src->dependent_files[i] && *src->dependent_files[i]) {
1468 if (drv_file_in_use(src->dependent_files[i], drv)) {
1469 in_use = True;
1470 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1471 trim_dependent_file(mem_ctx, src->dependent_files, i);
1472 } else
1473 i++;
1476 return in_use;
1479 /****************************************************************************
1480 Determine whether or not a particular driver files are currently being
1481 used by any other driver.
1483 Return value is True if any files were in use by other drivers
1484 and False otherwise.
1486 Upon return, *info has been modified to only contain the driver files
1487 which are not in use
1489 Fix from mz:
1491 This needs to check all drivers to ensure that all files in use
1492 have been removed from *info, not just the ones in the first
1493 match.
1494 ****************************************************************************/
1496 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1497 struct dcerpc_binding_handle *b,
1498 struct spoolss_DriverInfo8 *info)
1500 int i;
1501 uint32 version;
1502 struct spoolss_DriverInfo8 *driver;
1503 bool in_use = false;
1504 uint32_t num_drivers;
1505 const char **drivers;
1506 WERROR result;
1508 if ( !info )
1509 return False;
1511 version = info->version;
1513 /* loop over all driver versions */
1515 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1517 /* get the list of drivers */
1519 result = winreg_get_driver_list(mem_ctx, b,
1520 info->architecture, version,
1521 &num_drivers, &drivers);
1522 if (!W_ERROR_IS_OK(result)) {
1523 return true;
1526 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1527 num_drivers, info->architecture, version));
1529 /* check each driver for overlap in files */
1531 for (i = 0; i < num_drivers; i++) {
1532 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1534 driver = NULL;
1536 result = winreg_get_driver(mem_ctx, b,
1537 info->architecture, drivers[i],
1538 version, &driver);
1539 if (!W_ERROR_IS_OK(result)) {
1540 talloc_free(drivers);
1541 return True;
1544 /* check if d2 uses any files from d1 */
1545 /* only if this is a different driver than the one being deleted */
1547 if (!strequal(info->driver_name, driver->driver_name)) {
1548 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1549 /* mz: Do not instantly return -
1550 * we need to ensure this file isn't
1551 * also in use by other drivers. */
1552 in_use = true;
1556 talloc_free(driver);
1559 talloc_free(drivers);
1561 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1563 return in_use;
1566 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1567 const char *short_arch,
1568 int vers,
1569 const char *fname)
1571 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1572 struct smb_filename *smb_fname = NULL;
1573 char *print_dlr_path;
1574 NTSTATUS status = NT_STATUS_NO_MEMORY;
1576 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1577 short_arch, vers, fname);
1578 if (print_dlr_path == NULL) {
1579 goto err_out;
1582 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL);
1583 if (smb_fname == NULL) {
1584 goto err_out;
1587 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1588 err_out:
1589 talloc_free(tmp_ctx);
1590 return status;
1593 /****************************************************************************
1594 Actually delete the driver files. Make sure that
1595 printer_driver_files_in_use() return False before calling
1596 this.
1597 ****************************************************************************/
1599 bool delete_driver_files(const struct auth_session_info *session_info,
1600 const struct spoolss_DriverInfo8 *r)
1602 const char *short_arch;
1603 connection_struct *conn;
1604 NTSTATUS nt_status;
1605 char *oldcwd;
1606 char *printdollar = NULL;
1607 int printdollar_snum;
1608 bool ret = false;
1610 if (!r) {
1611 return false;
1614 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1615 r->driver_name, r->version));
1617 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1618 if (!printdollar) {
1619 return false;
1621 if (printdollar_snum == -1) {
1622 return false;
1625 nt_status = create_conn_struct_cwd(talloc_tos(),
1626 server_event_context(),
1627 server_messaging_context(),
1628 &conn,
1629 printdollar_snum,
1630 lp_path(talloc_tos(), printdollar_snum),
1631 session_info, &oldcwd);
1632 if (!NT_STATUS_IS_OK(nt_status)) {
1633 DEBUG(0,("delete_driver_files: create_conn_struct "
1634 "returned %s\n", nt_errstr(nt_status)));
1635 return false;
1638 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1639 if (!NT_STATUS_IS_OK(nt_status)) {
1640 DEBUG(0, ("failed set force user / group\n"));
1641 ret = false;
1642 goto err_free_conn;
1645 if (!become_user_by_session(conn, session_info)) {
1646 DEBUG(0, ("failed to become user\n"));
1647 ret = false;
1648 goto err_free_conn;
1651 if ( !CAN_WRITE(conn) ) {
1652 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1653 ret = false;
1654 goto err_out;
1657 short_arch = get_short_archi(r->architecture);
1658 if (short_arch == NULL) {
1659 DEBUG(0, ("bad architecture %s\n", r->architecture));
1660 ret = false;
1661 goto err_out;
1664 /* now delete the files */
1666 if (r->driver_path && r->driver_path[0]) {
1667 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1668 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1671 if (r->config_file && r->config_file[0]) {
1672 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1673 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1676 if (r->data_file && r->data_file[0]) {
1677 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1678 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1681 if (r->help_file && r->help_file[0]) {
1682 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1683 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1686 if (r->dependent_files) {
1687 int i = 0;
1688 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1689 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1690 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1691 i++;
1695 ret = true;
1696 err_out:
1697 unbecome_user();
1698 err_free_conn:
1699 if (conn != NULL) {
1700 vfs_ChDir(conn, oldcwd);
1701 SMB_VFS_DISCONNECT(conn);
1702 conn_free(conn);
1704 return ret;
1707 /* error code:
1708 0: everything OK
1709 1: level not implemented
1710 2: file doesn't exist
1711 3: can't allocate memory
1712 4: can't free memory
1713 5: non existent struct
1717 A printer and a printer driver are 2 different things.
1718 NT manages them separatelly, Samba does the same.
1719 Why ? Simply because it's easier and it makes sense !
1721 Now explanation: You have 3 printers behind your samba server,
1722 2 of them are the same make and model (laser A and B). But laser B
1723 has an 3000 sheet feeder and laser A doesn't such an option.
1724 Your third printer is an old dot-matrix model for the accounting :-).
1726 If the /usr/local/samba/lib directory (default dir), you will have
1727 5 files to describe all of this.
1729 3 files for the printers (1 by printer):
1730 NTprinter_laser A
1731 NTprinter_laser B
1732 NTprinter_accounting
1733 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1734 NTdriver_printer model X
1735 NTdriver_printer model Y
1737 jfm: I should use this comment for the text file to explain
1738 same thing for the forms BTW.
1739 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1743 /* Convert generic access rights to printer object specific access rights.
1744 It turns out that NT4 security descriptors use generic access rights and
1745 NT5 the object specific ones. */
1747 void map_printer_permissions(struct security_descriptor *sd)
1749 int i;
1751 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1752 se_map_generic(&sd->dacl->aces[i].access_mask,
1753 &printer_generic_mapping);
1757 void map_job_permissions(struct security_descriptor *sd)
1759 int i;
1761 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1762 se_map_generic(&sd->dacl->aces[i].access_mask,
1763 &job_generic_mapping);
1768 /****************************************************************************
1769 Check a user has permissions to perform the given operation. We use the
1770 permission constants defined in include/rpc_spoolss.h to check the various
1771 actions we perform when checking printer access.
1773 PRINTER_ACCESS_ADMINISTER:
1774 print_queue_pause, print_queue_resume, update_printer_sec,
1775 update_printer, spoolss_addprinterex_level_2,
1776 _spoolss_setprinterdata
1778 PRINTER_ACCESS_USE:
1779 print_job_start
1781 JOB_ACCESS_ADMINISTER:
1782 print_job_delete, print_job_pause, print_job_resume,
1783 print_queue_purge
1785 Try access control in the following order (for performance reasons):
1786 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1787 2) check security descriptor (bit comparisons in memory)
1788 3) "printer admins" (may result in numerous calls to winbind)
1790 ****************************************************************************/
1791 WERROR print_access_check(const struct auth_session_info *session_info,
1792 struct messaging_context *msg_ctx, int snum,
1793 int access_type)
1795 struct spoolss_security_descriptor *secdesc = NULL;
1796 uint32 access_granted;
1797 size_t sd_size;
1798 NTSTATUS status;
1799 WERROR result;
1800 const char *pname;
1801 TALLOC_CTX *mem_ctx = NULL;
1803 /* If user is NULL then use the current_user structure */
1805 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1807 if ((session_info->unix_token->uid == sec_initial_uid())
1808 || security_token_has_privilege(session_info->security_token,
1809 SEC_PRIV_PRINT_OPERATOR)) {
1810 return WERR_OK;
1813 /* Get printer name */
1815 pname = lp_printername(talloc_tos(), snum);
1817 if (!pname || !*pname) {
1818 return WERR_ACCESS_DENIED;
1821 /* Get printer security descriptor */
1823 if(!(mem_ctx = talloc_init("print_access_check"))) {
1824 return WERR_NOMEM;
1827 result = winreg_get_printer_secdesc_internal(mem_ctx,
1828 get_session_info_system(),
1829 msg_ctx,
1830 pname,
1831 &secdesc);
1832 if (!W_ERROR_IS_OK(result)) {
1833 talloc_destroy(mem_ctx);
1834 return WERR_NOMEM;
1837 if (access_type == JOB_ACCESS_ADMINISTER) {
1838 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1840 /* Create a child security descriptor to check permissions
1841 against. This is because print jobs are child objects
1842 objects of a printer. */
1843 status = se_create_child_secdesc(mem_ctx,
1844 &secdesc,
1845 &sd_size,
1846 parent_secdesc,
1847 parent_secdesc->owner_sid,
1848 parent_secdesc->group_sid,
1849 false);
1850 if (!NT_STATUS_IS_OK(status)) {
1851 talloc_destroy(mem_ctx);
1852 return ntstatus_to_werror(status);
1855 map_job_permissions(secdesc);
1856 } else {
1857 map_printer_permissions(secdesc);
1860 /* Check access */
1861 status = se_access_check(secdesc, session_info->security_token, access_type,
1862 &access_granted);
1864 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1866 talloc_destroy(mem_ctx);
1868 return ntstatus_to_werror(status);
1871 /****************************************************************************
1872 Check the time parameters allow a print operation.
1873 *****************************************************************************/
1875 bool print_time_access_check(const struct auth_session_info *session_info,
1876 struct messaging_context *msg_ctx,
1877 const char *servicename)
1879 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1880 WERROR result;
1881 bool ok = False;
1882 time_t now = time(NULL);
1883 struct tm *t;
1884 uint32 mins;
1886 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1887 servicename, &pinfo2);
1888 if (!W_ERROR_IS_OK(result)) {
1889 return False;
1892 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1893 ok = True;
1896 t = gmtime(&now);
1897 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1899 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1900 ok = True;
1903 TALLOC_FREE(pinfo2);
1905 if (!ok) {
1906 errno = EACCES;
1909 return ok;
1912 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1913 const struct auth_session_info *session_info,
1914 struct messaging_context *msg_ctx,
1915 const char *printer)
1917 WERROR result;
1919 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1920 printer, "");
1921 if (!W_ERROR_IS_OK(result)) {
1922 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1923 "%s\n", printer, win_errstr(result)));
1927 void nt_printer_add(TALLOC_CTX *mem_ctx,
1928 const struct auth_session_info *session_info,
1929 struct messaging_context *msg_ctx,
1930 const char *printer)
1932 WERROR result;
1934 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1935 printer);
1936 if (!W_ERROR_IS_OK(result)) {
1937 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1938 printer, win_errstr(result)));