s3:libsmb: add cli_{query,set}_security_descriptor() which take sec_info flags
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blob5050a5d0dcef05b360197e8417bb4f5b6263cfd6
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 /****************************************************************************
78 Open the NT printing tdbs. Done once before fork().
79 ****************************************************************************/
81 bool nt_printing_init(struct messaging_context *msg_ctx)
83 WERROR win_rc;
85 if (!nt_printing_tdb_upgrade()) {
86 return false;
90 * register callback to handle updating printers as new
91 * drivers are installed
93 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
94 do_drv_upgrade_printer);
96 /* of course, none of the message callbacks matter if you don't
97 tell messages.c that you interested in receiving PRINT_GENERAL
98 msgs. This is done in serverid_register() */
100 if ( lp_security() == SEC_ADS ) {
101 win_rc = check_published_printers(msg_ctx);
102 if (!W_ERROR_IS_OK(win_rc))
103 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
106 return true;
109 /*******************************************************************
110 Function to allow filename parsing "the old way".
111 ********************************************************************/
113 static NTSTATUS driver_unix_convert(connection_struct *conn,
114 const char *old_name,
115 struct smb_filename **smb_fname)
117 NTSTATUS status;
118 TALLOC_CTX *ctx = talloc_tos();
119 char *name = talloc_strdup(ctx, old_name);
121 if (!name) {
122 return NT_STATUS_NO_MEMORY;
124 unix_format(name);
125 name = unix_clean_name(ctx, name);
126 if (!name) {
127 return NT_STATUS_NO_MEMORY;
129 trim_string(name,"/","/");
131 status = unix_convert(ctx, conn, name, smb_fname, 0);
132 if (!NT_STATUS_IS_OK(status)) {
133 return NT_STATUS_NO_MEMORY;
136 return NT_STATUS_OK;
139 /****************************************************************************
140 Function to do the mapping between the long architecture name and
141 the short one.
142 ****************************************************************************/
144 const char *get_short_archi(const char *long_archi)
146 int i=-1;
148 DEBUG(107,("Getting architecture dependent directory\n"));
149 do {
150 i++;
151 } while ( (archi_table[i].long_archi!=NULL ) &&
152 strcasecmp_m(long_archi, archi_table[i].long_archi) );
154 if (archi_table[i].long_archi==NULL) {
155 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
156 return NULL;
159 /* this might be client code - but shouldn't this be an fstrcpy etc? */
161 DEBUGADD(108,("index: [%d]\n", i));
162 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
163 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
165 return archi_table[i].short_archi;
168 /****************************************************************************
169 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
170 There are two case to be covered here: PE (Portable Executable) and NE (New
171 Executable) files. Both files support the same INFO structure, but PE files
172 store the signature in unicode, and NE files store it as !unicode.
173 returns -1 on error, 1 on version info found, and 0 on no version info found.
174 ****************************************************************************/
176 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
178 int i;
179 char *buf = NULL;
180 ssize_t byte_count;
182 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
183 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
184 fname, DOS_HEADER_SIZE));
185 goto error_exit;
188 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
189 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
190 fname, (unsigned long)byte_count));
191 goto no_version_info;
194 /* Is this really a DOS header? */
195 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
196 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
197 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
198 goto no_version_info;
201 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
202 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (off_t)-1) {
203 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
204 fname, errno));
205 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
206 goto no_version_info;
209 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
210 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
211 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
212 fname, (unsigned long)byte_count));
213 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
214 goto no_version_info;
217 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
218 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
219 unsigned int num_sections;
220 unsigned int section_table_bytes;
222 /* Just skip over optional header to get to section table */
223 if (SMB_VFS_LSEEK(fsp,
224 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
225 SEEK_CUR) == (off_t)-1) {
226 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
227 fname, errno));
228 goto error_exit;
231 /* get the section table */
232 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
233 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
234 if (section_table_bytes == 0)
235 goto error_exit;
237 SAFE_FREE(buf);
238 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
239 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
240 fname, section_table_bytes));
241 goto error_exit;
244 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
245 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
246 fname, (unsigned long)byte_count));
247 goto error_exit;
250 /* Iterate the section table looking for the resource section ".rsrc" */
251 for (i = 0; i < num_sections; i++) {
252 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
254 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
255 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
256 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
258 if (section_bytes == 0)
259 goto error_exit;
261 SAFE_FREE(buf);
262 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
263 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
264 fname, section_bytes));
265 goto error_exit;
268 /* Seek to the start of the .rsrc section info */
269 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (off_t)-1) {
270 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
271 fname, errno));
272 goto error_exit;
275 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
276 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
277 fname, (unsigned long)byte_count));
278 goto error_exit;
281 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
282 goto error_exit;
284 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
285 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
286 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
287 /* Align to next long address */
288 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
290 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
291 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
292 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
294 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
295 fname, *major, *minor,
296 (*major>>16)&0xffff, *major&0xffff,
297 (*minor>>16)&0xffff, *minor&0xffff));
298 SAFE_FREE(buf);
299 return 1;
306 /* Version info not found, fall back to origin date/time */
307 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
308 SAFE_FREE(buf);
309 return 0;
311 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
312 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
313 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
314 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
315 /* At this point, we assume the file is in error. It still could be somthing
316 * else besides a NE file, but it unlikely at this point. */
317 goto error_exit;
320 /* Allocate a bit more space to speed up things */
321 SAFE_FREE(buf);
322 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
323 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
324 fname, PE_HEADER_SIZE));
325 goto error_exit;
328 /* This is a HACK! I got tired of trying to sort through the messy
329 * 'NE' file format. If anyone wants to clean this up please have at
330 * it, but this works. 'NE' files will eventually fade away. JRR */
331 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
332 /* Cover case that should not occur in a well formed 'NE' .dll file */
333 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
335 for(i=0; i<byte_count; i++) {
336 /* Fast skip past data that can't possibly match */
337 if (buf[i] != 'V') continue;
339 /* Potential match data crosses buf boundry, move it to beginning
340 * of buf, and fill the buf with as much as it will hold. */
341 if (i>byte_count-VS_VERSION_INFO_SIZE) {
342 int bc;
344 memcpy(buf, &buf[i], byte_count-i);
345 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
346 (byte_count-i))) < 0) {
348 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
349 fname, errno));
350 goto error_exit;
353 byte_count = bc + (byte_count - i);
354 if (byte_count<VS_VERSION_INFO_SIZE) break;
356 i = 0;
359 /* Check that the full signature string and the magic number that
360 * follows exist (not a perfect solution, but the chances that this
361 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
362 * twice, as it is simpler to read the code. */
363 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
364 /* Compute skip alignment to next long address */
365 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
366 sizeof(VS_SIGNATURE)) & 3;
367 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
369 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
370 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
371 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
372 fname, *major, *minor,
373 (*major>>16)&0xffff, *major&0xffff,
374 (*minor>>16)&0xffff, *minor&0xffff));
375 SAFE_FREE(buf);
376 return 1;
381 /* Version info not found, fall back to origin date/time */
382 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
383 SAFE_FREE(buf);
384 return 0;
386 } else
387 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
388 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
389 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
391 no_version_info:
392 SAFE_FREE(buf);
393 return 0;
395 error_exit:
396 SAFE_FREE(buf);
397 return -1;
400 /****************************************************************************
401 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
402 share one or more files. During the MS installation process files are checked
403 to insure that only a newer version of a shared file is installed over an
404 older version. There are several possibilities for this comparison. If there
405 is no previous version, the new one is newer (obviously). If either file is
406 missing the version info structure, compare the creation date (on Unix use
407 the modification date). Otherwise chose the numerically larger version number.
408 ****************************************************************************/
410 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
412 bool use_version = true;
414 uint32 new_major;
415 uint32 new_minor;
416 time_t new_create_time;
418 uint32 old_major;
419 uint32 old_minor;
420 time_t old_create_time;
422 struct smb_filename *smb_fname = NULL;
423 files_struct *fsp = NULL;
424 SMB_STRUCT_STAT st;
426 NTSTATUS status;
427 int ret;
429 SET_STAT_INVALID(st);
430 new_create_time = (time_t)0;
431 old_create_time = (time_t)0;
433 /* Get file version info (if available) for previous file (if it exists) */
434 status = driver_unix_convert(conn, old_file, &smb_fname);
435 if (!NT_STATUS_IS_OK(status)) {
436 goto error_exit;
439 status = SMB_VFS_CREATE_FILE(
440 conn, /* conn */
441 NULL, /* req */
442 0, /* root_dir_fid */
443 smb_fname, /* fname */
444 FILE_GENERIC_READ, /* access_mask */
445 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
446 FILE_OPEN, /* create_disposition*/
447 0, /* create_options */
448 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
449 INTERNAL_OPEN_ONLY, /* oplock_request */
450 0, /* allocation_size */
451 0, /* private_flags */
452 NULL, /* sd */
453 NULL, /* ea_list */
454 &fsp, /* result */
455 NULL); /* pinfo */
457 if (!NT_STATUS_IS_OK(status)) {
458 /* Old file not found, so by definition new file is in fact newer */
459 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
460 "errno = %d\n", smb_fname_str_dbg(smb_fname),
461 errno));
462 ret = 1;
463 goto done;
465 } else {
466 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
467 if (ret == -1) {
468 goto error_exit;
471 if (!ret) {
472 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
473 old_file));
474 use_version = false;
475 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
476 goto error_exit;
478 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
479 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
480 (long)old_create_time));
483 close_file(NULL, fsp, NORMAL_CLOSE);
484 fsp = NULL;
486 /* Get file version info (if available) for new file */
487 status = driver_unix_convert(conn, new_file, &smb_fname);
488 if (!NT_STATUS_IS_OK(status)) {
489 goto error_exit;
492 status = SMB_VFS_CREATE_FILE(
493 conn, /* conn */
494 NULL, /* req */
495 0, /* root_dir_fid */
496 smb_fname, /* fname */
497 FILE_GENERIC_READ, /* access_mask */
498 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
499 FILE_OPEN, /* create_disposition*/
500 0, /* create_options */
501 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
502 INTERNAL_OPEN_ONLY, /* oplock_request */
503 0, /* allocation_size */
504 0, /* private_flags */
505 NULL, /* sd */
506 NULL, /* ea_list */
507 &fsp, /* result */
508 NULL); /* pinfo */
510 if (!NT_STATUS_IS_OK(status)) {
511 /* New file not found, this shouldn't occur if the caller did its job */
512 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
513 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
514 goto error_exit;
516 } else {
517 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
518 if (ret == -1) {
519 goto error_exit;
522 if (!ret) {
523 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
524 new_file));
525 use_version = false;
526 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
527 goto error_exit;
529 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
530 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
531 (long)new_create_time));
534 close_file(NULL, fsp, NORMAL_CLOSE);
535 fsp = NULL;
537 if (use_version && (new_major != old_major || new_minor != old_minor)) {
538 /* Compare versions and choose the larger version number */
539 if (new_major > old_major ||
540 (new_major == old_major && new_minor > old_minor)) {
542 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
543 ret = 1;
544 goto done;
546 else {
547 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
548 ret = 0;
549 goto done;
552 } else {
553 /* Compare modification time/dates and choose the newest time/date */
554 if (new_create_time > old_create_time) {
555 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
556 ret = 1;
557 goto done;
559 else {
560 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
561 ret = 0;
562 goto done;
566 error_exit:
567 if(fsp)
568 close_file(NULL, fsp, NORMAL_CLOSE);
569 ret = -1;
570 done:
571 TALLOC_FREE(smb_fname);
572 return ret;
575 /****************************************************************************
576 Determine the correct cVersion associated with an architecture and driver
577 ****************************************************************************/
578 static uint32 get_correct_cversion(struct auth_session_info *session_info,
579 const char *architecture,
580 const char *driverpath_in,
581 WERROR *perr)
583 int cversion = -1;
584 NTSTATUS nt_status;
585 struct smb_filename *smb_fname = NULL;
586 char *driverpath = NULL;
587 files_struct *fsp = NULL;
588 connection_struct *conn = NULL;
589 char *oldcwd;
590 char *printdollar = NULL;
591 int printdollar_snum;
593 *perr = WERR_INVALID_PARAM;
595 /* If architecture is Windows 95/98/ME, the version is always 0. */
596 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
597 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
598 *perr = WERR_OK;
599 return 0;
602 /* If architecture is Windows x64, the version is always 3. */
603 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
604 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
605 *perr = WERR_OK;
606 return 3;
609 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
610 if (!printdollar) {
611 *perr = WERR_NOMEM;
612 return -1;
614 if (printdollar_snum == -1) {
615 *perr = WERR_NO_SUCH_SHARE;
616 return -1;
619 nt_status = create_conn_struct(talloc_tos(),
620 server_event_context(),
621 server_messaging_context(),
622 &conn,
623 printdollar_snum,
624 lp_pathname(talloc_tos(), printdollar_snum),
625 session_info, &oldcwd);
626 if (!NT_STATUS_IS_OK(nt_status)) {
627 DEBUG(0,("get_correct_cversion: create_conn_struct "
628 "returned %s\n", nt_errstr(nt_status)));
629 *perr = ntstatus_to_werror(nt_status);
630 return -1;
633 nt_status = set_conn_force_user_group(conn, printdollar_snum);
634 if (!NT_STATUS_IS_OK(nt_status)) {
635 DEBUG(0, ("failed set force user / group\n"));
636 *perr = ntstatus_to_werror(nt_status);
637 goto error_free_conn;
640 if (!become_user_by_session(conn, session_info)) {
641 DEBUG(0, ("failed to become user\n"));
642 *perr = WERR_ACCESS_DENIED;
643 goto error_free_conn;
646 /* Open the driver file (Portable Executable format) and determine the
647 * deriver the cversion. */
648 driverpath = talloc_asprintf(talloc_tos(),
649 "%s/%s",
650 architecture,
651 driverpath_in);
652 if (!driverpath) {
653 *perr = WERR_NOMEM;
654 goto error_exit;
657 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
658 if (!NT_STATUS_IS_OK(nt_status)) {
659 *perr = ntstatus_to_werror(nt_status);
660 goto error_exit;
663 nt_status = vfs_file_exist(conn, smb_fname);
664 if (!NT_STATUS_IS_OK(nt_status)) {
665 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
666 *perr = WERR_BADFILE;
667 goto error_exit;
670 nt_status = SMB_VFS_CREATE_FILE(
671 conn, /* conn */
672 NULL, /* req */
673 0, /* root_dir_fid */
674 smb_fname, /* fname */
675 FILE_GENERIC_READ, /* access_mask */
676 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
677 FILE_OPEN, /* create_disposition*/
678 0, /* create_options */
679 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
680 INTERNAL_OPEN_ONLY, /* oplock_request */
681 0, /* private_flags */
682 0, /* allocation_size */
683 NULL, /* sd */
684 NULL, /* ea_list */
685 &fsp, /* result */
686 NULL); /* pinfo */
688 if (!NT_STATUS_IS_OK(nt_status)) {
689 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
690 "%d\n", smb_fname_str_dbg(smb_fname), errno));
691 *perr = WERR_ACCESS_DENIED;
692 goto error_exit;
693 } else {
694 uint32 major;
695 uint32 minor;
696 int ret;
698 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
699 if (ret == -1) {
700 *perr = WERR_INVALID_PARAM;
701 goto error_exit;
702 } else if (!ret) {
703 DEBUG(6,("get_correct_cversion: Version info not "
704 "found [%s]\n",
705 smb_fname_str_dbg(smb_fname)));
706 *perr = WERR_INVALID_PARAM;
707 goto error_exit;
711 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
712 * for more details. Version in this case is not just the version of the
713 * file, but the version in the sense of kernal mode (2) vs. user mode
714 * (3) drivers. Other bits of the version fields are the version info.
715 * JRR 010716
717 cversion = major & 0x0000ffff;
718 switch (cversion) {
719 case 2: /* WinNT drivers */
720 case 3: /* Win2K drivers */
721 break;
723 default:
724 DEBUG(6,("get_correct_cversion: cversion "
725 "invalid [%s] cversion = %d\n",
726 smb_fname_str_dbg(smb_fname),
727 cversion));
728 goto error_exit;
731 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
732 " = 0x%x minor = 0x%x\n",
733 smb_fname_str_dbg(smb_fname), major, minor));
736 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
737 smb_fname_str_dbg(smb_fname), cversion));
738 *perr = WERR_OK;
740 error_exit:
741 unbecome_user();
742 error_free_conn:
743 TALLOC_FREE(smb_fname);
744 if (fsp != NULL) {
745 close_file(NULL, fsp, NORMAL_CLOSE);
747 if (conn != NULL) {
748 vfs_ChDir(conn, oldcwd);
749 SMB_VFS_DISCONNECT(conn);
750 conn_free(conn);
752 if (!W_ERROR_IS_OK(*perr)) {
753 cversion = -1;
756 return cversion;
759 /****************************************************************************
760 ****************************************************************************/
762 #define strip_driver_path(_mem_ctx, _element) do { \
763 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
764 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
765 W_ERROR_HAVE_NO_MEMORY((_element)); \
767 } while (0);
769 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
770 struct auth_session_info *session_info,
771 const char *architecture,
772 const char **driver_path,
773 const char **data_file,
774 const char **config_file,
775 const char **help_file,
776 struct spoolss_StringArray *dependent_files,
777 enum spoolss_DriverOSVersion *version)
779 const char *short_architecture;
780 int i;
781 WERROR err;
782 char *_p;
784 if (!*driver_path || !*data_file) {
785 return WERR_INVALID_PARAM;
788 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
789 return WERR_INVALID_PARAM;
792 /* clean up the driver name.
793 * we can get .\driver.dll
794 * or worse c:\windows\system\driver.dll !
796 /* using an intermediate string to not have overlaping memcpy()'s */
798 strip_driver_path(mem_ctx, *driver_path);
799 strip_driver_path(mem_ctx, *data_file);
800 if (*config_file) {
801 strip_driver_path(mem_ctx, *config_file);
803 if (help_file) {
804 strip_driver_path(mem_ctx, *help_file);
807 if (dependent_files && dependent_files->string) {
808 for (i=0; dependent_files->string[i]; i++) {
809 strip_driver_path(mem_ctx, dependent_files->string[i]);
813 short_architecture = get_short_archi(architecture);
814 if (!short_architecture) {
815 return WERR_UNKNOWN_PRINTER_DRIVER;
818 /* jfm:7/16/2000 the client always sends the cversion=0.
819 * The server should check which version the driver is by reading
820 * the PE header of driver->driverpath.
822 * For Windows 95/98 the version is 0 (so the value sent is correct)
823 * For Windows NT (the architecture doesn't matter)
824 * NT 3.1: cversion=0
825 * NT 3.5/3.51: cversion=1
826 * NT 4: cversion=2
827 * NT2K: cversion=3
830 *version = get_correct_cversion(session_info, short_architecture,
831 *driver_path, &err);
832 if (*version == -1) {
833 return err;
836 return WERR_OK;
839 /****************************************************************************
840 ****************************************************************************/
842 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
843 struct auth_session_info *session_info,
844 struct spoolss_AddDriverInfoCtr *r)
846 switch (r->level) {
847 case 3:
848 return clean_up_driver_struct_level(mem_ctx, session_info,
849 r->info.info3->architecture,
850 &r->info.info3->driver_path,
851 &r->info.info3->data_file,
852 &r->info.info3->config_file,
853 &r->info.info3->help_file,
854 r->info.info3->dependent_files,
855 &r->info.info3->version);
856 case 6:
857 return clean_up_driver_struct_level(mem_ctx, session_info,
858 r->info.info6->architecture,
859 &r->info.info6->driver_path,
860 &r->info.info6->data_file,
861 &r->info.info6->config_file,
862 &r->info.info6->help_file,
863 r->info.info6->dependent_files,
864 &r->info.info6->version);
865 default:
866 return WERR_NOT_SUPPORTED;
870 /****************************************************************************
871 This function sucks and should be replaced. JRA.
872 ****************************************************************************/
874 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
875 const struct spoolss_AddDriverInfo6 *src)
877 dst->version = src->version;
879 dst->driver_name = src->driver_name;
880 dst->architecture = src->architecture;
881 dst->driver_path = src->driver_path;
882 dst->data_file = src->data_file;
883 dst->config_file = src->config_file;
884 dst->help_file = src->help_file;
885 dst->monitor_name = src->monitor_name;
886 dst->default_datatype = src->default_datatype;
887 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
888 dst->dependent_files = src->dependent_files;
891 /****************************************************************************
892 ****************************************************************************/
894 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
895 connection_struct *conn,
896 const char *driver_file,
897 const char *short_architecture,
898 uint32_t driver_version,
899 uint32_t version)
901 struct smb_filename *smb_fname_old = NULL;
902 struct smb_filename *smb_fname_new = NULL;
903 char *old_name = NULL;
904 char *new_name = NULL;
905 NTSTATUS status;
906 WERROR ret;
908 old_name = talloc_asprintf(mem_ctx, "%s/%s",
909 short_architecture, driver_file);
910 W_ERROR_HAVE_NO_MEMORY(old_name);
912 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
913 short_architecture, driver_version, driver_file);
914 if (new_name == NULL) {
915 TALLOC_FREE(old_name);
916 return WERR_NOMEM;
919 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
921 status = driver_unix_convert(conn, old_name, &smb_fname_old);
922 if (!NT_STATUS_IS_OK(status)) {
923 ret = WERR_NOMEM;
924 goto out;
927 /* Setup a synthetic smb_filename struct */
928 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
929 if (!smb_fname_new) {
930 ret = WERR_NOMEM;
931 goto out;
934 smb_fname_new->base_name = new_name;
936 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
937 "'%s'\n", smb_fname_old->base_name,
938 smb_fname_new->base_name));
940 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
941 OPENX_FILE_EXISTS_TRUNCATE |
942 OPENX_FILE_CREATE_IF_NOT_EXIST,
943 0, false);
945 if (!NT_STATUS_IS_OK(status)) {
946 DEBUG(0,("move_driver_file_to_download_area: Unable "
947 "to rename [%s] to [%s]: %s\n",
948 smb_fname_old->base_name, new_name,
949 nt_errstr(status)));
950 ret = WERR_ACCESS_DENIED;
951 goto out;
955 ret = WERR_OK;
956 out:
957 TALLOC_FREE(smb_fname_old);
958 TALLOC_FREE(smb_fname_new);
959 return ret;
962 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
963 struct spoolss_AddDriverInfoCtr *r)
965 struct spoolss_AddDriverInfo3 *driver;
966 struct spoolss_AddDriverInfo3 converted_driver;
967 const char *short_architecture;
968 struct smb_filename *smb_dname = NULL;
969 char *new_dir = NULL;
970 connection_struct *conn = NULL;
971 NTSTATUS nt_status;
972 int i;
973 TALLOC_CTX *ctx = talloc_tos();
974 int ver = 0;
975 char *oldcwd;
976 char *printdollar = NULL;
977 int printdollar_snum;
978 WERROR err = WERR_OK;
980 switch (r->level) {
981 case 3:
982 driver = r->info.info3;
983 break;
984 case 6:
985 convert_level_6_to_level3(&converted_driver, r->info.info6);
986 driver = &converted_driver;
987 break;
988 default:
989 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
990 return WERR_UNKNOWN_LEVEL;
993 short_architecture = get_short_archi(driver->architecture);
994 if (!short_architecture) {
995 return WERR_UNKNOWN_PRINTER_DRIVER;
998 printdollar_snum = find_service(ctx, "print$", &printdollar);
999 if (!printdollar) {
1000 return WERR_NOMEM;
1002 if (printdollar_snum == -1) {
1003 return WERR_NO_SUCH_SHARE;
1006 nt_status = create_conn_struct(talloc_tos(),
1007 server_event_context(),
1008 server_messaging_context(),
1009 &conn,
1010 printdollar_snum,
1011 lp_pathname(talloc_tos(), printdollar_snum),
1012 session_info, &oldcwd);
1013 if (!NT_STATUS_IS_OK(nt_status)) {
1014 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1015 "returned %s\n", nt_errstr(nt_status)));
1016 err = ntstatus_to_werror(nt_status);
1017 return err;
1020 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1021 if (!NT_STATUS_IS_OK(nt_status)) {
1022 DEBUG(0, ("failed set force user / group\n"));
1023 err = ntstatus_to_werror(nt_status);
1024 goto err_free_conn;
1027 if (!become_user_by_session(conn, session_info)) {
1028 DEBUG(0, ("failed to become user\n"));
1029 err = WERR_ACCESS_DENIED;
1030 goto err_free_conn;
1033 new_dir = talloc_asprintf(ctx,
1034 "%s/%d",
1035 short_architecture,
1036 driver->version);
1037 if (!new_dir) {
1038 err = WERR_NOMEM;
1039 goto err_exit;
1041 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1042 if (!NT_STATUS_IS_OK(nt_status)) {
1043 err = WERR_NOMEM;
1044 goto err_exit;
1047 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1049 nt_status = create_directory(conn, NULL, smb_dname);
1050 if (!NT_STATUS_IS_OK(nt_status)
1051 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1052 DEBUG(0, ("failed to create driver destination directory: %s\n",
1053 nt_errstr(nt_status)));
1054 err = ntstatus_to_werror(nt_status);
1055 goto err_exit;
1058 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1059 * listed for this driver which has already been moved, skip it (note:
1060 * drivers may list the same file name several times. Then check if the
1061 * file already exists in archi\version\, if so, check that the version
1062 * info (or time stamps if version info is unavailable) is newer (or the
1063 * date is later). If it is, move it to archi\version\filexxx.yyy.
1064 * Otherwise, delete the file.
1066 * If a file is not moved to archi\version\ because of an error, all the
1067 * rest of the 'unmoved' driver files are removed from archi\. If one or
1068 * more of the driver's files was already moved to archi\version\, it
1069 * potentially leaves the driver in a partially updated state. Version
1070 * trauma will most likely occur if an client attempts to use any printer
1071 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1072 * done is appropriate... later JRR
1075 DEBUG(5,("Moving files now !\n"));
1077 if (driver->driver_path && strlen(driver->driver_path)) {
1079 err = move_driver_file_to_download_area(ctx,
1080 conn,
1081 driver->driver_path,
1082 short_architecture,
1083 driver->version,
1084 ver);
1085 if (!W_ERROR_IS_OK(err)) {
1086 goto err_exit;
1090 if (driver->data_file && strlen(driver->data_file)) {
1091 if (!strequal(driver->data_file, driver->driver_path)) {
1093 err = move_driver_file_to_download_area(ctx,
1094 conn,
1095 driver->data_file,
1096 short_architecture,
1097 driver->version,
1098 ver);
1099 if (!W_ERROR_IS_OK(err)) {
1100 goto err_exit;
1105 if (driver->config_file && strlen(driver->config_file)) {
1106 if (!strequal(driver->config_file, driver->driver_path) &&
1107 !strequal(driver->config_file, driver->data_file)) {
1109 err = move_driver_file_to_download_area(ctx,
1110 conn,
1111 driver->config_file,
1112 short_architecture,
1113 driver->version,
1114 ver);
1115 if (!W_ERROR_IS_OK(err)) {
1116 goto err_exit;
1121 if (driver->help_file && strlen(driver->help_file)) {
1122 if (!strequal(driver->help_file, driver->driver_path) &&
1123 !strequal(driver->help_file, driver->data_file) &&
1124 !strequal(driver->help_file, driver->config_file)) {
1126 err = move_driver_file_to_download_area(ctx,
1127 conn,
1128 driver->help_file,
1129 short_architecture,
1130 driver->version,
1131 ver);
1132 if (!W_ERROR_IS_OK(err)) {
1133 goto err_exit;
1138 if (driver->dependent_files && driver->dependent_files->string) {
1139 for (i=0; driver->dependent_files->string[i]; i++) {
1140 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1141 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1142 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1143 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1144 int j;
1145 for (j=0; j < i; j++) {
1146 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1147 goto NextDriver;
1151 err = move_driver_file_to_download_area(ctx,
1152 conn,
1153 driver->dependent_files->string[i],
1154 short_architecture,
1155 driver->version,
1156 ver);
1157 if (!W_ERROR_IS_OK(err)) {
1158 goto err_exit;
1161 NextDriver: ;
1165 err = WERR_OK;
1166 err_exit:
1167 unbecome_user();
1168 err_free_conn:
1169 TALLOC_FREE(smb_dname);
1171 if (conn != NULL) {
1172 vfs_ChDir(conn, oldcwd);
1173 SMB_VFS_DISCONNECT(conn);
1174 conn_free(conn);
1177 return err;
1180 /****************************************************************************
1181 Determine whether or not a particular driver is currently assigned
1182 to a printer
1183 ****************************************************************************/
1185 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1186 struct dcerpc_binding_handle *b,
1187 const struct spoolss_DriverInfo8 *r)
1189 int snum;
1190 int n_services = lp_numservices();
1191 bool in_use = False;
1192 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1193 WERROR result;
1195 if (!r) {
1196 return false;
1199 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1201 /* loop through the printers.tdb and check for the drivername */
1203 for (snum=0; snum<n_services && !in_use; snum++) {
1204 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1205 continue;
1208 result = winreg_get_printer(mem_ctx, b,
1209 lp_servicename(talloc_tos(), snum),
1210 &pinfo2);
1211 if (!W_ERROR_IS_OK(result)) {
1212 continue; /* skip */
1215 if (strequal(r->driver_name, pinfo2->drivername)) {
1216 in_use = True;
1219 TALLOC_FREE(pinfo2);
1222 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1224 if ( in_use ) {
1225 struct spoolss_DriverInfo8 *driver;
1226 WERROR werr;
1228 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1230 /* we can still remove the driver if there is one of
1231 "Windows NT x86" version 2 or 3 left */
1233 if (!strequal("Windows NT x86", r->architecture)) {
1234 werr = winreg_get_driver(mem_ctx, b,
1235 "Windows NT x86",
1236 r->driver_name,
1237 DRIVER_ANY_VERSION,
1238 &driver);
1239 } else if (r->version == 2) {
1240 werr = winreg_get_driver(mem_ctx, b,
1241 "Windows NT x86",
1242 r->driver_name,
1243 3, &driver);
1244 } else if (r->version == 3) {
1245 werr = winreg_get_driver(mem_ctx, b,
1246 "Windows NT x86",
1247 r->driver_name,
1248 2, &driver);
1249 } else {
1250 DEBUG(0, ("printer_driver_in_use: ERROR!"
1251 " unknown driver version (%d)\n",
1252 r->version));
1253 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1256 /* now check the error code */
1258 if ( W_ERROR_IS_OK(werr) ) {
1259 /* it's ok to remove the driver, we have other architctures left */
1260 in_use = False;
1261 talloc_free(driver);
1265 /* report that the driver is not in use by default */
1267 return in_use;
1271 /**********************************************************************
1272 Check to see if a ogiven file is in use by *info
1273 *********************************************************************/
1275 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1277 int i = 0;
1279 if ( !info )
1280 return False;
1282 /* mz: skip files that are in the list but already deleted */
1283 if (!file || !file[0]) {
1284 return false;
1287 if (strequal(file, info->driver_path))
1288 return True;
1290 if (strequal(file, info->data_file))
1291 return True;
1293 if (strequal(file, info->config_file))
1294 return True;
1296 if (strequal(file, info->help_file))
1297 return True;
1299 /* see of there are any dependent files to examine */
1301 if (!info->dependent_files)
1302 return False;
1304 while (info->dependent_files[i] && *info->dependent_files[i]) {
1305 if (strequal(file, info->dependent_files[i]))
1306 return True;
1307 i++;
1310 return False;
1314 /**********************************************************************
1315 Utility function to remove the dependent file pointed to by the
1316 input parameter from the list
1317 *********************************************************************/
1319 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1322 /* bump everything down a slot */
1324 while (files && files[idx+1]) {
1325 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1326 idx++;
1329 files[idx] = NULL;
1331 return;
1334 /**********************************************************************
1335 Check if any of the files used by src are also used by drv
1336 *********************************************************************/
1338 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1339 struct spoolss_DriverInfo8 *src,
1340 const struct spoolss_DriverInfo8 *drv)
1342 bool in_use = False;
1343 int i = 0;
1345 if ( !src || !drv )
1346 return False;
1348 /* check each file. Remove it from the src structure if it overlaps */
1350 if (drv_file_in_use(src->driver_path, drv)) {
1351 in_use = True;
1352 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1353 src->driver_path = talloc_strdup(mem_ctx, "");
1354 if (!src->driver_path) { return false; }
1357 if (drv_file_in_use(src->data_file, drv)) {
1358 in_use = True;
1359 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1360 src->data_file = talloc_strdup(mem_ctx, "");
1361 if (!src->data_file) { return false; }
1364 if (drv_file_in_use(src->config_file, drv)) {
1365 in_use = True;
1366 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1367 src->config_file = talloc_strdup(mem_ctx, "");
1368 if (!src->config_file) { return false; }
1371 if (drv_file_in_use(src->help_file, drv)) {
1372 in_use = True;
1373 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1374 src->help_file = talloc_strdup(mem_ctx, "");
1375 if (!src->help_file) { return false; }
1378 /* are there any dependentfiles to examine? */
1380 if (!src->dependent_files)
1381 return in_use;
1383 while (src->dependent_files[i] && *src->dependent_files[i]) {
1384 if (drv_file_in_use(src->dependent_files[i], drv)) {
1385 in_use = True;
1386 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1387 trim_dependent_file(mem_ctx, src->dependent_files, i);
1388 } else
1389 i++;
1392 return in_use;
1395 /****************************************************************************
1396 Determine whether or not a particular driver files are currently being
1397 used by any other driver.
1399 Return value is True if any files were in use by other drivers
1400 and False otherwise.
1402 Upon return, *info has been modified to only contain the driver files
1403 which are not in use
1405 Fix from mz:
1407 This needs to check all drivers to ensure that all files in use
1408 have been removed from *info, not just the ones in the first
1409 match.
1410 ****************************************************************************/
1412 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1413 struct dcerpc_binding_handle *b,
1414 struct spoolss_DriverInfo8 *info)
1416 int i;
1417 uint32 version;
1418 struct spoolss_DriverInfo8 *driver;
1419 bool in_use = false;
1420 uint32_t num_drivers;
1421 const char **drivers;
1422 WERROR result;
1424 if ( !info )
1425 return False;
1427 version = info->version;
1429 /* loop over all driver versions */
1431 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1433 /* get the list of drivers */
1435 result = winreg_get_driver_list(mem_ctx, b,
1436 info->architecture, version,
1437 &num_drivers, &drivers);
1438 if (!W_ERROR_IS_OK(result)) {
1439 return true;
1442 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1443 num_drivers, info->architecture, version));
1445 /* check each driver for overlap in files */
1447 for (i = 0; i < num_drivers; i++) {
1448 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1450 driver = NULL;
1452 result = winreg_get_driver(mem_ctx, b,
1453 info->architecture, drivers[i],
1454 version, &driver);
1455 if (!W_ERROR_IS_OK(result)) {
1456 talloc_free(drivers);
1457 return True;
1460 /* check if d2 uses any files from d1 */
1461 /* only if this is a different driver than the one being deleted */
1463 if (!strequal(info->driver_name, driver->driver_name)) {
1464 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1465 /* mz: Do not instantly return -
1466 * we need to ensure this file isn't
1467 * also in use by other drivers. */
1468 in_use = true;
1472 talloc_free(driver);
1475 talloc_free(drivers);
1477 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1479 return in_use;
1482 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1483 const char *short_arch,
1484 int vers,
1485 const char *fname)
1487 TALLOC_CTX *tmp_ctx = talloc_new(conn);
1488 struct smb_filename *smb_fname = NULL;
1489 char *print_dlr_path;
1490 NTSTATUS status = NT_STATUS_NO_MEMORY;
1492 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
1493 short_arch, vers, fname);
1494 if (print_dlr_path == NULL) {
1495 goto err_out;
1498 status = create_synthetic_smb_fname(tmp_ctx, print_dlr_path,
1499 NULL, NULL, &smb_fname);
1500 if (!NT_STATUS_IS_OK(status)) {
1501 goto err_out;
1504 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1505 err_out:
1506 talloc_free(tmp_ctx);
1507 return status;
1510 /****************************************************************************
1511 Actually delete the driver files. Make sure that
1512 printer_driver_files_in_use() return False before calling
1513 this.
1514 ****************************************************************************/
1516 bool delete_driver_files(const struct auth_session_info *session_info,
1517 const struct spoolss_DriverInfo8 *r)
1519 const char *short_arch;
1520 connection_struct *conn;
1521 NTSTATUS nt_status;
1522 char *oldcwd;
1523 char *printdollar = NULL;
1524 int printdollar_snum;
1525 bool ret = false;
1527 if (!r) {
1528 return false;
1531 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1532 r->driver_name, r->version));
1534 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1535 if (!printdollar) {
1536 return false;
1538 if (printdollar_snum == -1) {
1539 return false;
1542 nt_status = create_conn_struct(talloc_tos(),
1543 server_event_context(),
1544 server_messaging_context(),
1545 &conn,
1546 printdollar_snum,
1547 lp_pathname(talloc_tos(), printdollar_snum),
1548 session_info, &oldcwd);
1549 if (!NT_STATUS_IS_OK(nt_status)) {
1550 DEBUG(0,("delete_driver_files: create_conn_struct "
1551 "returned %s\n", nt_errstr(nt_status)));
1552 return false;
1555 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1556 if (!NT_STATUS_IS_OK(nt_status)) {
1557 DEBUG(0, ("failed set force user / group\n"));
1558 ret = false;
1559 goto err_free_conn;
1562 if (!become_user_by_session(conn, session_info)) {
1563 DEBUG(0, ("failed to become user\n"));
1564 ret = false;
1565 goto err_free_conn;
1568 if ( !CAN_WRITE(conn) ) {
1569 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1570 ret = false;
1571 goto err_out;
1574 short_arch = get_short_archi(r->architecture);
1575 if (short_arch == NULL) {
1576 DEBUG(0, ("bad architecture %s\n", r->architecture));
1577 ret = false;
1578 goto err_out;
1581 /* now delete the files */
1583 if (r->driver_path && r->driver_path[0]) {
1584 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
1585 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
1588 if (r->config_file && r->config_file[0]) {
1589 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
1590 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
1593 if (r->data_file && r->data_file[0]) {
1594 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
1595 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
1598 if (r->help_file && r->help_file[0]) {
1599 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
1600 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
1603 if (r->dependent_files) {
1604 int i = 0;
1605 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1606 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
1607 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
1608 i++;
1612 ret = true;
1613 err_out:
1614 unbecome_user();
1615 err_free_conn:
1616 if (conn != NULL) {
1617 vfs_ChDir(conn, oldcwd);
1618 SMB_VFS_DISCONNECT(conn);
1619 conn_free(conn);
1621 return ret;
1624 /* error code:
1625 0: everything OK
1626 1: level not implemented
1627 2: file doesn't exist
1628 3: can't allocate memory
1629 4: can't free memory
1630 5: non existent struct
1634 A printer and a printer driver are 2 different things.
1635 NT manages them separatelly, Samba does the same.
1636 Why ? Simply because it's easier and it makes sense !
1638 Now explanation: You have 3 printers behind your samba server,
1639 2 of them are the same make and model (laser A and B). But laser B
1640 has an 3000 sheet feeder and laser A doesn't such an option.
1641 Your third printer is an old dot-matrix model for the accounting :-).
1643 If the /usr/local/samba/lib directory (default dir), you will have
1644 5 files to describe all of this.
1646 3 files for the printers (1 by printer):
1647 NTprinter_laser A
1648 NTprinter_laser B
1649 NTprinter_accounting
1650 2 files for the drivers (1 for the laser and 1 for the dot matrix)
1651 NTdriver_printer model X
1652 NTdriver_printer model Y
1654 jfm: I should use this comment for the text file to explain
1655 same thing for the forms BTW.
1656 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
1660 /* Convert generic access rights to printer object specific access rights.
1661 It turns out that NT4 security descriptors use generic access rights and
1662 NT5 the object specific ones. */
1664 void map_printer_permissions(struct security_descriptor *sd)
1666 int i;
1668 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1669 se_map_generic(&sd->dacl->aces[i].access_mask,
1670 &printer_generic_mapping);
1674 void map_job_permissions(struct security_descriptor *sd)
1676 int i;
1678 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
1679 se_map_generic(&sd->dacl->aces[i].access_mask,
1680 &job_generic_mapping);
1685 /****************************************************************************
1686 Check a user has permissions to perform the given operation. We use the
1687 permission constants defined in include/rpc_spoolss.h to check the various
1688 actions we perform when checking printer access.
1690 PRINTER_ACCESS_ADMINISTER:
1691 print_queue_pause, print_queue_resume, update_printer_sec,
1692 update_printer, spoolss_addprinterex_level_2,
1693 _spoolss_setprinterdata
1695 PRINTER_ACCESS_USE:
1696 print_job_start
1698 JOB_ACCESS_ADMINISTER:
1699 print_job_delete, print_job_pause, print_job_resume,
1700 print_queue_purge
1702 Try access control in the following order (for performance reasons):
1703 1) root and SE_PRINT_OPERATOR can do anything (easy check)
1704 2) check security descriptor (bit comparisons in memory)
1705 3) "printer admins" (may result in numerous calls to winbind)
1707 ****************************************************************************/
1708 bool print_access_check(const struct auth_session_info *session_info,
1709 struct messaging_context *msg_ctx, int snum,
1710 int access_type)
1712 struct spoolss_security_descriptor *secdesc = NULL;
1713 uint32 access_granted;
1714 size_t sd_size;
1715 NTSTATUS status;
1716 WERROR result;
1717 const char *pname;
1718 TALLOC_CTX *mem_ctx = NULL;
1720 /* If user is NULL then use the current_user structure */
1722 /* Always allow root or SE_PRINT_OPERATROR to do anything */
1724 if (session_info->unix_token->uid == sec_initial_uid()
1725 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
1726 return True;
1729 /* Get printer name */
1731 pname = lp_printername(talloc_tos(), snum);
1733 if (!pname || !*pname) {
1734 errno = EACCES;
1735 return False;
1738 /* Get printer security descriptor */
1740 if(!(mem_ctx = talloc_init("print_access_check"))) {
1741 errno = ENOMEM;
1742 return False;
1745 result = winreg_get_printer_secdesc_internal(mem_ctx,
1746 get_session_info_system(),
1747 msg_ctx,
1748 pname,
1749 &secdesc);
1750 if (!W_ERROR_IS_OK(result)) {
1751 talloc_destroy(mem_ctx);
1752 errno = ENOMEM;
1753 return False;
1756 if (access_type == JOB_ACCESS_ADMINISTER) {
1757 struct spoolss_security_descriptor *parent_secdesc = secdesc;
1759 /* Create a child security descriptor to check permissions
1760 against. This is because print jobs are child objects
1761 objects of a printer. */
1762 status = se_create_child_secdesc(mem_ctx,
1763 &secdesc,
1764 &sd_size,
1765 parent_secdesc,
1766 parent_secdesc->owner_sid,
1767 parent_secdesc->group_sid,
1768 false);
1769 if (!NT_STATUS_IS_OK(status)) {
1770 talloc_destroy(mem_ctx);
1771 errno = map_errno_from_nt_status(status);
1772 return False;
1775 map_job_permissions(secdesc);
1776 } else {
1777 map_printer_permissions(secdesc);
1780 /* Check access */
1781 status = se_access_check(secdesc, session_info->security_token, access_type,
1782 &access_granted);
1784 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
1786 talloc_destroy(mem_ctx);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 errno = EACCES;
1792 return NT_STATUS_IS_OK(status);
1795 /****************************************************************************
1796 Check the time parameters allow a print operation.
1797 *****************************************************************************/
1799 bool print_time_access_check(const struct auth_session_info *session_info,
1800 struct messaging_context *msg_ctx,
1801 const char *servicename)
1803 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1804 WERROR result;
1805 bool ok = False;
1806 time_t now = time(NULL);
1807 struct tm *t;
1808 uint32 mins;
1810 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
1811 servicename, &pinfo2);
1812 if (!W_ERROR_IS_OK(result)) {
1813 return False;
1816 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
1817 ok = True;
1820 t = gmtime(&now);
1821 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
1823 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
1824 ok = True;
1827 TALLOC_FREE(pinfo2);
1829 if (!ok) {
1830 errno = EACCES;
1833 return ok;
1836 void nt_printer_remove(TALLOC_CTX *mem_ctx,
1837 const struct auth_session_info *session_info,
1838 struct messaging_context *msg_ctx,
1839 const char *printer)
1841 WERROR result;
1843 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
1844 printer, "");
1845 if (!W_ERROR_IS_OK(result)) {
1846 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
1847 "%s\n", printer, win_errstr(result)));
1851 void nt_printer_add(TALLOC_CTX *mem_ctx,
1852 const struct auth_session_info *session_info,
1853 struct messaging_context *msg_ctx,
1854 const char *printer)
1856 WERROR result;
1858 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
1859 printer);
1860 if (!W_ERROR_IS_OK(result)) {
1861 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
1862 printer, win_errstr(result)));