s3: VFS: shadow_copy2: Fix usage of saved_errno to only set errno on error.
[Samba.git] / source3 / printing / nt_printing.c
blobd5660630f79e5cb063fc1c3cb2f9dac580152de5
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 static bool print_driver_directories_init(void)
79 int service, i;
80 char *driver_path;
81 bool ok;
82 TALLOC_CTX *mem_ctx = talloc_stackframe();
84 service = lp_servicenumber("print$");
85 if (service < 0) {
86 /* We don't have a print$ share */
87 DEBUG(5, ("No print$ share has been configured.\n"));
88 talloc_free(mem_ctx);
89 return true;
92 driver_path = lp_path(mem_ctx, service);
93 if (driver_path == NULL) {
94 talloc_free(mem_ctx);
95 return false;
98 ok = directory_create_or_exist(driver_path, 0755);
99 if (!ok) {
100 DEBUG(1, ("Failed to create printer driver directory %s\n",
101 driver_path));
102 talloc_free(mem_ctx);
103 return false;
106 for (i = 0; archi_table[i].long_archi != NULL; i++) {
107 const char *arch_path;
109 arch_path = talloc_asprintf(mem_ctx,
110 "%s/%s",
111 driver_path,
112 archi_table[i].short_archi);
113 if (arch_path == NULL) {
114 talloc_free(mem_ctx);
115 return false;
118 ok = directory_create_or_exist(arch_path, 0755);
119 if (!ok) {
120 DEBUG(1, ("Failed to create printer driver "
121 "architecture directory %s\n",
122 arch_path));
123 talloc_free(mem_ctx);
124 return false;
128 talloc_free(mem_ctx);
129 return true;
132 /****************************************************************************
133 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
134 background lpq updater.
135 ****************************************************************************/
137 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
138 void *private_data,
139 uint32_t msg_type,
140 struct server_id server_id,
141 DATA_BLOB *data)
143 extern pid_t background_lpq_updater_pid;
145 if (background_lpq_updater_pid == -1) {
146 DEBUG(3,("no background lpq queue updater\n"));
147 return;
150 messaging_send_buf(msg,
151 pid_to_procid(background_lpq_updater_pid),
152 MSG_PRINTER_DRVUPGRADE,
153 data->data,
154 data->length);
157 /****************************************************************************
158 Open the NT printing tdbs. Done once before fork().
159 ****************************************************************************/
161 bool nt_printing_init(struct messaging_context *msg_ctx)
163 WERROR win_rc;
165 if (!print_driver_directories_init()) {
166 return false;
169 if (!nt_printing_tdb_upgrade()) {
170 return false;
174 * register callback to handle updating printers as new
175 * drivers are installed. Forwards to background lpq updater.
177 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
178 forward_drv_upgrade_printer_msg);
180 /* of course, none of the message callbacks matter if you don't
181 tell messages.c that you interested in receiving PRINT_GENERAL
182 msgs. This is done in serverid_register() */
184 if ( lp_security() == SEC_ADS ) {
185 win_rc = check_published_printers(msg_ctx);
186 if (!W_ERROR_IS_OK(win_rc))
187 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
190 return true;
193 /*******************************************************************
194 Function to allow filename parsing "the old way".
195 ********************************************************************/
197 static NTSTATUS driver_unix_convert(connection_struct *conn,
198 const char *old_name,
199 struct smb_filename **smb_fname)
201 NTSTATUS status;
202 TALLOC_CTX *ctx = talloc_tos();
203 char *name = talloc_strdup(ctx, old_name);
205 if (!name) {
206 return NT_STATUS_NO_MEMORY;
208 unix_format(name);
209 name = unix_clean_name(ctx, name);
210 if (!name) {
211 return NT_STATUS_NO_MEMORY;
213 trim_string(name,"/","/");
215 status = unix_convert(ctx, conn, name, smb_fname, 0);
216 if (!NT_STATUS_IS_OK(status)) {
217 return NT_STATUS_NO_MEMORY;
220 return NT_STATUS_OK;
223 /****************************************************************************
224 Function to do the mapping between the long architecture name and
225 the short one.
226 ****************************************************************************/
228 const char *get_short_archi(const char *long_archi)
230 int i=-1;
232 DEBUG(107,("Getting architecture dependent directory\n"));
233 do {
234 i++;
235 } while ( (archi_table[i].long_archi!=NULL ) &&
236 strcasecmp_m(long_archi, archi_table[i].long_archi) );
238 if (archi_table[i].long_archi==NULL) {
239 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
240 return NULL;
243 /* this might be client code - but shouldn't this be an fstrcpy etc? */
245 DEBUGADD(108,("index: [%d]\n", i));
246 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
247 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
249 return archi_table[i].short_archi;
252 /****************************************************************************
253 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
254 There are two case to be covered here: PE (Portable Executable) and NE (New
255 Executable) files. Both files support the same INFO structure, but PE files
256 store the signature in unicode, and NE files store it as !unicode.
257 returns -1 on error, 1 on version info found, and 0 on no version info found.
258 ****************************************************************************/
260 static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint32_t *minor)
262 int i;
263 char *buf = NULL;
264 ssize_t byte_count;
266 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
267 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
268 fname, DOS_HEADER_SIZE));
269 goto error_exit;
272 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
273 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
274 fname, (unsigned long)byte_count));
275 goto no_version_info;
278 /* Is this really a DOS header? */
279 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
280 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
281 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
282 goto no_version_info;
285 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
286 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
287 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
288 fname, errno));
289 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
290 goto no_version_info;
293 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
294 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
295 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
296 fname, (unsigned long)byte_count));
297 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
298 goto no_version_info;
301 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
302 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
303 unsigned int num_sections;
304 unsigned int section_table_bytes;
306 /* Just skip over optional header to get to section table */
307 if (SMB_VFS_LSEEK(fsp,
308 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
309 SEEK_CUR) == (off_t)-1) {
310 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
311 fname, errno));
312 goto error_exit;
315 /* get the section table */
316 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
317 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
318 if (section_table_bytes == 0)
319 goto error_exit;
321 SAFE_FREE(buf);
322 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
323 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
324 fname, section_table_bytes));
325 goto error_exit;
328 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
329 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
330 fname, (unsigned long)byte_count));
331 goto error_exit;
334 /* Iterate the section table looking for the resource section ".rsrc" */
335 for (i = 0; i < num_sections; i++) {
336 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
338 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
339 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
340 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
342 if (section_bytes == 0)
343 goto error_exit;
345 SAFE_FREE(buf);
346 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
347 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
348 fname, section_bytes));
349 goto error_exit;
352 /* Seek to the start of the .rsrc section info */
353 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
354 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
355 fname, errno));
356 goto error_exit;
359 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
360 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
361 fname, (unsigned long)byte_count));
362 goto error_exit;
365 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
366 goto error_exit;
368 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
369 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
370 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
371 /* Align to next long address */
372 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
374 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
375 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
376 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
378 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
379 fname, *major, *minor,
380 (*major>>16)&0xffff, *major&0xffff,
381 (*minor>>16)&0xffff, *minor&0xffff));
382 SAFE_FREE(buf);
383 return 1;
390 /* Version info not found, fall back to origin date/time */
391 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
392 SAFE_FREE(buf);
393 return 0;
395 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
396 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
397 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
398 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
399 /* At this point, we assume the file is in error. It still could be somthing
400 * else besides a NE file, but it unlikely at this point. */
401 goto error_exit;
404 /* Allocate a bit more space to speed up things */
405 SAFE_FREE(buf);
406 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
407 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
408 fname, PE_HEADER_SIZE));
409 goto error_exit;
412 /* This is a HACK! I got tired of trying to sort through the messy
413 * 'NE' file format. If anyone wants to clean this up please have at
414 * it, but this works. 'NE' files will eventually fade away. JRR */
415 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
416 /* Cover case that should not occur in a well formed 'NE' .dll file */
417 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
419 for(i=0; i<byte_count; i++) {
420 /* Fast skip past data that can't possibly match */
421 if (buf[i] != 'V') continue;
423 /* Potential match data crosses buf boundry, move it to beginning
424 * of buf, and fill the buf with as much as it will hold. */
425 if (i>byte_count-VS_VERSION_INFO_SIZE) {
426 int bc;
428 memcpy(buf, &buf[i], byte_count-i);
429 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
430 (byte_count-i))) < 0) {
432 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
433 fname, errno));
434 goto error_exit;
437 byte_count = bc + (byte_count - i);
438 if (byte_count<VS_VERSION_INFO_SIZE) break;
440 i = 0;
443 /* Check that the full signature string and the magic number that
444 * follows exist (not a perfect solution, but the chances that this
445 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
446 * twice, as it is simpler to read the code. */
447 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
448 /* Compute skip alignment to next long address */
449 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
450 sizeof(VS_SIGNATURE)) & 3;
451 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
453 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
454 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
455 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
456 fname, *major, *minor,
457 (*major>>16)&0xffff, *major&0xffff,
458 (*minor>>16)&0xffff, *minor&0xffff));
459 SAFE_FREE(buf);
460 return 1;
465 /* Version info not found, fall back to origin date/time */
466 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
467 SAFE_FREE(buf);
468 return 0;
470 } else
471 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
472 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
473 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
475 no_version_info:
476 SAFE_FREE(buf);
477 return 0;
479 error_exit:
480 SAFE_FREE(buf);
481 return -1;
484 /****************************************************************************
485 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
486 share one or more files. During the MS installation process files are checked
487 to insure that only a newer version of a shared file is installed over an
488 older version. There are several possibilities for this comparison. If there
489 is no previous version, the new one is newer (obviously). If either file is
490 missing the version info structure, compare the creation date (on Unix use
491 the modification date). Otherwise chose the numerically larger version number.
492 ****************************************************************************/
494 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
496 bool use_version = true;
498 uint32_t new_major;
499 uint32_t new_minor;
500 time_t new_create_time;
502 uint32_t old_major;
503 uint32_t old_minor;
504 time_t old_create_time;
506 struct smb_filename *smb_fname = NULL;
507 files_struct *fsp = NULL;
508 SMB_STRUCT_STAT st;
510 NTSTATUS status;
511 int ret;
513 SET_STAT_INVALID(st);
514 new_create_time = (time_t)0;
515 old_create_time = (time_t)0;
517 /* Get file version info (if available) for previous file (if it exists) */
518 status = driver_unix_convert(conn, old_file, &smb_fname);
519 if (!NT_STATUS_IS_OK(status)) {
520 goto error_exit;
523 status = SMB_VFS_CREATE_FILE(
524 conn, /* conn */
525 NULL, /* req */
526 0, /* root_dir_fid */
527 smb_fname, /* fname */
528 FILE_GENERIC_READ, /* access_mask */
529 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
530 FILE_OPEN, /* create_disposition*/
531 0, /* create_options */
532 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
533 INTERNAL_OPEN_ONLY, /* oplock_request */
534 NULL, /* lease */
535 0, /* allocation_size */
536 0, /* private_flags */
537 NULL, /* sd */
538 NULL, /* ea_list */
539 &fsp, /* result */
540 NULL, /* pinfo */
541 NULL, NULL); /* create context */
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 NULL, /* lease */
590 0, /* allocation_size */
591 0, /* private_flags */
592 NULL, /* sd */
593 NULL, /* ea_list */
594 &fsp, /* result */
595 NULL, /* pinfo */
596 NULL, NULL); /* create context */
598 if (!NT_STATUS_IS_OK(status)) {
599 /* New file not found, this shouldn't occur if the caller did its job */
600 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
601 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
602 goto error_exit;
604 } else {
605 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
606 if (ret == -1) {
607 goto error_exit;
610 if (!ret) {
611 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
612 new_file));
613 use_version = false;
614 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
615 goto error_exit;
617 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
618 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
619 (long)new_create_time));
622 close_file(NULL, fsp, NORMAL_CLOSE);
623 fsp = NULL;
625 if (use_version && (new_major != old_major || new_minor != old_minor)) {
626 /* Compare versions and choose the larger version number */
627 if (new_major > old_major ||
628 (new_major == old_major && new_minor > old_minor)) {
630 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
631 ret = 1;
632 goto done;
634 else {
635 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
636 ret = 0;
637 goto done;
640 } else {
641 /* Compare modification time/dates and choose the newest time/date */
642 if (new_create_time > old_create_time) {
643 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
644 ret = 1;
645 goto done;
647 else {
648 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
649 ret = 0;
650 goto done;
654 error_exit:
655 if(fsp)
656 close_file(NULL, fsp, NORMAL_CLOSE);
657 ret = -1;
658 done:
659 TALLOC_FREE(smb_fname);
660 return ret;
663 /****************************************************************************
664 Determine the correct cVersion associated with an architecture and driver
665 ****************************************************************************/
666 static uint32_t get_correct_cversion(struct auth_session_info *session_info,
667 const char *architecture,
668 const char *driverpath_in,
669 WERROR *perr)
671 int cversion = -1;
672 NTSTATUS nt_status;
673 struct smb_filename *smb_fname = NULL;
674 char *driverpath = NULL;
675 files_struct *fsp = NULL;
676 connection_struct *conn = NULL;
677 char *oldcwd;
678 char *printdollar = NULL;
679 int printdollar_snum;
681 *perr = WERR_INVALID_PARAM;
683 /* If architecture is Windows 95/98/ME, the version is always 0. */
684 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
685 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
686 *perr = WERR_OK;
687 return 0;
690 /* If architecture is Windows x64, the version is always 3. */
691 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
692 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
693 *perr = WERR_OK;
694 return 3;
697 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
698 if (!printdollar) {
699 *perr = WERR_NOMEM;
700 return -1;
702 if (printdollar_snum == -1) {
703 *perr = WERR_NO_SUCH_SHARE;
704 return -1;
707 nt_status = create_conn_struct_cwd(talloc_tos(),
708 server_event_context(),
709 server_messaging_context(),
710 &conn,
711 printdollar_snum,
712 lp_path(talloc_tos(), printdollar_snum),
713 session_info, &oldcwd);
714 if (!NT_STATUS_IS_OK(nt_status)) {
715 DEBUG(0,("get_correct_cversion: create_conn_struct "
716 "returned %s\n", nt_errstr(nt_status)));
717 *perr = ntstatus_to_werror(nt_status);
718 return -1;
721 nt_status = set_conn_force_user_group(conn, printdollar_snum);
722 if (!NT_STATUS_IS_OK(nt_status)) {
723 DEBUG(0, ("failed set force user / group\n"));
724 *perr = ntstatus_to_werror(nt_status);
725 goto error_free_conn;
728 if (!become_user_by_session(conn, session_info)) {
729 DEBUG(0, ("failed to become user\n"));
730 *perr = WERR_ACCESS_DENIED;
731 goto error_free_conn;
734 /* Open the driver file (Portable Executable format) and determine the
735 * deriver the cversion. */
736 driverpath = talloc_asprintf(talloc_tos(),
737 "%s/%s",
738 architecture,
739 driverpath_in);
740 if (!driverpath) {
741 *perr = WERR_NOMEM;
742 goto error_exit;
745 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
746 if (!NT_STATUS_IS_OK(nt_status)) {
747 *perr = ntstatus_to_werror(nt_status);
748 goto error_exit;
751 nt_status = vfs_file_exist(conn, smb_fname);
752 if (!NT_STATUS_IS_OK(nt_status)) {
753 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
754 *perr = WERR_BADFILE;
755 goto error_exit;
758 nt_status = SMB_VFS_CREATE_FILE(
759 conn, /* conn */
760 NULL, /* req */
761 0, /* root_dir_fid */
762 smb_fname, /* fname */
763 FILE_GENERIC_READ, /* access_mask */
764 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
765 FILE_OPEN, /* create_disposition*/
766 0, /* create_options */
767 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
768 INTERNAL_OPEN_ONLY, /* oplock_request */
769 NULL, /* lease */
770 0, /* private_flags */
771 0, /* allocation_size */
772 NULL, /* sd */
773 NULL, /* ea_list */
774 &fsp, /* result */
775 NULL, /* pinfo */
776 NULL, NULL); /* create context */
778 if (!NT_STATUS_IS_OK(nt_status)) {
779 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
780 "%d\n", smb_fname_str_dbg(smb_fname), errno));
781 *perr = WERR_ACCESS_DENIED;
782 goto error_exit;
783 } else {
784 uint32_t major;
785 uint32_t minor;
786 int ret;
788 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
789 if (ret == -1) {
790 *perr = WERR_INVALID_PARAM;
791 goto error_exit;
792 } else if (!ret) {
793 DEBUG(6,("get_correct_cversion: Version info not "
794 "found [%s]\n",
795 smb_fname_str_dbg(smb_fname)));
796 *perr = WERR_INVALID_PARAM;
797 goto error_exit;
801 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
802 * for more details. Version in this case is not just the version of the
803 * file, but the version in the sense of kernal mode (2) vs. user mode
804 * (3) drivers. Other bits of the version fields are the version info.
805 * JRR 010716
807 cversion = major & 0x0000ffff;
808 switch (cversion) {
809 case 2: /* WinNT drivers */
810 case 3: /* Win2K drivers */
811 break;
813 default:
814 DEBUG(6,("get_correct_cversion: cversion "
815 "invalid [%s] cversion = %d\n",
816 smb_fname_str_dbg(smb_fname),
817 cversion));
818 goto error_exit;
821 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
822 " = 0x%x minor = 0x%x\n",
823 smb_fname_str_dbg(smb_fname), major, minor));
826 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
827 smb_fname_str_dbg(smb_fname), cversion));
828 *perr = WERR_OK;
830 error_exit:
831 unbecome_user();
832 error_free_conn:
833 TALLOC_FREE(smb_fname);
834 if (fsp != NULL) {
835 close_file(NULL, fsp, NORMAL_CLOSE);
837 if (conn != NULL) {
838 vfs_ChDir(conn, oldcwd);
839 SMB_VFS_DISCONNECT(conn);
840 conn_free(conn);
842 if (!W_ERROR_IS_OK(*perr)) {
843 cversion = -1;
846 return cversion;
849 /****************************************************************************
850 ****************************************************************************/
852 #define strip_driver_path(_mem_ctx, _element) do { \
853 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
854 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
855 W_ERROR_HAVE_NO_MEMORY((_element)); \
857 } while (0);
859 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
860 struct auth_session_info *session_info,
861 const char *architecture,
862 const char **driver_path,
863 const char **data_file,
864 const char **config_file,
865 const char **help_file,
866 struct spoolss_StringArray *dependent_files,
867 enum spoolss_DriverOSVersion *version,
868 uint32_t flags,
869 const char **driver_directory)
871 const char *short_architecture;
872 int i;
873 WERROR err;
874 char *_p;
876 if (!*driver_path || !*data_file) {
877 return WERR_INVALID_PARAM;
880 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
881 return WERR_INVALID_PARAM;
884 if (flags & APD_COPY_FROM_DIRECTORY) {
885 char *path;
886 char *q;
889 * driver_path is set to:
891 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
893 path = talloc_strdup(mem_ctx, *driver_path);
894 if (path == NULL) {
895 return WERR_NOT_ENOUGH_MEMORY;
898 /* Remove pscript5.dll */
899 q = strrchr_m(path, '\\');
900 if (q == NULL) {
901 return WERR_INVALID_PARAMETER;
903 *q = '\0';
905 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
906 q = strrchr_m(path, '\\');
907 if (q == NULL) {
908 return WERR_INVALID_PARAMETER;
912 * Set driver_directory to:
914 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
916 * This is the directory where all the files have been uploaded
918 *driver_directory = q + 1;
921 /* clean up the driver name.
922 * we can get .\driver.dll
923 * or worse c:\windows\system\driver.dll !
925 /* using an intermediate string to not have overlaping memcpy()'s */
927 strip_driver_path(mem_ctx, *driver_path);
928 strip_driver_path(mem_ctx, *data_file);
929 if (*config_file) {
930 strip_driver_path(mem_ctx, *config_file);
932 if (help_file) {
933 strip_driver_path(mem_ctx, *help_file);
936 if (dependent_files && dependent_files->string) {
937 for (i=0; dependent_files->string[i]; i++) {
938 strip_driver_path(mem_ctx, dependent_files->string[i]);
942 short_architecture = get_short_archi(architecture);
943 if (!short_architecture) {
944 return WERR_UNKNOWN_PRINTER_DRIVER;
947 /* jfm:7/16/2000 the client always sends the cversion=0.
948 * The server should check which version the driver is by reading
949 * the PE header of driver->driverpath.
951 * For Windows 95/98 the version is 0 (so the value sent is correct)
952 * For Windows NT (the architecture doesn't matter)
953 * NT 3.1: cversion=0
954 * NT 3.5/3.51: cversion=1
955 * NT 4: cversion=2
956 * NT2K: cversion=3
959 *version = get_correct_cversion(session_info, short_architecture,
960 *driver_path, &err);
961 if (*version == -1) {
962 return err;
965 return WERR_OK;
968 /****************************************************************************
969 ****************************************************************************/
971 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
972 struct auth_session_info *session_info,
973 struct spoolss_AddDriverInfoCtr *r,
974 uint32_t flags,
975 const char **driver_directory)
977 switch (r->level) {
978 case 3:
979 return clean_up_driver_struct_level(mem_ctx, session_info,
980 r->info.info3->architecture,
981 &r->info.info3->driver_path,
982 &r->info.info3->data_file,
983 &r->info.info3->config_file,
984 &r->info.info3->help_file,
985 r->info.info3->dependent_files,
986 &r->info.info3->version,
987 flags,
988 driver_directory);
989 case 6:
990 return clean_up_driver_struct_level(mem_ctx, session_info,
991 r->info.info6->architecture,
992 &r->info.info6->driver_path,
993 &r->info.info6->data_file,
994 &r->info.info6->config_file,
995 &r->info.info6->help_file,
996 r->info.info6->dependent_files,
997 &r->info.info6->version,
998 flags,
999 driver_directory);
1000 default:
1001 return WERR_NOT_SUPPORTED;
1005 /****************************************************************************
1006 This function sucks and should be replaced. JRA.
1007 ****************************************************************************/
1009 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1010 const struct spoolss_AddDriverInfo6 *src)
1012 dst->version = src->version;
1014 dst->driver_name = src->driver_name;
1015 dst->architecture = src->architecture;
1016 dst->driver_path = src->driver_path;
1017 dst->data_file = src->data_file;
1018 dst->config_file = src->config_file;
1019 dst->help_file = src->help_file;
1020 dst->monitor_name = src->monitor_name;
1021 dst->default_datatype = src->default_datatype;
1022 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1023 dst->dependent_files = src->dependent_files;
1026 /****************************************************************************
1027 ****************************************************************************/
1029 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1030 connection_struct *conn,
1031 const char *driver_file,
1032 const char *short_architecture,
1033 uint32_t driver_version,
1034 uint32_t version,
1035 const char *driver_directory)
1037 struct smb_filename *smb_fname_old = NULL;
1038 struct smb_filename *smb_fname_new = NULL;
1039 char *old_name = NULL;
1040 char *new_name = NULL;
1041 NTSTATUS status;
1042 WERROR ret;
1044 if (driver_directory != NULL) {
1045 old_name = talloc_asprintf(mem_ctx,
1046 "%s/%s/%s",
1047 short_architecture,
1048 driver_directory,
1049 driver_file);
1050 } else {
1051 old_name = talloc_asprintf(mem_ctx,
1052 "%s/%s",
1053 short_architecture,
1054 driver_file);
1056 if (old_name == NULL) {
1057 return WERR_NOT_ENOUGH_MEMORY;
1060 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1061 short_architecture, driver_version, driver_file);
1062 if (new_name == NULL) {
1063 TALLOC_FREE(old_name);
1064 return WERR_NOMEM;
1067 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1069 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1070 if (!NT_STATUS_IS_OK(status)) {
1071 ret = WERR_NOMEM;
1072 goto out;
1075 /* Setup a synthetic smb_filename struct */
1076 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1077 if (!smb_fname_new) {
1078 ret = WERR_NOMEM;
1079 goto out;
1082 smb_fname_new->base_name = new_name;
1084 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1085 "'%s'\n", smb_fname_old->base_name,
1086 smb_fname_new->base_name));
1088 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1089 OPENX_FILE_EXISTS_TRUNCATE |
1090 OPENX_FILE_CREATE_IF_NOT_EXIST,
1091 0, false);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 DEBUG(0,("move_driver_file_to_download_area: Unable "
1095 "to rename [%s] to [%s]: %s\n",
1096 smb_fname_old->base_name, new_name,
1097 nt_errstr(status)));
1098 ret = WERR_ACCESS_DENIED;
1099 goto out;
1103 ret = WERR_OK;
1104 out:
1105 TALLOC_FREE(smb_fname_old);
1106 TALLOC_FREE(smb_fname_new);
1107 return ret;
1110 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1111 struct spoolss_AddDriverInfoCtr *r,
1112 const char *driver_directory)
1114 struct spoolss_AddDriverInfo3 *driver;
1115 struct spoolss_AddDriverInfo3 converted_driver;
1116 const char *short_architecture;
1117 struct smb_filename *smb_dname = NULL;
1118 char *new_dir = NULL;
1119 connection_struct *conn = NULL;
1120 NTSTATUS nt_status;
1121 int i;
1122 TALLOC_CTX *ctx = talloc_tos();
1123 int ver = 0;
1124 char *oldcwd;
1125 char *printdollar = NULL;
1126 int printdollar_snum;
1127 WERROR err = WERR_OK;
1129 switch (r->level) {
1130 case 3:
1131 driver = r->info.info3;
1132 break;
1133 case 6:
1134 convert_level_6_to_level3(&converted_driver, r->info.info6);
1135 driver = &converted_driver;
1136 break;
1137 default:
1138 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1139 return WERR_UNKNOWN_LEVEL;
1142 short_architecture = get_short_archi(driver->architecture);
1143 if (!short_architecture) {
1144 return WERR_UNKNOWN_PRINTER_DRIVER;
1147 printdollar_snum = find_service(ctx, "print$", &printdollar);
1148 if (!printdollar) {
1149 return WERR_NOMEM;
1151 if (printdollar_snum == -1) {
1152 return WERR_NO_SUCH_SHARE;
1155 nt_status = create_conn_struct_cwd(talloc_tos(),
1156 server_event_context(),
1157 server_messaging_context(),
1158 &conn,
1159 printdollar_snum,
1160 lp_path(talloc_tos(), printdollar_snum),
1161 session_info, &oldcwd);
1162 if (!NT_STATUS_IS_OK(nt_status)) {
1163 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1164 "returned %s\n", nt_errstr(nt_status)));
1165 err = ntstatus_to_werror(nt_status);
1166 return err;
1169 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1170 if (!NT_STATUS_IS_OK(nt_status)) {
1171 DEBUG(0, ("failed set force user / group\n"));
1172 err = ntstatus_to_werror(nt_status);
1173 goto err_free_conn;
1176 if (!become_user_by_session(conn, session_info)) {
1177 DEBUG(0, ("failed to become user\n"));
1178 err = WERR_ACCESS_DENIED;
1179 goto err_free_conn;
1182 new_dir = talloc_asprintf(ctx,
1183 "%s/%d",
1184 short_architecture,
1185 driver->version);
1186 if (!new_dir) {
1187 err = WERR_NOMEM;
1188 goto err_exit;
1190 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1191 if (!NT_STATUS_IS_OK(nt_status)) {
1192 err = WERR_NOMEM;
1193 goto err_exit;
1196 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1198 nt_status = create_directory(conn, NULL, smb_dname);
1199 if (!NT_STATUS_IS_OK(nt_status)
1200 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1201 DEBUG(0, ("failed to create driver destination directory: %s\n",
1202 nt_errstr(nt_status)));
1203 err = ntstatus_to_werror(nt_status);
1204 goto err_exit;
1207 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1208 * listed for this driver which has already been moved, skip it (note:
1209 * drivers may list the same file name several times. Then check if the
1210 * file already exists in archi\version\, if so, check that the version
1211 * info (or time stamps if version info is unavailable) is newer (or the
1212 * date is later). If it is, move it to archi\version\filexxx.yyy.
1213 * Otherwise, delete the file.
1215 * If a file is not moved to archi\version\ because of an error, all the
1216 * rest of the 'unmoved' driver files are removed from archi\. If one or
1217 * more of the driver's files was already moved to archi\version\, it
1218 * potentially leaves the driver in a partially updated state. Version
1219 * trauma will most likely occur if an client attempts to use any printer
1220 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1221 * done is appropriate... later JRR
1224 DEBUG(5,("Moving files now !\n"));
1226 if (driver->driver_path && strlen(driver->driver_path)) {
1228 err = move_driver_file_to_download_area(ctx,
1229 conn,
1230 driver->driver_path,
1231 short_architecture,
1232 driver->version,
1233 ver,
1234 driver_directory);
1235 if (!W_ERROR_IS_OK(err)) {
1236 goto err_exit;
1240 if (driver->data_file && strlen(driver->data_file)) {
1241 if (!strequal(driver->data_file, driver->driver_path)) {
1243 err = move_driver_file_to_download_area(ctx,
1244 conn,
1245 driver->data_file,
1246 short_architecture,
1247 driver->version,
1248 ver,
1249 driver_directory);
1250 if (!W_ERROR_IS_OK(err)) {
1251 goto err_exit;
1256 if (driver->config_file && strlen(driver->config_file)) {
1257 if (!strequal(driver->config_file, driver->driver_path) &&
1258 !strequal(driver->config_file, driver->data_file)) {
1260 err = move_driver_file_to_download_area(ctx,
1261 conn,
1262 driver->config_file,
1263 short_architecture,
1264 driver->version,
1265 ver,
1266 driver_directory);
1267 if (!W_ERROR_IS_OK(err)) {
1268 goto err_exit;
1273 if (driver->help_file && strlen(driver->help_file)) {
1274 if (!strequal(driver->help_file, driver->driver_path) &&
1275 !strequal(driver->help_file, driver->data_file) &&
1276 !strequal(driver->help_file, driver->config_file)) {
1278 err = move_driver_file_to_download_area(ctx,
1279 conn,
1280 driver->help_file,
1281 short_architecture,
1282 driver->version,
1283 ver,
1284 driver_directory);
1285 if (!W_ERROR_IS_OK(err)) {
1286 goto err_exit;
1291 if (driver->dependent_files && driver->dependent_files->string) {
1292 for (i=0; driver->dependent_files->string[i]; i++) {
1293 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1294 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1295 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1296 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1297 int j;
1298 for (j=0; j < i; j++) {
1299 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1300 goto NextDriver;
1304 err = move_driver_file_to_download_area(ctx,
1305 conn,
1306 driver->dependent_files->string[i],
1307 short_architecture,
1308 driver->version,
1309 ver,
1310 driver_directory);
1311 if (!W_ERROR_IS_OK(err)) {
1312 goto err_exit;
1315 NextDriver: ;
1319 err = WERR_OK;
1320 err_exit:
1321 unbecome_user();
1322 err_free_conn:
1323 TALLOC_FREE(smb_dname);
1325 if (conn != NULL) {
1326 vfs_ChDir(conn, oldcwd);
1327 SMB_VFS_DISCONNECT(conn);
1328 conn_free(conn);
1331 return err;
1334 /****************************************************************************
1335 Determine whether or not a particular driver is currently assigned
1336 to a printer
1337 ****************************************************************************/
1339 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1340 struct dcerpc_binding_handle *b,
1341 const struct spoolss_DriverInfo8 *r)
1343 int snum;
1344 int n_services = lp_numservices();
1345 bool in_use = False;
1346 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1347 WERROR result;
1349 if (!r) {
1350 return false;
1353 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1355 /* loop through the printers.tdb and check for the drivername */
1357 for (snum=0; snum<n_services && !in_use; snum++) {
1358 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1359 continue;
1362 result = winreg_get_printer(mem_ctx, b,
1363 lp_servicename(talloc_tos(), snum),
1364 &pinfo2);
1365 if (!W_ERROR_IS_OK(result)) {
1366 continue; /* skip */
1369 if (strequal(r->driver_name, pinfo2->drivername)) {
1370 in_use = True;
1373 TALLOC_FREE(pinfo2);
1376 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1378 if ( in_use ) {
1379 struct spoolss_DriverInfo8 *driver = NULL;
1380 WERROR werr;
1382 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1384 /* we can still remove the driver if there is one of
1385 "Windows NT x86" version 2 or 3 left */
1387 if (!strequal("Windows NT x86", r->architecture)) {
1388 werr = winreg_get_driver(mem_ctx, b,
1389 "Windows NT x86",
1390 r->driver_name,
1391 DRIVER_ANY_VERSION,
1392 &driver);
1393 } else if (r->version == 2) {
1394 werr = winreg_get_driver(mem_ctx, b,
1395 "Windows NT x86",
1396 r->driver_name,
1397 3, &driver);
1398 } else if (r->version == 3) {
1399 werr = winreg_get_driver(mem_ctx, b,
1400 "Windows NT x86",
1401 r->driver_name,
1402 2, &driver);
1403 } else {
1404 DEBUG(0, ("printer_driver_in_use: ERROR!"
1405 " unknown driver version (%d)\n",
1406 r->version));
1407 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1410 /* now check the error code */
1412 if ( W_ERROR_IS_OK(werr) ) {
1413 /* it's ok to remove the driver, we have other architctures left */
1414 in_use = False;
1415 talloc_free(driver);
1419 /* report that the driver is not in use by default */
1421 return in_use;
1425 /**********************************************************************
1426 Check to see if a ogiven file is in use by *info
1427 *********************************************************************/
1429 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1431 int i = 0;
1433 if ( !info )
1434 return False;
1436 /* mz: skip files that are in the list but already deleted */
1437 if (!file || !file[0]) {
1438 return false;
1441 if (strequal(file, info->driver_path))
1442 return True;
1444 if (strequal(file, info->data_file))
1445 return True;
1447 if (strequal(file, info->config_file))
1448 return True;
1450 if (strequal(file, info->help_file))
1451 return True;
1453 /* see of there are any dependent files to examine */
1455 if (!info->dependent_files)
1456 return False;
1458 while (info->dependent_files[i] && *info->dependent_files[i]) {
1459 if (strequal(file, info->dependent_files[i]))
1460 return True;
1461 i++;
1464 return False;
1468 /**********************************************************************
1469 Utility function to remove the dependent file pointed to by the
1470 input parameter from the list
1471 *********************************************************************/
1473 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1476 /* bump everything down a slot */
1478 while (files && files[idx+1]) {
1479 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1480 idx++;
1483 files[idx] = NULL;
1485 return;
1488 /**********************************************************************
1489 Check if any of the files used by src are also used by drv
1490 *********************************************************************/
1492 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1493 struct spoolss_DriverInfo8 *src,
1494 const struct spoolss_DriverInfo8 *drv)
1496 bool in_use = False;
1497 int i = 0;
1499 if ( !src || !drv )
1500 return False;
1502 /* check each file. Remove it from the src structure if it overlaps */
1504 if (drv_file_in_use(src->driver_path, drv)) {
1505 in_use = True;
1506 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1507 src->driver_path = talloc_strdup(mem_ctx, "");
1508 if (!src->driver_path) { return false; }
1511 if (drv_file_in_use(src->data_file, drv)) {
1512 in_use = True;
1513 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1514 src->data_file = talloc_strdup(mem_ctx, "");
1515 if (!src->data_file) { return false; }
1518 if (drv_file_in_use(src->config_file, drv)) {
1519 in_use = True;
1520 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1521 src->config_file = talloc_strdup(mem_ctx, "");
1522 if (!src->config_file) { return false; }
1525 if (drv_file_in_use(src->help_file, drv)) {
1526 in_use = True;
1527 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1528 src->help_file = talloc_strdup(mem_ctx, "");
1529 if (!src->help_file) { return false; }
1532 /* are there any dependentfiles to examine? */
1534 if (!src->dependent_files)
1535 return in_use;
1537 while (src->dependent_files[i] && *src->dependent_files[i]) {
1538 if (drv_file_in_use(src->dependent_files[i], drv)) {
1539 in_use = True;
1540 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1541 trim_dependent_file(mem_ctx, src->dependent_files, i);
1542 } else
1543 i++;
1546 return in_use;
1549 /****************************************************************************
1550 Determine whether or not a particular driver files are currently being
1551 used by any other driver.
1553 Return value is True if any files were in use by other drivers
1554 and False otherwise.
1556 Upon return, *info has been modified to only contain the driver files
1557 which are not in use
1559 Fix from mz:
1561 This needs to check all drivers to ensure that all files in use
1562 have been removed from *info, not just the ones in the first
1563 match.
1564 ****************************************************************************/
1566 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1567 struct dcerpc_binding_handle *b,
1568 struct spoolss_DriverInfo8 *info)
1570 int i;
1571 uint32_t version;
1572 struct spoolss_DriverInfo8 *driver;
1573 bool in_use = false;
1574 uint32_t num_drivers;
1575 const char **drivers;
1576 WERROR result;
1578 if ( !info )
1579 return False;
1581 version = info->version;
1583 /* loop over all driver versions */
1585 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1587 /* get the list of drivers */
1589 result = winreg_get_driver_list(mem_ctx, b,
1590 info->architecture, version,
1591 &num_drivers, &drivers);
1592 if (!W_ERROR_IS_OK(result)) {
1593 return true;
1596 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1597 num_drivers, info->architecture, version));
1599 /* check each driver for overlap in files */
1601 for (i = 0; i < num_drivers; i++) {
1602 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1604 driver = NULL;
1606 result = winreg_get_driver(mem_ctx, b,
1607 info->architecture, drivers[i],
1608 version, &driver);
1609 if (!W_ERROR_IS_OK(result)) {
1610 talloc_free(drivers);
1611 return True;
1614 /* check if d2 uses any files from d1 */
1615 /* only if this is a different driver than the one being deleted */
1617 if (!strequal(info->driver_name, driver->driver_name)) {
1618 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1619 /* mz: Do not instantly return -
1620 * we need to ensure this file isn't
1621 * also in use by other drivers. */
1622 in_use = true;
1626 talloc_free(driver);
1629 talloc_free(drivers);
1631 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1633 return in_use;
1636 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1637 const char *short_arch,
1638 int vers,
1639 const char *fname)
1641 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1642 struct smb_filename *smb_fname = NULL;
1643 char *print_dlr_path;
1644 NTSTATUS status = NT_STATUS_NO_MEMORY;
1646 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1647 short_arch, vers, fname);
1648 if (print_dlr_path == NULL) {
1649 goto err_out;
1652 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL);
1653 if (smb_fname == NULL) {
1654 goto err_out;
1657 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1658 err_out:
1659 talloc_free(tmp_ctx);
1660 return status;
1663 /****************************************************************************
1664 Actually delete the driver files. Make sure that
1665 printer_driver_files_in_use() return False before calling
1666 this.
1667 ****************************************************************************/
1669 bool delete_driver_files(const struct auth_session_info *session_info,
1670 const struct spoolss_DriverInfo8 *r)
1672 const char *short_arch;
1673 connection_struct *conn;
1674 NTSTATUS nt_status;
1675 char *oldcwd;
1676 char *printdollar = NULL;
1677 int printdollar_snum;
1678 bool ret = false;
1680 if (!r) {
1681 return false;
1684 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1685 r->driver_name, r->version));
1687 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1688 if (!printdollar) {
1689 return false;
1691 if (printdollar_snum == -1) {
1692 return false;
1695 nt_status = create_conn_struct_cwd(talloc_tos(),
1696 server_event_context(),
1697 server_messaging_context(),
1698 &conn,
1699 printdollar_snum,
1700 lp_path(talloc_tos(), printdollar_snum),
1701 session_info, &oldcwd);
1702 if (!NT_STATUS_IS_OK(nt_status)) {
1703 DEBUG(0,("delete_driver_files: create_conn_struct "
1704 "returned %s\n", nt_errstr(nt_status)));
1705 return false;
1708 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1709 if (!NT_STATUS_IS_OK(nt_status)) {
1710 DEBUG(0, ("failed set force user / group\n"));
1711 ret = false;
1712 goto err_free_conn;
1715 if (!become_user_by_session(conn, session_info)) {
1716 DEBUG(0, ("failed to become user\n"));
1717 ret = false;
1718 goto err_free_conn;
1721 if ( !CAN_WRITE(conn) ) {
1722 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1723 ret = false;
1724 goto err_out;
1727 short_arch = get_short_archi(r->architecture);
1728 if (short_arch == NULL) {
1729 DEBUG(0, ("bad architecture %s\n", r->architecture));
1730 ret = false;
1731 goto err_out;
1734 /* now delete the files */
1736 if (r->driver_path && r->driver_path[0]) {
1737 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1738 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1741 if (r->config_file && r->config_file[0]) {
1742 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1743 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1746 if (r->data_file && r->data_file[0]) {
1747 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1748 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1751 if (r->help_file && r->help_file[0]) {
1752 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1753 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1756 if (r->dependent_files) {
1757 int i = 0;
1758 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1759 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1760 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1761 i++;
1765 ret = true;
1766 err_out:
1767 unbecome_user();
1768 err_free_conn:
1769 if (conn != NULL) {
1770 vfs_ChDir(conn, oldcwd);
1771 SMB_VFS_DISCONNECT(conn);
1772 conn_free(conn);
1774 return ret;
1777 /* error code:
1778 0: everything OK
1779 1: level not implemented
1780 2: file doesn't exist
1781 3: can't allocate memory
1782 4: can't free memory
1783 5: non existent struct
1787 A printer and a printer driver are 2 different things.
1788 NT manages them separatelly, Samba does the same.
1789 Why ? Simply because it's easier and it makes sense !
1791 Now explanation: You have 3 printers behind your samba server,
1792 2 of them are the same make and model (laser A and B). But laser B
1793 has an 3000 sheet feeder and laser A doesn't such an option.
1794 Your third printer is an old dot-matrix model for the accounting :-).
1796 If the /usr/local/samba/lib directory (default dir), you will have
1797 5 files to describe all of this.
1799 3 files for the printers (1 by printer):
1800 NTprinter_laser A
1801 NTprinter_laser B
1802 NTprinter_accounting
1803 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1804 NTdriver_printer model X
1805 NTdriver_printer model Y
1807 jfm: I should use this comment for the text file to explain
1808 same thing for the forms BTW.
1809 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1813 /* Convert generic access rights to printer object specific access rights.
1814 It turns out that NT4 security descriptors use generic access rights and
1815 NT5 the object specific ones. */
1817 void map_printer_permissions(struct security_descriptor *sd)
1819 int i;
1821 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1822 se_map_generic(&sd->dacl->aces[i].access_mask,
1823 &printer_generic_mapping);
1827 void map_job_permissions(struct security_descriptor *sd)
1829 int i;
1831 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1832 se_map_generic(&sd->dacl->aces[i].access_mask,
1833 &job_generic_mapping);
1838 /****************************************************************************
1839 Check a user has permissions to perform the given operation. We use the
1840 permission constants defined in include/rpc_spoolss.h to check the various
1841 actions we perform when checking printer access.
1843 PRINTER_ACCESS_ADMINISTER:
1844 print_queue_pause, print_queue_resume, update_printer_sec,
1845 update_printer, spoolss_addprinterex_level_2,
1846 _spoolss_setprinterdata
1848 PRINTER_ACCESS_USE:
1849 print_job_start
1851 JOB_ACCESS_ADMINISTER:
1852 print_job_delete, print_job_pause, print_job_resume,
1853 print_queue_purge
1855 Try access control in the following order (for performance reasons):
1856 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1857 2) check security descriptor (bit comparisons in memory)
1858 3) "printer admins" (may result in numerous calls to winbind)
1860 ****************************************************************************/
1861 WERROR print_access_check(const struct auth_session_info *session_info,
1862 struct messaging_context *msg_ctx, int snum,
1863 int access_type)
1865 struct spoolss_security_descriptor *secdesc = NULL;
1866 uint32_t access_granted;
1867 size_t sd_size;
1868 NTSTATUS status;
1869 WERROR result;
1870 const char *pname;
1871 TALLOC_CTX *mem_ctx = NULL;
1873 /* If user is NULL then use the current_user structure */
1875 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1877 if ((session_info->unix_token->uid == sec_initial_uid())
1878 || security_token_has_privilege(session_info->security_token,
1879 SEC_PRIV_PRINT_OPERATOR)) {
1880 return WERR_OK;
1883 /* Get printer name */
1885 pname = lp_printername(talloc_tos(), snum);
1887 if (!pname || !*pname) {
1888 return WERR_ACCESS_DENIED;
1891 /* Get printer security descriptor */
1893 if(!(mem_ctx = talloc_init("print_access_check"))) {
1894 return WERR_NOMEM;
1897 result = winreg_get_printer_secdesc_internal(mem_ctx,
1898 get_session_info_system(),
1899 msg_ctx,
1900 pname,
1901 &secdesc);
1902 if (!W_ERROR_IS_OK(result)) {
1903 talloc_destroy(mem_ctx);
1904 return WERR_NOMEM;
1907 if (access_type == JOB_ACCESS_ADMINISTER) {
1908 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1910 /* Create a child security descriptor to check permissions
1911 against. This is because print jobs are child objects
1912 objects of a printer. */
1913 status = se_create_child_secdesc(mem_ctx,
1914 &secdesc,
1915 &sd_size,
1916 parent_secdesc,
1917 parent_secdesc->owner_sid,
1918 parent_secdesc->group_sid,
1919 false);
1920 if (!NT_STATUS_IS_OK(status)) {
1921 talloc_destroy(mem_ctx);
1922 return ntstatus_to_werror(status);
1925 map_job_permissions(secdesc);
1926 } else {
1927 map_printer_permissions(secdesc);
1930 /* Check access */
1931 status = se_access_check(secdesc, session_info->security_token, access_type,
1932 &access_granted);
1934 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1936 talloc_destroy(mem_ctx);
1938 return ntstatus_to_werror(status);
1941 /****************************************************************************
1942 Check the time parameters allow a print operation.
1943 *****************************************************************************/
1945 bool print_time_access_check(const struct auth_session_info *session_info,
1946 struct messaging_context *msg_ctx,
1947 const char *servicename)
1949 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1950 WERROR result;
1951 bool ok = False;
1952 time_t now = time(NULL);
1953 struct tm *t;
1954 uint32_t mins;
1956 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1957 servicename, &pinfo2);
1958 if (!W_ERROR_IS_OK(result)) {
1959 return False;
1962 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1963 ok = True;
1966 t = gmtime(&now);
1967 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
1969 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1970 ok = True;
1973 TALLOC_FREE(pinfo2);
1975 if (!ok) {
1976 errno = EACCES;
1979 return ok;
1982 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1983 const struct auth_session_info *session_info,
1984 struct messaging_context *msg_ctx,
1985 const char *printer)
1987 WERROR result;
1989 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1990 printer, "");
1991 if (!W_ERROR_IS_OK(result)) {
1992 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1993 "%s\n", printer, win_errstr(result)));
1997 void nt_printer_add(TALLOC_CTX *mem_ctx,
1998 const struct auth_session_info *session_info,
1999 struct messaging_context *msg_ctx,
2000 const char *printer)
2002 WERROR result;
2004 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2005 printer);
2006 if (!W_ERROR_IS_OK(result)) {
2007 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2008 printer, win_errstr(result)));