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