s3-utils/net_rpc_printer.c: print more info on write error
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blob7d1dd9e4d0cb35c092c445fe1a22e4194ffe69bc
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 "auth.h"
33 #include "messages.h"
34 #include "rpc_server/spoolss/srv_spoolss_nt.h"
35 #include "rpc_client/cli_winreg_spoolss.h"
37 /* Map generic permissions to printer object specific permissions */
39 const struct generic_mapping printer_generic_mapping = {
40 PRINTER_READ,
41 PRINTER_WRITE,
42 PRINTER_EXECUTE,
43 PRINTER_ALL_ACCESS
46 /* Map generic permissions to print server object specific permissions */
48 const struct generic_mapping printserver_generic_mapping = {
49 SERVER_READ,
50 SERVER_WRITE,
51 SERVER_EXECUTE,
52 SERVER_ALL_ACCESS
55 /* Map generic permissions to job object specific permissions */
57 const struct generic_mapping job_generic_mapping = {
58 JOB_READ,
59 JOB_WRITE,
60 JOB_EXECUTE,
61 JOB_ALL_ACCESS
64 static const struct print_architecture_table_node archi_table[]= {
66 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
67 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
68 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
69 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
70 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
71 {"Windows IA64", SPL_ARCH_IA64, 3 },
72 {"Windows x64", SPL_ARCH_X64, 3 },
73 {NULL, "", -1 }
76 /****************************************************************************
77 Open the NT printing tdbs. Done once before fork().
78 ****************************************************************************/
80 bool nt_printing_init(struct messaging_context *msg_ctx)
82 WERROR win_rc;
84 if (!nt_printing_tdb_upgrade()) {
85 return false;
89 * register callback to handle updating printers as new
90 * drivers are installed
92 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
93 do_drv_upgrade_printer);
95 /* of course, none of the message callbacks matter if you don't
96 tell messages.c that you interested in receiving PRINT_GENERAL
97 msgs. This is done in serverid_register() */
99 if ( lp_security() == SEC_ADS ) {
100 win_rc = check_published_printers(msg_ctx);
101 if (!W_ERROR_IS_OK(win_rc))
102 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
105 return true;
108 /*******************************************************************
109 Function to allow filename parsing "the old way".
110 ********************************************************************/
112 static NTSTATUS driver_unix_convert(connection_struct *conn,
113 const char *old_name,
114 struct smb_filename **smb_fname)
116 NTSTATUS status;
117 TALLOC_CTX *ctx = talloc_tos();
118 char *name = talloc_strdup(ctx, old_name);
120 if (!name) {
121 return NT_STATUS_NO_MEMORY;
123 unix_format(name);
124 name = unix_clean_name(ctx, name);
125 if (!name) {
126 return NT_STATUS_NO_MEMORY;
128 trim_string(name,"/","/");
130 status = unix_convert(ctx, conn, name, smb_fname, 0);
131 if (!NT_STATUS_IS_OK(status)) {
132 return NT_STATUS_NO_MEMORY;
135 return NT_STATUS_OK;
138 /****************************************************************************
139 Function to do the mapping between the long architecture name and
140 the short one.
141 ****************************************************************************/
143 const char *get_short_archi(const char *long_archi)
145 int i=-1;
147 DEBUG(107,("Getting architecture dependent directory\n"));
148 do {
149 i++;
150 } while ( (archi_table[i].long_archi!=NULL ) &&
151 strcasecmp_m(long_archi, archi_table[i].long_archi) );
153 if (archi_table[i].long_archi==NULL) {
154 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
155 return NULL;
158 /* this might be client code - but shouldn't this be an fstrcpy etc? */
160 DEBUGADD(108,("index: [%d]\n", i));
161 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
162 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
164 return archi_table[i].short_archi;
167 /****************************************************************************
168 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
169 There are two case to be covered here: PE (Portable Executable) and NE (New
170 Executable) files. Both files support the same INFO structure, but PE files
171 store the signature in unicode, and NE files store it as !unicode.
172 returns -1 on error, 1 on version info found, and 0 on no version info found.
173 ****************************************************************************/
175 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
177 int i;
178 char *buf = NULL;
179 ssize_t byte_count;
181 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
182 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
183 fname, DOS_HEADER_SIZE));
184 goto error_exit;
187 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
188 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
189 fname, (unsigned long)byte_count));
190 goto no_version_info;
193 /* Is this really a DOS header? */
194 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
195 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
196 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
197 goto no_version_info;
200 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
201 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
202 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
203 fname, errno));
204 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
205 goto no_version_info;
208 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
209 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
210 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
211 fname, (unsigned long)byte_count));
212 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
213 goto no_version_info;
216 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
217 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
218 unsigned int num_sections;
219 unsigned int section_table_bytes;
221 /* Just skip over optional header to get to section table */
222 if (SMB_VFS_LSEEK(fsp,
223 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
224 SEEK_CUR) == (SMB_OFF_T)-1) {
225 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
226 fname, errno));
227 goto error_exit;
230 /* get the section table */
231 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
232 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
233 if (section_table_bytes == 0)
234 goto error_exit;
236 SAFE_FREE(buf);
237 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
238 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
239 fname, section_table_bytes));
240 goto error_exit;
243 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
244 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
245 fname, (unsigned long)byte_count));
246 goto error_exit;
249 /* Iterate the section table looking for the resource section ".rsrc" */
250 for (i = 0; i < num_sections; i++) {
251 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
253 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
254 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
255 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
257 if (section_bytes == 0)
258 goto error_exit;
260 SAFE_FREE(buf);
261 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
262 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
263 fname, section_bytes));
264 goto error_exit;
267 /* Seek to the start of the .rsrc section info */
268 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
269 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
270 fname, errno));
271 goto error_exit;
274 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
275 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
276 fname, (unsigned long)byte_count));
277 goto error_exit;
280 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
281 goto error_exit;
283 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
284 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
285 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
286 /* Align to next long address */
287 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
289 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
290 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
291 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
293 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
294 fname, *major, *minor,
295 (*major>>16)&0xffff, *major&0xffff,
296 (*minor>>16)&0xffff, *minor&0xffff));
297 SAFE_FREE(buf);
298 return 1;
305 /* Version info not found, fall back to origin date/time */
306 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
307 SAFE_FREE(buf);
308 return 0;
310 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
311 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
312 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
313 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
314 /* At this point, we assume the file is in error. It still could be somthing
315 * else besides a NE file, but it unlikely at this point. */
316 goto error_exit;
319 /* Allocate a bit more space to speed up things */
320 SAFE_FREE(buf);
321 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
322 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
323 fname, PE_HEADER_SIZE));
324 goto error_exit;
327 /* This is a HACK! I got tired of trying to sort through the messy
328 * 'NE' file format. If anyone wants to clean this up please have at
329 * it, but this works. 'NE' files will eventually fade away. JRR */
330 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
331 /* Cover case that should not occur in a well formed 'NE' .dll file */
332 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
334 for(i=0; i<byte_count; i++) {
335 /* Fast skip past data that can't possibly match */
336 if (buf[i] != 'V') continue;
338 /* Potential match data crosses buf boundry, move it to beginning
339 * of buf, and fill the buf with as much as it will hold. */
340 if (i>byte_count-VS_VERSION_INFO_SIZE) {
341 int bc;
343 memcpy(buf, &buf[i], byte_count-i);
344 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
345 (byte_count-i))) < 0) {
347 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
348 fname, errno));
349 goto error_exit;
352 byte_count = bc + (byte_count - i);
353 if (byte_count<VS_VERSION_INFO_SIZE) break;
355 i = 0;
358 /* Check that the full signature string and the magic number that
359 * follows exist (not a perfect solution, but the chances that this
360 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
361 * twice, as it is simpler to read the code. */
362 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
363 /* Compute skip alignment to next long address */
364 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
365 sizeof(VS_SIGNATURE)) & 3;
366 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
368 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
369 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
370 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
371 fname, *major, *minor,
372 (*major>>16)&0xffff, *major&0xffff,
373 (*minor>>16)&0xffff, *minor&0xffff));
374 SAFE_FREE(buf);
375 return 1;
380 /* Version info not found, fall back to origin date/time */
381 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
382 SAFE_FREE(buf);
383 return 0;
385 } else
386 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
387 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
388 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
390 no_version_info:
391 SAFE_FREE(buf);
392 return 0;
394 error_exit:
395 SAFE_FREE(buf);
396 return -1;
399 /****************************************************************************
400 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
401 share one or more files. During the MS installation process files are checked
402 to insure that only a newer version of a shared file is installed over an
403 older version. There are several possibilities for this comparison. If there
404 is no previous version, the new one is newer (obviously). If either file is
405 missing the version info structure, compare the creation date (on Unix use
406 the modification date). Otherwise chose the numerically larger version number.
407 ****************************************************************************/
409 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
411 bool use_version = true;
413 uint32 new_major;
414 uint32 new_minor;
415 time_t new_create_time;
417 uint32 old_major;
418 uint32 old_minor;
419 time_t old_create_time;
421 struct smb_filename *smb_fname = NULL;
422 files_struct *fsp = NULL;
423 SMB_STRUCT_STAT st;
425 NTSTATUS status;
426 int ret;
428 SET_STAT_INVALID(st);
429 new_create_time = (time_t)0;
430 old_create_time = (time_t)0;
432 /* Get file version info (if available) for previous file (if it exists) */
433 status = driver_unix_convert(conn, old_file, &smb_fname);
434 if (!NT_STATUS_IS_OK(status)) {
435 goto error_exit;
438 status = SMB_VFS_CREATE_FILE(
439 conn, /* conn */
440 NULL, /* req */
441 0, /* root_dir_fid */
442 smb_fname, /* fname */
443 FILE_GENERIC_READ, /* access_mask */
444 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
445 FILE_OPEN, /* create_disposition*/
446 0, /* create_options */
447 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
448 INTERNAL_OPEN_ONLY, /* oplock_request */
449 0, /* allocation_size */
450 0, /* private_flags */
451 NULL, /* sd */
452 NULL, /* ea_list */
453 &fsp, /* result */
454 NULL); /* pinfo */
456 if (!NT_STATUS_IS_OK(status)) {
457 /* Old file not found, so by definition new file is in fact newer */
458 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
459 "errno = %d\n", smb_fname_str_dbg(smb_fname),
460 errno));
461 ret = 1;
462 goto done;
464 } else {
465 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
466 if (ret == -1) {
467 goto error_exit;
470 if (!ret) {
471 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
472 old_file));
473 use_version = false;
474 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
475 goto error_exit;
477 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
478 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
479 (long)old_create_time));
482 close_file(NULL, fsp, NORMAL_CLOSE);
483 fsp = NULL;
485 /* Get file version info (if available) for new file */
486 status = driver_unix_convert(conn, new_file, &smb_fname);
487 if (!NT_STATUS_IS_OK(status)) {
488 goto error_exit;
491 status = SMB_VFS_CREATE_FILE(
492 conn, /* conn */
493 NULL, /* req */
494 0, /* root_dir_fid */
495 smb_fname, /* fname */
496 FILE_GENERIC_READ, /* access_mask */
497 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
498 FILE_OPEN, /* create_disposition*/
499 0, /* create_options */
500 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
501 INTERNAL_OPEN_ONLY, /* oplock_request */
502 0, /* allocation_size */
503 0, /* private_flags */
504 NULL, /* sd */
505 NULL, /* ea_list */
506 &fsp, /* result */
507 NULL); /* pinfo */
509 if (!NT_STATUS_IS_OK(status)) {
510 /* New file not found, this shouldn't occur if the caller did its job */
511 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
512 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
513 goto error_exit;
515 } else {
516 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
517 if (ret == -1) {
518 goto error_exit;
521 if (!ret) {
522 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
523 new_file));
524 use_version = false;
525 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
526 goto error_exit;
528 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
529 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
530 (long)new_create_time));
533 close_file(NULL, fsp, NORMAL_CLOSE);
534 fsp = NULL;
536 if (use_version && (new_major != old_major || new_minor != old_minor)) {
537 /* Compare versions and choose the larger version number */
538 if (new_major > old_major ||
539 (new_major == old_major && new_minor > old_minor)) {
541 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
542 ret = 1;
543 goto done;
545 else {
546 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
547 ret = 0;
548 goto done;
551 } else {
552 /* Compare modification time/dates and choose the newest time/date */
553 if (new_create_time > old_create_time) {
554 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
555 ret = 1;
556 goto done;
558 else {
559 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
560 ret = 0;
561 goto done;
565 error_exit:
566 if(fsp)
567 close_file(NULL, fsp, NORMAL_CLOSE);
568 ret = -1;
569 done:
570 TALLOC_FREE(smb_fname);
571 return ret;
574 /****************************************************************************
575 Determine the correct cVersion associated with an architecture and driver
576 ****************************************************************************/
577 static uint32 get_correct_cversion(struct auth_session_info *session_info,
578 const char *architecture,
579 const char *driverpath_in,
580 WERROR *perr)
582 int cversion = -1;
583 NTSTATUS nt_status;
584 struct smb_filename *smb_fname = NULL;
585 char *driverpath = NULL;
586 files_struct *fsp = NULL;
587 connection_struct *conn = NULL;
588 char *oldcwd;
589 char *printdollar = NULL;
590 int printdollar_snum;
592 *perr = WERR_INVALID_PARAM;
594 /* If architecture is Windows 95/98/ME, the version is always 0. */
595 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
596 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
597 *perr = WERR_OK;
598 return 0;
601 /* If architecture is Windows x64, the version is always 3. */
602 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
603 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
604 *perr = WERR_OK;
605 return 3;
608 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
609 if (!printdollar) {
610 *perr = WERR_NOMEM;
611 return -1;
613 if (printdollar_snum == -1) {
614 *perr = WERR_NO_SUCH_SHARE;
615 return -1;
618 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
619 lp_pathname(printdollar_snum),
620 session_info, &oldcwd);
621 if (!NT_STATUS_IS_OK(nt_status)) {
622 DEBUG(0,("get_correct_cversion: create_conn_struct "
623 "returned %s\n", nt_errstr(nt_status)));
624 *perr = ntstatus_to_werror(nt_status);
625 return -1;
628 nt_status = set_conn_force_user_group(conn, printdollar_snum);
629 if (!NT_STATUS_IS_OK(nt_status)) {
630 DEBUG(0, ("failed set force user / group\n"));
631 *perr = ntstatus_to_werror(nt_status);
632 goto error_free_conn;
635 if (!become_user_by_session(conn, session_info)) {
636 DEBUG(0, ("failed to become user\n"));
637 *perr = WERR_ACCESS_DENIED;
638 goto error_free_conn;
641 /* Open the driver file (Portable Executable format) and determine the
642 * deriver the cversion. */
643 driverpath = talloc_asprintf(talloc_tos(),
644 "%s/%s",
645 architecture,
646 driverpath_in);
647 if (!driverpath) {
648 *perr = WERR_NOMEM;
649 goto error_exit;
652 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
653 if (!NT_STATUS_IS_OK(nt_status)) {
654 *perr = ntstatus_to_werror(nt_status);
655 goto error_exit;
658 nt_status = vfs_file_exist(conn, smb_fname);
659 if (!NT_STATUS_IS_OK(nt_status)) {
660 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
661 *perr = WERR_BADFILE;
662 goto error_exit;
665 nt_status = SMB_VFS_CREATE_FILE(
666 conn, /* conn */
667 NULL, /* req */
668 0, /* root_dir_fid */
669 smb_fname, /* fname */
670 FILE_GENERIC_READ, /* access_mask */
671 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
672 FILE_OPEN, /* create_disposition*/
673 0, /* create_options */
674 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
675 INTERNAL_OPEN_ONLY, /* oplock_request */
676 0, /* private_flags */
677 0, /* allocation_size */
678 NULL, /* sd */
679 NULL, /* ea_list */
680 &fsp, /* result */
681 NULL); /* pinfo */
683 if (!NT_STATUS_IS_OK(nt_status)) {
684 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
685 "%d\n", smb_fname_str_dbg(smb_fname), errno));
686 *perr = WERR_ACCESS_DENIED;
687 goto error_exit;
688 } else {
689 uint32 major;
690 uint32 minor;
691 int ret;
693 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
694 if (ret == -1) {
695 *perr = WERR_INVALID_PARAM;
696 goto error_exit;
697 } else if (!ret) {
698 DEBUG(6,("get_correct_cversion: Version info not "
699 "found [%s]\n",
700 smb_fname_str_dbg(smb_fname)));
701 *perr = WERR_INVALID_PARAM;
702 goto error_exit;
706 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
707 * for more details. Version in this case is not just the version of the
708 * file, but the version in the sense of kernal mode (2) vs. user mode
709 * (3) drivers. Other bits of the version fields are the version info.
710 * JRR 010716
712 cversion = major & 0x0000ffff;
713 switch (cversion) {
714 case 2: /* WinNT drivers */
715 case 3: /* Win2K drivers */
716 break;
718 default:
719 DEBUG(6,("get_correct_cversion: cversion "
720 "invalid [%s] cversion = %d\n",
721 smb_fname_str_dbg(smb_fname),
722 cversion));
723 goto error_exit;
726 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
727 " = 0x%x minor = 0x%x\n",
728 smb_fname_str_dbg(smb_fname), major, minor));
731 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
732 smb_fname_str_dbg(smb_fname), cversion));
733 *perr = WERR_OK;
735 error_exit:
736 unbecome_user();
737 error_free_conn:
738 TALLOC_FREE(smb_fname);
739 if (fsp != NULL) {
740 close_file(NULL, fsp, NORMAL_CLOSE);
742 if (conn != NULL) {
743 vfs_ChDir(conn, oldcwd);
744 SMB_VFS_DISCONNECT(conn);
745 conn_free(conn);
747 if (!NT_STATUS_IS_OK(*perr)) {
748 cversion = -1;
751 return cversion;
754 /****************************************************************************
755 ****************************************************************************/
757 #define strip_driver_path(_mem_ctx, _element) do { \
758 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
759 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
760 W_ERROR_HAVE_NO_MEMORY((_element)); \
762 } while (0);
764 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
765 struct auth_session_info *session_info,
766 const char *architecture,
767 const char **driver_path,
768 const char **data_file,
769 const char **config_file,
770 const char **help_file,
771 struct spoolss_StringArray *dependent_files,
772 enum spoolss_DriverOSVersion *version)
774 const char *short_architecture;
775 int i;
776 WERROR err;
777 char *_p;
779 if (!*driver_path || !*data_file) {
780 return WERR_INVALID_PARAM;
783 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
784 return WERR_INVALID_PARAM;
787 /* clean up the driver name.
788 * we can get .\driver.dll
789 * or worse c:\windows\system\driver.dll !
791 /* using an intermediate string to not have overlaping memcpy()'s */
793 strip_driver_path(mem_ctx, *driver_path);
794 strip_driver_path(mem_ctx, *data_file);
795 if (*config_file) {
796 strip_driver_path(mem_ctx, *config_file);
798 if (help_file) {
799 strip_driver_path(mem_ctx, *help_file);
802 if (dependent_files && dependent_files->string) {
803 for (i=0; dependent_files->string[i]; i++) {
804 strip_driver_path(mem_ctx, dependent_files->string[i]);
808 short_architecture = get_short_archi(architecture);
809 if (!short_architecture) {
810 return WERR_UNKNOWN_PRINTER_DRIVER;
813 /* jfm:7/16/2000 the client always sends the cversion=0.
814 * The server should check which version the driver is by reading
815 * the PE header of driver->driverpath.
817 * For Windows 95/98 the version is 0 (so the value sent is correct)
818 * For Windows NT (the architecture doesn't matter)
819 * NT 3.1: cversion=0
820 * NT 3.5/3.51: cversion=1
821 * NT 4: cversion=2
822 * NT2K: cversion=3
825 *version = get_correct_cversion(session_info, short_architecture,
826 *driver_path, &err);
827 if (*version == -1) {
828 return err;
831 return WERR_OK;
834 /****************************************************************************
835 ****************************************************************************/
837 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
838 struct auth_session_info *session_info,
839 struct spoolss_AddDriverInfoCtr *r)
841 switch (r->level) {
842 case 3:
843 return clean_up_driver_struct_level(mem_ctx, session_info,
844 r->info.info3->architecture,
845 &r->info.info3->driver_path,
846 &r->info.info3->data_file,
847 &r->info.info3->config_file,
848 &r->info.info3->help_file,
849 r->info.info3->dependent_files,
850 &r->info.info3->version);
851 case 6:
852 return clean_up_driver_struct_level(mem_ctx, session_info,
853 r->info.info6->architecture,
854 &r->info.info6->driver_path,
855 &r->info.info6->data_file,
856 &r->info.info6->config_file,
857 &r->info.info6->help_file,
858 r->info.info6->dependent_files,
859 &r->info.info6->version);
860 default:
861 return WERR_NOT_SUPPORTED;
865 /****************************************************************************
866 This function sucks and should be replaced. JRA.
867 ****************************************************************************/
869 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
870 const struct spoolss_AddDriverInfo6 *src)
872 dst->version = src->version;
874 dst->driver_name = src->driver_name;
875 dst->architecture = src->architecture;
876 dst->driver_path = src->driver_path;
877 dst->data_file = src->data_file;
878 dst->config_file = src->config_file;
879 dst->help_file = src->help_file;
880 dst->monitor_name = src->monitor_name;
881 dst->default_datatype = src->default_datatype;
882 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
883 dst->dependent_files = src->dependent_files;
886 /****************************************************************************
887 ****************************************************************************/
889 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
890 connection_struct *conn,
891 const char *driver_file,
892 const char *short_architecture,
893 uint32_t driver_version,
894 uint32_t version)
896 struct smb_filename *smb_fname_old = NULL;
897 struct smb_filename *smb_fname_new = NULL;
898 char *old_name = NULL;
899 char *new_name = NULL;
900 NTSTATUS status;
901 WERROR ret;
903 old_name = talloc_asprintf(mem_ctx, "%s/%s",
904 short_architecture, driver_file);
905 W_ERROR_HAVE_NO_MEMORY(old_name);
907 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
908 short_architecture, driver_version, driver_file);
909 if (new_name == NULL) {
910 TALLOC_FREE(old_name);
911 return WERR_NOMEM;
914 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
916 status = driver_unix_convert(conn, old_name, &smb_fname_old);
917 if (!NT_STATUS_IS_OK(status)) {
918 ret = WERR_NOMEM;
919 goto out;
922 /* Setup a synthetic smb_filename struct */
923 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
924 if (!smb_fname_new) {
925 ret = WERR_NOMEM;
926 goto out;
929 smb_fname_new->base_name = new_name;
931 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
932 "'%s'\n", smb_fname_old->base_name,
933 smb_fname_new->base_name));
935 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
936 OPENX_FILE_EXISTS_TRUNCATE |
937 OPENX_FILE_CREATE_IF_NOT_EXIST,
938 0, false);
940 if (!NT_STATUS_IS_OK(status)) {
941 DEBUG(0,("move_driver_file_to_download_area: Unable "
942 "to rename [%s] to [%s]: %s\n",
943 smb_fname_old->base_name, new_name,
944 nt_errstr(status)));
945 ret = WERR_ACCESS_DENIED;
946 goto out;
950 ret = WERR_OK;
951 out:
952 TALLOC_FREE(smb_fname_old);
953 TALLOC_FREE(smb_fname_new);
954 return ret;
957 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
958 struct spoolss_AddDriverInfoCtr *r)
960 struct spoolss_AddDriverInfo3 *driver;
961 struct spoolss_AddDriverInfo3 converted_driver;
962 const char *short_architecture;
963 struct smb_filename *smb_dname = NULL;
964 char *new_dir = NULL;
965 connection_struct *conn = NULL;
966 NTSTATUS nt_status;
967 int i;
968 TALLOC_CTX *ctx = talloc_tos();
969 int ver = 0;
970 char *oldcwd;
971 char *printdollar = NULL;
972 int printdollar_snum;
973 WERROR err = WERR_OK;
975 switch (r->level) {
976 case 3:
977 driver = r->info.info3;
978 break;
979 case 6:
980 convert_level_6_to_level3(&converted_driver, r->info.info6);
981 driver = &converted_driver;
982 break;
983 default:
984 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
985 return WERR_UNKNOWN_LEVEL;
988 short_architecture = get_short_archi(driver->architecture);
989 if (!short_architecture) {
990 return WERR_UNKNOWN_PRINTER_DRIVER;
993 printdollar_snum = find_service(ctx, "print$", &printdollar);
994 if (!printdollar) {
995 return WERR_NOMEM;
997 if (printdollar_snum == -1) {
998 return WERR_NO_SUCH_SHARE;
1001 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1002 lp_pathname(printdollar_snum),
1003 session_info, &oldcwd);
1004 if (!NT_STATUS_IS_OK(nt_status)) {
1005 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1006 "returned %s\n", nt_errstr(nt_status)));
1007 err = ntstatus_to_werror(nt_status);
1008 return err;
1011 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1012 if (!NT_STATUS_IS_OK(nt_status)) {
1013 DEBUG(0, ("failed set force user / group\n"));
1014 err = ntstatus_to_werror(nt_status);
1015 goto err_free_conn;
1018 if (!become_user_by_session(conn, session_info)) {
1019 DEBUG(0, ("failed to become user\n"));
1020 err = WERR_ACCESS_DENIED;
1021 goto err_free_conn;
1024 new_dir = talloc_asprintf(ctx,
1025 "%s/%d",
1026 short_architecture,
1027 driver->version);
1028 if (!new_dir) {
1029 err = WERR_NOMEM;
1030 goto err_exit;
1032 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1033 if (!NT_STATUS_IS_OK(nt_status)) {
1034 err = WERR_NOMEM;
1035 goto err_exit;
1038 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1040 nt_status = create_directory(conn, NULL, smb_dname);
1041 if (!NT_STATUS_IS_OK(nt_status)
1042 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1043 DEBUG(0, ("failed to create driver destination directory: %s\n",
1044 nt_errstr(nt_status)));
1045 err = ntstatus_to_werror(nt_status);
1046 goto err_exit;
1049 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1050 * listed for this driver which has already been moved, skip it (note:
1051 * drivers may list the same file name several times. Then check if the
1052 * file already exists in archi\version\, if so, check that the version
1053 * info (or time stamps if version info is unavailable) is newer (or the
1054 * date is later). If it is, move it to archi\version\filexxx.yyy.
1055 * Otherwise, delete the file.
1057 * If a file is not moved to archi\version\ because of an error, all the
1058 * rest of the 'unmoved' driver files are removed from archi\. If one or
1059 * more of the driver's files was already moved to archi\version\, it
1060 * potentially leaves the driver in a partially updated state. Version
1061 * trauma will most likely occur if an client attempts to use any printer
1062 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1063 * done is appropriate... later JRR
1066 DEBUG(5,("Moving files now !\n"));
1068 if (driver->driver_path && strlen(driver->driver_path)) {
1070 err = move_driver_file_to_download_area(ctx,
1071 conn,
1072 driver->driver_path,
1073 short_architecture,
1074 driver->version,
1075 ver);
1076 if (!W_ERROR_IS_OK(err)) {
1077 goto err_exit;
1081 if (driver->data_file && strlen(driver->data_file)) {
1082 if (!strequal(driver->data_file, driver->driver_path)) {
1084 err = move_driver_file_to_download_area(ctx,
1085 conn,
1086 driver->data_file,
1087 short_architecture,
1088 driver->version,
1089 ver);
1090 if (!W_ERROR_IS_OK(err)) {
1091 goto err_exit;
1096 if (driver->config_file && strlen(driver->config_file)) {
1097 if (!strequal(driver->config_file, driver->driver_path) &&
1098 !strequal(driver->config_file, driver->data_file)) {
1100 err = move_driver_file_to_download_area(ctx,
1101 conn,
1102 driver->config_file,
1103 short_architecture,
1104 driver->version,
1105 ver);
1106 if (!W_ERROR_IS_OK(err)) {
1107 goto err_exit;
1112 if (driver->help_file && strlen(driver->help_file)) {
1113 if (!strequal(driver->help_file, driver->driver_path) &&
1114 !strequal(driver->help_file, driver->data_file) &&
1115 !strequal(driver->help_file, driver->config_file)) {
1117 err = move_driver_file_to_download_area(ctx,
1118 conn,
1119 driver->help_file,
1120 short_architecture,
1121 driver->version,
1122 ver);
1123 if (!W_ERROR_IS_OK(err)) {
1124 goto err_exit;
1129 if (driver->dependent_files && driver->dependent_files->string) {
1130 for (i=0; driver->dependent_files->string[i]; i++) {
1131 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1132 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1133 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1134 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1135 int j;
1136 for (j=0; j < i; j++) {
1137 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1138 goto NextDriver;
1142 err = move_driver_file_to_download_area(ctx,
1143 conn,
1144 driver->dependent_files->string[i],
1145 short_architecture,
1146 driver->version,
1147 ver);
1148 if (!W_ERROR_IS_OK(err)) {
1149 goto err_exit;
1152 NextDriver: ;
1156 err = WERR_OK;
1157 err_exit:
1158 unbecome_user();
1159 err_free_conn:
1160 TALLOC_FREE(smb_dname);
1162 if (conn != NULL) {
1163 vfs_ChDir(conn, oldcwd);
1164 SMB_VFS_DISCONNECT(conn);
1165 conn_free(conn);
1168 return err;
1171 /****************************************************************************
1172 Determine whether or not a particular driver is currently assigned
1173 to a printer
1174 ****************************************************************************/
1176 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1177 const struct auth_session_info *session_info,
1178 struct messaging_context *msg_ctx,
1179 const struct spoolss_DriverInfo8 *r)
1181 int snum;
1182 int n_services = lp_numservices();
1183 bool in_use = False;
1184 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1185 WERROR result;
1186 struct dcerpc_binding_handle *b = NULL;
1188 if (!r) {
1189 return false;
1192 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1194 /* loop through the printers.tdb and check for the drivername */
1196 for (snum=0; snum<n_services && !in_use; snum++) {
1197 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1198 continue;
1201 if (b == NULL) {
1202 result = winreg_printer_binding_handle(mem_ctx,
1203 session_info,
1204 msg_ctx,
1205 &b);
1206 if (!W_ERROR_IS_OK(result)) {
1207 return false;
1211 result = winreg_get_printer(mem_ctx, b,
1212 lp_servicename(snum),
1213 &pinfo2);
1214 if (!W_ERROR_IS_OK(result)) {
1215 continue; /* skip */
1218 if (strequal(r->driver_name, pinfo2->drivername)) {
1219 in_use = True;
1222 TALLOC_FREE(pinfo2);
1225 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1227 if ( in_use ) {
1228 struct spoolss_DriverInfo8 *driver;
1229 WERROR werr;
1231 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1233 /* we can still remove the driver if there is one of
1234 "Windows NT x86" version 2 or 3 left */
1236 if (!strequal("Windows NT x86", r->architecture)) {
1237 werr = winreg_get_driver(mem_ctx, b,
1238 "Windows NT x86",
1239 r->driver_name,
1240 DRIVER_ANY_VERSION,
1241 &driver);
1242 } else if (r->version == 2) {
1243 werr = winreg_get_driver(mem_ctx, b,
1244 "Windows NT x86",
1245 r->driver_name,
1246 3, &driver);
1247 } else if (r->version == 3) {
1248 werr = winreg_get_driver(mem_ctx, b,
1249 "Windows NT x86",
1250 r->driver_name,
1251 2, &driver);
1252 } else {
1253 DEBUG(0, ("printer_driver_in_use: ERROR!"
1254 " unknown driver version (%d)\n",
1255 r->version));
1256 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1259 /* now check the error code */
1261 if ( W_ERROR_IS_OK(werr) ) {
1262 /* it's ok to remove the driver, we have other architctures left */
1263 in_use = False;
1264 talloc_free(driver);
1268 /* report that the driver is not in use by default */
1270 return in_use;
1274 /**********************************************************************
1275 Check to see if a ogiven file is in use by *info
1276 *********************************************************************/
1278 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1280 int i = 0;
1282 if ( !info )
1283 return False;
1285 /* mz: skip files that are in the list but already deleted */
1286 if (!file || !file[0]) {
1287 return false;
1290 if (strequal(file, info->driver_path))
1291 return True;
1293 if (strequal(file, info->data_file))
1294 return True;
1296 if (strequal(file, info->config_file))
1297 return True;
1299 if (strequal(file, info->help_file))
1300 return True;
1302 /* see of there are any dependent files to examine */
1304 if (!info->dependent_files)
1305 return False;
1307 while (info->dependent_files[i] && *info->dependent_files[i]) {
1308 if (strequal(file, info->dependent_files[i]))
1309 return True;
1310 i++;
1313 return False;
1317 /**********************************************************************
1318 Utility function to remove the dependent file pointed to by the
1319 input parameter from the list
1320 *********************************************************************/
1322 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1325 /* bump everything down a slot */
1327 while (files && files[idx+1]) {
1328 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1329 idx++;
1332 files[idx] = NULL;
1334 return;
1337 /**********************************************************************
1338 Check if any of the files used by src are also used by drv
1339 *********************************************************************/
1341 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1342 struct spoolss_DriverInfo8 *src,
1343 const struct spoolss_DriverInfo8 *drv)
1345 bool in_use = False;
1346 int i = 0;
1348 if ( !src || !drv )
1349 return False;
1351 /* check each file. Remove it from the src structure if it overlaps */
1353 if (drv_file_in_use(src->driver_path, drv)) {
1354 in_use = True;
1355 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1356 src->driver_path = talloc_strdup(mem_ctx, "");
1357 if (!src->driver_path) { return false; }
1360 if (drv_file_in_use(src->data_file, drv)) {
1361 in_use = True;
1362 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1363 src->data_file = talloc_strdup(mem_ctx, "");
1364 if (!src->data_file) { return false; }
1367 if (drv_file_in_use(src->config_file, drv)) {
1368 in_use = True;
1369 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1370 src->config_file = talloc_strdup(mem_ctx, "");
1371 if (!src->config_file) { return false; }
1374 if (drv_file_in_use(src->help_file, drv)) {
1375 in_use = True;
1376 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1377 src->help_file = talloc_strdup(mem_ctx, "");
1378 if (!src->help_file) { return false; }
1381 /* are there any dependentfiles to examine? */
1383 if (!src->dependent_files)
1384 return in_use;
1386 while (src->dependent_files[i] && *src->dependent_files[i]) {
1387 if (drv_file_in_use(src->dependent_files[i], drv)) {
1388 in_use = True;
1389 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1390 trim_dependent_file(mem_ctx, src->dependent_files, i);
1391 } else
1392 i++;
1395 return in_use;
1398 /****************************************************************************
1399 Determine whether or not a particular driver files are currently being
1400 used by any other driver.
1402 Return value is True if any files were in use by other drivers
1403 and False otherwise.
1405 Upon return, *info has been modified to only contain the driver files
1406 which are not in use
1408 Fix from mz:
1410 This needs to check all drivers to ensure that all files in use
1411 have been removed from *info, not just the ones in the first
1412 match.
1413 ****************************************************************************/
1415 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1416 const struct auth_session_info *session_info,
1417 struct messaging_context *msg_ctx,
1418 struct spoolss_DriverInfo8 *info)
1420 int i;
1421 uint32 version;
1422 struct spoolss_DriverInfo8 *driver;
1423 bool in_use = false;
1424 uint32_t num_drivers;
1425 const char **drivers;
1426 WERROR result;
1427 struct dcerpc_binding_handle *b;
1429 if ( !info )
1430 return False;
1432 version = info->version;
1434 /* loop over all driver versions */
1436 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1438 /* get the list of drivers */
1440 result = winreg_printer_binding_handle(mem_ctx,
1441 session_info,
1442 msg_ctx,
1443 &b);
1444 if (!W_ERROR_IS_OK(result)) {
1445 return false;
1448 result = winreg_get_driver_list(mem_ctx, b,
1449 info->architecture, version,
1450 &num_drivers, &drivers);
1451 if (!W_ERROR_IS_OK(result)) {
1452 return true;
1455 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1456 num_drivers, info->architecture, version));
1458 /* check each driver for overlap in files */
1460 for (i = 0; i < num_drivers; i++) {
1461 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1463 driver = NULL;
1465 result = winreg_get_driver(mem_ctx, b,
1466 info->architecture, drivers[i],
1467 version, &driver);
1468 if (!W_ERROR_IS_OK(result)) {
1469 talloc_free(drivers);
1470 return True;
1473 /* check if d2 uses any files from d1 */
1474 /* only if this is a different driver than the one being deleted */
1476 if (!strequal(info->driver_name, driver->driver_name)) {
1477 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1478 /* mz: Do not instantly return -
1479 * we need to ensure this file isn't
1480 * also in use by other drivers. */
1481 in_use = true;
1485 talloc_free(driver);
1488 talloc_free(drivers);
1490 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1492 return in_use;
1495 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1496 const char *name)
1498 struct smb_filename *smb_fname = NULL;
1499 NTSTATUS status;
1501 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1502 &smb_fname);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 return status;
1507 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1509 TALLOC_FREE(smb_fname);
1510 return status;
1513 /****************************************************************************
1514 Actually delete the driver files. Make sure that
1515 printer_driver_files_in_use() return False before calling
1516 this.
1517 ****************************************************************************/
1519 bool delete_driver_files(const struct auth_session_info *session_info,
1520 const struct spoolss_DriverInfo8 *r)
1522 int i = 0;
1523 char *s;
1524 const char *file;
1525 connection_struct *conn;
1526 NTSTATUS nt_status;
1527 char *oldcwd;
1528 char *printdollar = NULL;
1529 int printdollar_snum;
1530 bool ret = false;
1532 if (!r) {
1533 return false;
1536 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1537 r->driver_name, r->version));
1539 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1540 if (!printdollar) {
1541 return false;
1543 if (printdollar_snum == -1) {
1544 return false;
1547 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1548 lp_pathname(printdollar_snum),
1549 session_info, &oldcwd);
1550 if (!NT_STATUS_IS_OK(nt_status)) {
1551 DEBUG(0,("delete_driver_files: create_conn_struct "
1552 "returned %s\n", nt_errstr(nt_status)));
1553 return false;
1556 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1557 if (!NT_STATUS_IS_OK(nt_status)) {
1558 DEBUG(0, ("failed set force user / group\n"));
1559 ret = false;
1560 goto err_free_conn;
1563 if (!become_user_by_session(conn, session_info)) {
1564 DEBUG(0, ("failed to become user\n"));
1565 ret = false;
1566 goto err_free_conn;
1569 if ( !CAN_WRITE(conn) ) {
1570 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1571 ret = false;
1572 goto err_out;
1575 /* now delete the files; must strip the '\print$' string from
1576 fron of path */
1578 if (r->driver_path && r->driver_path[0]) {
1579 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1580 file = s;
1581 DEBUG(10,("deleting driverfile [%s]\n", s));
1582 driver_unlink_internals(conn, file);
1586 if (r->config_file && r->config_file[0]) {
1587 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1588 file = s;
1589 DEBUG(10,("deleting configfile [%s]\n", s));
1590 driver_unlink_internals(conn, file);
1594 if (r->data_file && r->data_file[0]) {
1595 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1596 file = s;
1597 DEBUG(10,("deleting datafile [%s]\n", s));
1598 driver_unlink_internals(conn, file);
1602 if (r->help_file && r->help_file[0]) {
1603 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1604 file = s;
1605 DEBUG(10,("deleting helpfile [%s]\n", s));
1606 driver_unlink_internals(conn, file);
1610 /* check if we are done removing files */
1612 if (r->dependent_files) {
1613 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1614 char *p;
1616 /* bypass the "\print$" portion of the path */
1618 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1619 file = p;
1620 DEBUG(10,("deleting dependent file [%s]\n", file));
1621 driver_unlink_internals(conn, file);
1624 i++;
1628 ret = true;
1629 err_out:
1630 unbecome_user();
1631 err_free_conn:
1632 if (conn != NULL) {
1633 vfs_ChDir(conn, oldcwd);
1634 SMB_VFS_DISCONNECT(conn);
1635 conn_free(conn);
1637 return ret;
1640 /* error code:
1641 0: everything OK
1642 1: level not implemented
1643 2: file doesn't exist
1644 3: can't allocate memory
1645 4: can't free memory
1646 5: non existant struct
1650 A printer and a printer driver are 2 different things.
1651 NT manages them separatelly, Samba does the same.
1652 Why ? Simply because it's easier and it makes sense !
1654 Now explanation: You have 3 printers behind your samba server,
1655 2 of them are the same make and model (laser A and B). But laser B
1656 has an 3000 sheet feeder and laser A doesn't such an option.
1657 Your third printer is an old dot-matrix model for the accounting :-).
1659 If the /usr/local/samba/lib directory (default dir), you will have
1660 5 files to describe all of this.
1662 3 files for the printers (1 by printer):
1663 NTprinter_laser A
1664 NTprinter_laser B
1665 NTprinter_accounting
1666 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1667 NTdriver_printer model X
1668 NTdriver_printer model Y
1670 jfm: I should use this comment for the text file to explain
1671 same thing for the forms BTW.
1672 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1676 /* Convert generic access rights to printer object specific access rights.
1677 It turns out that NT4 security descriptors use generic access rights and
1678 NT5 the object specific ones. */
1680 void map_printer_permissions(struct security_descriptor *sd)
1682 int i;
1684 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1685 se_map_generic(&sd->dacl->aces[i].access_mask,
1686 &printer_generic_mapping);
1690 void map_job_permissions(struct security_descriptor *sd)
1692 int i;
1694 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1695 se_map_generic(&sd->dacl->aces[i].access_mask,
1696 &job_generic_mapping);
1701 /****************************************************************************
1702 Check a user has permissions to perform the given operation. We use the
1703 permission constants defined in include/rpc_spoolss.h to check the various
1704 actions we perform when checking printer access.
1706 PRINTER_ACCESS_ADMINISTER:
1707 print_queue_pause, print_queue_resume, update_printer_sec,
1708 update_printer, spoolss_addprinterex_level_2,
1709 _spoolss_setprinterdata
1711 PRINTER_ACCESS_USE:
1712 print_job_start
1714 JOB_ACCESS_ADMINISTER:
1715 print_job_delete, print_job_pause, print_job_resume,
1716 print_queue_purge
1718 Try access control in the following order (for performance reasons):
1719 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1720 2) check security descriptor (bit comparisons in memory)
1721 3) "printer admins" (may result in numerous calls to winbind)
1723 ****************************************************************************/
1724 bool print_access_check(const struct auth_session_info *session_info,
1725 struct messaging_context *msg_ctx, int snum,
1726 int access_type)
1728 struct spoolss_security_descriptor *secdesc = NULL;
1729 uint32 access_granted;
1730 size_t sd_size;
1731 NTSTATUS status;
1732 WERROR result;
1733 const char *pname;
1734 TALLOC_CTX *mem_ctx = NULL;
1736 /* If user is NULL then use the current_user structure */
1738 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1740 if (session_info->unix_token->uid == sec_initial_uid()
1741 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1742 return True;
1745 /* Get printer name */
1747 pname = lp_printername(snum);
1749 if (!pname || !*pname) {
1750 errno = EACCES;
1751 return False;
1754 /* Get printer security descriptor */
1756 if(!(mem_ctx = talloc_init("print_access_check"))) {
1757 errno = ENOMEM;
1758 return False;
1761 result = winreg_get_printer_secdesc_internal(mem_ctx,
1762 get_session_info_system(),
1763 msg_ctx,
1764 pname,
1765 &secdesc);
1766 if (!W_ERROR_IS_OK(result)) {
1767 talloc_destroy(mem_ctx);
1768 errno = ENOMEM;
1769 return False;
1772 if (access_type == JOB_ACCESS_ADMINISTER) {
1773 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1775 /* Create a child security descriptor to check permissions
1776 against. This is because print jobs are child objects
1777 objects of a printer. */
1778 status = se_create_child_secdesc(mem_ctx,
1779 &secdesc,
1780 &sd_size,
1781 parent_secdesc,
1782 parent_secdesc->owner_sid,
1783 parent_secdesc->group_sid,
1784 false);
1785 if (!NT_STATUS_IS_OK(status)) {
1786 talloc_destroy(mem_ctx);
1787 errno = map_errno_from_nt_status(status);
1788 return False;
1791 map_job_permissions(secdesc);
1792 } else {
1793 map_printer_permissions(secdesc);
1796 /* Check access */
1797 status = se_access_check(secdesc, session_info->security_token, access_type,
1798 &access_granted);
1800 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1802 /* see if we need to try the printer admin list */
1804 if (!NT_STATUS_IS_OK(status) &&
1805 (token_contains_name_in_list(uidtoname(session_info->unix_token->uid),
1806 session_info->info->domain_name,
1807 NULL, session_info->security_token,
1808 lp_printer_admin(snum)))) {
1809 talloc_destroy(mem_ctx);
1810 return True;
1813 talloc_destroy(mem_ctx);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 errno = EACCES;
1819 return NT_STATUS_IS_OK(status);
1822 /****************************************************************************
1823 Check the time parameters allow a print operation.
1824 *****************************************************************************/
1826 bool print_time_access_check(const struct auth_session_info *session_info,
1827 struct messaging_context *msg_ctx,
1828 const char *servicename)
1830 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1831 WERROR result;
1832 bool ok = False;
1833 time_t now = time(NULL);
1834 struct tm *t;
1835 uint32 mins;
1837 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1838 servicename, &pinfo2);
1839 if (!W_ERROR_IS_OK(result)) {
1840 return False;
1843 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1844 ok = True;
1847 t = gmtime(&now);
1848 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1850 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1851 ok = True;
1854 TALLOC_FREE(pinfo2);
1856 if (!ok) {
1857 errno = EACCES;
1860 return ok;
1863 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1864 const struct auth_session_info *session_info,
1865 struct messaging_context *msg_ctx,
1866 const char *printer)
1868 WERROR result;
1870 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1871 printer, "");
1872 if (!W_ERROR_IS_OK(result)) {
1873 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
1874 printer));