tests: The pthreadpooltests do not need a full environment
[Samba.git] / source3 / printing / nt_printing.c
blob2e500f18c7d249fce970ab1fa3c1ade549e9974f
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 int bc;
490 memcpy(buf, &buf[i], byte_count-i);
491 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
492 (byte_count-i))) < 0) {
494 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
495 fname, errno));
496 goto error_exit;
499 byte_count = bc + (byte_count - i);
500 if (byte_count<VS_VERSION_INFO_SIZE) break;
502 i = 0;
505 /* Check that the full signature string and the magic number that
506 * follows exist (not a perfect solution, but the chances that this
507 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
508 * twice, as it is simpler to read the code. */
509 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
510 /* Compute skip alignment to next long address */
511 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
512 sizeof(VS_SIGNATURE)) & 3;
513 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
515 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
516 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
517 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
518 fname, *major, *minor,
519 (*major>>16)&0xffff, *major&0xffff,
520 (*minor>>16)&0xffff, *minor&0xffff));
521 SAFE_FREE(buf);
522 return 1;
527 /* Version info not found, fall back to origin date/time */
528 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
529 SAFE_FREE(buf);
530 return 0;
532 } else
533 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
534 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
535 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
537 no_version_info:
538 SAFE_FREE(buf);
539 return 0;
541 error_exit:
542 SAFE_FREE(buf);
543 return -1;
546 /****************************************************************************
547 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
548 share one or more files. During the MS installation process files are checked
549 to insure that only a newer version of a shared file is installed over an
550 older version. There are several possibilities for this comparison. If there
551 is no previous version, the new one is newer (obviously). If either file is
552 missing the version info structure, compare the creation date (on Unix use
553 the modification date). Otherwise chose the numerically larger version number.
554 ****************************************************************************/
556 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
558 bool use_version = true;
560 uint32_t new_major;
561 uint32_t new_minor;
562 time_t new_create_time;
564 uint32_t old_major;
565 uint32_t old_minor;
566 time_t old_create_time;
568 struct smb_filename *smb_fname = NULL;
569 files_struct *fsp = NULL;
570 SMB_STRUCT_STAT st;
572 NTSTATUS status;
573 int ret;
575 SET_STAT_INVALID(st);
576 new_create_time = (time_t)0;
577 old_create_time = (time_t)0;
579 /* Get file version info (if available) for previous file (if it exists) */
580 status = driver_unix_convert(conn, old_file, &smb_fname);
581 if (!NT_STATUS_IS_OK(status)) {
582 goto error_exit;
585 status = SMB_VFS_CREATE_FILE(
586 conn, /* conn */
587 NULL, /* req */
588 0, /* root_dir_fid */
589 smb_fname, /* fname */
590 FILE_GENERIC_READ, /* access_mask */
591 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
592 FILE_OPEN, /* create_disposition*/
593 0, /* create_options */
594 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
595 INTERNAL_OPEN_ONLY, /* oplock_request */
596 NULL, /* lease */
597 0, /* allocation_size */
598 0, /* private_flags */
599 NULL, /* sd */
600 NULL, /* ea_list */
601 &fsp, /* result */
602 NULL, /* pinfo */
603 NULL, NULL); /* create context */
605 if (!NT_STATUS_IS_OK(status)) {
606 /* Old file not found, so by definition new file is in fact newer */
607 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
608 "errno = %d\n", smb_fname_str_dbg(smb_fname),
609 errno));
610 ret = 1;
611 goto done;
613 } else {
614 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
615 if (ret == -1) {
616 goto error_exit;
619 if (!ret) {
620 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
621 old_file));
622 use_version = false;
623 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
624 goto error_exit;
626 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
627 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
628 (long)old_create_time));
631 close_file(NULL, fsp, NORMAL_CLOSE);
632 fsp = NULL;
634 /* Get file version info (if available) for new file */
635 status = driver_unix_convert(conn, new_file, &smb_fname);
636 if (!NT_STATUS_IS_OK(status)) {
637 goto error_exit;
640 status = SMB_VFS_CREATE_FILE(
641 conn, /* conn */
642 NULL, /* req */
643 0, /* root_dir_fid */
644 smb_fname, /* fname */
645 FILE_GENERIC_READ, /* access_mask */
646 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
647 FILE_OPEN, /* create_disposition*/
648 0, /* create_options */
649 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
650 INTERNAL_OPEN_ONLY, /* oplock_request */
651 NULL, /* lease */
652 0, /* allocation_size */
653 0, /* private_flags */
654 NULL, /* sd */
655 NULL, /* ea_list */
656 &fsp, /* result */
657 NULL, /* pinfo */
658 NULL, NULL); /* create context */
660 if (!NT_STATUS_IS_OK(status)) {
661 /* New file not found, this shouldn't occur if the caller did its job */
662 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
663 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
664 goto error_exit;
666 } else {
667 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
668 if (ret == -1) {
669 goto error_exit;
672 if (!ret) {
673 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
674 new_file));
675 use_version = false;
676 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
677 goto error_exit;
679 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
680 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
681 (long)new_create_time));
684 close_file(NULL, fsp, NORMAL_CLOSE);
685 fsp = NULL;
687 if (use_version && (new_major != old_major || new_minor != old_minor)) {
688 /* Compare versions and choose the larger version number */
689 if (new_major > old_major ||
690 (new_major == old_major && new_minor > old_minor)) {
692 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
693 ret = 1;
694 goto done;
696 else {
697 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
698 ret = 0;
699 goto done;
702 } else {
703 /* Compare modification time/dates and choose the newest time/date */
704 if (new_create_time > old_create_time) {
705 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
706 ret = 1;
707 goto done;
709 else {
710 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
711 ret = 0;
712 goto done;
716 error_exit:
717 if(fsp)
718 close_file(NULL, fsp, NORMAL_CLOSE);
719 ret = -1;
720 done:
721 TALLOC_FREE(smb_fname);
722 return ret;
725 /****************************************************************************
726 Determine the correct cVersion associated with an architecture and driver
727 ****************************************************************************/
728 static uint32_t get_correct_cversion(struct auth_session_info *session_info,
729 const char *architecture,
730 const char *driverpath_in,
731 const char *driver_directory,
732 WERROR *perr)
734 int cversion = -1;
735 NTSTATUS nt_status;
736 struct smb_filename *smb_fname = NULL;
737 files_struct *fsp = NULL;
738 connection_struct *conn = NULL;
739 struct smb_filename *oldcwd_fname = NULL;
740 char *printdollar = NULL;
741 char *printdollar_path = NULL;
742 char *working_dir = NULL;
743 int printdollar_snum;
745 *perr = WERR_INVALID_PARAMETER;
747 /* If architecture is Windows 95/98/ME, the version is always 0. */
748 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
749 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
750 *perr = WERR_OK;
751 return 0;
754 /* If architecture is Windows x64, the version is always 3. */
755 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
756 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
757 *perr = WERR_OK;
758 return 3;
761 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
762 if (!printdollar) {
763 *perr = WERR_NOT_ENOUGH_MEMORY;
764 return -1;
766 if (printdollar_snum == -1) {
767 *perr = WERR_BAD_NET_NAME;
768 return -1;
771 printdollar_path = lp_path(talloc_tos(), printdollar_snum);
772 if (printdollar_path == NULL) {
773 *perr = WERR_NOT_ENOUGH_MEMORY;
774 return -1;
777 working_dir = talloc_asprintf(talloc_tos(),
778 "%s/%s",
779 printdollar_path,
780 architecture);
782 * If the driver has been uploaded into a temorpary driver
783 * directory, switch to the driver directory.
785 if (driver_directory != NULL) {
786 working_dir = talloc_asprintf(talloc_tos(), "%s/%s/%s",
787 printdollar_path,
788 architecture,
789 driver_directory);
792 nt_status = create_conn_struct_cwd(talloc_tos(),
793 server_event_context(),
794 server_messaging_context(),
795 &conn,
796 printdollar_snum,
797 working_dir,
798 session_info, &oldcwd_fname);
799 if (!NT_STATUS_IS_OK(nt_status)) {
800 DEBUG(0,("get_correct_cversion: create_conn_struct "
801 "returned %s\n", nt_errstr(nt_status)));
802 *perr = ntstatus_to_werror(nt_status);
803 return -1;
806 nt_status = set_conn_force_user_group(conn, printdollar_snum);
807 if (!NT_STATUS_IS_OK(nt_status)) {
808 DEBUG(0, ("failed set force user / group\n"));
809 *perr = ntstatus_to_werror(nt_status);
810 goto error_free_conn;
813 if (!become_user_by_session(conn, session_info)) {
814 DEBUG(0, ("failed to become user\n"));
815 *perr = WERR_ACCESS_DENIED;
816 goto error_free_conn;
820 * We switch to the directory where the driver files are located,
821 * so only work on the file names
823 nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
824 if (!NT_STATUS_IS_OK(nt_status)) {
825 *perr = ntstatus_to_werror(nt_status);
826 goto error_exit;
829 nt_status = vfs_file_exist(conn, smb_fname);
830 if (!NT_STATUS_IS_OK(nt_status)) {
831 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
832 *perr = WERR_FILE_NOT_FOUND;
833 goto error_exit;
836 nt_status = SMB_VFS_CREATE_FILE(
837 conn, /* conn */
838 NULL, /* req */
839 0, /* root_dir_fid */
840 smb_fname, /* fname */
841 FILE_GENERIC_READ, /* access_mask */
842 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
843 FILE_OPEN, /* create_disposition*/
844 0, /* create_options */
845 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
846 INTERNAL_OPEN_ONLY, /* oplock_request */
847 NULL, /* lease */
848 0, /* private_flags */
849 0, /* allocation_size */
850 NULL, /* sd */
851 NULL, /* ea_list */
852 &fsp, /* result */
853 NULL, /* pinfo */
854 NULL, NULL); /* create context */
856 if (!NT_STATUS_IS_OK(nt_status)) {
857 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
858 "%d\n", smb_fname_str_dbg(smb_fname), errno));
859 *perr = WERR_ACCESS_DENIED;
860 goto error_exit;
861 } else {
862 uint32_t major;
863 uint32_t minor;
864 int ret;
866 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
867 if (ret == -1) {
868 *perr = WERR_INVALID_PARAMETER;
869 goto error_exit;
870 } else if (!ret) {
871 DEBUG(6,("get_correct_cversion: Version info not "
872 "found [%s]\n",
873 smb_fname_str_dbg(smb_fname)));
874 *perr = WERR_INVALID_PARAMETER;
875 goto error_exit;
879 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
880 * for more details. Version in this case is not just the version of the
881 * file, but the version in the sense of kernal mode (2) vs. user mode
882 * (3) drivers. Other bits of the version fields are the version info.
883 * JRR 010716
885 cversion = major & 0x0000ffff;
886 switch (cversion) {
887 case 2: /* WinNT drivers */
888 case 3: /* Win2K drivers */
889 break;
891 default:
892 DEBUG(6,("get_correct_cversion: cversion "
893 "invalid [%s] cversion = %d\n",
894 smb_fname_str_dbg(smb_fname),
895 cversion));
896 goto error_exit;
899 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
900 " = 0x%x minor = 0x%x\n",
901 smb_fname_str_dbg(smb_fname), major, minor));
904 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
905 smb_fname_str_dbg(smb_fname), cversion));
906 *perr = WERR_OK;
908 error_exit:
909 unbecome_user();
910 error_free_conn:
911 TALLOC_FREE(smb_fname);
912 if (fsp != NULL) {
913 close_file(NULL, fsp, NORMAL_CLOSE);
915 if (conn != NULL) {
916 vfs_ChDir(conn, oldcwd_fname);
917 TALLOC_FREE(oldcwd_fname);
918 SMB_VFS_DISCONNECT(conn);
919 conn_free(conn);
921 if (!W_ERROR_IS_OK(*perr)) {
922 cversion = -1;
925 return cversion;
928 /****************************************************************************
929 ****************************************************************************/
931 #define strip_driver_path(_mem_ctx, _element) do { \
932 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
933 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
934 W_ERROR_HAVE_NO_MEMORY((_element)); \
936 } while (0);
938 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
939 struct auth_session_info *session_info,
940 const char *architecture,
941 const char **driver_path,
942 const char **data_file,
943 const char **config_file,
944 const char **help_file,
945 struct spoolss_StringArray *dependent_files,
946 enum spoolss_DriverOSVersion *version,
947 uint32_t flags,
948 const char **driver_directory)
950 const char *short_architecture;
951 int i;
952 WERROR err;
953 char *_p;
955 if (!*driver_path || !*data_file) {
956 return WERR_INVALID_PARAMETER;
959 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
960 return WERR_INVALID_PARAMETER;
963 if (flags & APD_COPY_FROM_DIRECTORY) {
964 char *path;
965 char *q;
968 * driver_path is set to:
970 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
972 path = talloc_strdup(mem_ctx, *driver_path);
973 if (path == NULL) {
974 return WERR_NOT_ENOUGH_MEMORY;
977 /* Remove pscript5.dll */
978 q = strrchr_m(path, '\\');
979 if (q == NULL) {
980 return WERR_INVALID_PARAMETER;
982 *q = '\0';
984 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
985 q = strrchr_m(path, '\\');
986 if (q == NULL) {
987 return WERR_INVALID_PARAMETER;
991 * Set driver_directory to:
993 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
995 * This is the directory where all the files have been uploaded
997 *driver_directory = q + 1;
1000 /* clean up the driver name.
1001 * we can get .\driver.dll
1002 * or worse c:\windows\system\driver.dll !
1004 /* using an intermediate string to not have overlaping memcpy()'s */
1006 strip_driver_path(mem_ctx, *driver_path);
1007 strip_driver_path(mem_ctx, *data_file);
1008 if (*config_file) {
1009 strip_driver_path(mem_ctx, *config_file);
1011 if (help_file) {
1012 strip_driver_path(mem_ctx, *help_file);
1015 if (dependent_files && dependent_files->string) {
1016 for (i=0; dependent_files->string[i]; i++) {
1017 strip_driver_path(mem_ctx, dependent_files->string[i]);
1021 short_architecture = get_short_archi(architecture);
1022 if (!short_architecture) {
1023 return WERR_UNKNOWN_PRINTER_DRIVER;
1026 /* jfm:7/16/2000 the client always sends the cversion=0.
1027 * The server should check which version the driver is by reading
1028 * the PE header of driver->driverpath.
1030 * For Windows 95/98 the version is 0 (so the value sent is correct)
1031 * For Windows NT (the architecture doesn't matter)
1032 * NT 3.1: cversion=0
1033 * NT 3.5/3.51: cversion=1
1034 * NT 4: cversion=2
1035 * NT2K: cversion=3
1038 *version = get_correct_cversion(session_info,
1039 short_architecture,
1040 *driver_path,
1041 *driver_directory,
1042 &err);
1043 if (*version == -1) {
1044 return err;
1047 return WERR_OK;
1050 /****************************************************************************
1051 ****************************************************************************/
1053 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1054 struct auth_session_info *session_info,
1055 struct spoolss_AddDriverInfoCtr *r,
1056 uint32_t flags,
1057 const char **driver_directory)
1059 switch (r->level) {
1060 case 3:
1061 return clean_up_driver_struct_level(mem_ctx, session_info,
1062 r->info.info3->architecture,
1063 &r->info.info3->driver_path,
1064 &r->info.info3->data_file,
1065 &r->info.info3->config_file,
1066 &r->info.info3->help_file,
1067 r->info.info3->dependent_files,
1068 &r->info.info3->version,
1069 flags,
1070 driver_directory);
1071 case 6:
1072 return clean_up_driver_struct_level(mem_ctx, session_info,
1073 r->info.info6->architecture,
1074 &r->info.info6->driver_path,
1075 &r->info.info6->data_file,
1076 &r->info.info6->config_file,
1077 &r->info.info6->help_file,
1078 r->info.info6->dependent_files,
1079 &r->info.info6->version,
1080 flags,
1081 driver_directory);
1082 case 8:
1083 return clean_up_driver_struct_level(mem_ctx, session_info,
1084 r->info.info8->architecture,
1085 &r->info.info8->driver_path,
1086 &r->info.info8->data_file,
1087 &r->info.info8->config_file,
1088 &r->info.info8->help_file,
1089 r->info.info8->dependent_files,
1090 &r->info.info8->version,
1091 flags,
1092 driver_directory);
1093 default:
1094 return WERR_NOT_SUPPORTED;
1098 /****************************************************************************
1099 This function sucks and should be replaced. JRA.
1100 ****************************************************************************/
1102 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1103 const struct spoolss_AddDriverInfo6 *src)
1105 dst->version = src->version;
1107 dst->driver_name = src->driver_name;
1108 dst->architecture = src->architecture;
1109 dst->driver_path = src->driver_path;
1110 dst->data_file = src->data_file;
1111 dst->config_file = src->config_file;
1112 dst->help_file = src->help_file;
1113 dst->monitor_name = src->monitor_name;
1114 dst->default_datatype = src->default_datatype;
1115 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1116 dst->dependent_files = src->dependent_files;
1119 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1120 const struct spoolss_AddDriverInfo8 *src)
1122 dst->version = src->version;
1124 dst->driver_name = src->driver_name;
1125 dst->architecture = src->architecture;
1126 dst->driver_path = src->driver_path;
1127 dst->data_file = src->data_file;
1128 dst->config_file = src->config_file;
1129 dst->help_file = src->help_file;
1130 dst->monitor_name = src->monitor_name;
1131 dst->default_datatype = src->default_datatype;
1132 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1133 dst->dependent_files = src->dependent_files;
1136 /****************************************************************************
1137 ****************************************************************************/
1139 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1140 connection_struct *conn,
1141 const char *driver_file,
1142 const char *short_architecture,
1143 uint32_t driver_version,
1144 uint32_t version,
1145 const char *driver_directory)
1147 struct smb_filename *smb_fname_old = NULL;
1148 struct smb_filename *smb_fname_new = NULL;
1149 char *old_name = NULL;
1150 char *new_name = NULL;
1151 NTSTATUS status;
1152 WERROR ret;
1154 if (driver_directory != NULL) {
1155 old_name = talloc_asprintf(mem_ctx,
1156 "%s/%s/%s",
1157 short_architecture,
1158 driver_directory,
1159 driver_file);
1160 } else {
1161 old_name = talloc_asprintf(mem_ctx,
1162 "%s/%s",
1163 short_architecture,
1164 driver_file);
1166 if (old_name == NULL) {
1167 return WERR_NOT_ENOUGH_MEMORY;
1170 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1171 short_architecture, driver_version, driver_file);
1172 if (new_name == NULL) {
1173 TALLOC_FREE(old_name);
1174 return WERR_NOT_ENOUGH_MEMORY;
1177 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1179 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1180 if (!NT_STATUS_IS_OK(status)) {
1181 ret = WERR_NOT_ENOUGH_MEMORY;
1182 goto out;
1185 /* Setup a synthetic smb_filename struct */
1186 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1187 if (!smb_fname_new) {
1188 ret = WERR_NOT_ENOUGH_MEMORY;
1189 goto out;
1192 smb_fname_new->base_name = new_name;
1194 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1195 "'%s'\n", smb_fname_old->base_name,
1196 smb_fname_new->base_name));
1198 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1199 OPENX_FILE_EXISTS_TRUNCATE |
1200 OPENX_FILE_CREATE_IF_NOT_EXIST,
1201 0, false);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 DEBUG(0,("move_driver_file_to_download_area: Unable "
1205 "to rename [%s] to [%s]: %s\n",
1206 smb_fname_old->base_name, new_name,
1207 nt_errstr(status)));
1208 ret = WERR_ACCESS_DENIED;
1209 goto out;
1213 ret = WERR_OK;
1214 out:
1215 TALLOC_FREE(smb_fname_old);
1216 TALLOC_FREE(smb_fname_new);
1217 return ret;
1220 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1221 struct spoolss_AddDriverInfoCtr *r,
1222 const char *driver_directory)
1224 struct spoolss_AddDriverInfo3 *driver;
1225 struct spoolss_AddDriverInfo3 converted_driver;
1226 const char *short_architecture;
1227 struct smb_filename *smb_dname = NULL;
1228 char *new_dir = NULL;
1229 connection_struct *conn = NULL;
1230 NTSTATUS nt_status;
1231 int i;
1232 TALLOC_CTX *ctx = talloc_tos();
1233 int ver = 0;
1234 struct smb_filename *oldcwd_fname = NULL;
1235 char *printdollar = NULL;
1236 int printdollar_snum;
1237 WERROR err = WERR_OK;
1239 switch (r->level) {
1240 case 3:
1241 driver = r->info.info3;
1242 break;
1243 case 6:
1244 convert_level_6_to_level3(&converted_driver, r->info.info6);
1245 driver = &converted_driver;
1246 break;
1247 case 8:
1248 convert_level_8_to_level3(&converted_driver, r->info.info8);
1249 driver = &converted_driver;
1250 break;
1251 default:
1252 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1253 return WERR_INVALID_LEVEL;
1256 short_architecture = get_short_archi(driver->architecture);
1257 if (!short_architecture) {
1258 return WERR_UNKNOWN_PRINTER_DRIVER;
1261 printdollar_snum = find_service(ctx, "print$", &printdollar);
1262 if (!printdollar) {
1263 return WERR_NOT_ENOUGH_MEMORY;
1265 if (printdollar_snum == -1) {
1266 return WERR_BAD_NET_NAME;
1269 nt_status = create_conn_struct_cwd(talloc_tos(),
1270 server_event_context(),
1271 server_messaging_context(),
1272 &conn,
1273 printdollar_snum,
1274 lp_path(talloc_tos(), printdollar_snum),
1275 session_info, &oldcwd_fname);
1276 if (!NT_STATUS_IS_OK(nt_status)) {
1277 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1278 "returned %s\n", nt_errstr(nt_status)));
1279 err = ntstatus_to_werror(nt_status);
1280 return err;
1283 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1284 if (!NT_STATUS_IS_OK(nt_status)) {
1285 DEBUG(0, ("failed set force user / group\n"));
1286 err = ntstatus_to_werror(nt_status);
1287 goto err_free_conn;
1290 if (!become_user_by_session(conn, session_info)) {
1291 DEBUG(0, ("failed to become user\n"));
1292 err = WERR_ACCESS_DENIED;
1293 goto err_free_conn;
1296 new_dir = talloc_asprintf(ctx,
1297 "%s/%d",
1298 short_architecture,
1299 driver->version);
1300 if (!new_dir) {
1301 err = WERR_NOT_ENOUGH_MEMORY;
1302 goto err_exit;
1304 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1305 if (!NT_STATUS_IS_OK(nt_status)) {
1306 err = WERR_NOT_ENOUGH_MEMORY;
1307 goto err_exit;
1310 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1312 nt_status = create_directory(conn, NULL, smb_dname);
1313 if (!NT_STATUS_IS_OK(nt_status)
1314 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1315 DEBUG(0, ("failed to create driver destination directory: %s\n",
1316 nt_errstr(nt_status)));
1317 err = ntstatus_to_werror(nt_status);
1318 goto err_exit;
1321 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1322 * listed for this driver which has already been moved, skip it (note:
1323 * drivers may list the same file name several times. Then check if the
1324 * file already exists in archi\version\, if so, check that the version
1325 * info (or time stamps if version info is unavailable) is newer (or the
1326 * date is later). If it is, move it to archi\version\filexxx.yyy.
1327 * Otherwise, delete the file.
1329 * If a file is not moved to archi\version\ because of an error, all the
1330 * rest of the 'unmoved' driver files are removed from archi\. If one or
1331 * more of the driver's files was already moved to archi\version\, it
1332 * potentially leaves the driver in a partially updated state. Version
1333 * trauma will most likely occur if an client attempts to use any printer
1334 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1335 * done is appropriate... later JRR
1338 DEBUG(5,("Moving files now !\n"));
1340 if (driver->driver_path && strlen(driver->driver_path)) {
1342 err = move_driver_file_to_download_area(ctx,
1343 conn,
1344 driver->driver_path,
1345 short_architecture,
1346 driver->version,
1347 ver,
1348 driver_directory);
1349 if (!W_ERROR_IS_OK(err)) {
1350 goto err_exit;
1354 if (driver->data_file && strlen(driver->data_file)) {
1355 if (!strequal(driver->data_file, driver->driver_path)) {
1357 err = move_driver_file_to_download_area(ctx,
1358 conn,
1359 driver->data_file,
1360 short_architecture,
1361 driver->version,
1362 ver,
1363 driver_directory);
1364 if (!W_ERROR_IS_OK(err)) {
1365 goto err_exit;
1370 if (driver->config_file && strlen(driver->config_file)) {
1371 if (!strequal(driver->config_file, driver->driver_path) &&
1372 !strequal(driver->config_file, driver->data_file)) {
1374 err = move_driver_file_to_download_area(ctx,
1375 conn,
1376 driver->config_file,
1377 short_architecture,
1378 driver->version,
1379 ver,
1380 driver_directory);
1381 if (!W_ERROR_IS_OK(err)) {
1382 goto err_exit;
1387 if (driver->help_file && strlen(driver->help_file)) {
1388 if (!strequal(driver->help_file, driver->driver_path) &&
1389 !strequal(driver->help_file, driver->data_file) &&
1390 !strequal(driver->help_file, driver->config_file)) {
1392 err = move_driver_file_to_download_area(ctx,
1393 conn,
1394 driver->help_file,
1395 short_architecture,
1396 driver->version,
1397 ver,
1398 driver_directory);
1399 if (!W_ERROR_IS_OK(err)) {
1400 goto err_exit;
1405 if (driver->dependent_files && driver->dependent_files->string) {
1406 for (i=0; driver->dependent_files->string[i]; i++) {
1407 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1408 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1409 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1410 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1411 int j;
1412 for (j=0; j < i; j++) {
1413 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1414 goto NextDriver;
1418 err = move_driver_file_to_download_area(ctx,
1419 conn,
1420 driver->dependent_files->string[i],
1421 short_architecture,
1422 driver->version,
1423 ver,
1424 driver_directory);
1425 if (!W_ERROR_IS_OK(err)) {
1426 goto err_exit;
1429 NextDriver: ;
1433 err = WERR_OK;
1434 err_exit:
1435 unbecome_user();
1436 err_free_conn:
1437 TALLOC_FREE(smb_dname);
1439 if (conn != NULL) {
1440 vfs_ChDir(conn, oldcwd_fname);
1441 TALLOC_FREE(oldcwd_fname);
1442 SMB_VFS_DISCONNECT(conn);
1443 conn_free(conn);
1446 return err;
1449 /****************************************************************************
1450 Determine whether or not a particular driver is currently assigned
1451 to a printer
1452 ****************************************************************************/
1454 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1455 struct dcerpc_binding_handle *b,
1456 const struct spoolss_DriverInfo8 *r)
1458 int snum;
1459 int n_services = lp_numservices();
1460 bool in_use = false;
1461 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1462 WERROR result;
1464 if (!r) {
1465 return false;
1468 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1470 /* loop through the printers.tdb and check for the drivername */
1472 for (snum=0; snum<n_services && !in_use; snum++) {
1473 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1474 continue;
1477 result = winreg_get_printer(mem_ctx, b,
1478 lp_servicename(talloc_tos(), snum),
1479 &pinfo2);
1480 if (!W_ERROR_IS_OK(result)) {
1481 continue; /* skip */
1484 if (strequal(r->driver_name, pinfo2->drivername)) {
1485 in_use = true;
1488 TALLOC_FREE(pinfo2);
1491 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1493 if ( in_use ) {
1494 struct spoolss_DriverInfo8 *driver = NULL;
1495 WERROR werr;
1497 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1499 /* we can still remove the driver if there is one of
1500 "Windows NT x86" version 2 or 3 left */
1502 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1503 if (r->version == 2) {
1504 werr = winreg_get_driver(mem_ctx, b,
1505 r->architecture,
1506 r->driver_name,
1507 3, &driver);
1508 } else if (r->version == 3) {
1509 werr = winreg_get_driver(mem_ctx, b,
1510 r->architecture,
1511 r->driver_name,
1512 2, &driver);
1513 } else {
1514 DBG_ERR("Unknown driver version (%d)\n",
1515 r->version);
1516 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1518 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1519 werr = winreg_get_driver(mem_ctx, b,
1520 SPOOLSS_ARCHITECTURE_NT_X86,
1521 r->driver_name,
1522 DRIVER_ANY_VERSION,
1523 &driver);
1524 } else {
1525 DBG_ERR("Unknown driver architecture: %s\n",
1526 r->architecture);
1527 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1530 /* now check the error code */
1532 if ( W_ERROR_IS_OK(werr) ) {
1533 /* it's ok to remove the driver, we have other architctures left */
1534 in_use = false;
1535 talloc_free(driver);
1539 /* report that the driver is not in use by default */
1541 return in_use;
1545 /**********************************************************************
1546 Check to see if a ogiven file is in use by *info
1547 *********************************************************************/
1549 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1551 int i = 0;
1553 if ( !info )
1554 return False;
1556 /* mz: skip files that are in the list but already deleted */
1557 if (!file || !file[0]) {
1558 return false;
1561 if (strequal(file, info->driver_path))
1562 return True;
1564 if (strequal(file, info->data_file))
1565 return True;
1567 if (strequal(file, info->config_file))
1568 return True;
1570 if (strequal(file, info->help_file))
1571 return True;
1573 /* see of there are any dependent files to examine */
1575 if (!info->dependent_files)
1576 return False;
1578 while (info->dependent_files[i] && *info->dependent_files[i]) {
1579 if (strequal(file, info->dependent_files[i]))
1580 return True;
1581 i++;
1584 return False;
1588 /**********************************************************************
1589 Utility function to remove the dependent file pointed to by the
1590 input parameter from the list
1591 *********************************************************************/
1593 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1596 /* bump everything down a slot */
1598 while (files && files[idx+1]) {
1599 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1600 idx++;
1603 files[idx] = NULL;
1605 return;
1608 /**********************************************************************
1609 Check if any of the files used by src are also used by drv
1610 *********************************************************************/
1612 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1613 struct spoolss_DriverInfo8 *src,
1614 const struct spoolss_DriverInfo8 *drv)
1616 bool in_use = False;
1617 int i = 0;
1619 if ( !src || !drv )
1620 return False;
1622 /* check each file. Remove it from the src structure if it overlaps */
1624 if (drv_file_in_use(src->driver_path, drv)) {
1625 in_use = True;
1626 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1627 src->driver_path = talloc_strdup(mem_ctx, "");
1628 if (!src->driver_path) { return false; }
1631 if (drv_file_in_use(src->data_file, drv)) {
1632 in_use = True;
1633 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1634 src->data_file = talloc_strdup(mem_ctx, "");
1635 if (!src->data_file) { return false; }
1638 if (drv_file_in_use(src->config_file, drv)) {
1639 in_use = True;
1640 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1641 src->config_file = talloc_strdup(mem_ctx, "");
1642 if (!src->config_file) { return false; }
1645 if (drv_file_in_use(src->help_file, drv)) {
1646 in_use = True;
1647 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1648 src->help_file = talloc_strdup(mem_ctx, "");
1649 if (!src->help_file) { return false; }
1652 /* are there any dependentfiles to examine? */
1654 if (!src->dependent_files)
1655 return in_use;
1657 while (src->dependent_files[i] && *src->dependent_files[i]) {
1658 if (drv_file_in_use(src->dependent_files[i], drv)) {
1659 in_use = True;
1660 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1661 trim_dependent_file(mem_ctx, src->dependent_files, i);
1662 } else
1663 i++;
1666 return in_use;
1669 /****************************************************************************
1670 Determine whether or not a particular driver files are currently being
1671 used by any other driver.
1673 Return value is True if any files were in use by other drivers
1674 and False otherwise.
1676 Upon return, *info has been modified to only contain the driver files
1677 which are not in use
1679 Fix from mz:
1681 This needs to check all drivers to ensure that all files in use
1682 have been removed from *info, not just the ones in the first
1683 match.
1684 ****************************************************************************/
1686 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1687 struct dcerpc_binding_handle *b,
1688 struct spoolss_DriverInfo8 *info)
1690 int i;
1691 uint32_t version;
1692 struct spoolss_DriverInfo8 *driver;
1693 bool in_use = false;
1694 uint32_t num_drivers;
1695 const char **drivers;
1696 WERROR result;
1698 if ( !info )
1699 return False;
1701 version = info->version;
1703 /* loop over all driver versions */
1705 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1707 /* get the list of drivers */
1709 result = winreg_get_driver_list(mem_ctx, b,
1710 info->architecture, version,
1711 &num_drivers, &drivers);
1712 if (!W_ERROR_IS_OK(result)) {
1713 return true;
1716 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1717 num_drivers, info->architecture, version));
1719 /* check each driver for overlap in files */
1721 for (i = 0; i < num_drivers; i++) {
1722 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1724 driver = NULL;
1726 result = winreg_get_driver(mem_ctx, b,
1727 info->architecture, drivers[i],
1728 version, &driver);
1729 if (!W_ERROR_IS_OK(result)) {
1730 talloc_free(drivers);
1731 return True;
1734 /* check if d2 uses any files from d1 */
1735 /* only if this is a different driver than the one being deleted */
1737 if (!strequal(info->driver_name, driver->driver_name)) {
1738 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1739 /* mz: Do not instantly return -
1740 * we need to ensure this file isn't
1741 * also in use by other drivers. */
1742 in_use = true;
1746 talloc_free(driver);
1749 talloc_free(drivers);
1751 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1753 return in_use;
1756 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1757 const char *short_arch,
1758 int vers,
1759 const char *fname)
1761 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1762 struct smb_filename *smb_fname = NULL;
1763 char *print_dlr_path;
1764 NTSTATUS status = NT_STATUS_NO_MEMORY;
1766 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1767 short_arch, vers, fname);
1768 if (print_dlr_path == NULL) {
1769 goto err_out;
1772 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
1773 if (smb_fname == NULL) {
1774 goto err_out;
1777 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1778 err_out:
1779 talloc_free(tmp_ctx);
1780 return status;
1783 /****************************************************************************
1784 Actually delete the driver files. Make sure that
1785 printer_driver_files_in_use() return False before calling
1786 this.
1787 ****************************************************************************/
1789 bool delete_driver_files(const struct auth_session_info *session_info,
1790 const struct spoolss_DriverInfo8 *r)
1792 const char *short_arch;
1793 connection_struct *conn;
1794 NTSTATUS nt_status;
1795 struct smb_filename *oldcwd_fname = NULL;
1796 char *printdollar = NULL;
1797 int printdollar_snum;
1798 bool ret = false;
1800 if (!r) {
1801 return false;
1804 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1805 r->driver_name, r->version));
1807 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1808 if (!printdollar) {
1809 return false;
1811 if (printdollar_snum == -1) {
1812 return false;
1815 nt_status = create_conn_struct_cwd(talloc_tos(),
1816 server_event_context(),
1817 server_messaging_context(),
1818 &conn,
1819 printdollar_snum,
1820 lp_path(talloc_tos(), printdollar_snum),
1821 session_info, &oldcwd_fname);
1822 if (!NT_STATUS_IS_OK(nt_status)) {
1823 DEBUG(0,("delete_driver_files: create_conn_struct "
1824 "returned %s\n", nt_errstr(nt_status)));
1825 return false;
1828 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1829 if (!NT_STATUS_IS_OK(nt_status)) {
1830 DEBUG(0, ("failed set force user / group\n"));
1831 ret = false;
1832 goto err_free_conn;
1835 if (!become_user_by_session(conn, session_info)) {
1836 DEBUG(0, ("failed to become user\n"));
1837 ret = false;
1838 goto err_free_conn;
1841 if ( !CAN_WRITE(conn) ) {
1842 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1843 ret = false;
1844 goto err_out;
1847 short_arch = get_short_archi(r->architecture);
1848 if (short_arch == NULL) {
1849 DEBUG(0, ("bad architecture %s\n", r->architecture));
1850 ret = false;
1851 goto err_out;
1854 /* now delete the files */
1856 if (r->driver_path && r->driver_path[0]) {
1857 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1858 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1861 if (r->config_file && r->config_file[0]) {
1862 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1863 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1866 if (r->data_file && r->data_file[0]) {
1867 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1868 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1871 if (r->help_file && r->help_file[0]) {
1872 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1873 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1876 if (r->dependent_files) {
1877 int i = 0;
1878 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1879 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1880 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1881 i++;
1885 ret = true;
1886 err_out:
1887 unbecome_user();
1888 err_free_conn:
1889 if (conn != NULL) {
1890 vfs_ChDir(conn, oldcwd_fname);
1891 TALLOC_FREE(oldcwd_fname);
1892 SMB_VFS_DISCONNECT(conn);
1893 conn_free(conn);
1895 return ret;
1898 /* error code:
1899 0: everything OK
1900 1: level not implemented
1901 2: file doesn't exist
1902 3: can't allocate memory
1903 4: can't free memory
1904 5: non existent struct
1908 A printer and a printer driver are 2 different things.
1909 NT manages them separatelly, Samba does the same.
1910 Why ? Simply because it's easier and it makes sense !
1912 Now explanation: You have 3 printers behind your samba server,
1913 2 of them are the same make and model (laser A and B). But laser B
1914 has an 3000 sheet feeder and laser A doesn't such an option.
1915 Your third printer is an old dot-matrix model for the accounting :-).
1917 If the /usr/local/samba/lib directory (default dir), you will have
1918 5 files to describe all of this.
1920 3 files for the printers (1 by printer):
1921 NTprinter_laser A
1922 NTprinter_laser B
1923 NTprinter_accounting
1924 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1925 NTdriver_printer model X
1926 NTdriver_printer model Y
1928 jfm: I should use this comment for the text file to explain
1929 same thing for the forms BTW.
1930 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1934 /* Convert generic access rights to printer object specific access rights.
1935 It turns out that NT4 security descriptors use generic access rights and
1936 NT5 the object specific ones. */
1938 void map_printer_permissions(struct security_descriptor *sd)
1940 int i;
1942 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1943 se_map_generic(&sd->dacl->aces[i].access_mask,
1944 &printer_generic_mapping);
1948 void map_job_permissions(struct security_descriptor *sd)
1950 int i;
1952 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1953 se_map_generic(&sd->dacl->aces[i].access_mask,
1954 &job_generic_mapping);
1959 /****************************************************************************
1960 Check a user has permissions to perform the given operation. We use the
1961 permission constants defined in include/rpc_spoolss.h to check the various
1962 actions we perform when checking printer access.
1964 PRINTER_ACCESS_ADMINISTER:
1965 print_queue_pause, print_queue_resume, update_printer_sec,
1966 update_printer, spoolss_addprinterex_level_2,
1967 _spoolss_setprinterdata
1969 PRINTER_ACCESS_USE:
1970 print_job_start
1972 JOB_ACCESS_ADMINISTER:
1973 print_job_delete, print_job_pause, print_job_resume,
1974 print_queue_purge
1976 Try access control in the following order (for performance reasons):
1977 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1978 2) check security descriptor (bit comparisons in memory)
1979 3) "printer admins" (may result in numerous calls to winbind)
1981 ****************************************************************************/
1982 WERROR print_access_check(const struct auth_session_info *session_info,
1983 struct messaging_context *msg_ctx, int snum,
1984 int access_type)
1986 struct spoolss_security_descriptor *secdesc = NULL;
1987 uint32_t access_granted;
1988 size_t sd_size;
1989 NTSTATUS status;
1990 WERROR result;
1991 const char *pname;
1992 TALLOC_CTX *mem_ctx = NULL;
1994 /* If user is NULL then use the current_user structure */
1996 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1998 if ((session_info->unix_token->uid == sec_initial_uid())
1999 || security_token_has_privilege(session_info->security_token,
2000 SEC_PRIV_PRINT_OPERATOR)) {
2001 return WERR_OK;
2004 /* Get printer name */
2006 pname = lp_printername(talloc_tos(), snum);
2008 if (!pname || !*pname) {
2009 return WERR_ACCESS_DENIED;
2012 /* Get printer security descriptor */
2014 if(!(mem_ctx = talloc_init("print_access_check"))) {
2015 return WERR_NOT_ENOUGH_MEMORY;
2018 result = winreg_get_printer_secdesc_internal(mem_ctx,
2019 get_session_info_system(),
2020 msg_ctx,
2021 pname,
2022 &secdesc);
2023 if (!W_ERROR_IS_OK(result)) {
2024 talloc_destroy(mem_ctx);
2025 return WERR_NOT_ENOUGH_MEMORY;
2028 if (access_type == JOB_ACCESS_ADMINISTER) {
2029 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2031 /* Create a child security descriptor to check permissions
2032 against. This is because print jobs are child objects
2033 objects of a printer. */
2034 status = se_create_child_secdesc(mem_ctx,
2035 &secdesc,
2036 &sd_size,
2037 parent_secdesc,
2038 parent_secdesc->owner_sid,
2039 parent_secdesc->group_sid,
2040 false);
2041 if (!NT_STATUS_IS_OK(status)) {
2042 talloc_destroy(mem_ctx);
2043 return ntstatus_to_werror(status);
2046 map_job_permissions(secdesc);
2047 } else {
2048 map_printer_permissions(secdesc);
2051 /* Check access */
2052 status = se_access_check(secdesc, session_info->security_token, access_type,
2053 &access_granted);
2055 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2057 talloc_destroy(mem_ctx);
2059 return ntstatus_to_werror(status);
2062 /****************************************************************************
2063 Check the time parameters allow a print operation.
2064 *****************************************************************************/
2066 bool print_time_access_check(const struct auth_session_info *session_info,
2067 struct messaging_context *msg_ctx,
2068 const char *servicename)
2070 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2071 WERROR result;
2072 bool ok = False;
2073 time_t now = time(NULL);
2074 struct tm *t;
2075 uint32_t mins;
2077 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2078 servicename, &pinfo2);
2079 if (!W_ERROR_IS_OK(result)) {
2080 return False;
2083 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2084 ok = True;
2087 t = gmtime(&now);
2088 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2090 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2091 ok = True;
2094 TALLOC_FREE(pinfo2);
2096 if (!ok) {
2097 errno = EACCES;
2100 return ok;
2103 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2104 const struct auth_session_info *session_info,
2105 struct messaging_context *msg_ctx,
2106 const char *printer)
2108 WERROR result;
2110 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2111 printer, "");
2112 if (!W_ERROR_IS_OK(result)) {
2113 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2114 "%s\n", printer, win_errstr(result)));
2118 void nt_printer_add(TALLOC_CTX *mem_ctx,
2119 const struct auth_session_info *session_info,
2120 struct messaging_context *msg_ctx,
2121 const char *printer)
2123 WERROR result;
2125 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2126 printer);
2127 if (!W_ERROR_IS_OK(result)) {
2128 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2129 printer, win_errstr(result)));