s3:printing: Fix size check in get_file_version()
[Samba.git] / source3 / printing / nt_printing.c
blob241af37743ef9b1f0ecb59239743938bbf11f982
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();
83 const char *dir_list[] = {
84 "W32X86/PCC",
85 "x64/PCC",
86 "color"
89 service = lp_servicenumber("print$");
90 if (service < 0) {
91 /* We don't have a print$ share */
92 DEBUG(5, ("No print$ share has been configured.\n"));
93 talloc_free(mem_ctx);
94 return true;
97 driver_path = lp_path(mem_ctx, service);
98 if (driver_path == NULL) {
99 talloc_free(mem_ctx);
100 return false;
103 ok = directory_create_or_exist(driver_path, 0755);
104 if (!ok) {
105 DEBUG(1, ("Failed to create printer driver directory %s\n",
106 driver_path));
107 talloc_free(mem_ctx);
108 return false;
111 for (i = 0; archi_table[i].long_archi != NULL; i++) {
112 const char *arch_path;
114 arch_path = talloc_asprintf(mem_ctx,
115 "%s/%s",
116 driver_path,
117 archi_table[i].short_archi);
118 if (arch_path == NULL) {
119 talloc_free(mem_ctx);
120 return false;
123 ok = directory_create_or_exist(arch_path, 0755);
124 if (!ok) {
125 DEBUG(1, ("Failed to create printer driver "
126 "architecture directory %s\n",
127 arch_path));
128 talloc_free(mem_ctx);
129 return false;
133 for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
134 const char *path;
136 path = talloc_asprintf(mem_ctx,
137 "%s/%s",
138 driver_path,
139 dir_list[i]);
140 if (path == NULL) {
141 talloc_free(mem_ctx);
142 return false;
145 ok = directory_create_or_exist(path, 0755);
146 if (!ok) {
147 DEBUG(1, ("Failed to create printer driver "
148 "architecture directory %s\n",
149 path));
150 talloc_free(mem_ctx);
151 return false;
155 driver_path = state_path("DriverStore");
156 if (driver_path == NULL) {
157 talloc_free(mem_ctx);
158 return false;
161 ok = directory_create_or_exist(driver_path, 0755);
162 if (!ok) {
163 DEBUG(1,("failed to create path %s\n", driver_path));
164 talloc_free(mem_ctx);
165 return false;
168 driver_path = state_path("DriverStore/FileRepository");
169 if (driver_path == NULL) {
170 talloc_free(mem_ctx);
171 return false;
174 ok = directory_create_or_exist(driver_path, 0755);
175 if (!ok) {
176 DEBUG(1,("failed to create path %s\n", driver_path));
177 talloc_free(mem_ctx);
178 return false;
181 driver_path = state_path("DriverStore/Temp");
182 if (driver_path == NULL) {
183 talloc_free(mem_ctx);
184 return false;
187 ok = directory_create_or_exist(driver_path, 0755);
188 if (!ok) {
189 DEBUG(1,("failed to create path %s\n", driver_path));
190 talloc_free(mem_ctx);
191 return false;
194 talloc_free(mem_ctx);
195 return true;
198 /****************************************************************************
199 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
200 background lpq updater.
201 ****************************************************************************/
203 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
204 void *private_data,
205 uint32_t msg_type,
206 struct server_id server_id,
207 DATA_BLOB *data)
209 extern pid_t background_lpq_updater_pid;
211 if (background_lpq_updater_pid == -1) {
212 DEBUG(3,("no background lpq queue updater\n"));
213 return;
216 messaging_send_buf(msg,
217 pid_to_procid(background_lpq_updater_pid),
218 MSG_PRINTER_DRVUPGRADE,
219 data->data,
220 data->length);
223 /****************************************************************************
224 Open the NT printing tdbs. Done once before fork().
225 ****************************************************************************/
227 bool nt_printing_init(struct messaging_context *msg_ctx)
229 WERROR win_rc;
231 if (!print_driver_directories_init()) {
232 return false;
235 if (!nt_printing_tdb_upgrade()) {
236 return false;
240 * register callback to handle updating printers as new
241 * drivers are installed. Forwards to background lpq updater.
243 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
244 forward_drv_upgrade_printer_msg);
246 if ( lp_security() == SEC_ADS ) {
247 win_rc = check_published_printers(msg_ctx);
248 if (!W_ERROR_IS_OK(win_rc))
249 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
252 return true;
255 /*******************************************************************
256 Function to allow filename parsing "the old way".
257 ********************************************************************/
259 static NTSTATUS driver_unix_convert(connection_struct *conn,
260 const char *old_name,
261 struct smb_filename **smb_fname)
263 NTSTATUS status;
264 TALLOC_CTX *ctx = talloc_tos();
265 char *name = talloc_strdup(ctx, old_name);
267 if (!name) {
268 return NT_STATUS_NO_MEMORY;
270 unix_format(name);
271 name = unix_clean_name(ctx, name);
272 if (!name) {
273 return NT_STATUS_NO_MEMORY;
275 trim_string(name,"/","/");
277 status = unix_convert(ctx, conn, name, smb_fname, 0);
278 if (!NT_STATUS_IS_OK(status)) {
279 return NT_STATUS_NO_MEMORY;
282 return NT_STATUS_OK;
285 /****************************************************************************
286 Function to do the mapping between the long architecture name and
287 the short one.
288 ****************************************************************************/
290 const char *get_short_archi(const char *long_archi)
292 int i=-1;
294 DEBUG(107,("Getting architecture dependent directory\n"));
295 do {
296 i++;
297 } while ( (archi_table[i].long_archi!=NULL ) &&
298 strcasecmp_m(long_archi, archi_table[i].long_archi) );
300 if (archi_table[i].long_archi==NULL) {
301 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
302 return NULL;
305 /* this might be client code - but shouldn't this be an fstrcpy etc? */
307 DEBUGADD(108,("index: [%d]\n", i));
308 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
309 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
311 return archi_table[i].short_archi;
314 /****************************************************************************
315 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
316 There are two case to be covered here: PE (Portable Executable) and NE (New
317 Executable) files. Both files support the same INFO structure, but PE files
318 store the signature in unicode, and NE files store it as !unicode.
319 returns -1 on error, 1 on version info found, and 0 on no version info found.
320 ****************************************************************************/
322 static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint32_t *minor)
324 int i;
325 char *buf = NULL;
326 ssize_t byte_count;
328 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
329 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
330 fname, DOS_HEADER_SIZE));
331 goto error_exit;
334 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
335 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
336 fname, (unsigned long)byte_count));
337 goto no_version_info;
340 /* Is this really a DOS header? */
341 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
342 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
343 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
344 goto no_version_info;
347 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
348 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
349 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
350 fname, errno));
351 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
352 goto no_version_info;
355 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
356 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
357 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
358 fname, (unsigned long)byte_count));
359 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
360 goto no_version_info;
363 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
364 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
365 unsigned int num_sections;
366 unsigned int section_table_bytes;
368 /* Just skip over optional header to get to section table */
369 if (SMB_VFS_LSEEK(fsp,
370 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
371 SEEK_CUR) == (off_t)-1) {
372 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
373 fname, errno));
374 goto error_exit;
377 /* get the section table */
378 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
379 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
380 if (section_table_bytes == 0)
381 goto error_exit;
383 SAFE_FREE(buf);
384 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
385 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
386 fname, section_table_bytes));
387 goto error_exit;
390 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
391 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
392 fname, (unsigned long)byte_count));
393 goto error_exit;
396 /* Iterate the section table looking for the resource section ".rsrc" */
397 for (i = 0; i < num_sections; i++) {
398 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
400 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
401 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
402 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
404 if (section_bytes == 0)
405 goto error_exit;
407 SAFE_FREE(buf);
408 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
409 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
410 fname, section_bytes));
411 goto error_exit;
414 /* Seek to the start of the .rsrc section info */
415 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
416 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
417 fname, errno));
418 goto error_exit;
421 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
422 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
423 fname, (unsigned long)byte_count));
424 goto error_exit;
427 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
428 goto error_exit;
430 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
431 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
432 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
433 /* Align to next long address */
434 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
436 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
437 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
438 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
440 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
441 fname, *major, *minor,
442 (*major>>16)&0xffff, *major&0xffff,
443 (*minor>>16)&0xffff, *minor&0xffff));
444 SAFE_FREE(buf);
445 return 1;
452 /* Version info not found, fall back to origin date/time */
453 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
454 SAFE_FREE(buf);
455 return 0;
457 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
458 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
459 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
460 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
461 /* At this point, we assume the file is in error. It still could be something
462 * else besides a NE file, but it unlikely at this point. */
463 goto error_exit;
466 /* Allocate a bit more space to speed up things */
467 SAFE_FREE(buf);
468 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
469 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
470 fname, PE_HEADER_SIZE));
471 goto error_exit;
474 /* This is a HACK! I got tired of trying to sort through the messy
475 * 'NE' file format. If anyone wants to clean this up please have at
476 * it, but this works. 'NE' files will eventually fade away. JRR */
477 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
478 /* Cover case that should not occur in a well formed 'NE' .dll file */
479 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
481 for(i=0; i<byte_count; i++) {
482 /* Fast skip past data that can't possibly match */
483 if (buf[i] != 'V') continue;
485 /* Potential match data crosses buf boundry, move it to beginning
486 * of buf, and fill the buf with as much as it will hold. */
487 if (i>byte_count-VS_VERSION_INFO_SIZE) {
488 ssize_t amount_read;
489 ssize_t amount_unused = byte_count-i;
491 memmove(buf, &buf[i], amount_unused);
492 amount_read = vfs_read_data(fsp,
493 &buf[amount_unused],
494 VS_NE_BUF_SIZE- amount_unused);
495 if (amount_read < 0) {
497 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
498 fname, errno));
499 goto error_exit;
502 if (amount_read + amount_unused <
503 amount_read) {
504 /* Check for integer wrap. */
505 break;
508 byte_count = amount_read +
509 amount_unused;
510 if (byte_count < VS_VERSION_INFO_SIZE) {
511 break;
514 i = 0;
517 /* Check that the full signature string and the magic number that
518 * follows exist (not a perfect solution, but the chances that this
519 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
520 * twice, as it is simpler to read the code. */
521 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
522 /* Compute skip alignment to next long address */
523 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
524 sizeof(VS_SIGNATURE)) & 3;
525 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
527 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
528 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
529 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
530 fname, *major, *minor,
531 (*major>>16)&0xffff, *major&0xffff,
532 (*minor>>16)&0xffff, *minor&0xffff));
533 SAFE_FREE(buf);
534 return 1;
539 /* Version info not found, fall back to origin date/time */
540 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
541 SAFE_FREE(buf);
542 return 0;
544 } else
545 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
546 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
547 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
549 no_version_info:
550 SAFE_FREE(buf);
551 return 0;
553 error_exit:
554 SAFE_FREE(buf);
555 return -1;
558 /****************************************************************************
559 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
560 share one or more files. During the MS installation process files are checked
561 to insure that only a newer version of a shared file is installed over an
562 older version. There are several possibilities for this comparison. If there
563 is no previous version, the new one is newer (obviously). If either file is
564 missing the version info structure, compare the creation date (on Unix use
565 the modification date). Otherwise chose the numerically larger version number.
566 ****************************************************************************/
568 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
570 bool use_version = true;
572 uint32_t new_major;
573 uint32_t new_minor;
574 time_t new_create_time;
576 uint32_t old_major;
577 uint32_t old_minor;
578 time_t old_create_time;
580 struct smb_filename *smb_fname = NULL;
581 files_struct *fsp = NULL;
582 SMB_STRUCT_STAT st;
584 NTSTATUS status;
585 int ret;
587 SET_STAT_INVALID(st);
588 new_create_time = (time_t)0;
589 old_create_time = (time_t)0;
591 /* Get file version info (if available) for previous file (if it exists) */
592 status = driver_unix_convert(conn, old_file, &smb_fname);
593 if (!NT_STATUS_IS_OK(status)) {
594 goto error_exit;
597 status = SMB_VFS_CREATE_FILE(
598 conn, /* conn */
599 NULL, /* req */
600 0, /* root_dir_fid */
601 smb_fname, /* fname */
602 FILE_GENERIC_READ, /* access_mask */
603 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
604 FILE_OPEN, /* create_disposition*/
605 0, /* create_options */
606 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
607 INTERNAL_OPEN_ONLY, /* oplock_request */
608 NULL, /* lease */
609 0, /* allocation_size */
610 0, /* private_flags */
611 NULL, /* sd */
612 NULL, /* ea_list */
613 &fsp, /* result */
614 NULL, /* pinfo */
615 NULL, NULL); /* create context */
617 if (!NT_STATUS_IS_OK(status)) {
618 /* Old file not found, so by definition new file is in fact newer */
619 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
620 "errno = %d\n", smb_fname_str_dbg(smb_fname),
621 errno));
622 ret = 1;
623 goto done;
625 } else {
626 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
627 if (ret == -1) {
628 goto error_exit;
631 if (!ret) {
632 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
633 old_file));
634 use_version = false;
635 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
636 goto error_exit;
638 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
639 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
640 (long)old_create_time));
643 close_file(NULL, fsp, NORMAL_CLOSE);
644 fsp = NULL;
646 /* Get file version info (if available) for new file */
647 status = driver_unix_convert(conn, new_file, &smb_fname);
648 if (!NT_STATUS_IS_OK(status)) {
649 goto error_exit;
652 status = SMB_VFS_CREATE_FILE(
653 conn, /* conn */
654 NULL, /* req */
655 0, /* root_dir_fid */
656 smb_fname, /* fname */
657 FILE_GENERIC_READ, /* access_mask */
658 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
659 FILE_OPEN, /* create_disposition*/
660 0, /* create_options */
661 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
662 INTERNAL_OPEN_ONLY, /* oplock_request */
663 NULL, /* lease */
664 0, /* allocation_size */
665 0, /* private_flags */
666 NULL, /* sd */
667 NULL, /* ea_list */
668 &fsp, /* result */
669 NULL, /* pinfo */
670 NULL, NULL); /* create context */
672 if (!NT_STATUS_IS_OK(status)) {
673 /* New file not found, this shouldn't occur if the caller did its job */
674 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
675 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
676 goto error_exit;
678 } else {
679 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
680 if (ret == -1) {
681 goto error_exit;
684 if (!ret) {
685 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
686 new_file));
687 use_version = false;
688 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
689 goto error_exit;
691 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
692 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
693 (long)new_create_time));
696 close_file(NULL, fsp, NORMAL_CLOSE);
697 fsp = NULL;
699 if (use_version && (new_major != old_major || new_minor != old_minor)) {
700 /* Compare versions and choose the larger version number */
701 if (new_major > old_major ||
702 (new_major == old_major && new_minor > old_minor)) {
704 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
705 ret = 1;
706 goto done;
708 else {
709 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
710 ret = 0;
711 goto done;
714 } else {
715 /* Compare modification time/dates and choose the newest time/date */
716 if (new_create_time > old_create_time) {
717 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
718 ret = 1;
719 goto done;
721 else {
722 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
723 ret = 0;
724 goto done;
728 error_exit:
729 if(fsp)
730 close_file(NULL, fsp, NORMAL_CLOSE);
731 ret = -1;
732 done:
733 TALLOC_FREE(smb_fname);
734 return ret;
737 /****************************************************************************
738 Determine the correct cVersion associated with an architecture and driver
739 ****************************************************************************/
740 static uint32_t get_correct_cversion(struct auth_session_info *session_info,
741 const char *architecture,
742 const char *driverpath_in,
743 const char *driver_directory,
744 WERROR *perr)
746 int cversion = -1;
747 NTSTATUS nt_status;
748 struct smb_filename *smb_fname = NULL;
749 files_struct *fsp = NULL;
750 connection_struct *conn = NULL;
751 struct smb_filename *oldcwd_fname = NULL;
752 char *printdollar = NULL;
753 char *printdollar_path = NULL;
754 char *working_dir = NULL;
755 int printdollar_snum;
757 *perr = WERR_INVALID_PARAMETER;
759 /* If architecture is Windows 95/98/ME, the version is always 0. */
760 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
761 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
762 *perr = WERR_OK;
763 return 0;
766 /* If architecture is Windows x64, the version is always 3. */
767 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
768 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
769 *perr = WERR_OK;
770 return 3;
773 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
774 if (!printdollar) {
775 *perr = WERR_NOT_ENOUGH_MEMORY;
776 return -1;
778 if (printdollar_snum == -1) {
779 *perr = WERR_BAD_NET_NAME;
780 return -1;
783 printdollar_path = lp_path(talloc_tos(), printdollar_snum);
784 if (printdollar_path == NULL) {
785 *perr = WERR_NOT_ENOUGH_MEMORY;
786 return -1;
789 working_dir = talloc_asprintf(talloc_tos(),
790 "%s/%s",
791 printdollar_path,
792 architecture);
794 * If the driver has been uploaded into a temorpary driver
795 * directory, switch to the driver directory.
797 if (driver_directory != NULL) {
798 working_dir = talloc_asprintf(talloc_tos(), "%s/%s/%s",
799 printdollar_path,
800 architecture,
801 driver_directory);
804 nt_status = create_conn_struct_cwd(talloc_tos(),
805 server_event_context(),
806 server_messaging_context(),
807 &conn,
808 printdollar_snum,
809 working_dir,
810 session_info, &oldcwd_fname);
811 if (!NT_STATUS_IS_OK(nt_status)) {
812 DEBUG(0,("get_correct_cversion: create_conn_struct "
813 "returned %s\n", nt_errstr(nt_status)));
814 *perr = ntstatus_to_werror(nt_status);
815 return -1;
818 nt_status = set_conn_force_user_group(conn, printdollar_snum);
819 if (!NT_STATUS_IS_OK(nt_status)) {
820 DEBUG(0, ("failed set force user / group\n"));
821 *perr = ntstatus_to_werror(nt_status);
822 goto error_free_conn;
825 if (!become_user_by_session(conn, session_info)) {
826 DEBUG(0, ("failed to become user\n"));
827 *perr = WERR_ACCESS_DENIED;
828 goto error_free_conn;
832 * We switch to the directory where the driver files are located,
833 * so only work on the file names
835 nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
836 if (!NT_STATUS_IS_OK(nt_status)) {
837 *perr = ntstatus_to_werror(nt_status);
838 goto error_exit;
841 nt_status = vfs_file_exist(conn, smb_fname);
842 if (!NT_STATUS_IS_OK(nt_status)) {
843 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
844 *perr = WERR_FILE_NOT_FOUND;
845 goto error_exit;
848 nt_status = SMB_VFS_CREATE_FILE(
849 conn, /* conn */
850 NULL, /* req */
851 0, /* root_dir_fid */
852 smb_fname, /* fname */
853 FILE_GENERIC_READ, /* access_mask */
854 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
855 FILE_OPEN, /* create_disposition*/
856 0, /* create_options */
857 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
858 INTERNAL_OPEN_ONLY, /* oplock_request */
859 NULL, /* lease */
860 0, /* private_flags */
861 0, /* allocation_size */
862 NULL, /* sd */
863 NULL, /* ea_list */
864 &fsp, /* result */
865 NULL, /* pinfo */
866 NULL, NULL); /* create context */
868 if (!NT_STATUS_IS_OK(nt_status)) {
869 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
870 "%d\n", smb_fname_str_dbg(smb_fname), errno));
871 *perr = WERR_ACCESS_DENIED;
872 goto error_exit;
873 } else {
874 uint32_t major;
875 uint32_t minor;
876 int ret;
878 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
879 if (ret == -1) {
880 *perr = WERR_INVALID_PARAMETER;
881 goto error_exit;
882 } else if (!ret) {
883 DEBUG(6,("get_correct_cversion: Version info not "
884 "found [%s]\n",
885 smb_fname_str_dbg(smb_fname)));
886 *perr = WERR_INVALID_PARAMETER;
887 goto error_exit;
891 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
892 * for more details. Version in this case is not just the version of the
893 * file, but the version in the sense of kernal mode (2) vs. user mode
894 * (3) drivers. Other bits of the version fields are the version info.
895 * JRR 010716
897 cversion = major & 0x0000ffff;
898 switch (cversion) {
899 case 2: /* WinNT drivers */
900 case 3: /* Win2K drivers */
901 break;
903 default:
904 DEBUG(6,("get_correct_cversion: cversion "
905 "invalid [%s] cversion = %d\n",
906 smb_fname_str_dbg(smb_fname),
907 cversion));
908 goto error_exit;
911 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
912 " = 0x%x minor = 0x%x\n",
913 smb_fname_str_dbg(smb_fname), major, minor));
916 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
917 smb_fname_str_dbg(smb_fname), cversion));
918 *perr = WERR_OK;
920 error_exit:
921 unbecome_user();
922 error_free_conn:
923 TALLOC_FREE(smb_fname);
924 if (fsp != NULL) {
925 close_file(NULL, fsp, NORMAL_CLOSE);
927 if (conn != NULL) {
928 vfs_ChDir(conn, oldcwd_fname);
929 TALLOC_FREE(oldcwd_fname);
930 SMB_VFS_DISCONNECT(conn);
931 conn_free(conn);
933 if (!W_ERROR_IS_OK(*perr)) {
934 cversion = -1;
937 return cversion;
940 /****************************************************************************
941 ****************************************************************************/
943 #define strip_driver_path(_mem_ctx, _element) do { \
944 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
945 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
946 W_ERROR_HAVE_NO_MEMORY((_element)); \
948 } while (0);
950 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
951 struct auth_session_info *session_info,
952 const char *architecture,
953 const char **driver_path,
954 const char **data_file,
955 const char **config_file,
956 const char **help_file,
957 struct spoolss_StringArray *dependent_files,
958 enum spoolss_DriverOSVersion *version,
959 uint32_t flags,
960 const char **driver_directory)
962 const char *short_architecture;
963 int i;
964 WERROR err;
965 char *_p;
967 if (!*driver_path || !*data_file) {
968 return WERR_INVALID_PARAMETER;
971 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
972 return WERR_INVALID_PARAMETER;
975 if (flags & APD_COPY_FROM_DIRECTORY) {
976 char *path;
977 char *q;
980 * driver_path is set to:
982 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
984 path = talloc_strdup(mem_ctx, *driver_path);
985 if (path == NULL) {
986 return WERR_NOT_ENOUGH_MEMORY;
989 /* Remove pscript5.dll */
990 q = strrchr_m(path, '\\');
991 if (q == NULL) {
992 return WERR_INVALID_PARAMETER;
994 *q = '\0';
996 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
997 q = strrchr_m(path, '\\');
998 if (q == NULL) {
999 return WERR_INVALID_PARAMETER;
1003 * Set driver_directory to:
1005 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1007 * This is the directory where all the files have been uploaded
1009 *driver_directory = q + 1;
1012 /* clean up the driver name.
1013 * we can get .\driver.dll
1014 * or worse c:\windows\system\driver.dll !
1016 /* using an intermediate string to not have overlaping memcpy()'s */
1018 strip_driver_path(mem_ctx, *driver_path);
1019 strip_driver_path(mem_ctx, *data_file);
1020 if (*config_file) {
1021 strip_driver_path(mem_ctx, *config_file);
1023 if (help_file) {
1024 strip_driver_path(mem_ctx, *help_file);
1027 if (dependent_files && dependent_files->string) {
1028 for (i=0; dependent_files->string[i]; i++) {
1029 strip_driver_path(mem_ctx, dependent_files->string[i]);
1033 short_architecture = get_short_archi(architecture);
1034 if (!short_architecture) {
1035 return WERR_UNKNOWN_PRINTER_DRIVER;
1038 /* jfm:7/16/2000 the client always sends the cversion=0.
1039 * The server should check which version the driver is by reading
1040 * the PE header of driver->driverpath.
1042 * For Windows 95/98 the version is 0 (so the value sent is correct)
1043 * For Windows NT (the architecture doesn't matter)
1044 * NT 3.1: cversion=0
1045 * NT 3.5/3.51: cversion=1
1046 * NT 4: cversion=2
1047 * NT2K: cversion=3
1050 *version = get_correct_cversion(session_info,
1051 short_architecture,
1052 *driver_path,
1053 *driver_directory,
1054 &err);
1055 if (*version == -1) {
1056 return err;
1059 return WERR_OK;
1062 /****************************************************************************
1063 ****************************************************************************/
1065 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1066 struct auth_session_info *session_info,
1067 struct spoolss_AddDriverInfoCtr *r,
1068 uint32_t flags,
1069 const char **driver_directory)
1071 switch (r->level) {
1072 case 3:
1073 return clean_up_driver_struct_level(mem_ctx, session_info,
1074 r->info.info3->architecture,
1075 &r->info.info3->driver_path,
1076 &r->info.info3->data_file,
1077 &r->info.info3->config_file,
1078 &r->info.info3->help_file,
1079 r->info.info3->dependent_files,
1080 &r->info.info3->version,
1081 flags,
1082 driver_directory);
1083 case 6:
1084 return clean_up_driver_struct_level(mem_ctx, session_info,
1085 r->info.info6->architecture,
1086 &r->info.info6->driver_path,
1087 &r->info.info6->data_file,
1088 &r->info.info6->config_file,
1089 &r->info.info6->help_file,
1090 r->info.info6->dependent_files,
1091 &r->info.info6->version,
1092 flags,
1093 driver_directory);
1094 case 8:
1095 return clean_up_driver_struct_level(mem_ctx, session_info,
1096 r->info.info8->architecture,
1097 &r->info.info8->driver_path,
1098 &r->info.info8->data_file,
1099 &r->info.info8->config_file,
1100 &r->info.info8->help_file,
1101 r->info.info8->dependent_files,
1102 &r->info.info8->version,
1103 flags,
1104 driver_directory);
1105 default:
1106 return WERR_NOT_SUPPORTED;
1110 /****************************************************************************
1111 This function sucks and should be replaced. JRA.
1112 ****************************************************************************/
1114 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1115 const struct spoolss_AddDriverInfo6 *src)
1117 dst->version = src->version;
1119 dst->driver_name = src->driver_name;
1120 dst->architecture = src->architecture;
1121 dst->driver_path = src->driver_path;
1122 dst->data_file = src->data_file;
1123 dst->config_file = src->config_file;
1124 dst->help_file = src->help_file;
1125 dst->monitor_name = src->monitor_name;
1126 dst->default_datatype = src->default_datatype;
1127 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1128 dst->dependent_files = src->dependent_files;
1131 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1132 const struct spoolss_AddDriverInfo8 *src)
1134 dst->version = src->version;
1136 dst->driver_name = src->driver_name;
1137 dst->architecture = src->architecture;
1138 dst->driver_path = src->driver_path;
1139 dst->data_file = src->data_file;
1140 dst->config_file = src->config_file;
1141 dst->help_file = src->help_file;
1142 dst->monitor_name = src->monitor_name;
1143 dst->default_datatype = src->default_datatype;
1144 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1145 dst->dependent_files = src->dependent_files;
1148 /****************************************************************************
1149 ****************************************************************************/
1151 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1152 connection_struct *conn,
1153 const char *driver_file,
1154 const char *short_architecture,
1155 uint32_t driver_version,
1156 uint32_t version,
1157 const char *driver_directory)
1159 struct smb_filename *smb_fname_old = NULL;
1160 struct smb_filename *smb_fname_new = NULL;
1161 char *old_name = NULL;
1162 char *new_name = NULL;
1163 NTSTATUS status;
1164 WERROR ret;
1166 if (driver_directory != NULL) {
1167 old_name = talloc_asprintf(mem_ctx,
1168 "%s/%s/%s",
1169 short_architecture,
1170 driver_directory,
1171 driver_file);
1172 } else {
1173 old_name = talloc_asprintf(mem_ctx,
1174 "%s/%s",
1175 short_architecture,
1176 driver_file);
1178 if (old_name == NULL) {
1179 return WERR_NOT_ENOUGH_MEMORY;
1182 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1183 short_architecture, driver_version, driver_file);
1184 if (new_name == NULL) {
1185 TALLOC_FREE(old_name);
1186 return WERR_NOT_ENOUGH_MEMORY;
1189 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1191 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1192 if (!NT_STATUS_IS_OK(status)) {
1193 ret = WERR_NOT_ENOUGH_MEMORY;
1194 goto out;
1197 /* Setup a synthetic smb_filename struct */
1198 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1199 if (!smb_fname_new) {
1200 ret = WERR_NOT_ENOUGH_MEMORY;
1201 goto out;
1204 smb_fname_new->base_name = new_name;
1206 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1207 "'%s'\n", smb_fname_old->base_name,
1208 smb_fname_new->base_name));
1210 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1211 OPENX_FILE_EXISTS_TRUNCATE |
1212 OPENX_FILE_CREATE_IF_NOT_EXIST,
1213 0, false);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DEBUG(0,("move_driver_file_to_download_area: Unable "
1217 "to rename [%s] to [%s]: %s\n",
1218 smb_fname_old->base_name, new_name,
1219 nt_errstr(status)));
1220 ret = WERR_ACCESS_DENIED;
1221 goto out;
1225 ret = WERR_OK;
1226 out:
1227 TALLOC_FREE(smb_fname_old);
1228 TALLOC_FREE(smb_fname_new);
1229 return ret;
1232 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1233 struct spoolss_AddDriverInfoCtr *r,
1234 const char *driver_directory)
1236 struct spoolss_AddDriverInfo3 *driver;
1237 struct spoolss_AddDriverInfo3 converted_driver;
1238 const char *short_architecture;
1239 struct smb_filename *smb_dname = NULL;
1240 char *new_dir = NULL;
1241 connection_struct *conn = NULL;
1242 NTSTATUS nt_status;
1243 int i;
1244 TALLOC_CTX *ctx = talloc_tos();
1245 int ver = 0;
1246 struct smb_filename *oldcwd_fname = NULL;
1247 char *printdollar = NULL;
1248 int printdollar_snum;
1249 WERROR err = WERR_OK;
1251 switch (r->level) {
1252 case 3:
1253 driver = r->info.info3;
1254 break;
1255 case 6:
1256 convert_level_6_to_level3(&converted_driver, r->info.info6);
1257 driver = &converted_driver;
1258 break;
1259 case 8:
1260 convert_level_8_to_level3(&converted_driver, r->info.info8);
1261 driver = &converted_driver;
1262 break;
1263 default:
1264 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1265 return WERR_INVALID_LEVEL;
1268 short_architecture = get_short_archi(driver->architecture);
1269 if (!short_architecture) {
1270 return WERR_UNKNOWN_PRINTER_DRIVER;
1273 printdollar_snum = find_service(ctx, "print$", &printdollar);
1274 if (!printdollar) {
1275 return WERR_NOT_ENOUGH_MEMORY;
1277 if (printdollar_snum == -1) {
1278 return WERR_BAD_NET_NAME;
1281 nt_status = create_conn_struct_cwd(talloc_tos(),
1282 server_event_context(),
1283 server_messaging_context(),
1284 &conn,
1285 printdollar_snum,
1286 lp_path(talloc_tos(), printdollar_snum),
1287 session_info, &oldcwd_fname);
1288 if (!NT_STATUS_IS_OK(nt_status)) {
1289 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1290 "returned %s\n", nt_errstr(nt_status)));
1291 err = ntstatus_to_werror(nt_status);
1292 return err;
1295 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1296 if (!NT_STATUS_IS_OK(nt_status)) {
1297 DEBUG(0, ("failed set force user / group\n"));
1298 err = ntstatus_to_werror(nt_status);
1299 goto err_free_conn;
1302 if (!become_user_by_session(conn, session_info)) {
1303 DEBUG(0, ("failed to become user\n"));
1304 err = WERR_ACCESS_DENIED;
1305 goto err_free_conn;
1308 new_dir = talloc_asprintf(ctx,
1309 "%s/%d",
1310 short_architecture,
1311 driver->version);
1312 if (!new_dir) {
1313 err = WERR_NOT_ENOUGH_MEMORY;
1314 goto err_exit;
1316 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1317 if (!NT_STATUS_IS_OK(nt_status)) {
1318 err = WERR_NOT_ENOUGH_MEMORY;
1319 goto err_exit;
1322 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1324 nt_status = create_directory(conn, NULL, smb_dname);
1325 if (!NT_STATUS_IS_OK(nt_status)
1326 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1327 DEBUG(0, ("failed to create driver destination directory: %s\n",
1328 nt_errstr(nt_status)));
1329 err = ntstatus_to_werror(nt_status);
1330 goto err_exit;
1333 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1334 * listed for this driver which has already been moved, skip it (note:
1335 * drivers may list the same file name several times. Then check if the
1336 * file already exists in archi\version\, if so, check that the version
1337 * info (or time stamps if version info is unavailable) is newer (or the
1338 * date is later). If it is, move it to archi\version\filexxx.yyy.
1339 * Otherwise, delete the file.
1341 * If a file is not moved to archi\version\ because of an error, all the
1342 * rest of the 'unmoved' driver files are removed from archi\. If one or
1343 * more of the driver's files was already moved to archi\version\, it
1344 * potentially leaves the driver in a partially updated state. Version
1345 * trauma will most likely occur if an client attempts to use any printer
1346 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1347 * done is appropriate... later JRR
1350 DEBUG(5,("Moving files now !\n"));
1352 if (driver->driver_path && strlen(driver->driver_path)) {
1354 err = move_driver_file_to_download_area(ctx,
1355 conn,
1356 driver->driver_path,
1357 short_architecture,
1358 driver->version,
1359 ver,
1360 driver_directory);
1361 if (!W_ERROR_IS_OK(err)) {
1362 goto err_exit;
1366 if (driver->data_file && strlen(driver->data_file)) {
1367 if (!strequal(driver->data_file, driver->driver_path)) {
1369 err = move_driver_file_to_download_area(ctx,
1370 conn,
1371 driver->data_file,
1372 short_architecture,
1373 driver->version,
1374 ver,
1375 driver_directory);
1376 if (!W_ERROR_IS_OK(err)) {
1377 goto err_exit;
1382 if (driver->config_file && strlen(driver->config_file)) {
1383 if (!strequal(driver->config_file, driver->driver_path) &&
1384 !strequal(driver->config_file, driver->data_file)) {
1386 err = move_driver_file_to_download_area(ctx,
1387 conn,
1388 driver->config_file,
1389 short_architecture,
1390 driver->version,
1391 ver,
1392 driver_directory);
1393 if (!W_ERROR_IS_OK(err)) {
1394 goto err_exit;
1399 if (driver->help_file && strlen(driver->help_file)) {
1400 if (!strequal(driver->help_file, driver->driver_path) &&
1401 !strequal(driver->help_file, driver->data_file) &&
1402 !strequal(driver->help_file, driver->config_file)) {
1404 err = move_driver_file_to_download_area(ctx,
1405 conn,
1406 driver->help_file,
1407 short_architecture,
1408 driver->version,
1409 ver,
1410 driver_directory);
1411 if (!W_ERROR_IS_OK(err)) {
1412 goto err_exit;
1417 if (driver->dependent_files && driver->dependent_files->string) {
1418 for (i=0; driver->dependent_files->string[i]; i++) {
1419 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1420 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1421 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1422 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1423 int j;
1424 for (j=0; j < i; j++) {
1425 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1426 goto NextDriver;
1430 err = move_driver_file_to_download_area(ctx,
1431 conn,
1432 driver->dependent_files->string[i],
1433 short_architecture,
1434 driver->version,
1435 ver,
1436 driver_directory);
1437 if (!W_ERROR_IS_OK(err)) {
1438 goto err_exit;
1441 NextDriver: ;
1445 err = WERR_OK;
1446 err_exit:
1447 unbecome_user();
1448 err_free_conn:
1449 TALLOC_FREE(smb_dname);
1451 if (conn != NULL) {
1452 vfs_ChDir(conn, oldcwd_fname);
1453 TALLOC_FREE(oldcwd_fname);
1454 SMB_VFS_DISCONNECT(conn);
1455 conn_free(conn);
1458 return err;
1461 /****************************************************************************
1462 Determine whether or not a particular driver is currently assigned
1463 to a printer
1464 ****************************************************************************/
1466 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1467 struct dcerpc_binding_handle *b,
1468 const struct spoolss_DriverInfo8 *r)
1470 int snum;
1471 int n_services = lp_numservices();
1472 bool in_use = false;
1473 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1474 WERROR result;
1476 if (!r) {
1477 return false;
1480 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1482 /* loop through the printers.tdb and check for the drivername */
1484 for (snum=0; snum<n_services && !in_use; snum++) {
1485 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1486 continue;
1489 result = winreg_get_printer(mem_ctx, b,
1490 lp_servicename(talloc_tos(), snum),
1491 &pinfo2);
1492 if (!W_ERROR_IS_OK(result)) {
1493 continue; /* skip */
1496 if (strequal(r->driver_name, pinfo2->drivername)) {
1497 in_use = true;
1500 TALLOC_FREE(pinfo2);
1503 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1505 if ( in_use ) {
1506 struct spoolss_DriverInfo8 *driver = NULL;
1507 WERROR werr;
1509 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1511 /* we can still remove the driver if there is one of
1512 "Windows NT x86" version 2 or 3 left */
1514 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1515 if (r->version == 2) {
1516 werr = winreg_get_driver(mem_ctx, b,
1517 r->architecture,
1518 r->driver_name,
1519 3, &driver);
1520 } else if (r->version == 3) {
1521 werr = winreg_get_driver(mem_ctx, b,
1522 r->architecture,
1523 r->driver_name,
1524 2, &driver);
1525 } else {
1526 DBG_ERR("Unknown driver version (%d)\n",
1527 r->version);
1528 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1530 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1531 werr = winreg_get_driver(mem_ctx, b,
1532 SPOOLSS_ARCHITECTURE_NT_X86,
1533 r->driver_name,
1534 DRIVER_ANY_VERSION,
1535 &driver);
1536 } else {
1537 DBG_ERR("Unknown driver architecture: %s\n",
1538 r->architecture);
1539 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1542 /* now check the error code */
1544 if ( W_ERROR_IS_OK(werr) ) {
1545 /* it's ok to remove the driver, we have other architctures left */
1546 in_use = false;
1547 talloc_free(driver);
1551 /* report that the driver is not in use by default */
1553 return in_use;
1557 /**********************************************************************
1558 Check to see if a ogiven file is in use by *info
1559 *********************************************************************/
1561 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1563 int i = 0;
1565 if ( !info )
1566 return False;
1568 /* mz: skip files that are in the list but already deleted */
1569 if (!file || !file[0]) {
1570 return false;
1573 if (strequal(file, info->driver_path))
1574 return True;
1576 if (strequal(file, info->data_file))
1577 return True;
1579 if (strequal(file, info->config_file))
1580 return True;
1582 if (strequal(file, info->help_file))
1583 return True;
1585 /* see of there are any dependent files to examine */
1587 if (!info->dependent_files)
1588 return False;
1590 while (info->dependent_files[i] && *info->dependent_files[i]) {
1591 if (strequal(file, info->dependent_files[i]))
1592 return True;
1593 i++;
1596 return False;
1600 /**********************************************************************
1601 Utility function to remove the dependent file pointed to by the
1602 input parameter from the list
1603 *********************************************************************/
1605 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1608 /* bump everything down a slot */
1610 while (files && files[idx+1]) {
1611 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1612 idx++;
1615 files[idx] = NULL;
1617 return;
1620 /**********************************************************************
1621 Check if any of the files used by src are also used by drv
1622 *********************************************************************/
1624 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1625 struct spoolss_DriverInfo8 *src,
1626 const struct spoolss_DriverInfo8 *drv)
1628 bool in_use = False;
1629 int i = 0;
1631 if ( !src || !drv )
1632 return False;
1634 /* check each file. Remove it from the src structure if it overlaps */
1636 if (drv_file_in_use(src->driver_path, drv)) {
1637 in_use = True;
1638 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1639 src->driver_path = talloc_strdup(mem_ctx, "");
1640 if (!src->driver_path) { return false; }
1643 if (drv_file_in_use(src->data_file, drv)) {
1644 in_use = True;
1645 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1646 src->data_file = talloc_strdup(mem_ctx, "");
1647 if (!src->data_file) { return false; }
1650 if (drv_file_in_use(src->config_file, drv)) {
1651 in_use = True;
1652 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1653 src->config_file = talloc_strdup(mem_ctx, "");
1654 if (!src->config_file) { return false; }
1657 if (drv_file_in_use(src->help_file, drv)) {
1658 in_use = True;
1659 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1660 src->help_file = talloc_strdup(mem_ctx, "");
1661 if (!src->help_file) { return false; }
1664 /* are there any dependentfiles to examine? */
1666 if (!src->dependent_files)
1667 return in_use;
1669 while (src->dependent_files[i] && *src->dependent_files[i]) {
1670 if (drv_file_in_use(src->dependent_files[i], drv)) {
1671 in_use = True;
1672 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1673 trim_dependent_file(mem_ctx, src->dependent_files, i);
1674 } else
1675 i++;
1678 return in_use;
1681 /****************************************************************************
1682 Determine whether or not a particular driver files are currently being
1683 used by any other driver.
1685 Return value is True if any files were in use by other drivers
1686 and False otherwise.
1688 Upon return, *info has been modified to only contain the driver files
1689 which are not in use
1691 Fix from mz:
1693 This needs to check all drivers to ensure that all files in use
1694 have been removed from *info, not just the ones in the first
1695 match.
1696 ****************************************************************************/
1698 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1699 struct dcerpc_binding_handle *b,
1700 struct spoolss_DriverInfo8 *info)
1702 int i;
1703 uint32_t version;
1704 struct spoolss_DriverInfo8 *driver;
1705 bool in_use = false;
1706 uint32_t num_drivers;
1707 const char **drivers;
1708 WERROR result;
1710 if ( !info )
1711 return False;
1713 version = info->version;
1715 /* loop over all driver versions */
1717 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1719 /* get the list of drivers */
1721 result = winreg_get_driver_list(mem_ctx, b,
1722 info->architecture, version,
1723 &num_drivers, &drivers);
1724 if (!W_ERROR_IS_OK(result)) {
1725 return true;
1728 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1729 num_drivers, info->architecture, version));
1731 /* check each driver for overlap in files */
1733 for (i = 0; i < num_drivers; i++) {
1734 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1736 driver = NULL;
1738 result = winreg_get_driver(mem_ctx, b,
1739 info->architecture, drivers[i],
1740 version, &driver);
1741 if (!W_ERROR_IS_OK(result)) {
1742 talloc_free(drivers);
1743 return True;
1746 /* check if d2 uses any files from d1 */
1747 /* only if this is a different driver than the one being deleted */
1749 if (!strequal(info->driver_name, driver->driver_name)) {
1750 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1751 /* mz: Do not instantly return -
1752 * we need to ensure this file isn't
1753 * also in use by other drivers. */
1754 in_use = true;
1758 talloc_free(driver);
1761 talloc_free(drivers);
1763 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1765 return in_use;
1768 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1769 const char *short_arch,
1770 int vers,
1771 const char *fname)
1773 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1774 struct smb_filename *smb_fname = NULL;
1775 char *print_dlr_path;
1776 NTSTATUS status = NT_STATUS_NO_MEMORY;
1778 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1779 short_arch, vers, fname);
1780 if (print_dlr_path == NULL) {
1781 goto err_out;
1784 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
1785 if (smb_fname == NULL) {
1786 goto err_out;
1789 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1790 err_out:
1791 talloc_free(tmp_ctx);
1792 return status;
1795 /****************************************************************************
1796 Actually delete the driver files. Make sure that
1797 printer_driver_files_in_use() return False before calling
1798 this.
1799 ****************************************************************************/
1801 bool delete_driver_files(const struct auth_session_info *session_info,
1802 const struct spoolss_DriverInfo8 *r)
1804 const char *short_arch;
1805 connection_struct *conn;
1806 NTSTATUS nt_status;
1807 struct smb_filename *oldcwd_fname = NULL;
1808 char *printdollar = NULL;
1809 int printdollar_snum;
1810 bool ret = false;
1812 if (!r) {
1813 return false;
1816 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1817 r->driver_name, r->version));
1819 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1820 if (!printdollar) {
1821 return false;
1823 if (printdollar_snum == -1) {
1824 return false;
1827 nt_status = create_conn_struct_cwd(talloc_tos(),
1828 server_event_context(),
1829 server_messaging_context(),
1830 &conn,
1831 printdollar_snum,
1832 lp_path(talloc_tos(), printdollar_snum),
1833 session_info, &oldcwd_fname);
1834 if (!NT_STATUS_IS_OK(nt_status)) {
1835 DEBUG(0,("delete_driver_files: create_conn_struct "
1836 "returned %s\n", nt_errstr(nt_status)));
1837 return false;
1840 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1841 if (!NT_STATUS_IS_OK(nt_status)) {
1842 DEBUG(0, ("failed set force user / group\n"));
1843 ret = false;
1844 goto err_free_conn;
1847 if (!become_user_by_session(conn, session_info)) {
1848 DEBUG(0, ("failed to become user\n"));
1849 ret = false;
1850 goto err_free_conn;
1853 if ( !CAN_WRITE(conn) ) {
1854 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1855 ret = false;
1856 goto err_out;
1859 short_arch = get_short_archi(r->architecture);
1860 if (short_arch == NULL) {
1861 DEBUG(0, ("bad architecture %s\n", r->architecture));
1862 ret = false;
1863 goto err_out;
1866 /* now delete the files */
1868 if (r->driver_path && r->driver_path[0]) {
1869 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1870 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1873 if (r->config_file && r->config_file[0]) {
1874 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1875 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1878 if (r->data_file && r->data_file[0]) {
1879 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1880 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1883 if (r->help_file && r->help_file[0]) {
1884 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1885 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1888 if (r->dependent_files) {
1889 int i = 0;
1890 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1891 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1892 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1893 i++;
1897 ret = true;
1898 err_out:
1899 unbecome_user();
1900 err_free_conn:
1901 if (conn != NULL) {
1902 vfs_ChDir(conn, oldcwd_fname);
1903 TALLOC_FREE(oldcwd_fname);
1904 SMB_VFS_DISCONNECT(conn);
1905 conn_free(conn);
1907 return ret;
1910 /* error code:
1911 0: everything OK
1912 1: level not implemented
1913 2: file doesn't exist
1914 3: can't allocate memory
1915 4: can't free memory
1916 5: non existent struct
1920 A printer and a printer driver are 2 different things.
1921 NT manages them separatelly, Samba does the same.
1922 Why ? Simply because it's easier and it makes sense !
1924 Now explanation: You have 3 printers behind your samba server,
1925 2 of them are the same make and model (laser A and B). But laser B
1926 has an 3000 sheet feeder and laser A doesn't such an option.
1927 Your third printer is an old dot-matrix model for the accounting :-).
1929 If the /usr/local/samba/lib directory (default dir), you will have
1930 5 files to describe all of this.
1932 3 files for the printers (1 by printer):
1933 NTprinter_laser A
1934 NTprinter_laser B
1935 NTprinter_accounting
1936 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1937 NTdriver_printer model X
1938 NTdriver_printer model Y
1940 jfm: I should use this comment for the text file to explain
1941 same thing for the forms BTW.
1942 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1946 /* Convert generic access rights to printer object specific access rights.
1947 It turns out that NT4 security descriptors use generic access rights and
1948 NT5 the object specific ones. */
1950 void map_printer_permissions(struct security_descriptor *sd)
1952 int i;
1954 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1955 se_map_generic(&sd->dacl->aces[i].access_mask,
1956 &printer_generic_mapping);
1960 void map_job_permissions(struct security_descriptor *sd)
1962 int i;
1964 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1965 se_map_generic(&sd->dacl->aces[i].access_mask,
1966 &job_generic_mapping);
1971 /****************************************************************************
1972 Check a user has permissions to perform the given operation. We use the
1973 permission constants defined in include/rpc_spoolss.h to check the various
1974 actions we perform when checking printer access.
1976 PRINTER_ACCESS_ADMINISTER:
1977 print_queue_pause, print_queue_resume, update_printer_sec,
1978 update_printer, spoolss_addprinterex_level_2,
1979 _spoolss_setprinterdata
1981 PRINTER_ACCESS_USE:
1982 print_job_start
1984 JOB_ACCESS_ADMINISTER:
1985 print_job_delete, print_job_pause, print_job_resume,
1986 print_queue_purge
1988 Try access control in the following order (for performance reasons):
1989 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1990 2) check security descriptor (bit comparisons in memory)
1991 3) "printer admins" (may result in numerous calls to winbind)
1993 ****************************************************************************/
1994 WERROR print_access_check(const struct auth_session_info *session_info,
1995 struct messaging_context *msg_ctx, int snum,
1996 int access_type)
1998 struct spoolss_security_descriptor *secdesc = NULL;
1999 uint32_t access_granted;
2000 size_t sd_size;
2001 NTSTATUS status;
2002 WERROR result;
2003 const char *pname;
2004 TALLOC_CTX *mem_ctx = NULL;
2006 /* If user is NULL then use the current_user structure */
2008 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2010 if ((session_info->unix_token->uid == sec_initial_uid())
2011 || security_token_has_privilege(session_info->security_token,
2012 SEC_PRIV_PRINT_OPERATOR)) {
2013 return WERR_OK;
2016 /* Get printer name */
2018 pname = lp_printername(talloc_tos(), snum);
2020 if (!pname || !*pname) {
2021 return WERR_ACCESS_DENIED;
2024 /* Get printer security descriptor */
2026 if(!(mem_ctx = talloc_init("print_access_check"))) {
2027 return WERR_NOT_ENOUGH_MEMORY;
2030 result = winreg_get_printer_secdesc_internal(mem_ctx,
2031 get_session_info_system(),
2032 msg_ctx,
2033 pname,
2034 &secdesc);
2035 if (!W_ERROR_IS_OK(result)) {
2036 talloc_destroy(mem_ctx);
2037 return WERR_NOT_ENOUGH_MEMORY;
2040 if (access_type == JOB_ACCESS_ADMINISTER) {
2041 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2043 /* Create a child security descriptor to check permissions
2044 against. This is because print jobs are child objects
2045 objects of a printer. */
2046 status = se_create_child_secdesc(mem_ctx,
2047 &secdesc,
2048 &sd_size,
2049 parent_secdesc,
2050 parent_secdesc->owner_sid,
2051 parent_secdesc->group_sid,
2052 false);
2053 if (!NT_STATUS_IS_OK(status)) {
2054 talloc_destroy(mem_ctx);
2055 return ntstatus_to_werror(status);
2058 map_job_permissions(secdesc);
2059 } else {
2060 map_printer_permissions(secdesc);
2063 /* Check access */
2064 status = se_access_check(secdesc, session_info->security_token, access_type,
2065 &access_granted);
2067 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2069 talloc_destroy(mem_ctx);
2071 return ntstatus_to_werror(status);
2074 /****************************************************************************
2075 Check the time parameters allow a print operation.
2076 *****************************************************************************/
2078 bool print_time_access_check(const struct auth_session_info *session_info,
2079 struct messaging_context *msg_ctx,
2080 const char *servicename)
2082 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2083 WERROR result;
2084 bool ok = False;
2085 time_t now = time(NULL);
2086 struct tm *t;
2087 uint32_t mins;
2089 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2090 servicename, &pinfo2);
2091 if (!W_ERROR_IS_OK(result)) {
2092 return False;
2095 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2096 ok = True;
2099 t = gmtime(&now);
2100 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2102 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2103 ok = True;
2106 TALLOC_FREE(pinfo2);
2108 if (!ok) {
2109 errno = EACCES;
2112 return ok;
2115 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2116 const struct auth_session_info *session_info,
2117 struct messaging_context *msg_ctx,
2118 const char *printer)
2120 WERROR result;
2122 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2123 printer, "");
2124 if (!W_ERROR_IS_OK(result)) {
2125 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2126 "%s\n", printer, win_errstr(result)));
2130 void nt_printer_add(TALLOC_CTX *mem_ctx,
2131 const struct auth_session_info *session_info,
2132 struct messaging_context *msg_ctx,
2133 const char *printer)
2135 WERROR result;
2137 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2138 printer);
2139 if (!W_ERROR_IS_OK(result)) {
2140 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2141 printer, win_errstr(result)));