s3-printing: clean up get_correct_cversion error paths
[Samba/bjacke.git] / source3 / printing / nt_printing.c
blob3b805f4f55457628043025c185e72ecb8024ead0
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 "librpc/gen_ndr/messaging.h"
24 #include "printing/pcap.h"
25 #include "printing/nt_printing_tdb.h"
26 #include "printing/nt_printing_migrate.h"
27 #include "registry.h"
28 #include "registry/reg_objects.h"
29 #include "../librpc/gen_ndr/ndr_security.h"
30 #include "../librpc/gen_ndr/ndr_spoolss.h"
31 #include "rpc_server/spoolss/srv_spoolss_util.h"
32 #include "nt_printing.h"
33 #include "secrets.h"
34 #include "../librpc/gen_ndr/netlogon.h"
35 #include "../libcli/security/security.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(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 pipes_struct *p,
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 p->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 /* Open the driver file (Portable Executable format) and determine the
629 * deriver the cversion. */
630 driverpath = talloc_asprintf(talloc_tos(),
631 "%s/%s",
632 architecture,
633 driverpath_in);
634 if (!driverpath) {
635 *perr = WERR_NOMEM;
636 goto error_exit;
639 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
640 if (!NT_STATUS_IS_OK(nt_status)) {
641 *perr = ntstatus_to_werror(nt_status);
642 goto error_exit;
645 nt_status = vfs_file_exist(conn, smb_fname);
646 if (!NT_STATUS_IS_OK(nt_status)) {
647 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
648 *perr = WERR_BADFILE;
649 goto error_exit;
652 nt_status = SMB_VFS_CREATE_FILE(
653 conn, /* conn */
654 NULL, /* req */
655 0, /* root_dir_fid */
656 smb_fname, /* fname */
657 FILE_GENERIC_READ, /* access_mask */
658 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
659 FILE_OPEN, /* create_disposition*/
660 0, /* create_options */
661 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
662 INTERNAL_OPEN_ONLY, /* oplock_request */
663 0, /* private_flags */
664 0, /* allocation_size */
665 NULL, /* sd */
666 NULL, /* ea_list */
667 &fsp, /* result */
668 NULL); /* pinfo */
670 if (!NT_STATUS_IS_OK(nt_status)) {
671 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
672 "%d\n", smb_fname_str_dbg(smb_fname), errno));
673 *perr = WERR_ACCESS_DENIED;
674 goto error_exit;
675 } else {
676 uint32 major;
677 uint32 minor;
678 int ret;
680 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
681 if (ret == -1) {
682 *perr = WERR_INVALID_PARAM;
683 goto error_exit;
684 } else if (!ret) {
685 DEBUG(6,("get_correct_cversion: Version info not "
686 "found [%s]\n",
687 smb_fname_str_dbg(smb_fname)));
688 *perr = WERR_INVALID_PARAM;
689 goto error_exit;
693 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
694 * for more details. Version in this case is not just the version of the
695 * file, but the version in the sense of kernal mode (2) vs. user mode
696 * (3) drivers. Other bits of the version fields are the version info.
697 * JRR 010716
699 cversion = major & 0x0000ffff;
700 switch (cversion) {
701 case 2: /* WinNT drivers */
702 case 3: /* Win2K drivers */
703 break;
705 default:
706 DEBUG(6,("get_correct_cversion: cversion "
707 "invalid [%s] cversion = %d\n",
708 smb_fname_str_dbg(smb_fname),
709 cversion));
710 goto error_exit;
713 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
714 " = 0x%x minor = 0x%x\n",
715 smb_fname_str_dbg(smb_fname), major, minor));
718 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
719 smb_fname_str_dbg(smb_fname), cversion));
720 *perr = WERR_OK;
722 error_exit:
723 TALLOC_FREE(smb_fname);
724 if (fsp != NULL) {
725 close_file(NULL, fsp, NORMAL_CLOSE);
727 if (conn != NULL) {
728 vfs_ChDir(conn, oldcwd);
729 conn_free(conn);
731 if (!NT_STATUS_IS_OK(*perr)) {
732 cversion = -1;
735 return cversion;
738 /****************************************************************************
739 ****************************************************************************/
741 #define strip_driver_path(_mem_ctx, _element) do { \
742 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
743 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
744 W_ERROR_HAVE_NO_MEMORY((_element)); \
746 } while (0);
748 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
749 struct pipes_struct *rpc_pipe,
750 const char *architecture,
751 const char **driver_path,
752 const char **data_file,
753 const char **config_file,
754 const char **help_file,
755 struct spoolss_StringArray *dependent_files,
756 enum spoolss_DriverOSVersion *version)
758 const char *short_architecture;
759 int i;
760 WERROR err;
761 char *_p;
763 if (!*driver_path || !*data_file) {
764 return WERR_INVALID_PARAM;
767 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
768 return WERR_INVALID_PARAM;
771 /* clean up the driver name.
772 * we can get .\driver.dll
773 * or worse c:\windows\system\driver.dll !
775 /* using an intermediate string to not have overlaping memcpy()'s */
777 strip_driver_path(mem_ctx, *driver_path);
778 strip_driver_path(mem_ctx, *data_file);
779 if (*config_file) {
780 strip_driver_path(mem_ctx, *config_file);
782 if (help_file) {
783 strip_driver_path(mem_ctx, *help_file);
786 if (dependent_files && dependent_files->string) {
787 for (i=0; dependent_files->string[i]; i++) {
788 strip_driver_path(mem_ctx, dependent_files->string[i]);
792 short_architecture = get_short_archi(architecture);
793 if (!short_architecture) {
794 return WERR_UNKNOWN_PRINTER_DRIVER;
797 /* jfm:7/16/2000 the client always sends the cversion=0.
798 * The server should check which version the driver is by reading
799 * the PE header of driver->driverpath.
801 * For Windows 95/98 the version is 0 (so the value sent is correct)
802 * For Windows NT (the architecture doesn't matter)
803 * NT 3.1: cversion=0
804 * NT 3.5/3.51: cversion=1
805 * NT 4: cversion=2
806 * NT2K: cversion=3
809 *version = get_correct_cversion(rpc_pipe, short_architecture,
810 *driver_path, &err);
811 if (*version == -1) {
812 return err;
815 return WERR_OK;
818 /****************************************************************************
819 ****************************************************************************/
821 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
822 struct pipes_struct *rpc_pipe,
823 struct spoolss_AddDriverInfoCtr *r)
825 switch (r->level) {
826 case 3:
827 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
828 r->info.info3->architecture,
829 &r->info.info3->driver_path,
830 &r->info.info3->data_file,
831 &r->info.info3->config_file,
832 &r->info.info3->help_file,
833 r->info.info3->dependent_files,
834 &r->info.info3->version);
835 case 6:
836 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
837 r->info.info6->architecture,
838 &r->info.info6->driver_path,
839 &r->info.info6->data_file,
840 &r->info.info6->config_file,
841 &r->info.info6->help_file,
842 r->info.info6->dependent_files,
843 &r->info.info6->version);
844 default:
845 return WERR_NOT_SUPPORTED;
849 /****************************************************************************
850 This function sucks and should be replaced. JRA.
851 ****************************************************************************/
853 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
854 const struct spoolss_AddDriverInfo6 *src)
856 dst->version = src->version;
858 dst->driver_name = src->driver_name;
859 dst->architecture = src->architecture;
860 dst->driver_path = src->driver_path;
861 dst->data_file = src->data_file;
862 dst->config_file = src->config_file;
863 dst->help_file = src->help_file;
864 dst->monitor_name = src->monitor_name;
865 dst->default_datatype = src->default_datatype;
866 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
867 dst->dependent_files = src->dependent_files;
870 /****************************************************************************
871 ****************************************************************************/
873 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
874 connection_struct *conn,
875 const char *driver_file,
876 const char *short_architecture,
877 uint32_t driver_version,
878 uint32_t version)
880 struct smb_filename *smb_fname_old = NULL;
881 struct smb_filename *smb_fname_new = NULL;
882 char *old_name = NULL;
883 char *new_name = NULL;
884 NTSTATUS status;
885 WERROR ret;
887 old_name = talloc_asprintf(mem_ctx, "%s/%s",
888 short_architecture, driver_file);
889 W_ERROR_HAVE_NO_MEMORY(old_name);
891 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
892 short_architecture, driver_version, driver_file);
893 if (new_name == NULL) {
894 TALLOC_FREE(old_name);
895 return WERR_NOMEM;
898 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
900 status = driver_unix_convert(conn, old_name, &smb_fname_old);
901 if (!NT_STATUS_IS_OK(status)) {
902 ret = WERR_NOMEM;
903 goto out;
906 /* Setup a synthetic smb_filename struct */
907 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
908 if (!smb_fname_new) {
909 ret = WERR_NOMEM;
910 goto out;
913 smb_fname_new->base_name = new_name;
915 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
916 "'%s'\n", smb_fname_old->base_name,
917 smb_fname_new->base_name));
919 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
920 OPENX_FILE_EXISTS_TRUNCATE |
921 OPENX_FILE_CREATE_IF_NOT_EXIST,
922 0, false);
924 if (!NT_STATUS_IS_OK(status)) {
925 DEBUG(0,("move_driver_file_to_download_area: Unable "
926 "to rename [%s] to [%s]: %s\n",
927 smb_fname_old->base_name, new_name,
928 nt_errstr(status)));
929 ret = WERR_ACCESS_DENIED;
930 goto out;
934 ret = WERR_OK;
935 out:
936 TALLOC_FREE(smb_fname_old);
937 TALLOC_FREE(smb_fname_new);
938 return ret;
941 WERROR move_driver_to_download_area(struct pipes_struct *p,
942 struct spoolss_AddDriverInfoCtr *r)
944 struct spoolss_AddDriverInfo3 *driver;
945 struct spoolss_AddDriverInfo3 converted_driver;
946 const char *short_architecture;
947 struct smb_filename *smb_dname = NULL;
948 char *new_dir = NULL;
949 connection_struct *conn = NULL;
950 NTSTATUS nt_status;
951 int i;
952 TALLOC_CTX *ctx = talloc_tos();
953 int ver = 0;
954 char *oldcwd;
955 char *printdollar = NULL;
956 int printdollar_snum;
957 WERROR err = WERR_OK;
959 switch (r->level) {
960 case 3:
961 driver = r->info.info3;
962 break;
963 case 6:
964 convert_level_6_to_level3(&converted_driver, r->info.info6);
965 driver = &converted_driver;
966 break;
967 default:
968 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
969 return WERR_UNKNOWN_LEVEL;
972 short_architecture = get_short_archi(driver->architecture);
973 if (!short_architecture) {
974 return WERR_UNKNOWN_PRINTER_DRIVER;
977 printdollar_snum = find_service(ctx, "print$", &printdollar);
978 if (!printdollar) {
979 return WERR_NOMEM;
981 if (printdollar_snum == -1) {
982 return WERR_NO_SUCH_SHARE;
985 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
986 lp_pathname(printdollar_snum),
987 p->session_info, &oldcwd);
988 if (!NT_STATUS_IS_OK(nt_status)) {
989 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
990 "returned %s\n", nt_errstr(nt_status)));
991 err = ntstatus_to_werror(nt_status);
992 return err;
995 new_dir = talloc_asprintf(ctx,
996 "%s/%d",
997 short_architecture,
998 driver->version);
999 if (!new_dir) {
1000 err = WERR_NOMEM;
1001 goto err_exit;
1003 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1004 if (!NT_STATUS_IS_OK(nt_status)) {
1005 err = WERR_NOMEM;
1006 goto err_exit;
1009 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1011 nt_status = create_directory(conn, NULL, smb_dname);
1012 if (!NT_STATUS_IS_OK(nt_status)
1013 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1014 DEBUG(0, ("failed to create driver destination directory: %s\n",
1015 nt_errstr(nt_status)));
1016 err = ntstatus_to_werror(nt_status);
1017 goto err_exit;
1020 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1021 * listed for this driver which has already been moved, skip it (note:
1022 * drivers may list the same file name several times. Then check if the
1023 * file already exists in archi\version\, if so, check that the version
1024 * info (or time stamps if version info is unavailable) is newer (or the
1025 * date is later). If it is, move it to archi\version\filexxx.yyy.
1026 * Otherwise, delete the file.
1028 * If a file is not moved to archi\version\ because of an error, all the
1029 * rest of the 'unmoved' driver files are removed from archi\. If one or
1030 * more of the driver's files was already moved to archi\version\, it
1031 * potentially leaves the driver in a partially updated state. Version
1032 * trauma will most likely occur if an client attempts to use any printer
1033 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1034 * done is appropriate... later JRR
1037 DEBUG(5,("Moving files now !\n"));
1039 if (driver->driver_path && strlen(driver->driver_path)) {
1041 err = move_driver_file_to_download_area(ctx,
1042 conn,
1043 driver->driver_path,
1044 short_architecture,
1045 driver->version,
1046 ver);
1047 if (!W_ERROR_IS_OK(err)) {
1048 goto err_exit;
1052 if (driver->data_file && strlen(driver->data_file)) {
1053 if (!strequal(driver->data_file, driver->driver_path)) {
1055 err = move_driver_file_to_download_area(ctx,
1056 conn,
1057 driver->data_file,
1058 short_architecture,
1059 driver->version,
1060 ver);
1061 if (!W_ERROR_IS_OK(err)) {
1062 goto err_exit;
1067 if (driver->config_file && strlen(driver->config_file)) {
1068 if (!strequal(driver->config_file, driver->driver_path) &&
1069 !strequal(driver->config_file, driver->data_file)) {
1071 err = move_driver_file_to_download_area(ctx,
1072 conn,
1073 driver->config_file,
1074 short_architecture,
1075 driver->version,
1076 ver);
1077 if (!W_ERROR_IS_OK(err)) {
1078 goto err_exit;
1083 if (driver->help_file && strlen(driver->help_file)) {
1084 if (!strequal(driver->help_file, driver->driver_path) &&
1085 !strequal(driver->help_file, driver->data_file) &&
1086 !strequal(driver->help_file, driver->config_file)) {
1088 err = move_driver_file_to_download_area(ctx,
1089 conn,
1090 driver->help_file,
1091 short_architecture,
1092 driver->version,
1093 ver);
1094 if (!W_ERROR_IS_OK(err)) {
1095 goto err_exit;
1100 if (driver->dependent_files && driver->dependent_files->string) {
1101 for (i=0; driver->dependent_files->string[i]; i++) {
1102 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1103 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1104 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1105 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1106 int j;
1107 for (j=0; j < i; j++) {
1108 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1109 goto NextDriver;
1113 err = move_driver_file_to_download_area(ctx,
1114 conn,
1115 driver->dependent_files->string[i],
1116 short_architecture,
1117 driver->version,
1118 ver);
1119 if (!W_ERROR_IS_OK(err)) {
1120 goto err_exit;
1123 NextDriver: ;
1127 err = WERR_OK;
1128 err_exit:
1129 TALLOC_FREE(smb_dname);
1131 if (conn != NULL) {
1132 vfs_ChDir(conn, oldcwd);
1133 conn_free(conn);
1136 return err;
1139 /****************************************************************************
1140 Create and allocate a default devicemode.
1141 ****************************************************************************/
1143 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1144 const char *devicename,
1145 struct spoolss_DeviceMode **devmode)
1147 struct spoolss_DeviceMode *dm;
1148 char *dname;
1150 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1151 if (dm == NULL) {
1152 return WERR_NOMEM;
1155 dname = talloc_asprintf(dm, "%s", devicename);
1156 if (dname == NULL) {
1157 return WERR_NOMEM;
1159 if (strlen(dname) > MAXDEVICENAME) {
1160 dname[MAXDEVICENAME] = '\0';
1162 dm->devicename = dname;
1164 dm->formname = talloc_strdup(dm, "Letter");
1165 if (dm->formname == NULL) {
1166 return WERR_NOMEM;
1169 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1170 dm->driverversion = 0x0400;
1171 dm->size = 0x00DC;
1172 dm->__driverextra_length = 0;
1173 dm->fields = DEVMODE_FORMNAME |
1174 DEVMODE_TTOPTION |
1175 DEVMODE_PRINTQUALITY |
1176 DEVMODE_DEFAULTSOURCE |
1177 DEVMODE_COPIES |
1178 DEVMODE_SCALE |
1179 DEVMODE_PAPERSIZE |
1180 DEVMODE_ORIENTATION;
1181 dm->orientation = DMORIENT_PORTRAIT;
1182 dm->papersize = DMPAPER_LETTER;
1183 dm->paperlength = 0;
1184 dm->paperwidth = 0;
1185 dm->scale = 0x64;
1186 dm->copies = 1;
1187 dm->defaultsource = DMBIN_FORMSOURCE;
1188 dm->printquality = DMRES_HIGH; /* 0x0258 */
1189 dm->color = DMRES_MONOCHROME;
1190 dm->duplex = DMDUP_SIMPLEX;
1191 dm->yresolution = 0;
1192 dm->ttoption = DMTT_SUBDEV;
1193 dm->collate = DMCOLLATE_FALSE;
1194 dm->icmmethod = 0;
1195 dm->icmintent = 0;
1196 dm->mediatype = 0;
1197 dm->dithertype = 0;
1199 dm->logpixels = 0;
1200 dm->bitsperpel = 0;
1201 dm->pelswidth = 0;
1202 dm->pelsheight = 0;
1203 dm->displayflags = 0;
1204 dm->displayfrequency = 0;
1205 dm->reserved1 = 0;
1206 dm->reserved2 = 0;
1207 dm->panningwidth = 0;
1208 dm->panningheight = 0;
1210 dm->driverextra_data.data = NULL;
1211 dm->driverextra_data.length = 0;
1213 *devmode = dm;
1214 return WERR_OK;
1217 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1218 struct spoolss_security_descriptor **secdesc)
1220 struct security_ace ace[7]; /* max number of ace entries */
1221 int i = 0;
1222 uint32_t sa;
1223 struct security_acl *psa = NULL;
1224 struct security_descriptor *psd = NULL;
1225 struct dom_sid adm_sid;
1226 size_t sd_size;
1228 /* Create an ACE where Everyone is allowed to print */
1230 sa = PRINTER_ACE_PRINT;
1231 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1232 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1234 /* Add the domain admins group if we are a DC */
1236 if ( IS_DC ) {
1237 struct dom_sid domadmins_sid;
1239 sid_compose(&domadmins_sid, get_global_sam_sid(),
1240 DOMAIN_RID_ADMINS);
1242 sa = PRINTER_ACE_FULL_CONTROL;
1243 init_sec_ace(&ace[i++], &domadmins_sid,
1244 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1245 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1246 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1247 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1249 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1250 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1252 sa = PRINTER_ACE_FULL_CONTROL;
1253 init_sec_ace(&ace[i++], &adm_sid,
1254 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1255 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1256 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1257 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1260 /* add BUILTIN\Administrators as FULL CONTROL */
1262 sa = PRINTER_ACE_FULL_CONTROL;
1263 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1264 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1265 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1266 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1267 SEC_ACE_TYPE_ACCESS_ALLOWED,
1268 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1270 /* add BUILTIN\Print Operators as FULL CONTROL */
1272 sa = PRINTER_ACE_FULL_CONTROL;
1273 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1274 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1275 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1276 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1277 SEC_ACE_TYPE_ACCESS_ALLOWED,
1278 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1280 /* Make the security descriptor owned by the BUILTIN\Administrators */
1282 /* The ACL revision number in rpc_secdesc.h differs from the one
1283 created by NT when setting ACE entries in printer
1284 descriptors. NT4 complains about the property being edited by a
1285 NT5 machine. */
1287 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1288 psd = make_sec_desc(mem_ctx,
1289 SD_REVISION,
1290 SEC_DESC_SELF_RELATIVE,
1291 &global_sid_Builtin_Administrators,
1292 &global_sid_Builtin_Administrators,
1293 NULL,
1294 psa,
1295 &sd_size);
1298 if (psd == NULL) {
1299 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1300 return WERR_NOMEM;
1303 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1304 (unsigned int)sd_size));
1306 *secdesc = psd;
1308 return WERR_OK;
1311 /****************************************************************************
1312 ***************************************************************************/
1314 static char *win_driver;
1315 static char *os2_driver;
1317 static const char *get_win_driver(void)
1319 if (win_driver == NULL) {
1320 return "";
1322 return win_driver;
1325 static const char *get_os2_driver(void)
1327 if (os2_driver == NULL) {
1328 return "";
1330 return os2_driver;
1333 static bool set_driver_mapping(const char *from, const char *to)
1335 SAFE_FREE(win_driver);
1336 SAFE_FREE(os2_driver);
1338 win_driver = SMB_STRDUP(from);
1339 os2_driver = SMB_STRDUP(to);
1341 if (win_driver == NULL || os2_driver == NULL) {
1342 SAFE_FREE(win_driver);
1343 SAFE_FREE(os2_driver);
1344 return false;
1346 return true;
1350 * @internal
1352 * @brief Map a Windows driver to a OS/2 driver.
1354 * @param[in] mem_ctx The memory context to use.
1356 * @param[in,out] pdrivername The drivername of Windows to remap.
1358 * @return WERR_OK on success, a corresponding WERROR on failure.
1360 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1362 const char *mapfile = lp_os2_driver_map();
1363 char **lines = NULL;
1364 const char *drivername;
1365 int numlines = 0;
1366 int i;
1368 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1369 return WERR_INVALID_PARAMETER;
1372 drivername = *pdrivername;
1374 if (mapfile[0] == '\0') {
1375 return WERR_BADFILE;
1378 if (strequal(drivername, get_win_driver())) {
1379 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1380 drivername, get_os2_driver()));
1381 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1382 if (drivername == NULL) {
1383 return WERR_NOMEM;
1385 *pdrivername = drivername;
1386 return WERR_OK;
1389 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1390 if (numlines == 0 || lines == NULL) {
1391 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1392 TALLOC_FREE(lines);
1393 return WERR_EMPTY;
1396 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1398 for( i = 0; i < numlines; i++) {
1399 char *nt_name = lines[i];
1400 char *os2_name = strchr(nt_name, '=');
1402 if (os2_name == NULL) {
1403 continue;
1406 *os2_name++ = '\0';
1408 while (isspace(*nt_name)) {
1409 nt_name++;
1412 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1413 continue;
1417 int l = strlen(nt_name);
1418 while (l && isspace(nt_name[l - 1])) {
1419 nt_name[l - 1] = 0;
1420 l--;
1424 while (isspace(*os2_name)) {
1425 os2_name++;
1429 int l = strlen(os2_name);
1430 while (l && isspace(os2_name[l-1])) {
1431 os2_name[l-1] = 0;
1432 l--;
1436 if (strequal(nt_name, drivername)) {
1437 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1438 set_driver_mapping(drivername, os2_name);
1439 drivername = talloc_strdup(mem_ctx, os2_name);
1440 TALLOC_FREE(lines);
1441 if (drivername == NULL) {
1442 return WERR_NOMEM;
1444 *pdrivername = drivername;
1445 return WERR_OK;
1449 TALLOC_FREE(lines);
1450 return WERR_OK;
1453 /****************************************************************************
1454 ****************************************************************************/
1456 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1457 struct spoolss_DriverInfo8 *_info8)
1459 struct spoolss_DriverInfo8 info8;
1461 ZERO_STRUCT(info8);
1463 switch (r->level) {
1464 case 3:
1465 info8.version = r->info.info3->version;
1466 info8.driver_name = r->info.info3->driver_name;
1467 info8.architecture = r->info.info3->architecture;
1468 info8.driver_path = r->info.info3->driver_path;
1469 info8.data_file = r->info.info3->data_file;
1470 info8.config_file = r->info.info3->config_file;
1471 info8.help_file = r->info.info3->help_file;
1472 info8.monitor_name = r->info.info3->monitor_name;
1473 info8.default_datatype = r->info.info3->default_datatype;
1474 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1475 info8.dependent_files = r->info.info3->dependent_files->string;
1477 break;
1478 case 6:
1479 info8.version = r->info.info6->version;
1480 info8.driver_name = r->info.info6->driver_name;
1481 info8.architecture = r->info.info6->architecture;
1482 info8.driver_path = r->info.info6->driver_path;
1483 info8.data_file = r->info.info6->data_file;
1484 info8.config_file = r->info.info6->config_file;
1485 info8.help_file = r->info.info6->help_file;
1486 info8.monitor_name = r->info.info6->monitor_name;
1487 info8.default_datatype = r->info.info6->default_datatype;
1488 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1489 info8.dependent_files = r->info.info6->dependent_files->string;
1491 info8.driver_date = r->info.info6->driver_date;
1492 info8.driver_version = r->info.info6->driver_version;
1493 info8.manufacturer_name = r->info.info6->manufacturer_name;
1494 info8.manufacturer_url = r->info.info6->manufacturer_url;
1495 info8.hardware_id = r->info.info6->hardware_id;
1496 info8.provider = r->info.info6->provider;
1497 break;
1498 case 8:
1499 info8.version = r->info.info8->version;
1500 info8.driver_name = r->info.info8->driver_name;
1501 info8.architecture = r->info.info8->architecture;
1502 info8.driver_path = r->info.info8->driver_path;
1503 info8.data_file = r->info.info8->data_file;
1504 info8.config_file = r->info.info8->config_file;
1505 info8.help_file = r->info.info8->help_file;
1506 info8.monitor_name = r->info.info8->monitor_name;
1507 info8.default_datatype = r->info.info8->default_datatype;
1508 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1509 info8.dependent_files = r->info.info8->dependent_files->string;
1511 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1512 info8.previous_names = r->info.info8->previous_names->string;
1514 info8.driver_date = r->info.info8->driver_date;
1515 info8.driver_version = r->info.info8->driver_version;
1516 info8.manufacturer_name = r->info.info8->manufacturer_name;
1517 info8.manufacturer_url = r->info.info8->manufacturer_url;
1518 info8.hardware_id = r->info.info8->hardware_id;
1519 info8.provider = r->info.info8->provider;
1520 info8.print_processor = r->info.info8->print_processor;
1521 info8.vendor_setup = r->info.info8->vendor_setup;
1522 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1523 info8.color_profiles = r->info.info8->color_profiles->string;
1525 info8.inf_path = r->info.info8->inf_path;
1526 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1527 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1528 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1530 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1531 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1532 break;
1533 default:
1534 return false;
1537 *_info8 = info8;
1539 return true;
1543 /****************************************************************************
1544 Determine whether or not a particular driver is currently assigned
1545 to a printer
1546 ****************************************************************************/
1548 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1549 const struct auth_serversupplied_info *session_info,
1550 struct messaging_context *msg_ctx,
1551 const struct spoolss_DriverInfo8 *r)
1553 int snum;
1554 int n_services = lp_numservices();
1555 bool in_use = False;
1556 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1557 WERROR result;
1559 if (!r) {
1560 return false;
1563 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1565 /* loop through the printers.tdb and check for the drivername */
1567 for (snum=0; snum<n_services && !in_use; snum++) {
1568 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1569 continue;
1572 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
1573 lp_servicename(snum),
1574 &pinfo2);
1575 if (!W_ERROR_IS_OK(result)) {
1576 continue; /* skip */
1579 if (strequal(r->driver_name, pinfo2->drivername)) {
1580 in_use = True;
1583 TALLOC_FREE(pinfo2);
1586 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1588 if ( in_use ) {
1589 struct spoolss_DriverInfo8 *driver;
1590 WERROR werr;
1592 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1594 /* we can still remove the driver if there is one of
1595 "Windows NT x86" version 2 or 3 left */
1597 if (!strequal("Windows NT x86", r->architecture)) {
1598 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1599 "Windows NT x86",
1600 r->driver_name,
1601 DRIVER_ANY_VERSION,
1602 &driver);
1603 } else if (r->version == 2) {
1604 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1605 "Windows NT x86",
1606 r->driver_name,
1607 3, &driver);
1608 } else if (r->version == 3) {
1609 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1610 "Windows NT x86",
1611 r->driver_name,
1612 2, &driver);
1613 } else {
1614 DEBUG(0, ("printer_driver_in_use: ERROR!"
1615 " unknown driver version (%d)\n",
1616 r->version));
1617 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1620 /* now check the error code */
1622 if ( W_ERROR_IS_OK(werr) ) {
1623 /* it's ok to remove the driver, we have other architctures left */
1624 in_use = False;
1625 talloc_free(driver);
1629 /* report that the driver is not in use by default */
1631 return in_use;
1635 /**********************************************************************
1636 Check to see if a ogiven file is in use by *info
1637 *********************************************************************/
1639 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1641 int i = 0;
1643 if ( !info )
1644 return False;
1646 /* mz: skip files that are in the list but already deleted */
1647 if (!file || !file[0]) {
1648 return false;
1651 if (strequal(file, info->driver_path))
1652 return True;
1654 if (strequal(file, info->data_file))
1655 return True;
1657 if (strequal(file, info->config_file))
1658 return True;
1660 if (strequal(file, info->help_file))
1661 return True;
1663 /* see of there are any dependent files to examine */
1665 if (!info->dependent_files)
1666 return False;
1668 while (info->dependent_files[i] && *info->dependent_files[i]) {
1669 if (strequal(file, info->dependent_files[i]))
1670 return True;
1671 i++;
1674 return False;
1678 /**********************************************************************
1679 Utility function to remove the dependent file pointed to by the
1680 input parameter from the list
1681 *********************************************************************/
1683 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1686 /* bump everything down a slot */
1688 while (files && files[idx+1]) {
1689 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1690 idx++;
1693 files[idx] = NULL;
1695 return;
1698 /**********************************************************************
1699 Check if any of the files used by src are also used by drv
1700 *********************************************************************/
1702 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1703 struct spoolss_DriverInfo8 *src,
1704 const struct spoolss_DriverInfo8 *drv)
1706 bool in_use = False;
1707 int i = 0;
1709 if ( !src || !drv )
1710 return False;
1712 /* check each file. Remove it from the src structure if it overlaps */
1714 if (drv_file_in_use(src->driver_path, drv)) {
1715 in_use = True;
1716 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1717 src->driver_path = talloc_strdup(mem_ctx, "");
1718 if (!src->driver_path) { return false; }
1721 if (drv_file_in_use(src->data_file, drv)) {
1722 in_use = True;
1723 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1724 src->data_file = talloc_strdup(mem_ctx, "");
1725 if (!src->data_file) { return false; }
1728 if (drv_file_in_use(src->config_file, drv)) {
1729 in_use = True;
1730 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1731 src->config_file = talloc_strdup(mem_ctx, "");
1732 if (!src->config_file) { return false; }
1735 if (drv_file_in_use(src->help_file, drv)) {
1736 in_use = True;
1737 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1738 src->help_file = talloc_strdup(mem_ctx, "");
1739 if (!src->help_file) { return false; }
1742 /* are there any dependentfiles to examine? */
1744 if (!src->dependent_files)
1745 return in_use;
1747 while (src->dependent_files[i] && *src->dependent_files[i]) {
1748 if (drv_file_in_use(src->dependent_files[i], drv)) {
1749 in_use = True;
1750 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1751 trim_dependent_file(mem_ctx, src->dependent_files, i);
1752 } else
1753 i++;
1756 return in_use;
1759 /****************************************************************************
1760 Determine whether or not a particular driver files are currently being
1761 used by any other driver.
1763 Return value is True if any files were in use by other drivers
1764 and False otherwise.
1766 Upon return, *info has been modified to only contain the driver files
1767 which are not in use
1769 Fix from mz:
1771 This needs to check all drivers to ensure that all files in use
1772 have been removed from *info, not just the ones in the first
1773 match.
1774 ****************************************************************************/
1776 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1777 const struct auth_serversupplied_info *session_info,
1778 struct messaging_context *msg_ctx,
1779 struct spoolss_DriverInfo8 *info)
1781 int i;
1782 uint32 version;
1783 struct spoolss_DriverInfo8 *driver;
1784 bool in_use = false;
1785 uint32_t num_drivers;
1786 const char **drivers;
1787 WERROR result;
1789 if ( !info )
1790 return False;
1792 version = info->version;
1794 /* loop over all driver versions */
1796 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1798 /* get the list of drivers */
1800 result = winreg_get_driver_list(mem_ctx, session_info, msg_ctx,
1801 info->architecture, version,
1802 &num_drivers, &drivers);
1803 if (!W_ERROR_IS_OK(result)) {
1804 return true;
1807 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1808 num_drivers, info->architecture, version));
1810 /* check each driver for overlap in files */
1812 for (i = 0; i < num_drivers; i++) {
1813 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1815 driver = NULL;
1817 result = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1818 info->architecture, drivers[i],
1819 version, &driver);
1820 if (!W_ERROR_IS_OK(result)) {
1821 talloc_free(drivers);
1822 return True;
1825 /* check if d2 uses any files from d1 */
1826 /* only if this is a different driver than the one being deleted */
1828 if (!strequal(info->driver_name, driver->driver_name)) {
1829 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1830 /* mz: Do not instantly return -
1831 * we need to ensure this file isn't
1832 * also in use by other drivers. */
1833 in_use = true;
1837 talloc_free(driver);
1840 talloc_free(drivers);
1842 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1844 return in_use;
1847 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1848 const char *name)
1850 struct smb_filename *smb_fname = NULL;
1851 NTSTATUS status;
1853 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1854 &smb_fname);
1855 if (!NT_STATUS_IS_OK(status)) {
1856 return status;
1859 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1861 TALLOC_FREE(smb_fname);
1862 return status;
1865 /****************************************************************************
1866 Actually delete the driver files. Make sure that
1867 printer_driver_files_in_use() return False before calling
1868 this.
1869 ****************************************************************************/
1871 bool delete_driver_files(const struct auth_serversupplied_info *session_info,
1872 const struct spoolss_DriverInfo8 *r)
1874 int i = 0;
1875 char *s;
1876 const char *file;
1877 connection_struct *conn;
1878 NTSTATUS nt_status;
1879 char *oldcwd;
1880 char *printdollar = NULL;
1881 int printdollar_snum;
1882 bool ret = false;
1884 if (!r) {
1885 return false;
1888 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1889 r->driver_name, r->version));
1891 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1892 if (!printdollar) {
1893 return false;
1895 if (printdollar_snum == -1) {
1896 return false;
1899 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1900 lp_pathname(printdollar_snum),
1901 session_info, &oldcwd);
1902 if (!NT_STATUS_IS_OK(nt_status)) {
1903 DEBUG(0,("delete_driver_files: create_conn_struct "
1904 "returned %s\n", nt_errstr(nt_status)));
1905 return false;
1908 if ( !CAN_WRITE(conn) ) {
1909 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1910 ret = false;
1911 goto err_out;
1914 /* now delete the files; must strip the '\print$' string from
1915 fron of path */
1917 if (r->driver_path && r->driver_path[0]) {
1918 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1919 file = s;
1920 DEBUG(10,("deleting driverfile [%s]\n", s));
1921 driver_unlink_internals(conn, file);
1925 if (r->config_file && r->config_file[0]) {
1926 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1927 file = s;
1928 DEBUG(10,("deleting configfile [%s]\n", s));
1929 driver_unlink_internals(conn, file);
1933 if (r->data_file && r->data_file[0]) {
1934 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1935 file = s;
1936 DEBUG(10,("deleting datafile [%s]\n", s));
1937 driver_unlink_internals(conn, file);
1941 if (r->help_file && r->help_file[0]) {
1942 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1943 file = s;
1944 DEBUG(10,("deleting helpfile [%s]\n", s));
1945 driver_unlink_internals(conn, file);
1949 /* check if we are done removing files */
1951 if (r->dependent_files) {
1952 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1953 char *p;
1955 /* bypass the "\print$" portion of the path */
1957 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1958 file = p;
1959 DEBUG(10,("deleting dependent file [%s]\n", file));
1960 driver_unlink_internals(conn, file);
1963 i++;
1967 ret = true;
1968 err_out:
1969 if (conn != NULL) {
1970 vfs_ChDir(conn, oldcwd);
1971 conn_free(conn);
1973 return ret;
1976 /* error code:
1977 0: everything OK
1978 1: level not implemented
1979 2: file doesn't exist
1980 3: can't allocate memory
1981 4: can't free memory
1982 5: non existant struct
1986 A printer and a printer driver are 2 different things.
1987 NT manages them separatelly, Samba does the same.
1988 Why ? Simply because it's easier and it makes sense !
1990 Now explanation: You have 3 printers behind your samba server,
1991 2 of them are the same make and model (laser A and B). But laser B
1992 has an 3000 sheet feeder and laser A doesn't such an option.
1993 Your third printer is an old dot-matrix model for the accounting :-).
1995 If the /usr/local/samba/lib directory (default dir), you will have
1996 5 files to describe all of this.
1998 3 files for the printers (1 by printer):
1999 NTprinter_laser A
2000 NTprinter_laser B
2001 NTprinter_accounting
2002 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2003 NTdriver_printer model X
2004 NTdriver_printer model Y
2006 jfm: I should use this comment for the text file to explain
2007 same thing for the forms BTW.
2008 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2012 /* Convert generic access rights to printer object specific access rights.
2013 It turns out that NT4 security descriptors use generic access rights and
2014 NT5 the object specific ones. */
2016 void map_printer_permissions(struct security_descriptor *sd)
2018 int i;
2020 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2021 se_map_generic(&sd->dacl->aces[i].access_mask,
2022 &printer_generic_mapping);
2026 void map_job_permissions(struct security_descriptor *sd)
2028 int i;
2030 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2031 se_map_generic(&sd->dacl->aces[i].access_mask,
2032 &job_generic_mapping);
2037 /****************************************************************************
2038 Check a user has permissions to perform the given operation. We use the
2039 permission constants defined in include/rpc_spoolss.h to check the various
2040 actions we perform when checking printer access.
2042 PRINTER_ACCESS_ADMINISTER:
2043 print_queue_pause, print_queue_resume, update_printer_sec,
2044 update_printer, spoolss_addprinterex_level_2,
2045 _spoolss_setprinterdata
2047 PRINTER_ACCESS_USE:
2048 print_job_start
2050 JOB_ACCESS_ADMINISTER:
2051 print_job_delete, print_job_pause, print_job_resume,
2052 print_queue_purge
2054 Try access control in the following order (for performance reasons):
2055 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2056 2) check security descriptor (bit comparisons in memory)
2057 3) "printer admins" (may result in numerous calls to winbind)
2059 ****************************************************************************/
2060 bool print_access_check(const struct auth_serversupplied_info *session_info,
2061 struct messaging_context *msg_ctx, int snum,
2062 int access_type)
2064 struct spoolss_security_descriptor *secdesc = NULL;
2065 uint32 access_granted;
2066 size_t sd_size;
2067 NTSTATUS status;
2068 WERROR result;
2069 const char *pname;
2070 TALLOC_CTX *mem_ctx = NULL;
2072 /* If user is NULL then use the current_user structure */
2074 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2076 if (session_info->utok.uid == sec_initial_uid()
2077 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
2078 return True;
2081 /* Get printer name */
2083 pname = lp_printername(snum);
2085 if (!pname || !*pname) {
2086 errno = EACCES;
2087 return False;
2090 /* Get printer security descriptor */
2092 if(!(mem_ctx = talloc_init("print_access_check"))) {
2093 errno = ENOMEM;
2094 return False;
2097 result = winreg_get_printer_secdesc(mem_ctx,
2098 get_session_info_system(),
2099 msg_ctx,
2100 pname,
2101 &secdesc);
2102 if (!W_ERROR_IS_OK(result)) {
2103 talloc_destroy(mem_ctx);
2104 errno = ENOMEM;
2105 return False;
2108 if (access_type == JOB_ACCESS_ADMINISTER) {
2109 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2111 /* Create a child security descriptor to check permissions
2112 against. This is because print jobs are child objects
2113 objects of a printer. */
2114 status = se_create_child_secdesc(mem_ctx,
2115 &secdesc,
2116 &sd_size,
2117 parent_secdesc,
2118 parent_secdesc->owner_sid,
2119 parent_secdesc->group_sid,
2120 false);
2121 if (!NT_STATUS_IS_OK(status)) {
2122 talloc_destroy(mem_ctx);
2123 errno = map_errno_from_nt_status(status);
2124 return False;
2127 map_job_permissions(secdesc);
2128 } else {
2129 map_printer_permissions(secdesc);
2132 /* Check access */
2133 status = se_access_check(secdesc, session_info->security_token, access_type,
2134 &access_granted);
2136 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2138 /* see if we need to try the printer admin list */
2140 if (!NT_STATUS_IS_OK(status) &&
2141 (token_contains_name_in_list(uidtoname(session_info->utok.uid),
2142 session_info->info3->base.domain.string,
2143 NULL, session_info->security_token,
2144 lp_printer_admin(snum)))) {
2145 talloc_destroy(mem_ctx);
2146 return True;
2149 talloc_destroy(mem_ctx);
2151 if (!NT_STATUS_IS_OK(status)) {
2152 errno = EACCES;
2155 return NT_STATUS_IS_OK(status);
2158 /****************************************************************************
2159 Check the time parameters allow a print operation.
2160 *****************************************************************************/
2162 bool print_time_access_check(const struct auth_serversupplied_info *session_info,
2163 struct messaging_context *msg_ctx,
2164 const char *servicename)
2166 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2167 WERROR result;
2168 bool ok = False;
2169 time_t now = time(NULL);
2170 struct tm *t;
2171 uint32 mins;
2173 result = winreg_get_printer(NULL, session_info, msg_ctx,
2174 servicename, &pinfo2);
2175 if (!W_ERROR_IS_OK(result)) {
2176 return False;
2179 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2180 ok = True;
2183 t = gmtime(&now);
2184 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2186 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2187 ok = True;
2190 TALLOC_FREE(pinfo2);
2192 if (!ok) {
2193 errno = EACCES;
2196 return ok;
2199 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2200 const struct auth_serversupplied_info *session_info,
2201 struct messaging_context *msg_ctx,
2202 const char *printer)
2204 WERROR result;
2206 result = winreg_delete_printer_key(mem_ctx, session_info, msg_ctx,
2207 printer, "");
2208 if (!W_ERROR_IS_OK(result)) {
2209 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2210 printer));