libcli: Remove an unused variable
[Samba.git] / source3 / printing / nt_printing.c
blob6a5f2d744a19a8107f82dfb3233463555e205a6f
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, sec_initial_uid(), 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,
119 sec_initial_uid(),
120 0755);
121 if (!ok) {
122 DEBUG(1, ("Failed to create printer driver "
123 "architecture directory %s\n",
124 arch_path));
125 talloc_free(mem_ctx);
126 return false;
130 talloc_free(mem_ctx);
131 return true;
134 /****************************************************************************
135 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
136 background lpq updater.
137 ****************************************************************************/
139 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
140 void *private_data,
141 uint32_t msg_type,
142 struct server_id server_id,
143 DATA_BLOB *data)
145 extern pid_t background_lpq_updater_pid;
147 if (background_lpq_updater_pid == -1) {
148 DEBUG(3,("no background lpq queue updater\n"));
149 return;
152 messaging_send_buf(msg,
153 pid_to_procid(background_lpq_updater_pid),
154 MSG_PRINTER_DRVUPGRADE,
155 data->data,
156 data->length);
159 /****************************************************************************
160 Open the NT printing tdbs. Done once before fork().
161 ****************************************************************************/
163 bool nt_printing_init(struct messaging_context *msg_ctx)
165 WERROR win_rc;
167 if (!print_driver_directories_init()) {
168 return false;
171 if (!nt_printing_tdb_upgrade()) {
172 return false;
176 * register callback to handle updating printers as new
177 * drivers are installed. Forwards to background lpq updater.
179 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
180 forward_drv_upgrade_printer_msg);
182 /* of course, none of the message callbacks matter if you don't
183 tell messages.c that you interested in receiving PRINT_GENERAL
184 msgs. This is done in serverid_register() */
186 if ( lp_security() == SEC_ADS ) {
187 win_rc = check_published_printers(msg_ctx);
188 if (!W_ERROR_IS_OK(win_rc))
189 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
192 return true;
195 /*******************************************************************
196 Function to allow filename parsing "the old way".
197 ********************************************************************/
199 static NTSTATUS driver_unix_convert(connection_struct *conn,
200 const char *old_name,
201 struct smb_filename **smb_fname)
203 NTSTATUS status;
204 TALLOC_CTX *ctx = talloc_tos();
205 char *name = talloc_strdup(ctx, old_name);
207 if (!name) {
208 return NT_STATUS_NO_MEMORY;
210 unix_format(name);
211 name = unix_clean_name(ctx, name);
212 if (!name) {
213 return NT_STATUS_NO_MEMORY;
215 trim_string(name,"/","/");
217 status = unix_convert(ctx, conn, name, smb_fname, 0);
218 if (!NT_STATUS_IS_OK(status)) {
219 return NT_STATUS_NO_MEMORY;
222 return NT_STATUS_OK;
225 /****************************************************************************
226 Function to do the mapping between the long architecture name and
227 the short one.
228 ****************************************************************************/
230 const char *get_short_archi(const char *long_archi)
232 int i=-1;
234 DEBUG(107,("Getting architecture dependent directory\n"));
235 do {
236 i++;
237 } while ( (archi_table[i].long_archi!=NULL ) &&
238 strcasecmp_m(long_archi, archi_table[i].long_archi) );
240 if (archi_table[i].long_archi==NULL) {
241 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
242 return NULL;
245 /* this might be client code - but shouldn't this be an fstrcpy etc? */
247 DEBUGADD(108,("index: [%d]\n", i));
248 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
249 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
251 return archi_table[i].short_archi;
254 /****************************************************************************
255 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
256 There are two case to be covered here: PE (Portable Executable) and NE (New
257 Executable) files. Both files support the same INFO structure, but PE files
258 store the signature in unicode, and NE files store it as !unicode.
259 returns -1 on error, 1 on version info found, and 0 on no version info found.
260 ****************************************************************************/
262 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
264 int i;
265 char *buf = NULL;
266 ssize_t byte_count;
268 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
269 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
270 fname, DOS_HEADER_SIZE));
271 goto error_exit;
274 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
275 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
276 fname, (unsigned long)byte_count));
277 goto no_version_info;
280 /* Is this really a DOS header? */
281 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
282 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
283 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
284 goto no_version_info;
287 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
288 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
289 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
290 fname, errno));
291 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
292 goto no_version_info;
295 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
296 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
297 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
298 fname, (unsigned long)byte_count));
299 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
300 goto no_version_info;
303 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
304 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
305 unsigned int num_sections;
306 unsigned int section_table_bytes;
308 /* Just skip over optional header to get to section table */
309 if (SMB_VFS_LSEEK(fsp,
310 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
311 SEEK_CUR) == (off_t)-1) {
312 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
313 fname, errno));
314 goto error_exit;
317 /* get the section table */
318 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
319 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
320 if (section_table_bytes == 0)
321 goto error_exit;
323 SAFE_FREE(buf);
324 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
325 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
326 fname, section_table_bytes));
327 goto error_exit;
330 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
331 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
332 fname, (unsigned long)byte_count));
333 goto error_exit;
336 /* Iterate the section table looking for the resource section ".rsrc" */
337 for (i = 0; i < num_sections; i++) {
338 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
340 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
341 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
342 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
344 if (section_bytes == 0)
345 goto error_exit;
347 SAFE_FREE(buf);
348 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
349 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
350 fname, section_bytes));
351 goto error_exit;
354 /* Seek to the start of the .rsrc section info */
355 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
356 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
357 fname, errno));
358 goto error_exit;
361 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
362 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
363 fname, (unsigned long)byte_count));
364 goto error_exit;
367 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
368 goto error_exit;
370 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
371 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
372 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
373 /* Align to next long address */
374 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
376 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
377 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
378 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
380 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
381 fname, *major, *minor,
382 (*major>>16)&0xffff, *major&0xffff,
383 (*minor>>16)&0xffff, *minor&0xffff));
384 SAFE_FREE(buf);
385 return 1;
392 /* Version info not found, fall back to origin date/time */
393 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
394 SAFE_FREE(buf);
395 return 0;
397 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
398 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
399 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
400 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
401 /* At this point, we assume the file is in error. It still could be somthing
402 * else besides a NE file, but it unlikely at this point. */
403 goto error_exit;
406 /* Allocate a bit more space to speed up things */
407 SAFE_FREE(buf);
408 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
409 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
410 fname, PE_HEADER_SIZE));
411 goto error_exit;
414 /* This is a HACK! I got tired of trying to sort through the messy
415 * 'NE' file format. If anyone wants to clean this up please have at
416 * it, but this works. 'NE' files will eventually fade away. JRR */
417 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
418 /* Cover case that should not occur in a well formed 'NE' .dll file */
419 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
421 for(i=0; i<byte_count; i++) {
422 /* Fast skip past data that can't possibly match */
423 if (buf[i] != 'V') continue;
425 /* Potential match data crosses buf boundry, move it to beginning
426 * of buf, and fill the buf with as much as it will hold. */
427 if (i>byte_count-VS_VERSION_INFO_SIZE) {
428 int bc;
430 memcpy(buf, &buf[i], byte_count-i);
431 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
432 (byte_count-i))) < 0) {
434 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
435 fname, errno));
436 goto error_exit;
439 byte_count = bc + (byte_count - i);
440 if (byte_count<VS_VERSION_INFO_SIZE) break;
442 i = 0;
445 /* Check that the full signature string and the magic number that
446 * follows exist (not a perfect solution, but the chances that this
447 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
448 * twice, as it is simpler to read the code. */
449 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
450 /* Compute skip alignment to next long address */
451 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
452 sizeof(VS_SIGNATURE)) & 3;
453 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
455 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
456 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
457 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
458 fname, *major, *minor,
459 (*major>>16)&0xffff, *major&0xffff,
460 (*minor>>16)&0xffff, *minor&0xffff));
461 SAFE_FREE(buf);
462 return 1;
467 /* Version info not found, fall back to origin date/time */
468 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
469 SAFE_FREE(buf);
470 return 0;
472 } else
473 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
474 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
475 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
477 no_version_info:
478 SAFE_FREE(buf);
479 return 0;
481 error_exit:
482 SAFE_FREE(buf);
483 return -1;
486 /****************************************************************************
487 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
488 share one or more files. During the MS installation process files are checked
489 to insure that only a newer version of a shared file is installed over an
490 older version. There are several possibilities for this comparison. If there
491 is no previous version, the new one is newer (obviously). If either file is
492 missing the version info structure, compare the creation date (on Unix use
493 the modification date). Otherwise chose the numerically larger version number.
494 ****************************************************************************/
496 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
498 bool use_version = true;
500 uint32 new_major;
501 uint32 new_minor;
502 time_t new_create_time;
504 uint32 old_major;
505 uint32 old_minor;
506 time_t old_create_time;
508 struct smb_filename *smb_fname = NULL;
509 files_struct *fsp = NULL;
510 SMB_STRUCT_STAT st;
512 NTSTATUS status;
513 int ret;
515 SET_STAT_INVALID(st);
516 new_create_time = (time_t)0;
517 old_create_time = (time_t)0;
519 /* Get file version info (if available) for previous file (if it exists) */
520 status = driver_unix_convert(conn, old_file, &smb_fname);
521 if (!NT_STATUS_IS_OK(status)) {
522 goto error_exit;
525 status = SMB_VFS_CREATE_FILE(
526 conn, /* conn */
527 NULL, /* req */
528 0, /* root_dir_fid */
529 smb_fname, /* fname */
530 FILE_GENERIC_READ, /* access_mask */
531 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
532 FILE_OPEN, /* create_disposition*/
533 0, /* create_options */
534 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
535 INTERNAL_OPEN_ONLY, /* oplock_request */
536 0, /* allocation_size */
537 0, /* private_flags */
538 NULL, /* sd */
539 NULL, /* ea_list */
540 &fsp, /* result */
541 NULL); /* pinfo */
543 if (!NT_STATUS_IS_OK(status)) {
544 /* Old file not found, so by definition new file is in fact newer */
545 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
546 "errno = %d\n", smb_fname_str_dbg(smb_fname),
547 errno));
548 ret = 1;
549 goto done;
551 } else {
552 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
553 if (ret == -1) {
554 goto error_exit;
557 if (!ret) {
558 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
559 old_file));
560 use_version = false;
561 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
562 goto error_exit;
564 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
565 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
566 (long)old_create_time));
569 close_file(NULL, fsp, NORMAL_CLOSE);
570 fsp = NULL;
572 /* Get file version info (if available) for new file */
573 status = driver_unix_convert(conn, new_file, &smb_fname);
574 if (!NT_STATUS_IS_OK(status)) {
575 goto error_exit;
578 status = SMB_VFS_CREATE_FILE(
579 conn, /* conn */
580 NULL, /* req */
581 0, /* root_dir_fid */
582 smb_fname, /* fname */
583 FILE_GENERIC_READ, /* access_mask */
584 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
585 FILE_OPEN, /* create_disposition*/
586 0, /* create_options */
587 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
588 INTERNAL_OPEN_ONLY, /* oplock_request */
589 0, /* allocation_size */
590 0, /* private_flags */
591 NULL, /* sd */
592 NULL, /* ea_list */
593 &fsp, /* result */
594 NULL); /* pinfo */
596 if (!NT_STATUS_IS_OK(status)) {
597 /* New file not found, this shouldn't occur if the caller did its job */
598 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
599 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
600 goto error_exit;
602 } else {
603 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
604 if (ret == -1) {
605 goto error_exit;
608 if (!ret) {
609 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
610 new_file));
611 use_version = false;
612 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
613 goto error_exit;
615 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
616 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
617 (long)new_create_time));
620 close_file(NULL, fsp, NORMAL_CLOSE);
621 fsp = NULL;
623 if (use_version && (new_major != old_major || new_minor != old_minor)) {
624 /* Compare versions and choose the larger version number */
625 if (new_major > old_major ||
626 (new_major == old_major && new_minor > old_minor)) {
628 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
629 ret = 1;
630 goto done;
632 else {
633 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
634 ret = 0;
635 goto done;
638 } else {
639 /* Compare modification time/dates and choose the newest time/date */
640 if (new_create_time > old_create_time) {
641 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
642 ret = 1;
643 goto done;
645 else {
646 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
647 ret = 0;
648 goto done;
652 error_exit:
653 if(fsp)
654 close_file(NULL, fsp, NORMAL_CLOSE);
655 ret = -1;
656 done:
657 TALLOC_FREE(smb_fname);
658 return ret;
661 /****************************************************************************
662 Determine the correct cVersion associated with an architecture and driver
663 ****************************************************************************/
664 static uint32 get_correct_cversion(struct auth_session_info *session_info,
665 const char *architecture,
666 const char *driverpath_in,
667 WERROR *perr)
669 int cversion = -1;
670 NTSTATUS nt_status;
671 struct smb_filename *smb_fname = NULL;
672 char *driverpath = NULL;
673 files_struct *fsp = NULL;
674 connection_struct *conn = NULL;
675 char *oldcwd;
676 char *printdollar = NULL;
677 int printdollar_snum;
679 *perr = WERR_INVALID_PARAM;
681 /* If architecture is Windows 95/98/ME, the version is always 0. */
682 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
683 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
684 *perr = WERR_OK;
685 return 0;
688 /* If architecture is Windows x64, the version is always 3. */
689 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
690 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
691 *perr = WERR_OK;
692 return 3;
695 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
696 if (!printdollar) {
697 *perr = WERR_NOMEM;
698 return -1;
700 if (printdollar_snum == -1) {
701 *perr = WERR_NO_SUCH_SHARE;
702 return -1;
705 nt_status = create_conn_struct_cwd(talloc_tos(),
706 server_event_context(),
707 server_messaging_context(),
708 &conn,
709 printdollar_snum,
710 lp_path(talloc_tos(), printdollar_snum),
711 session_info, &oldcwd);
712 if (!NT_STATUS_IS_OK(nt_status)) {
713 DEBUG(0,("get_correct_cversion: create_conn_struct "
714 "returned %s\n", nt_errstr(nt_status)));
715 *perr = ntstatus_to_werror(nt_status);
716 return -1;
719 nt_status = set_conn_force_user_group(conn, printdollar_snum);
720 if (!NT_STATUS_IS_OK(nt_status)) {
721 DEBUG(0, ("failed set force user / group\n"));
722 *perr = ntstatus_to_werror(nt_status);
723 goto error_free_conn;
726 if (!become_user_by_session(conn, session_info)) {
727 DEBUG(0, ("failed to become user\n"));
728 *perr = WERR_ACCESS_DENIED;
729 goto error_free_conn;
732 /* Open the driver file (Portable Executable format) and determine the
733 * deriver the cversion. */
734 driverpath = talloc_asprintf(talloc_tos(),
735 "%s/%s",
736 architecture,
737 driverpath_in);
738 if (!driverpath) {
739 *perr = WERR_NOMEM;
740 goto error_exit;
743 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
744 if (!NT_STATUS_IS_OK(nt_status)) {
745 *perr = ntstatus_to_werror(nt_status);
746 goto error_exit;
749 nt_status = vfs_file_exist(conn, smb_fname);
750 if (!NT_STATUS_IS_OK(nt_status)) {
751 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
752 *perr = WERR_BADFILE;
753 goto error_exit;
756 nt_status = SMB_VFS_CREATE_FILE(
757 conn, /* conn */
758 NULL, /* req */
759 0, /* root_dir_fid */
760 smb_fname, /* fname */
761 FILE_GENERIC_READ, /* access_mask */
762 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
763 FILE_OPEN, /* create_disposition*/
764 0, /* create_options */
765 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
766 INTERNAL_OPEN_ONLY, /* oplock_request */
767 0, /* private_flags */
768 0, /* allocation_size */
769 NULL, /* sd */
770 NULL, /* ea_list */
771 &fsp, /* result */
772 NULL); /* pinfo */
774 if (!NT_STATUS_IS_OK(nt_status)) {
775 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
776 "%d\n", smb_fname_str_dbg(smb_fname), errno));
777 *perr = WERR_ACCESS_DENIED;
778 goto error_exit;
779 } else {
780 uint32 major;
781 uint32 minor;
782 int ret;
784 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
785 if (ret == -1) {
786 *perr = WERR_INVALID_PARAM;
787 goto error_exit;
788 } else if (!ret) {
789 DEBUG(6,("get_correct_cversion: Version info not "
790 "found [%s]\n",
791 smb_fname_str_dbg(smb_fname)));
792 *perr = WERR_INVALID_PARAM;
793 goto error_exit;
797 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
798 * for more details. Version in this case is not just the version of the
799 * file, but the version in the sense of kernal mode (2) vs. user mode
800 * (3) drivers. Other bits of the version fields are the version info.
801 * JRR 010716
803 cversion = major & 0x0000ffff;
804 switch (cversion) {
805 case 2: /* WinNT drivers */
806 case 3: /* Win2K drivers */
807 break;
809 default:
810 DEBUG(6,("get_correct_cversion: cversion "
811 "invalid [%s] cversion = %d\n",
812 smb_fname_str_dbg(smb_fname),
813 cversion));
814 goto error_exit;
817 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
818 " = 0x%x minor = 0x%x\n",
819 smb_fname_str_dbg(smb_fname), major, minor));
822 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
823 smb_fname_str_dbg(smb_fname), cversion));
824 *perr = WERR_OK;
826 error_exit:
827 unbecome_user();
828 error_free_conn:
829 TALLOC_FREE(smb_fname);
830 if (fsp != NULL) {
831 close_file(NULL, fsp, NORMAL_CLOSE);
833 if (conn != NULL) {
834 vfs_ChDir(conn, oldcwd);
835 SMB_VFS_DISCONNECT(conn);
836 conn_free(conn);
838 if (!W_ERROR_IS_OK(*perr)) {
839 cversion = -1;
842 return cversion;
845 /****************************************************************************
846 ****************************************************************************/
848 #define strip_driver_path(_mem_ctx, _element) do { \
849 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
850 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
851 W_ERROR_HAVE_NO_MEMORY((_element)); \
853 } while (0);
855 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
856 struct auth_session_info *session_info,
857 const char *architecture,
858 const char **driver_path,
859 const char **data_file,
860 const char **config_file,
861 const char **help_file,
862 struct spoolss_StringArray *dependent_files,
863 enum spoolss_DriverOSVersion *version)
865 const char *short_architecture;
866 int i;
867 WERROR err;
868 char *_p;
870 if (!*driver_path || !*data_file) {
871 return WERR_INVALID_PARAM;
874 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
875 return WERR_INVALID_PARAM;
878 /* clean up the driver name.
879 * we can get .\driver.dll
880 * or worse c:\windows\system\driver.dll !
882 /* using an intermediate string to not have overlaping memcpy()'s */
884 strip_driver_path(mem_ctx, *driver_path);
885 strip_driver_path(mem_ctx, *data_file);
886 if (*config_file) {
887 strip_driver_path(mem_ctx, *config_file);
889 if (help_file) {
890 strip_driver_path(mem_ctx, *help_file);
893 if (dependent_files && dependent_files->string) {
894 for (i=0; dependent_files->string[i]; i++) {
895 strip_driver_path(mem_ctx, dependent_files->string[i]);
899 short_architecture = get_short_archi(architecture);
900 if (!short_architecture) {
901 return WERR_UNKNOWN_PRINTER_DRIVER;
904 /* jfm:7/16/2000 the client always sends the cversion=0.
905 * The server should check which version the driver is by reading
906 * the PE header of driver->driverpath.
908 * For Windows 95/98 the version is 0 (so the value sent is correct)
909 * For Windows NT (the architecture doesn't matter)
910 * NT 3.1: cversion=0
911 * NT 3.5/3.51: cversion=1
912 * NT 4: cversion=2
913 * NT2K: cversion=3
916 *version = get_correct_cversion(session_info, short_architecture,
917 *driver_path, &err);
918 if (*version == -1) {
919 return err;
922 return WERR_OK;
925 /****************************************************************************
926 ****************************************************************************/
928 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
929 struct auth_session_info *session_info,
930 struct spoolss_AddDriverInfoCtr *r)
932 switch (r->level) {
933 case 3:
934 return clean_up_driver_struct_level(mem_ctx, session_info,
935 r->info.info3->architecture,
936 &r->info.info3->driver_path,
937 &r->info.info3->data_file,
938 &r->info.info3->config_file,
939 &r->info.info3->help_file,
940 r->info.info3->dependent_files,
941 &r->info.info3->version);
942 case 6:
943 return clean_up_driver_struct_level(mem_ctx, session_info,
944 r->info.info6->architecture,
945 &r->info.info6->driver_path,
946 &r->info.info6->data_file,
947 &r->info.info6->config_file,
948 &r->info.info6->help_file,
949 r->info.info6->dependent_files,
950 &r->info.info6->version);
951 default:
952 return WERR_NOT_SUPPORTED;
956 /****************************************************************************
957 This function sucks and should be replaced. JRA.
958 ****************************************************************************/
960 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
961 const struct spoolss_AddDriverInfo6 *src)
963 dst->version = src->version;
965 dst->driver_name = src->driver_name;
966 dst->architecture = src->architecture;
967 dst->driver_path = src->driver_path;
968 dst->data_file = src->data_file;
969 dst->config_file = src->config_file;
970 dst->help_file = src->help_file;
971 dst->monitor_name = src->monitor_name;
972 dst->default_datatype = src->default_datatype;
973 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
974 dst->dependent_files = src->dependent_files;
977 /****************************************************************************
978 ****************************************************************************/
980 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
981 connection_struct *conn,
982 const char *driver_file,
983 const char *short_architecture,
984 uint32_t driver_version,
985 uint32_t version)
987 struct smb_filename *smb_fname_old = NULL;
988 struct smb_filename *smb_fname_new = NULL;
989 char *old_name = NULL;
990 char *new_name = NULL;
991 NTSTATUS status;
992 WERROR ret;
994 old_name = talloc_asprintf(mem_ctx, "%s/%s",
995 short_architecture, driver_file);
996 W_ERROR_HAVE_NO_MEMORY(old_name);
998 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
999 short_architecture, driver_version, driver_file);
1000 if (new_name == NULL) {
1001 TALLOC_FREE(old_name);
1002 return WERR_NOMEM;
1005 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1007 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1008 if (!NT_STATUS_IS_OK(status)) {
1009 ret = WERR_NOMEM;
1010 goto out;
1013 /* Setup a synthetic smb_filename struct */
1014 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1015 if (!smb_fname_new) {
1016 ret = WERR_NOMEM;
1017 goto out;
1020 smb_fname_new->base_name = new_name;
1022 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1023 "'%s'\n", smb_fname_old->base_name,
1024 smb_fname_new->base_name));
1026 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1027 OPENX_FILE_EXISTS_TRUNCATE |
1028 OPENX_FILE_CREATE_IF_NOT_EXIST,
1029 0, false);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 DEBUG(0,("move_driver_file_to_download_area: Unable "
1033 "to rename [%s] to [%s]: %s\n",
1034 smb_fname_old->base_name, new_name,
1035 nt_errstr(status)));
1036 ret = WERR_ACCESS_DENIED;
1037 goto out;
1041 ret = WERR_OK;
1042 out:
1043 TALLOC_FREE(smb_fname_old);
1044 TALLOC_FREE(smb_fname_new);
1045 return ret;
1048 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1049 struct spoolss_AddDriverInfoCtr *r)
1051 struct spoolss_AddDriverInfo3 *driver;
1052 struct spoolss_AddDriverInfo3 converted_driver;
1053 const char *short_architecture;
1054 struct smb_filename *smb_dname = NULL;
1055 char *new_dir = NULL;
1056 connection_struct *conn = NULL;
1057 NTSTATUS nt_status;
1058 int i;
1059 TALLOC_CTX *ctx = talloc_tos();
1060 int ver = 0;
1061 char *oldcwd;
1062 char *printdollar = NULL;
1063 int printdollar_snum;
1064 WERROR err = WERR_OK;
1066 switch (r->level) {
1067 case 3:
1068 driver = r->info.info3;
1069 break;
1070 case 6:
1071 convert_level_6_to_level3(&converted_driver, r->info.info6);
1072 driver = &converted_driver;
1073 break;
1074 default:
1075 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1076 return WERR_UNKNOWN_LEVEL;
1079 short_architecture = get_short_archi(driver->architecture);
1080 if (!short_architecture) {
1081 return WERR_UNKNOWN_PRINTER_DRIVER;
1084 printdollar_snum = find_service(ctx, "print$", &printdollar);
1085 if (!printdollar) {
1086 return WERR_NOMEM;
1088 if (printdollar_snum == -1) {
1089 return WERR_NO_SUCH_SHARE;
1092 nt_status = create_conn_struct_cwd(talloc_tos(),
1093 server_event_context(),
1094 server_messaging_context(),
1095 &conn,
1096 printdollar_snum,
1097 lp_path(talloc_tos(), printdollar_snum),
1098 session_info, &oldcwd);
1099 if (!NT_STATUS_IS_OK(nt_status)) {
1100 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1101 "returned %s\n", nt_errstr(nt_status)));
1102 err = ntstatus_to_werror(nt_status);
1103 return err;
1106 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1107 if (!NT_STATUS_IS_OK(nt_status)) {
1108 DEBUG(0, ("failed set force user / group\n"));
1109 err = ntstatus_to_werror(nt_status);
1110 goto err_free_conn;
1113 if (!become_user_by_session(conn, session_info)) {
1114 DEBUG(0, ("failed to become user\n"));
1115 err = WERR_ACCESS_DENIED;
1116 goto err_free_conn;
1119 new_dir = talloc_asprintf(ctx,
1120 "%s/%d",
1121 short_architecture,
1122 driver->version);
1123 if (!new_dir) {
1124 err = WERR_NOMEM;
1125 goto err_exit;
1127 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1128 if (!NT_STATUS_IS_OK(nt_status)) {
1129 err = WERR_NOMEM;
1130 goto err_exit;
1133 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1135 nt_status = create_directory(conn, NULL, smb_dname);
1136 if (!NT_STATUS_IS_OK(nt_status)
1137 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1138 DEBUG(0, ("failed to create driver destination directory: %s\n",
1139 nt_errstr(nt_status)));
1140 err = ntstatus_to_werror(nt_status);
1141 goto err_exit;
1144 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1145 * listed for this driver which has already been moved, skip it (note:
1146 * drivers may list the same file name several times. Then check if the
1147 * file already exists in archi\version\, if so, check that the version
1148 * info (or time stamps if version info is unavailable) is newer (or the
1149 * date is later). If it is, move it to archi\version\filexxx.yyy.
1150 * Otherwise, delete the file.
1152 * If a file is not moved to archi\version\ because of an error, all the
1153 * rest of the 'unmoved' driver files are removed from archi\. If one or
1154 * more of the driver's files was already moved to archi\version\, it
1155 * potentially leaves the driver in a partially updated state. Version
1156 * trauma will most likely occur if an client attempts to use any printer
1157 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1158 * done is appropriate... later JRR
1161 DEBUG(5,("Moving files now !\n"));
1163 if (driver->driver_path && strlen(driver->driver_path)) {
1165 err = move_driver_file_to_download_area(ctx,
1166 conn,
1167 driver->driver_path,
1168 short_architecture,
1169 driver->version,
1170 ver);
1171 if (!W_ERROR_IS_OK(err)) {
1172 goto err_exit;
1176 if (driver->data_file && strlen(driver->data_file)) {
1177 if (!strequal(driver->data_file, driver->driver_path)) {
1179 err = move_driver_file_to_download_area(ctx,
1180 conn,
1181 driver->data_file,
1182 short_architecture,
1183 driver->version,
1184 ver);
1185 if (!W_ERROR_IS_OK(err)) {
1186 goto err_exit;
1191 if (driver->config_file && strlen(driver->config_file)) {
1192 if (!strequal(driver->config_file, driver->driver_path) &&
1193 !strequal(driver->config_file, driver->data_file)) {
1195 err = move_driver_file_to_download_area(ctx,
1196 conn,
1197 driver->config_file,
1198 short_architecture,
1199 driver->version,
1200 ver);
1201 if (!W_ERROR_IS_OK(err)) {
1202 goto err_exit;
1207 if (driver->help_file && strlen(driver->help_file)) {
1208 if (!strequal(driver->help_file, driver->driver_path) &&
1209 !strequal(driver->help_file, driver->data_file) &&
1210 !strequal(driver->help_file, driver->config_file)) {
1212 err = move_driver_file_to_download_area(ctx,
1213 conn,
1214 driver->help_file,
1215 short_architecture,
1216 driver->version,
1217 ver);
1218 if (!W_ERROR_IS_OK(err)) {
1219 goto err_exit;
1224 if (driver->dependent_files && driver->dependent_files->string) {
1225 for (i=0; driver->dependent_files->string[i]; i++) {
1226 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1227 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1228 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1229 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1230 int j;
1231 for (j=0; j < i; j++) {
1232 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1233 goto NextDriver;
1237 err = move_driver_file_to_download_area(ctx,
1238 conn,
1239 driver->dependent_files->string[i],
1240 short_architecture,
1241 driver->version,
1242 ver);
1243 if (!W_ERROR_IS_OK(err)) {
1244 goto err_exit;
1247 NextDriver: ;
1251 err = WERR_OK;
1252 err_exit:
1253 unbecome_user();
1254 err_free_conn:
1255 TALLOC_FREE(smb_dname);
1257 if (conn != NULL) {
1258 vfs_ChDir(conn, oldcwd);
1259 SMB_VFS_DISCONNECT(conn);
1260 conn_free(conn);
1263 return err;
1266 /****************************************************************************
1267 Determine whether or not a particular driver is currently assigned
1268 to a printer
1269 ****************************************************************************/
1271 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1272 struct dcerpc_binding_handle *b,
1273 const struct spoolss_DriverInfo8 *r)
1275 int snum;
1276 int n_services = lp_numservices();
1277 bool in_use = False;
1278 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1279 WERROR result;
1281 if (!r) {
1282 return false;
1285 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1287 /* loop through the printers.tdb and check for the drivername */
1289 for (snum=0; snum<n_services && !in_use; snum++) {
1290 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1291 continue;
1294 result = winreg_get_printer(mem_ctx, b,
1295 lp_servicename(talloc_tos(), snum),
1296 &pinfo2);
1297 if (!W_ERROR_IS_OK(result)) {
1298 continue; /* skip */
1301 if (strequal(r->driver_name, pinfo2->drivername)) {
1302 in_use = True;
1305 TALLOC_FREE(pinfo2);
1308 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1310 if ( in_use ) {
1311 struct spoolss_DriverInfo8 *driver = NULL;
1312 WERROR werr;
1314 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1316 /* we can still remove the driver if there is one of
1317 "Windows NT x86" version 2 or 3 left */
1319 if (!strequal("Windows NT x86", r->architecture)) {
1320 werr = winreg_get_driver(mem_ctx, b,
1321 "Windows NT x86",
1322 r->driver_name,
1323 DRIVER_ANY_VERSION,
1324 &driver);
1325 } else if (r->version == 2) {
1326 werr = winreg_get_driver(mem_ctx, b,
1327 "Windows NT x86",
1328 r->driver_name,
1329 3, &driver);
1330 } else if (r->version == 3) {
1331 werr = winreg_get_driver(mem_ctx, b,
1332 "Windows NT x86",
1333 r->driver_name,
1334 2, &driver);
1335 } else {
1336 DEBUG(0, ("printer_driver_in_use: ERROR!"
1337 " unknown driver version (%d)\n",
1338 r->version));
1339 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1342 /* now check the error code */
1344 if ( W_ERROR_IS_OK(werr) ) {
1345 /* it's ok to remove the driver, we have other architctures left */
1346 in_use = False;
1347 talloc_free(driver);
1351 /* report that the driver is not in use by default */
1353 return in_use;
1357 /**********************************************************************
1358 Check to see if a ogiven file is in use by *info
1359 *********************************************************************/
1361 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1363 int i = 0;
1365 if ( !info )
1366 return False;
1368 /* mz: skip files that are in the list but already deleted */
1369 if (!file || !file[0]) {
1370 return false;
1373 if (strequal(file, info->driver_path))
1374 return True;
1376 if (strequal(file, info->data_file))
1377 return True;
1379 if (strequal(file, info->config_file))
1380 return True;
1382 if (strequal(file, info->help_file))
1383 return True;
1385 /* see of there are any dependent files to examine */
1387 if (!info->dependent_files)
1388 return False;
1390 while (info->dependent_files[i] && *info->dependent_files[i]) {
1391 if (strequal(file, info->dependent_files[i]))
1392 return True;
1393 i++;
1396 return False;
1400 /**********************************************************************
1401 Utility function to remove the dependent file pointed to by the
1402 input parameter from the list
1403 *********************************************************************/
1405 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1408 /* bump everything down a slot */
1410 while (files && files[idx+1]) {
1411 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1412 idx++;
1415 files[idx] = NULL;
1417 return;
1420 /**********************************************************************
1421 Check if any of the files used by src are also used by drv
1422 *********************************************************************/
1424 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1425 struct spoolss_DriverInfo8 *src,
1426 const struct spoolss_DriverInfo8 *drv)
1428 bool in_use = False;
1429 int i = 0;
1431 if ( !src || !drv )
1432 return False;
1434 /* check each file. Remove it from the src structure if it overlaps */
1436 if (drv_file_in_use(src->driver_path, drv)) {
1437 in_use = True;
1438 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1439 src->driver_path = talloc_strdup(mem_ctx, "");
1440 if (!src->driver_path) { return false; }
1443 if (drv_file_in_use(src->data_file, drv)) {
1444 in_use = True;
1445 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1446 src->data_file = talloc_strdup(mem_ctx, "");
1447 if (!src->data_file) { return false; }
1450 if (drv_file_in_use(src->config_file, drv)) {
1451 in_use = True;
1452 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1453 src->config_file = talloc_strdup(mem_ctx, "");
1454 if (!src->config_file) { return false; }
1457 if (drv_file_in_use(src->help_file, drv)) {
1458 in_use = True;
1459 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1460 src->help_file = talloc_strdup(mem_ctx, "");
1461 if (!src->help_file) { return false; }
1464 /* are there any dependentfiles to examine? */
1466 if (!src->dependent_files)
1467 return in_use;
1469 while (src->dependent_files[i] && *src->dependent_files[i]) {
1470 if (drv_file_in_use(src->dependent_files[i], drv)) {
1471 in_use = True;
1472 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1473 trim_dependent_file(mem_ctx, src->dependent_files, i);
1474 } else
1475 i++;
1478 return in_use;
1481 /****************************************************************************
1482 Determine whether or not a particular driver files are currently being
1483 used by any other driver.
1485 Return value is True if any files were in use by other drivers
1486 and False otherwise.
1488 Upon return, *info has been modified to only contain the driver files
1489 which are not in use
1491 Fix from mz:
1493 This needs to check all drivers to ensure that all files in use
1494 have been removed from *info, not just the ones in the first
1495 match.
1496 ****************************************************************************/
1498 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1499 struct dcerpc_binding_handle *b,
1500 struct spoolss_DriverInfo8 *info)
1502 int i;
1503 uint32 version;
1504 struct spoolss_DriverInfo8 *driver;
1505 bool in_use = false;
1506 uint32_t num_drivers;
1507 const char **drivers;
1508 WERROR result;
1510 if ( !info )
1511 return False;
1513 version = info->version;
1515 /* loop over all driver versions */
1517 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1519 /* get the list of drivers */
1521 result = winreg_get_driver_list(mem_ctx, b,
1522 info->architecture, version,
1523 &num_drivers, &drivers);
1524 if (!W_ERROR_IS_OK(result)) {
1525 return true;
1528 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1529 num_drivers, info->architecture, version));
1531 /* check each driver for overlap in files */
1533 for (i = 0; i < num_drivers; i++) {
1534 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1536 driver = NULL;
1538 result = winreg_get_driver(mem_ctx, b,
1539 info->architecture, drivers[i],
1540 version, &driver);
1541 if (!W_ERROR_IS_OK(result)) {
1542 talloc_free(drivers);
1543 return True;
1546 /* check if d2 uses any files from d1 */
1547 /* only if this is a different driver than the one being deleted */
1549 if (!strequal(info->driver_name, driver->driver_name)) {
1550 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1551 /* mz: Do not instantly return -
1552 * we need to ensure this file isn't
1553 * also in use by other drivers. */
1554 in_use = true;
1558 talloc_free(driver);
1561 talloc_free(drivers);
1563 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1565 return in_use;
1568 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1569 const char *short_arch,
1570 int vers,
1571 const char *fname)
1573 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1574 struct smb_filename *smb_fname = NULL;
1575 char *print_dlr_path;
1576 NTSTATUS status = NT_STATUS_NO_MEMORY;
1578 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1579 short_arch, vers, fname);
1580 if (print_dlr_path == NULL) {
1581 goto err_out;
1584 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL);
1585 if (smb_fname == NULL) {
1586 goto err_out;
1589 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1590 err_out:
1591 talloc_free(tmp_ctx);
1592 return status;
1595 /****************************************************************************
1596 Actually delete the driver files. Make sure that
1597 printer_driver_files_in_use() return False before calling
1598 this.
1599 ****************************************************************************/
1601 bool delete_driver_files(const struct auth_session_info *session_info,
1602 const struct spoolss_DriverInfo8 *r)
1604 const char *short_arch;
1605 connection_struct *conn;
1606 NTSTATUS nt_status;
1607 char *oldcwd;
1608 char *printdollar = NULL;
1609 int printdollar_snum;
1610 bool ret = false;
1612 if (!r) {
1613 return false;
1616 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1617 r->driver_name, r->version));
1619 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1620 if (!printdollar) {
1621 return false;
1623 if (printdollar_snum == -1) {
1624 return false;
1627 nt_status = create_conn_struct_cwd(talloc_tos(),
1628 server_event_context(),
1629 server_messaging_context(),
1630 &conn,
1631 printdollar_snum,
1632 lp_path(talloc_tos(), printdollar_snum),
1633 session_info, &oldcwd);
1634 if (!NT_STATUS_IS_OK(nt_status)) {
1635 DEBUG(0,("delete_driver_files: create_conn_struct "
1636 "returned %s\n", nt_errstr(nt_status)));
1637 return false;
1640 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1641 if (!NT_STATUS_IS_OK(nt_status)) {
1642 DEBUG(0, ("failed set force user / group\n"));
1643 ret = false;
1644 goto err_free_conn;
1647 if (!become_user_by_session(conn, session_info)) {
1648 DEBUG(0, ("failed to become user\n"));
1649 ret = false;
1650 goto err_free_conn;
1653 if ( !CAN_WRITE(conn) ) {
1654 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1655 ret = false;
1656 goto err_out;
1659 short_arch = get_short_archi(r->architecture);
1660 if (short_arch == NULL) {
1661 DEBUG(0, ("bad architecture %s\n", r->architecture));
1662 ret = false;
1663 goto err_out;
1666 /* now delete the files */
1668 if (r->driver_path && r->driver_path[0]) {
1669 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1670 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1673 if (r->config_file && r->config_file[0]) {
1674 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1675 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1678 if (r->data_file && r->data_file[0]) {
1679 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1680 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1683 if (r->help_file && r->help_file[0]) {
1684 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1685 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1688 if (r->dependent_files) {
1689 int i = 0;
1690 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1691 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1692 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1693 i++;
1697 ret = true;
1698 err_out:
1699 unbecome_user();
1700 err_free_conn:
1701 if (conn != NULL) {
1702 vfs_ChDir(conn, oldcwd);
1703 SMB_VFS_DISCONNECT(conn);
1704 conn_free(conn);
1706 return ret;
1709 /* error code:
1710 0: everything OK
1711 1: level not implemented
1712 2: file doesn't exist
1713 3: can't allocate memory
1714 4: can't free memory
1715 5: non existent struct
1719 A printer and a printer driver are 2 different things.
1720 NT manages them separatelly, Samba does the same.
1721 Why ? Simply because it's easier and it makes sense !
1723 Now explanation: You have 3 printers behind your samba server,
1724 2 of them are the same make and model (laser A and B). But laser B
1725 has an 3000 sheet feeder and laser A doesn't such an option.
1726 Your third printer is an old dot-matrix model for the accounting :-).
1728 If the /usr/local/samba/lib directory (default dir), you will have
1729 5 files to describe all of this.
1731 3 files for the printers (1 by printer):
1732 NTprinter_laser A
1733 NTprinter_laser B
1734 NTprinter_accounting
1735 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1736 NTdriver_printer model X
1737 NTdriver_printer model Y
1739 jfm: I should use this comment for the text file to explain
1740 same thing for the forms BTW.
1741 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1745 /* Convert generic access rights to printer object specific access rights.
1746 It turns out that NT4 security descriptors use generic access rights and
1747 NT5 the object specific ones. */
1749 void map_printer_permissions(struct security_descriptor *sd)
1751 int i;
1753 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1754 se_map_generic(&sd->dacl->aces[i].access_mask,
1755 &printer_generic_mapping);
1759 void map_job_permissions(struct security_descriptor *sd)
1761 int i;
1763 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1764 se_map_generic(&sd->dacl->aces[i].access_mask,
1765 &job_generic_mapping);
1770 /****************************************************************************
1771 Check a user has permissions to perform the given operation. We use the
1772 permission constants defined in include/rpc_spoolss.h to check the various
1773 actions we perform when checking printer access.
1775 PRINTER_ACCESS_ADMINISTER:
1776 print_queue_pause, print_queue_resume, update_printer_sec,
1777 update_printer, spoolss_addprinterex_level_2,
1778 _spoolss_setprinterdata
1780 PRINTER_ACCESS_USE:
1781 print_job_start
1783 JOB_ACCESS_ADMINISTER:
1784 print_job_delete, print_job_pause, print_job_resume,
1785 print_queue_purge
1787 Try access control in the following order (for performance reasons):
1788 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1789 2) check security descriptor (bit comparisons in memory)
1790 3) "printer admins" (may result in numerous calls to winbind)
1792 ****************************************************************************/
1793 WERROR print_access_check(const struct auth_session_info *session_info,
1794 struct messaging_context *msg_ctx, int snum,
1795 int access_type)
1797 struct spoolss_security_descriptor *secdesc = NULL;
1798 uint32 access_granted;
1799 size_t sd_size;
1800 NTSTATUS status;
1801 WERROR result;
1802 const char *pname;
1803 TALLOC_CTX *mem_ctx = NULL;
1805 /* If user is NULL then use the current_user structure */
1807 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1809 if ((session_info->unix_token->uid == sec_initial_uid())
1810 || security_token_has_privilege(session_info->security_token,
1811 SEC_PRIV_PRINT_OPERATOR)) {
1812 return WERR_OK;
1815 /* Get printer name */
1817 pname = lp_printername(talloc_tos(), snum);
1819 if (!pname || !*pname) {
1820 return WERR_ACCESS_DENIED;
1823 /* Get printer security descriptor */
1825 if(!(mem_ctx = talloc_init("print_access_check"))) {
1826 return WERR_NOMEM;
1829 result = winreg_get_printer_secdesc_internal(mem_ctx,
1830 get_session_info_system(),
1831 msg_ctx,
1832 pname,
1833 &secdesc);
1834 if (!W_ERROR_IS_OK(result)) {
1835 talloc_destroy(mem_ctx);
1836 return WERR_NOMEM;
1839 if (access_type == JOB_ACCESS_ADMINISTER) {
1840 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1842 /* Create a child security descriptor to check permissions
1843 against. This is because print jobs are child objects
1844 objects of a printer. */
1845 status = se_create_child_secdesc(mem_ctx,
1846 &secdesc,
1847 &sd_size,
1848 parent_secdesc,
1849 parent_secdesc->owner_sid,
1850 parent_secdesc->group_sid,
1851 false);
1852 if (!NT_STATUS_IS_OK(status)) {
1853 talloc_destroy(mem_ctx);
1854 return ntstatus_to_werror(status);
1857 map_job_permissions(secdesc);
1858 } else {
1859 map_printer_permissions(secdesc);
1862 /* Check access */
1863 status = se_access_check(secdesc, session_info->security_token, access_type,
1864 &access_granted);
1866 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1868 talloc_destroy(mem_ctx);
1870 return ntstatus_to_werror(status);
1873 /****************************************************************************
1874 Check the time parameters allow a print operation.
1875 *****************************************************************************/
1877 bool print_time_access_check(const struct auth_session_info *session_info,
1878 struct messaging_context *msg_ctx,
1879 const char *servicename)
1881 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1882 WERROR result;
1883 bool ok = False;
1884 time_t now = time(NULL);
1885 struct tm *t;
1886 uint32 mins;
1888 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1889 servicename, &pinfo2);
1890 if (!W_ERROR_IS_OK(result)) {
1891 return False;
1894 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1895 ok = True;
1898 t = gmtime(&now);
1899 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1901 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1902 ok = True;
1905 TALLOC_FREE(pinfo2);
1907 if (!ok) {
1908 errno = EACCES;
1911 return ok;
1914 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1915 const struct auth_session_info *session_info,
1916 struct messaging_context *msg_ctx,
1917 const char *printer)
1919 WERROR result;
1921 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1922 printer, "");
1923 if (!W_ERROR_IS_OK(result)) {
1924 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1925 "%s\n", printer, win_errstr(result)));
1929 void nt_printer_add(TALLOC_CTX *mem_ctx,
1930 const struct auth_session_info *session_info,
1931 struct messaging_context *msg_ctx,
1932 const char *printer)
1934 WERROR result;
1936 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1937 printer);
1938 if (!W_ERROR_IS_OK(result)) {
1939 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1940 printer, win_errstr(result)));