g_lock: Reformat to allow userdata
[Samba.git] / source3 / printing / nt_printing.c
blobf87703905ed13afe51bf08f9d7e115df47ed0e14
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 static bool print_driver_directories_init(void)
79 int service, i;
80 char *driver_path;
81 bool ok;
82 TALLOC_CTX *mem_ctx = talloc_stackframe();
84 service = lp_servicenumber("print$");
85 if (service < 0) {
86 /* We don't have a print$ share */
87 DEBUG(5, ("No print$ share has been configured.\n"));
88 talloc_free(mem_ctx);
89 return true;
92 driver_path = lp_path(mem_ctx, service);
93 if (driver_path == NULL) {
94 talloc_free(mem_ctx);
95 return false;
98 ok = directory_create_or_exist(driver_path, 0755);
99 if (!ok) {
100 DEBUG(1, ("Failed to create printer driver directory %s\n",
101 driver_path));
102 talloc_free(mem_ctx);
103 return false;
106 for (i = 0; archi_table[i].long_archi != NULL; i++) {
107 const char *arch_path;
109 arch_path = talloc_asprintf(mem_ctx,
110 "%s/%s",
111 driver_path,
112 archi_table[i].short_archi);
113 if (arch_path == NULL) {
114 talloc_free(mem_ctx);
115 return false;
118 ok = directory_create_or_exist(arch_path, 0755);
119 if (!ok) {
120 DEBUG(1, ("Failed to create printer driver "
121 "architecture directory %s\n",
122 arch_path));
123 talloc_free(mem_ctx);
124 return false;
128 talloc_free(mem_ctx);
129 return true;
132 /****************************************************************************
133 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
134 background lpq updater.
135 ****************************************************************************/
137 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
138 void *private_data,
139 uint32_t msg_type,
140 struct server_id server_id,
141 DATA_BLOB *data)
143 extern pid_t background_lpq_updater_pid;
145 if (background_lpq_updater_pid == -1) {
146 DEBUG(3,("no background lpq queue updater\n"));
147 return;
150 messaging_send_buf(msg,
151 pid_to_procid(background_lpq_updater_pid),
152 MSG_PRINTER_DRVUPGRADE,
153 data->data,
154 data->length);
157 /****************************************************************************
158 Open the NT printing tdbs. Done once before fork().
159 ****************************************************************************/
161 bool nt_printing_init(struct messaging_context *msg_ctx)
163 WERROR win_rc;
165 if (!print_driver_directories_init()) {
166 return false;
169 if (!nt_printing_tdb_upgrade()) {
170 return false;
174 * register callback to handle updating printers as new
175 * drivers are installed. Forwards to background lpq updater.
177 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
178 forward_drv_upgrade_printer_msg);
180 /* of course, none of the message callbacks matter if you don't
181 tell messages.c that you interested in receiving PRINT_GENERAL
182 msgs. This is done in serverid_register() */
184 if ( lp_security() == SEC_ADS ) {
185 win_rc = check_published_printers(msg_ctx);
186 if (!W_ERROR_IS_OK(win_rc))
187 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
190 return true;
193 /*******************************************************************
194 Function to allow filename parsing "the old way".
195 ********************************************************************/
197 static NTSTATUS driver_unix_convert(connection_struct *conn,
198 const char *old_name,
199 struct smb_filename **smb_fname)
201 NTSTATUS status;
202 TALLOC_CTX *ctx = talloc_tos();
203 char *name = talloc_strdup(ctx, old_name);
205 if (!name) {
206 return NT_STATUS_NO_MEMORY;
208 unix_format(name);
209 name = unix_clean_name(ctx, name);
210 if (!name) {
211 return NT_STATUS_NO_MEMORY;
213 trim_string(name,"/","/");
215 status = unix_convert(ctx, conn, name, smb_fname, 0);
216 if (!NT_STATUS_IS_OK(status)) {
217 return NT_STATUS_NO_MEMORY;
220 return NT_STATUS_OK;
223 /****************************************************************************
224 Function to do the mapping between the long architecture name and
225 the short one.
226 ****************************************************************************/
228 const char *get_short_archi(const char *long_archi)
230 int i=-1;
232 DEBUG(107,("Getting architecture dependent directory\n"));
233 do {
234 i++;
235 } while ( (archi_table[i].long_archi!=NULL ) &&
236 strcasecmp_m(long_archi, archi_table[i].long_archi) );
238 if (archi_table[i].long_archi==NULL) {
239 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
240 return NULL;
243 /* this might be client code - but shouldn't this be an fstrcpy etc? */
245 DEBUGADD(108,("index: [%d]\n", i));
246 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
247 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
249 return archi_table[i].short_archi;
252 /****************************************************************************
253 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
254 There are two case to be covered here: PE (Portable Executable) and NE (New
255 Executable) files. Both files support the same INFO structure, but PE files
256 store the signature in unicode, and NE files store it as !unicode.
257 returns -1 on error, 1 on version info found, and 0 on no version info found.
258 ****************************************************************************/
260 static int get_file_version(files_struct *fsp, char *fname,uint32_t *major, uint32_t *minor)
262 int i;
263 char *buf = NULL;
264 ssize_t byte_count;
266 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
267 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
268 fname, DOS_HEADER_SIZE));
269 goto error_exit;
272 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
273 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
274 fname, (unsigned long)byte_count));
275 goto no_version_info;
278 /* Is this really a DOS header? */
279 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
280 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
281 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
282 goto no_version_info;
285 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
286 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
287 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
288 fname, errno));
289 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
290 goto no_version_info;
293 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
294 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
295 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
296 fname, (unsigned long)byte_count));
297 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
298 goto no_version_info;
301 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
302 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
303 unsigned int num_sections;
304 unsigned int section_table_bytes;
306 /* Just skip over optional header to get to section table */
307 if (SMB_VFS_LSEEK(fsp,
308 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
309 SEEK_CUR) == (off_t)-1) {
310 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
311 fname, errno));
312 goto error_exit;
315 /* get the section table */
316 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
317 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
318 if (section_table_bytes == 0)
319 goto error_exit;
321 SAFE_FREE(buf);
322 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
323 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
324 fname, section_table_bytes));
325 goto error_exit;
328 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
329 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
330 fname, (unsigned long)byte_count));
331 goto error_exit;
334 /* Iterate the section table looking for the resource section ".rsrc" */
335 for (i = 0; i < num_sections; i++) {
336 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
338 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
339 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
340 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
342 if (section_bytes == 0)
343 goto error_exit;
345 SAFE_FREE(buf);
346 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
347 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
348 fname, section_bytes));
349 goto error_exit;
352 /* Seek to the start of the .rsrc section info */
353 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
354 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
355 fname, errno));
356 goto error_exit;
359 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
360 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
361 fname, (unsigned long)byte_count));
362 goto error_exit;
365 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
366 goto error_exit;
368 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
369 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
370 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
371 /* Align to next long address */
372 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
374 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
375 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
376 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
378 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
379 fname, *major, *minor,
380 (*major>>16)&0xffff, *major&0xffff,
381 (*minor>>16)&0xffff, *minor&0xffff));
382 SAFE_FREE(buf);
383 return 1;
390 /* Version info not found, fall back to origin date/time */
391 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
392 SAFE_FREE(buf);
393 return 0;
395 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
396 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
397 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
398 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
399 /* At this point, we assume the file is in error. It still could be something
400 * else besides a NE file, but it unlikely at this point. */
401 goto error_exit;
404 /* Allocate a bit more space to speed up things */
405 SAFE_FREE(buf);
406 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
407 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
408 fname, PE_HEADER_SIZE));
409 goto error_exit;
412 /* This is a HACK! I got tired of trying to sort through the messy
413 * 'NE' file format. If anyone wants to clean this up please have at
414 * it, but this works. 'NE' files will eventually fade away. JRR */
415 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
416 /* Cover case that should not occur in a well formed 'NE' .dll file */
417 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
419 for(i=0; i<byte_count; i++) {
420 /* Fast skip past data that can't possibly match */
421 if (buf[i] != 'V') continue;
423 /* Potential match data crosses buf boundry, move it to beginning
424 * of buf, and fill the buf with as much as it will hold. */
425 if (i>byte_count-VS_VERSION_INFO_SIZE) {
426 int bc;
428 memcpy(buf, &buf[i], byte_count-i);
429 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
430 (byte_count-i))) < 0) {
432 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
433 fname, errno));
434 goto error_exit;
437 byte_count = bc + (byte_count - i);
438 if (byte_count<VS_VERSION_INFO_SIZE) break;
440 i = 0;
443 /* Check that the full signature string and the magic number that
444 * follows exist (not a perfect solution, but the chances that this
445 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
446 * twice, as it is simpler to read the code. */
447 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
448 /* Compute skip alignment to next long address */
449 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
450 sizeof(VS_SIGNATURE)) & 3;
451 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
453 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
454 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
455 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
456 fname, *major, *minor,
457 (*major>>16)&0xffff, *major&0xffff,
458 (*minor>>16)&0xffff, *minor&0xffff));
459 SAFE_FREE(buf);
460 return 1;
465 /* Version info not found, fall back to origin date/time */
466 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
467 SAFE_FREE(buf);
468 return 0;
470 } else
471 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
472 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
473 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
475 no_version_info:
476 SAFE_FREE(buf);
477 return 0;
479 error_exit:
480 SAFE_FREE(buf);
481 return -1;
484 /****************************************************************************
485 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
486 share one or more files. During the MS installation process files are checked
487 to insure that only a newer version of a shared file is installed over an
488 older version. There are several possibilities for this comparison. If there
489 is no previous version, the new one is newer (obviously). If either file is
490 missing the version info structure, compare the creation date (on Unix use
491 the modification date). Otherwise chose the numerically larger version number.
492 ****************************************************************************/
494 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
496 bool use_version = true;
498 uint32_t new_major;
499 uint32_t new_minor;
500 time_t new_create_time;
502 uint32_t old_major;
503 uint32_t old_minor;
504 time_t old_create_time;
506 struct smb_filename *smb_fname = NULL;
507 files_struct *fsp = NULL;
508 SMB_STRUCT_STAT st;
510 NTSTATUS status;
511 int ret;
513 SET_STAT_INVALID(st);
514 new_create_time = (time_t)0;
515 old_create_time = (time_t)0;
517 /* Get file version info (if available) for previous file (if it exists) */
518 status = driver_unix_convert(conn, old_file, &smb_fname);
519 if (!NT_STATUS_IS_OK(status)) {
520 goto error_exit;
523 status = SMB_VFS_CREATE_FILE(
524 conn, /* conn */
525 NULL, /* req */
526 0, /* root_dir_fid */
527 smb_fname, /* fname */
528 FILE_GENERIC_READ, /* access_mask */
529 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
530 FILE_OPEN, /* create_disposition*/
531 0, /* create_options */
532 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
533 INTERNAL_OPEN_ONLY, /* oplock_request */
534 NULL, /* lease */
535 0, /* allocation_size */
536 0, /* private_flags */
537 NULL, /* sd */
538 NULL, /* ea_list */
539 &fsp, /* result */
540 NULL, /* pinfo */
541 NULL, NULL); /* create context */
543 if (!NT_STATUS_IS_OK(status)) {
544 /* Old file not found, so by definition new file is in fact newer */
545 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
546 "errno = %d\n", smb_fname_str_dbg(smb_fname),
547 errno));
548 ret = 1;
549 goto done;
551 } else {
552 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
553 if (ret == -1) {
554 goto error_exit;
557 if (!ret) {
558 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
559 old_file));
560 use_version = false;
561 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
562 goto error_exit;
564 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
565 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
566 (long)old_create_time));
569 close_file(NULL, fsp, NORMAL_CLOSE);
570 fsp = NULL;
572 /* Get file version info (if available) for new file */
573 status = driver_unix_convert(conn, new_file, &smb_fname);
574 if (!NT_STATUS_IS_OK(status)) {
575 goto error_exit;
578 status = SMB_VFS_CREATE_FILE(
579 conn, /* conn */
580 NULL, /* req */
581 0, /* root_dir_fid */
582 smb_fname, /* fname */
583 FILE_GENERIC_READ, /* access_mask */
584 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
585 FILE_OPEN, /* create_disposition*/
586 0, /* create_options */
587 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
588 INTERNAL_OPEN_ONLY, /* oplock_request */
589 NULL, /* lease */
590 0, /* allocation_size */
591 0, /* private_flags */
592 NULL, /* sd */
593 NULL, /* ea_list */
594 &fsp, /* result */
595 NULL, /* pinfo */
596 NULL, NULL); /* create context */
598 if (!NT_STATUS_IS_OK(status)) {
599 /* New file not found, this shouldn't occur if the caller did its job */
600 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
601 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
602 goto error_exit;
604 } else {
605 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
606 if (ret == -1) {
607 goto error_exit;
610 if (!ret) {
611 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
612 new_file));
613 use_version = false;
614 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
615 goto error_exit;
617 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
618 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
619 (long)new_create_time));
622 close_file(NULL, fsp, NORMAL_CLOSE);
623 fsp = NULL;
625 if (use_version && (new_major != old_major || new_minor != old_minor)) {
626 /* Compare versions and choose the larger version number */
627 if (new_major > old_major ||
628 (new_major == old_major && new_minor > old_minor)) {
630 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
631 ret = 1;
632 goto done;
634 else {
635 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
636 ret = 0;
637 goto done;
640 } else {
641 /* Compare modification time/dates and choose the newest time/date */
642 if (new_create_time > old_create_time) {
643 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
644 ret = 1;
645 goto done;
647 else {
648 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
649 ret = 0;
650 goto done;
654 error_exit:
655 if(fsp)
656 close_file(NULL, fsp, NORMAL_CLOSE);
657 ret = -1;
658 done:
659 TALLOC_FREE(smb_fname);
660 return ret;
663 /****************************************************************************
664 Determine the correct cVersion associated with an architecture and driver
665 ****************************************************************************/
666 static uint32_t get_correct_cversion(struct auth_session_info *session_info,
667 const char *architecture,
668 const char *driverpath_in,
669 const char *driver_directory,
670 WERROR *perr)
672 int cversion = -1;
673 NTSTATUS nt_status;
674 struct smb_filename *smb_fname = NULL;
675 files_struct *fsp = NULL;
676 connection_struct *conn = NULL;
677 char *oldcwd;
678 char *printdollar = NULL;
679 char *printdollar_path = NULL;
680 char *working_dir = NULL;
681 int printdollar_snum;
683 *perr = WERR_INVALID_PARAMETER;
685 /* If architecture is Windows 95/98/ME, the version is always 0. */
686 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
687 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
688 *perr = WERR_OK;
689 return 0;
692 /* If architecture is Windows x64, the version is always 3. */
693 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
694 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
695 *perr = WERR_OK;
696 return 3;
699 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
700 if (!printdollar) {
701 *perr = WERR_NOT_ENOUGH_MEMORY;
702 return -1;
704 if (printdollar_snum == -1) {
705 *perr = WERR_BAD_NET_NAME;
706 return -1;
709 printdollar_path = lp_path(talloc_tos(), printdollar_snum);
710 if (printdollar_path == NULL) {
711 *perr = WERR_NOT_ENOUGH_MEMORY;
712 return -1;
715 working_dir = talloc_asprintf(talloc_tos(),
716 "%s/%s",
717 printdollar_path,
718 architecture);
720 * If the driver has been uploaded into a temorpary driver
721 * directory, switch to the driver directory.
723 if (driver_directory != NULL) {
724 working_dir = talloc_asprintf(talloc_tos(), "%s/%s/%s",
725 printdollar_path,
726 architecture,
727 driver_directory);
730 nt_status = create_conn_struct_cwd(talloc_tos(),
731 server_event_context(),
732 server_messaging_context(),
733 &conn,
734 printdollar_snum,
735 working_dir,
736 session_info, &oldcwd);
737 if (!NT_STATUS_IS_OK(nt_status)) {
738 DEBUG(0,("get_correct_cversion: create_conn_struct "
739 "returned %s\n", nt_errstr(nt_status)));
740 *perr = ntstatus_to_werror(nt_status);
741 return -1;
744 nt_status = set_conn_force_user_group(conn, printdollar_snum);
745 if (!NT_STATUS_IS_OK(nt_status)) {
746 DEBUG(0, ("failed set force user / group\n"));
747 *perr = ntstatus_to_werror(nt_status);
748 goto error_free_conn;
751 if (!become_user_by_session(conn, session_info)) {
752 DEBUG(0, ("failed to become user\n"));
753 *perr = WERR_ACCESS_DENIED;
754 goto error_free_conn;
758 * We switch to the directory where the driver files are located,
759 * so only work on the file names
761 nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
762 if (!NT_STATUS_IS_OK(nt_status)) {
763 *perr = ntstatus_to_werror(nt_status);
764 goto error_exit;
767 nt_status = vfs_file_exist(conn, smb_fname);
768 if (!NT_STATUS_IS_OK(nt_status)) {
769 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
770 *perr = WERR_FILE_NOT_FOUND;
771 goto error_exit;
774 nt_status = SMB_VFS_CREATE_FILE(
775 conn, /* conn */
776 NULL, /* req */
777 0, /* root_dir_fid */
778 smb_fname, /* fname */
779 FILE_GENERIC_READ, /* access_mask */
780 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
781 FILE_OPEN, /* create_disposition*/
782 0, /* create_options */
783 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
784 INTERNAL_OPEN_ONLY, /* oplock_request */
785 NULL, /* lease */
786 0, /* private_flags */
787 0, /* allocation_size */
788 NULL, /* sd */
789 NULL, /* ea_list */
790 &fsp, /* result */
791 NULL, /* pinfo */
792 NULL, NULL); /* create context */
794 if (!NT_STATUS_IS_OK(nt_status)) {
795 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
796 "%d\n", smb_fname_str_dbg(smb_fname), errno));
797 *perr = WERR_ACCESS_DENIED;
798 goto error_exit;
799 } else {
800 uint32_t major;
801 uint32_t minor;
802 int ret;
804 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
805 if (ret == -1) {
806 *perr = WERR_INVALID_PARAMETER;
807 goto error_exit;
808 } else if (!ret) {
809 DEBUG(6,("get_correct_cversion: Version info not "
810 "found [%s]\n",
811 smb_fname_str_dbg(smb_fname)));
812 *perr = WERR_INVALID_PARAMETER;
813 goto error_exit;
817 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
818 * for more details. Version in this case is not just the version of the
819 * file, but the version in the sense of kernal mode (2) vs. user mode
820 * (3) drivers. Other bits of the version fields are the version info.
821 * JRR 010716
823 cversion = major & 0x0000ffff;
824 switch (cversion) {
825 case 2: /* WinNT drivers */
826 case 3: /* Win2K drivers */
827 break;
829 default:
830 DEBUG(6,("get_correct_cversion: cversion "
831 "invalid [%s] cversion = %d\n",
832 smb_fname_str_dbg(smb_fname),
833 cversion));
834 goto error_exit;
837 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
838 " = 0x%x minor = 0x%x\n",
839 smb_fname_str_dbg(smb_fname), major, minor));
842 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
843 smb_fname_str_dbg(smb_fname), cversion));
844 *perr = WERR_OK;
846 error_exit:
847 unbecome_user();
848 error_free_conn:
849 TALLOC_FREE(smb_fname);
850 if (fsp != NULL) {
851 close_file(NULL, fsp, NORMAL_CLOSE);
853 if (conn != NULL) {
854 vfs_ChDir(conn, oldcwd);
855 SMB_VFS_DISCONNECT(conn);
856 conn_free(conn);
858 if (!W_ERROR_IS_OK(*perr)) {
859 cversion = -1;
862 return cversion;
865 /****************************************************************************
866 ****************************************************************************/
868 #define strip_driver_path(_mem_ctx, _element) do { \
869 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
870 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
871 W_ERROR_HAVE_NO_MEMORY((_element)); \
873 } while (0);
875 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
876 struct auth_session_info *session_info,
877 const char *architecture,
878 const char **driver_path,
879 const char **data_file,
880 const char **config_file,
881 const char **help_file,
882 struct spoolss_StringArray *dependent_files,
883 enum spoolss_DriverOSVersion *version,
884 uint32_t flags,
885 const char **driver_directory)
887 const char *short_architecture;
888 int i;
889 WERROR err;
890 char *_p;
892 if (!*driver_path || !*data_file) {
893 return WERR_INVALID_PARAMETER;
896 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
897 return WERR_INVALID_PARAMETER;
900 if (flags & APD_COPY_FROM_DIRECTORY) {
901 char *path;
902 char *q;
905 * driver_path is set to:
907 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
909 path = talloc_strdup(mem_ctx, *driver_path);
910 if (path == NULL) {
911 return WERR_NOT_ENOUGH_MEMORY;
914 /* Remove pscript5.dll */
915 q = strrchr_m(path, '\\');
916 if (q == NULL) {
917 return WERR_INVALID_PARAMETER;
919 *q = '\0';
921 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
922 q = strrchr_m(path, '\\');
923 if (q == NULL) {
924 return WERR_INVALID_PARAMETER;
928 * Set driver_directory to:
930 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
932 * This is the directory where all the files have been uploaded
934 *driver_directory = q + 1;
937 /* clean up the driver name.
938 * we can get .\driver.dll
939 * or worse c:\windows\system\driver.dll !
941 /* using an intermediate string to not have overlaping memcpy()'s */
943 strip_driver_path(mem_ctx, *driver_path);
944 strip_driver_path(mem_ctx, *data_file);
945 if (*config_file) {
946 strip_driver_path(mem_ctx, *config_file);
948 if (help_file) {
949 strip_driver_path(mem_ctx, *help_file);
952 if (dependent_files && dependent_files->string) {
953 for (i=0; dependent_files->string[i]; i++) {
954 strip_driver_path(mem_ctx, dependent_files->string[i]);
958 short_architecture = get_short_archi(architecture);
959 if (!short_architecture) {
960 return WERR_UNKNOWN_PRINTER_DRIVER;
963 /* jfm:7/16/2000 the client always sends the cversion=0.
964 * The server should check which version the driver is by reading
965 * the PE header of driver->driverpath.
967 * For Windows 95/98 the version is 0 (so the value sent is correct)
968 * For Windows NT (the architecture doesn't matter)
969 * NT 3.1: cversion=0
970 * NT 3.5/3.51: cversion=1
971 * NT 4: cversion=2
972 * NT2K: cversion=3
975 *version = get_correct_cversion(session_info,
976 short_architecture,
977 *driver_path,
978 *driver_directory,
979 &err);
980 if (*version == -1) {
981 return err;
984 return WERR_OK;
987 /****************************************************************************
988 ****************************************************************************/
990 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
991 struct auth_session_info *session_info,
992 struct spoolss_AddDriverInfoCtr *r,
993 uint32_t flags,
994 const char **driver_directory)
996 switch (r->level) {
997 case 3:
998 return clean_up_driver_struct_level(mem_ctx, session_info,
999 r->info.info3->architecture,
1000 &r->info.info3->driver_path,
1001 &r->info.info3->data_file,
1002 &r->info.info3->config_file,
1003 &r->info.info3->help_file,
1004 r->info.info3->dependent_files,
1005 &r->info.info3->version,
1006 flags,
1007 driver_directory);
1008 case 6:
1009 return clean_up_driver_struct_level(mem_ctx, session_info,
1010 r->info.info6->architecture,
1011 &r->info.info6->driver_path,
1012 &r->info.info6->data_file,
1013 &r->info.info6->config_file,
1014 &r->info.info6->help_file,
1015 r->info.info6->dependent_files,
1016 &r->info.info6->version,
1017 flags,
1018 driver_directory);
1019 case 8:
1020 return clean_up_driver_struct_level(mem_ctx, session_info,
1021 r->info.info8->architecture,
1022 &r->info.info8->driver_path,
1023 &r->info.info8->data_file,
1024 &r->info.info8->config_file,
1025 &r->info.info8->help_file,
1026 r->info.info8->dependent_files,
1027 &r->info.info8->version,
1028 flags,
1029 driver_directory);
1030 default:
1031 return WERR_NOT_SUPPORTED;
1035 /****************************************************************************
1036 This function sucks and should be replaced. JRA.
1037 ****************************************************************************/
1039 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1040 const struct spoolss_AddDriverInfo6 *src)
1042 dst->version = src->version;
1044 dst->driver_name = src->driver_name;
1045 dst->architecture = src->architecture;
1046 dst->driver_path = src->driver_path;
1047 dst->data_file = src->data_file;
1048 dst->config_file = src->config_file;
1049 dst->help_file = src->help_file;
1050 dst->monitor_name = src->monitor_name;
1051 dst->default_datatype = src->default_datatype;
1052 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1053 dst->dependent_files = src->dependent_files;
1056 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1057 const struct spoolss_AddDriverInfo8 *src)
1059 dst->version = src->version;
1061 dst->driver_name = src->driver_name;
1062 dst->architecture = src->architecture;
1063 dst->driver_path = src->driver_path;
1064 dst->data_file = src->data_file;
1065 dst->config_file = src->config_file;
1066 dst->help_file = src->help_file;
1067 dst->monitor_name = src->monitor_name;
1068 dst->default_datatype = src->default_datatype;
1069 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1070 dst->dependent_files = src->dependent_files;
1073 /****************************************************************************
1074 ****************************************************************************/
1076 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1077 connection_struct *conn,
1078 const char *driver_file,
1079 const char *short_architecture,
1080 uint32_t driver_version,
1081 uint32_t version,
1082 const char *driver_directory)
1084 struct smb_filename *smb_fname_old = NULL;
1085 struct smb_filename *smb_fname_new = NULL;
1086 char *old_name = NULL;
1087 char *new_name = NULL;
1088 NTSTATUS status;
1089 WERROR ret;
1091 if (driver_directory != NULL) {
1092 old_name = talloc_asprintf(mem_ctx,
1093 "%s/%s/%s",
1094 short_architecture,
1095 driver_directory,
1096 driver_file);
1097 } else {
1098 old_name = talloc_asprintf(mem_ctx,
1099 "%s/%s",
1100 short_architecture,
1101 driver_file);
1103 if (old_name == NULL) {
1104 return WERR_NOT_ENOUGH_MEMORY;
1107 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1108 short_architecture, driver_version, driver_file);
1109 if (new_name == NULL) {
1110 TALLOC_FREE(old_name);
1111 return WERR_NOT_ENOUGH_MEMORY;
1114 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1116 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 ret = WERR_NOT_ENOUGH_MEMORY;
1119 goto out;
1122 /* Setup a synthetic smb_filename struct */
1123 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1124 if (!smb_fname_new) {
1125 ret = WERR_NOT_ENOUGH_MEMORY;
1126 goto out;
1129 smb_fname_new->base_name = new_name;
1131 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1132 "'%s'\n", smb_fname_old->base_name,
1133 smb_fname_new->base_name));
1135 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1136 OPENX_FILE_EXISTS_TRUNCATE |
1137 OPENX_FILE_CREATE_IF_NOT_EXIST,
1138 0, false);
1140 if (!NT_STATUS_IS_OK(status)) {
1141 DEBUG(0,("move_driver_file_to_download_area: Unable "
1142 "to rename [%s] to [%s]: %s\n",
1143 smb_fname_old->base_name, new_name,
1144 nt_errstr(status)));
1145 ret = WERR_ACCESS_DENIED;
1146 goto out;
1150 ret = WERR_OK;
1151 out:
1152 TALLOC_FREE(smb_fname_old);
1153 TALLOC_FREE(smb_fname_new);
1154 return ret;
1157 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1158 struct spoolss_AddDriverInfoCtr *r,
1159 const char *driver_directory)
1161 struct spoolss_AddDriverInfo3 *driver;
1162 struct spoolss_AddDriverInfo3 converted_driver;
1163 const char *short_architecture;
1164 struct smb_filename *smb_dname = NULL;
1165 char *new_dir = NULL;
1166 connection_struct *conn = NULL;
1167 NTSTATUS nt_status;
1168 int i;
1169 TALLOC_CTX *ctx = talloc_tos();
1170 int ver = 0;
1171 char *oldcwd;
1172 char *printdollar = NULL;
1173 int printdollar_snum;
1174 WERROR err = WERR_OK;
1176 switch (r->level) {
1177 case 3:
1178 driver = r->info.info3;
1179 break;
1180 case 6:
1181 convert_level_6_to_level3(&converted_driver, r->info.info6);
1182 driver = &converted_driver;
1183 break;
1184 case 8:
1185 convert_level_8_to_level3(&converted_driver, r->info.info8);
1186 driver = &converted_driver;
1187 break;
1188 default:
1189 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1190 return WERR_INVALID_LEVEL;
1193 short_architecture = get_short_archi(driver->architecture);
1194 if (!short_architecture) {
1195 return WERR_UNKNOWN_PRINTER_DRIVER;
1198 printdollar_snum = find_service(ctx, "print$", &printdollar);
1199 if (!printdollar) {
1200 return WERR_NOT_ENOUGH_MEMORY;
1202 if (printdollar_snum == -1) {
1203 return WERR_BAD_NET_NAME;
1206 nt_status = create_conn_struct_cwd(talloc_tos(),
1207 server_event_context(),
1208 server_messaging_context(),
1209 &conn,
1210 printdollar_snum,
1211 lp_path(talloc_tos(), printdollar_snum),
1212 session_info, &oldcwd);
1213 if (!NT_STATUS_IS_OK(nt_status)) {
1214 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1215 "returned %s\n", nt_errstr(nt_status)));
1216 err = ntstatus_to_werror(nt_status);
1217 return err;
1220 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1221 if (!NT_STATUS_IS_OK(nt_status)) {
1222 DEBUG(0, ("failed set force user / group\n"));
1223 err = ntstatus_to_werror(nt_status);
1224 goto err_free_conn;
1227 if (!become_user_by_session(conn, session_info)) {
1228 DEBUG(0, ("failed to become user\n"));
1229 err = WERR_ACCESS_DENIED;
1230 goto err_free_conn;
1233 new_dir = talloc_asprintf(ctx,
1234 "%s/%d",
1235 short_architecture,
1236 driver->version);
1237 if (!new_dir) {
1238 err = WERR_NOT_ENOUGH_MEMORY;
1239 goto err_exit;
1241 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1242 if (!NT_STATUS_IS_OK(nt_status)) {
1243 err = WERR_NOT_ENOUGH_MEMORY;
1244 goto err_exit;
1247 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1249 nt_status = create_directory(conn, NULL, smb_dname);
1250 if (!NT_STATUS_IS_OK(nt_status)
1251 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1252 DEBUG(0, ("failed to create driver destination directory: %s\n",
1253 nt_errstr(nt_status)));
1254 err = ntstatus_to_werror(nt_status);
1255 goto err_exit;
1258 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1259 * listed for this driver which has already been moved, skip it (note:
1260 * drivers may list the same file name several times. Then check if the
1261 * file already exists in archi\version\, if so, check that the version
1262 * info (or time stamps if version info is unavailable) is newer (or the
1263 * date is later). If it is, move it to archi\version\filexxx.yyy.
1264 * Otherwise, delete the file.
1266 * If a file is not moved to archi\version\ because of an error, all the
1267 * rest of the 'unmoved' driver files are removed from archi\. If one or
1268 * more of the driver's files was already moved to archi\version\, it
1269 * potentially leaves the driver in a partially updated state. Version
1270 * trauma will most likely occur if an client attempts to use any printer
1271 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1272 * done is appropriate... later JRR
1275 DEBUG(5,("Moving files now !\n"));
1277 if (driver->driver_path && strlen(driver->driver_path)) {
1279 err = move_driver_file_to_download_area(ctx,
1280 conn,
1281 driver->driver_path,
1282 short_architecture,
1283 driver->version,
1284 ver,
1285 driver_directory);
1286 if (!W_ERROR_IS_OK(err)) {
1287 goto err_exit;
1291 if (driver->data_file && strlen(driver->data_file)) {
1292 if (!strequal(driver->data_file, driver->driver_path)) {
1294 err = move_driver_file_to_download_area(ctx,
1295 conn,
1296 driver->data_file,
1297 short_architecture,
1298 driver->version,
1299 ver,
1300 driver_directory);
1301 if (!W_ERROR_IS_OK(err)) {
1302 goto err_exit;
1307 if (driver->config_file && strlen(driver->config_file)) {
1308 if (!strequal(driver->config_file, driver->driver_path) &&
1309 !strequal(driver->config_file, driver->data_file)) {
1311 err = move_driver_file_to_download_area(ctx,
1312 conn,
1313 driver->config_file,
1314 short_architecture,
1315 driver->version,
1316 ver,
1317 driver_directory);
1318 if (!W_ERROR_IS_OK(err)) {
1319 goto err_exit;
1324 if (driver->help_file && strlen(driver->help_file)) {
1325 if (!strequal(driver->help_file, driver->driver_path) &&
1326 !strequal(driver->help_file, driver->data_file) &&
1327 !strequal(driver->help_file, driver->config_file)) {
1329 err = move_driver_file_to_download_area(ctx,
1330 conn,
1331 driver->help_file,
1332 short_architecture,
1333 driver->version,
1334 ver,
1335 driver_directory);
1336 if (!W_ERROR_IS_OK(err)) {
1337 goto err_exit;
1342 if (driver->dependent_files && driver->dependent_files->string) {
1343 for (i=0; driver->dependent_files->string[i]; i++) {
1344 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1345 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1346 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1347 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1348 int j;
1349 for (j=0; j < i; j++) {
1350 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1351 goto NextDriver;
1355 err = move_driver_file_to_download_area(ctx,
1356 conn,
1357 driver->dependent_files->string[i],
1358 short_architecture,
1359 driver->version,
1360 ver,
1361 driver_directory);
1362 if (!W_ERROR_IS_OK(err)) {
1363 goto err_exit;
1366 NextDriver: ;
1370 err = WERR_OK;
1371 err_exit:
1372 unbecome_user();
1373 err_free_conn:
1374 TALLOC_FREE(smb_dname);
1376 if (conn != NULL) {
1377 vfs_ChDir(conn, oldcwd);
1378 SMB_VFS_DISCONNECT(conn);
1379 conn_free(conn);
1382 return err;
1385 /****************************************************************************
1386 Determine whether or not a particular driver is currently assigned
1387 to a printer
1388 ****************************************************************************/
1390 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1391 struct dcerpc_binding_handle *b,
1392 const struct spoolss_DriverInfo8 *r)
1394 int snum;
1395 int n_services = lp_numservices();
1396 bool in_use = false;
1397 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1398 WERROR result;
1400 if (!r) {
1401 return false;
1404 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1406 /* loop through the printers.tdb and check for the drivername */
1408 for (snum=0; snum<n_services && !in_use; snum++) {
1409 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1410 continue;
1413 result = winreg_get_printer(mem_ctx, b,
1414 lp_servicename(talloc_tos(), snum),
1415 &pinfo2);
1416 if (!W_ERROR_IS_OK(result)) {
1417 continue; /* skip */
1420 if (strequal(r->driver_name, pinfo2->drivername)) {
1421 in_use = true;
1424 TALLOC_FREE(pinfo2);
1427 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1429 if ( in_use ) {
1430 struct spoolss_DriverInfo8 *driver = NULL;
1431 WERROR werr;
1433 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1435 /* we can still remove the driver if there is one of
1436 "Windows NT x86" version 2 or 3 left */
1438 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1439 if (r->version == 2) {
1440 werr = winreg_get_driver(mem_ctx, b,
1441 r->architecture,
1442 r->driver_name,
1443 3, &driver);
1444 } else if (r->version == 3) {
1445 werr = winreg_get_driver(mem_ctx, b,
1446 r->architecture,
1447 r->driver_name,
1448 2, &driver);
1449 } else {
1450 DBG_ERR("Unknown driver version (%d)\n",
1451 r->version);
1452 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1454 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1455 werr = winreg_get_driver(mem_ctx, b,
1456 SPOOLSS_ARCHITECTURE_NT_X86,
1457 r->driver_name,
1458 DRIVER_ANY_VERSION,
1459 &driver);
1460 } else {
1461 DBG_ERR("Unknown driver architecture: %s\n",
1462 r->architecture);
1463 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1466 /* now check the error code */
1468 if ( W_ERROR_IS_OK(werr) ) {
1469 /* it's ok to remove the driver, we have other architctures left */
1470 in_use = false;
1471 talloc_free(driver);
1475 /* report that the driver is not in use by default */
1477 return in_use;
1481 /**********************************************************************
1482 Check to see if a ogiven file is in use by *info
1483 *********************************************************************/
1485 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1487 int i = 0;
1489 if ( !info )
1490 return False;
1492 /* mz: skip files that are in the list but already deleted */
1493 if (!file || !file[0]) {
1494 return false;
1497 if (strequal(file, info->driver_path))
1498 return True;
1500 if (strequal(file, info->data_file))
1501 return True;
1503 if (strequal(file, info->config_file))
1504 return True;
1506 if (strequal(file, info->help_file))
1507 return True;
1509 /* see of there are any dependent files to examine */
1511 if (!info->dependent_files)
1512 return False;
1514 while (info->dependent_files[i] && *info->dependent_files[i]) {
1515 if (strequal(file, info->dependent_files[i]))
1516 return True;
1517 i++;
1520 return False;
1524 /**********************************************************************
1525 Utility function to remove the dependent file pointed to by the
1526 input parameter from the list
1527 *********************************************************************/
1529 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1532 /* bump everything down a slot */
1534 while (files && files[idx+1]) {
1535 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1536 idx++;
1539 files[idx] = NULL;
1541 return;
1544 /**********************************************************************
1545 Check if any of the files used by src are also used by drv
1546 *********************************************************************/
1548 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1549 struct spoolss_DriverInfo8 *src,
1550 const struct spoolss_DriverInfo8 *drv)
1552 bool in_use = False;
1553 int i = 0;
1555 if ( !src || !drv )
1556 return False;
1558 /* check each file. Remove it from the src structure if it overlaps */
1560 if (drv_file_in_use(src->driver_path, drv)) {
1561 in_use = True;
1562 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1563 src->driver_path = talloc_strdup(mem_ctx, "");
1564 if (!src->driver_path) { return false; }
1567 if (drv_file_in_use(src->data_file, drv)) {
1568 in_use = True;
1569 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1570 src->data_file = talloc_strdup(mem_ctx, "");
1571 if (!src->data_file) { return false; }
1574 if (drv_file_in_use(src->config_file, drv)) {
1575 in_use = True;
1576 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1577 src->config_file = talloc_strdup(mem_ctx, "");
1578 if (!src->config_file) { return false; }
1581 if (drv_file_in_use(src->help_file, drv)) {
1582 in_use = True;
1583 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1584 src->help_file = talloc_strdup(mem_ctx, "");
1585 if (!src->help_file) { return false; }
1588 /* are there any dependentfiles to examine? */
1590 if (!src->dependent_files)
1591 return in_use;
1593 while (src->dependent_files[i] && *src->dependent_files[i]) {
1594 if (drv_file_in_use(src->dependent_files[i], drv)) {
1595 in_use = True;
1596 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1597 trim_dependent_file(mem_ctx, src->dependent_files, i);
1598 } else
1599 i++;
1602 return in_use;
1605 /****************************************************************************
1606 Determine whether or not a particular driver files are currently being
1607 used by any other driver.
1609 Return value is True if any files were in use by other drivers
1610 and False otherwise.
1612 Upon return, *info has been modified to only contain the driver files
1613 which are not in use
1615 Fix from mz:
1617 This needs to check all drivers to ensure that all files in use
1618 have been removed from *info, not just the ones in the first
1619 match.
1620 ****************************************************************************/
1622 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1623 struct dcerpc_binding_handle *b,
1624 struct spoolss_DriverInfo8 *info)
1626 int i;
1627 uint32_t version;
1628 struct spoolss_DriverInfo8 *driver;
1629 bool in_use = false;
1630 uint32_t num_drivers;
1631 const char **drivers;
1632 WERROR result;
1634 if ( !info )
1635 return False;
1637 version = info->version;
1639 /* loop over all driver versions */
1641 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1643 /* get the list of drivers */
1645 result = winreg_get_driver_list(mem_ctx, b,
1646 info->architecture, version,
1647 &num_drivers, &drivers);
1648 if (!W_ERROR_IS_OK(result)) {
1649 return true;
1652 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1653 num_drivers, info->architecture, version));
1655 /* check each driver for overlap in files */
1657 for (i = 0; i < num_drivers; i++) {
1658 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1660 driver = NULL;
1662 result = winreg_get_driver(mem_ctx, b,
1663 info->architecture, drivers[i],
1664 version, &driver);
1665 if (!W_ERROR_IS_OK(result)) {
1666 talloc_free(drivers);
1667 return True;
1670 /* check if d2 uses any files from d1 */
1671 /* only if this is a different driver than the one being deleted */
1673 if (!strequal(info->driver_name, driver->driver_name)) {
1674 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1675 /* mz: Do not instantly return -
1676 * we need to ensure this file isn't
1677 * also in use by other drivers. */
1678 in_use = true;
1682 talloc_free(driver);
1685 talloc_free(drivers);
1687 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1689 return in_use;
1692 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1693 const char *short_arch,
1694 int vers,
1695 const char *fname)
1697 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1698 struct smb_filename *smb_fname = NULL;
1699 char *print_dlr_path;
1700 NTSTATUS status = NT_STATUS_NO_MEMORY;
1702 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1703 short_arch, vers, fname);
1704 if (print_dlr_path == NULL) {
1705 goto err_out;
1708 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
1709 if (smb_fname == NULL) {
1710 goto err_out;
1713 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1714 err_out:
1715 talloc_free(tmp_ctx);
1716 return status;
1719 /****************************************************************************
1720 Actually delete the driver files. Make sure that
1721 printer_driver_files_in_use() return False before calling
1722 this.
1723 ****************************************************************************/
1725 bool delete_driver_files(const struct auth_session_info *session_info,
1726 const struct spoolss_DriverInfo8 *r)
1728 const char *short_arch;
1729 connection_struct *conn;
1730 NTSTATUS nt_status;
1731 char *oldcwd;
1732 char *printdollar = NULL;
1733 int printdollar_snum;
1734 bool ret = false;
1736 if (!r) {
1737 return false;
1740 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1741 r->driver_name, r->version));
1743 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1744 if (!printdollar) {
1745 return false;
1747 if (printdollar_snum == -1) {
1748 return false;
1751 nt_status = create_conn_struct_cwd(talloc_tos(),
1752 server_event_context(),
1753 server_messaging_context(),
1754 &conn,
1755 printdollar_snum,
1756 lp_path(talloc_tos(), printdollar_snum),
1757 session_info, &oldcwd);
1758 if (!NT_STATUS_IS_OK(nt_status)) {
1759 DEBUG(0,("delete_driver_files: create_conn_struct "
1760 "returned %s\n", nt_errstr(nt_status)));
1761 return false;
1764 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1765 if (!NT_STATUS_IS_OK(nt_status)) {
1766 DEBUG(0, ("failed set force user / group\n"));
1767 ret = false;
1768 goto err_free_conn;
1771 if (!become_user_by_session(conn, session_info)) {
1772 DEBUG(0, ("failed to become user\n"));
1773 ret = false;
1774 goto err_free_conn;
1777 if ( !CAN_WRITE(conn) ) {
1778 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1779 ret = false;
1780 goto err_out;
1783 short_arch = get_short_archi(r->architecture);
1784 if (short_arch == NULL) {
1785 DEBUG(0, ("bad architecture %s\n", r->architecture));
1786 ret = false;
1787 goto err_out;
1790 /* now delete the files */
1792 if (r->driver_path && r->driver_path[0]) {
1793 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1794 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1797 if (r->config_file && r->config_file[0]) {
1798 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1799 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1802 if (r->data_file && r->data_file[0]) {
1803 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1804 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1807 if (r->help_file && r->help_file[0]) {
1808 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1809 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1812 if (r->dependent_files) {
1813 int i = 0;
1814 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1815 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1816 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1817 i++;
1821 ret = true;
1822 err_out:
1823 unbecome_user();
1824 err_free_conn:
1825 if (conn != NULL) {
1826 vfs_ChDir(conn, oldcwd);
1827 SMB_VFS_DISCONNECT(conn);
1828 conn_free(conn);
1830 return ret;
1833 /* error code:
1834 0: everything OK
1835 1: level not implemented
1836 2: file doesn't exist
1837 3: can't allocate memory
1838 4: can't free memory
1839 5: non existent struct
1843 A printer and a printer driver are 2 different things.
1844 NT manages them separatelly, Samba does the same.
1845 Why ? Simply because it's easier and it makes sense !
1847 Now explanation: You have 3 printers behind your samba server,
1848 2 of them are the same make and model (laser A and B). But laser B
1849 has an 3000 sheet feeder and laser A doesn't such an option.
1850 Your third printer is an old dot-matrix model for the accounting :-).
1852 If the /usr/local/samba/lib directory (default dir), you will have
1853 5 files to describe all of this.
1855 3 files for the printers (1 by printer):
1856 NTprinter_laser A
1857 NTprinter_laser B
1858 NTprinter_accounting
1859 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1860 NTdriver_printer model X
1861 NTdriver_printer model Y
1863 jfm: I should use this comment for the text file to explain
1864 same thing for the forms BTW.
1865 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1869 /* Convert generic access rights to printer object specific access rights.
1870 It turns out that NT4 security descriptors use generic access rights and
1871 NT5 the object specific ones. */
1873 void map_printer_permissions(struct security_descriptor *sd)
1875 int i;
1877 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1878 se_map_generic(&sd->dacl->aces[i].access_mask,
1879 &printer_generic_mapping);
1883 void map_job_permissions(struct security_descriptor *sd)
1885 int i;
1887 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1888 se_map_generic(&sd->dacl->aces[i].access_mask,
1889 &job_generic_mapping);
1894 /****************************************************************************
1895 Check a user has permissions to perform the given operation. We use the
1896 permission constants defined in include/rpc_spoolss.h to check the various
1897 actions we perform when checking printer access.
1899 PRINTER_ACCESS_ADMINISTER:
1900 print_queue_pause, print_queue_resume, update_printer_sec,
1901 update_printer, spoolss_addprinterex_level_2,
1902 _spoolss_setprinterdata
1904 PRINTER_ACCESS_USE:
1905 print_job_start
1907 JOB_ACCESS_ADMINISTER:
1908 print_job_delete, print_job_pause, print_job_resume,
1909 print_queue_purge
1911 Try access control in the following order (for performance reasons):
1912 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1913 2) check security descriptor (bit comparisons in memory)
1914 3) "printer admins" (may result in numerous calls to winbind)
1916 ****************************************************************************/
1917 WERROR print_access_check(const struct auth_session_info *session_info,
1918 struct messaging_context *msg_ctx, int snum,
1919 int access_type)
1921 struct spoolss_security_descriptor *secdesc = NULL;
1922 uint32_t access_granted;
1923 size_t sd_size;
1924 NTSTATUS status;
1925 WERROR result;
1926 const char *pname;
1927 TALLOC_CTX *mem_ctx = NULL;
1929 /* If user is NULL then use the current_user structure */
1931 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1933 if ((session_info->unix_token->uid == sec_initial_uid())
1934 || security_token_has_privilege(session_info->security_token,
1935 SEC_PRIV_PRINT_OPERATOR)) {
1936 return WERR_OK;
1939 /* Get printer name */
1941 pname = lp_printername(talloc_tos(), snum);
1943 if (!pname || !*pname) {
1944 return WERR_ACCESS_DENIED;
1947 /* Get printer security descriptor */
1949 if(!(mem_ctx = talloc_init("print_access_check"))) {
1950 return WERR_NOT_ENOUGH_MEMORY;
1953 result = winreg_get_printer_secdesc_internal(mem_ctx,
1954 get_session_info_system(),
1955 msg_ctx,
1956 pname,
1957 &secdesc);
1958 if (!W_ERROR_IS_OK(result)) {
1959 talloc_destroy(mem_ctx);
1960 return WERR_NOT_ENOUGH_MEMORY;
1963 if (access_type == JOB_ACCESS_ADMINISTER) {
1964 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1966 /* Create a child security descriptor to check permissions
1967 against. This is because print jobs are child objects
1968 objects of a printer. */
1969 status = se_create_child_secdesc(mem_ctx,
1970 &secdesc,
1971 &sd_size,
1972 parent_secdesc,
1973 parent_secdesc->owner_sid,
1974 parent_secdesc->group_sid,
1975 false);
1976 if (!NT_STATUS_IS_OK(status)) {
1977 talloc_destroy(mem_ctx);
1978 return ntstatus_to_werror(status);
1981 map_job_permissions(secdesc);
1982 } else {
1983 map_printer_permissions(secdesc);
1986 /* Check access */
1987 status = se_access_check(secdesc, session_info->security_token, access_type,
1988 &access_granted);
1990 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1992 talloc_destroy(mem_ctx);
1994 return ntstatus_to_werror(status);
1997 /****************************************************************************
1998 Check the time parameters allow a print operation.
1999 *****************************************************************************/
2001 bool print_time_access_check(const struct auth_session_info *session_info,
2002 struct messaging_context *msg_ctx,
2003 const char *servicename)
2005 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2006 WERROR result;
2007 bool ok = False;
2008 time_t now = time(NULL);
2009 struct tm *t;
2010 uint32_t mins;
2012 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2013 servicename, &pinfo2);
2014 if (!W_ERROR_IS_OK(result)) {
2015 return False;
2018 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2019 ok = True;
2022 t = gmtime(&now);
2023 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2025 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2026 ok = True;
2029 TALLOC_FREE(pinfo2);
2031 if (!ok) {
2032 errno = EACCES;
2035 return ok;
2038 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2039 const struct auth_session_info *session_info,
2040 struct messaging_context *msg_ctx,
2041 const char *printer)
2043 WERROR result;
2045 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2046 printer, "");
2047 if (!W_ERROR_IS_OK(result)) {
2048 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2049 "%s\n", printer, win_errstr(result)));
2053 void nt_printer_add(TALLOC_CTX *mem_ctx,
2054 const struct auth_session_info *session_info,
2055 struct messaging_context *msg_ctx,
2056 const char *printer)
2058 WERROR result;
2060 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2061 printer);
2062 if (!W_ERROR_IS_OK(result)) {
2063 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2064 printer, win_errstr(result)));