s3: Lift the server_messaging_context from send_spoolss_notify2_msg
[Samba/gbeck.git] / source3 / printing / nt_printing.c
blob0b23a9729e1b3a183aaeff8a8f239d2846c9a810
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/srv_spoolss_util.h"
32 #include "nt_printing.h"
33 #include "secrets.h"
34 #include "../librpc/gen_ndr/netlogon.h"
36 /* Map generic permissions to printer object specific permissions */
38 const struct generic_mapping printer_generic_mapping = {
39 PRINTER_READ,
40 PRINTER_WRITE,
41 PRINTER_EXECUTE,
42 PRINTER_ALL_ACCESS
45 /* Map generic permissions to print server object specific permissions */
47 const struct generic_mapping printserver_generic_mapping = {
48 SERVER_READ,
49 SERVER_WRITE,
50 SERVER_EXECUTE,
51 SERVER_ALL_ACCESS
54 /* Map generic permissions to job object specific permissions */
56 const struct generic_mapping job_generic_mapping = {
57 JOB_READ,
58 JOB_WRITE,
59 JOB_EXECUTE,
60 JOB_ALL_ACCESS
63 static const struct print_architecture_table_node archi_table[]= {
65 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
66 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
67 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
68 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
69 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
70 {"Windows IA64", SPL_ARCH_IA64, 3 },
71 {"Windows x64", SPL_ARCH_X64, 3 },
72 {NULL, "", -1 }
75 /****************************************************************************
76 Open the NT printing tdbs. Done once before fork().
77 ****************************************************************************/
79 bool nt_printing_init(struct messaging_context *msg_ctx)
81 WERROR win_rc;
83 if (!nt_printing_tdb_upgrade()) {
84 return false;
88 * register callback to handle updating printers as new
89 * drivers are installed
91 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
92 do_drv_upgrade_printer);
94 /* of course, none of the message callbacks matter if you don't
95 tell messages.c that you interested in receiving PRINT_GENERAL
96 msgs. This is done in serverid_register() */
98 if ( lp_security() == SEC_ADS ) {
99 win_rc = check_published_printers(msg_ctx);
100 if (!W_ERROR_IS_OK(win_rc))
101 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
104 return true;
107 /*******************************************************************
108 Function to allow filename parsing "the old way".
109 ********************************************************************/
111 static NTSTATUS driver_unix_convert(connection_struct *conn,
112 const char *old_name,
113 struct smb_filename **smb_fname)
115 NTSTATUS status;
116 TALLOC_CTX *ctx = talloc_tos();
117 char *name = talloc_strdup(ctx, old_name);
119 if (!name) {
120 return NT_STATUS_NO_MEMORY;
122 unix_format(name);
123 name = unix_clean_name(ctx, name);
124 if (!name) {
125 return NT_STATUS_NO_MEMORY;
127 trim_string(name,"/","/");
129 status = unix_convert(ctx, conn, name, smb_fname, 0);
130 if (!NT_STATUS_IS_OK(status)) {
131 return NT_STATUS_NO_MEMORY;
134 return NT_STATUS_OK;
137 /****************************************************************************
138 Function to do the mapping between the long architecture name and
139 the short one.
140 ****************************************************************************/
142 const char *get_short_archi(const char *long_archi)
144 int i=-1;
146 DEBUG(107,("Getting architecture dependant directory\n"));
147 do {
148 i++;
149 } while ( (archi_table[i].long_archi!=NULL ) &&
150 StrCaseCmp(long_archi, archi_table[i].long_archi) );
152 if (archi_table[i].long_archi==NULL) {
153 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
154 return NULL;
157 /* this might be client code - but shouldn't this be an fstrcpy etc? */
159 DEBUGADD(108,("index: [%d]\n", i));
160 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
161 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
163 return archi_table[i].short_archi;
166 /****************************************************************************
167 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
168 There are two case to be covered here: PE (Portable Executable) and NE (New
169 Executable) files. Both files support the same INFO structure, but PE files
170 store the signature in unicode, and NE files store it as !unicode.
171 returns -1 on error, 1 on version info found, and 0 on no version info found.
172 ****************************************************************************/
174 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
176 int i;
177 char *buf = NULL;
178 ssize_t byte_count;
180 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
181 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
182 fname, DOS_HEADER_SIZE));
183 goto error_exit;
186 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
187 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
188 fname, (unsigned long)byte_count));
189 goto no_version_info;
192 /* Is this really a DOS header? */
193 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
194 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
195 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
196 goto no_version_info;
199 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
200 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
201 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
202 fname, errno));
203 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
204 goto no_version_info;
207 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
208 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
209 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
210 fname, (unsigned long)byte_count));
211 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
212 goto no_version_info;
215 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
216 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
217 unsigned int num_sections;
218 unsigned int section_table_bytes;
220 /* Just skip over optional header to get to section table */
221 if (SMB_VFS_LSEEK(fsp,
222 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
223 SEEK_CUR) == (SMB_OFF_T)-1) {
224 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
225 fname, errno));
226 goto error_exit;
229 /* get the section table */
230 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
231 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
232 if (section_table_bytes == 0)
233 goto error_exit;
235 SAFE_FREE(buf);
236 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
237 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
238 fname, section_table_bytes));
239 goto error_exit;
242 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
243 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
244 fname, (unsigned long)byte_count));
245 goto error_exit;
248 /* Iterate the section table looking for the resource section ".rsrc" */
249 for (i = 0; i < num_sections; i++) {
250 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
252 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
253 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
254 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
256 if (section_bytes == 0)
257 goto error_exit;
259 SAFE_FREE(buf);
260 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
261 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
262 fname, section_bytes));
263 goto error_exit;
266 /* Seek to the start of the .rsrc section info */
267 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
268 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
269 fname, errno));
270 goto error_exit;
273 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
274 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
275 fname, (unsigned long)byte_count));
276 goto error_exit;
279 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
280 goto error_exit;
282 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
283 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
284 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
285 /* Align to next long address */
286 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
288 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
289 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
290 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
292 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
293 fname, *major, *minor,
294 (*major>>16)&0xffff, *major&0xffff,
295 (*minor>>16)&0xffff, *minor&0xffff));
296 SAFE_FREE(buf);
297 return 1;
304 /* Version info not found, fall back to origin date/time */
305 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
306 SAFE_FREE(buf);
307 return 0;
309 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
310 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
311 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
312 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
313 /* At this point, we assume the file is in error. It still could be somthing
314 * else besides a NE file, but it unlikely at this point. */
315 goto error_exit;
318 /* Allocate a bit more space to speed up things */
319 SAFE_FREE(buf);
320 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
321 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
322 fname, PE_HEADER_SIZE));
323 goto error_exit;
326 /* This is a HACK! I got tired of trying to sort through the messy
327 * 'NE' file format. If anyone wants to clean this up please have at
328 * it, but this works. 'NE' files will eventually fade away. JRR */
329 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
330 /* Cover case that should not occur in a well formed 'NE' .dll file */
331 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
333 for(i=0; i<byte_count; i++) {
334 /* Fast skip past data that can't possibly match */
335 if (buf[i] != 'V') continue;
337 /* Potential match data crosses buf boundry, move it to beginning
338 * of buf, and fill the buf with as much as it will hold. */
339 if (i>byte_count-VS_VERSION_INFO_SIZE) {
340 int bc;
342 memcpy(buf, &buf[i], byte_count-i);
343 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
344 (byte_count-i))) < 0) {
346 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
347 fname, errno));
348 goto error_exit;
351 byte_count = bc + (byte_count - i);
352 if (byte_count<VS_VERSION_INFO_SIZE) break;
354 i = 0;
357 /* Check that the full signature string and the magic number that
358 * follows exist (not a perfect solution, but the chances that this
359 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
360 * twice, as it is simpler to read the code. */
361 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
362 /* Compute skip alignment to next long address */
363 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
364 sizeof(VS_SIGNATURE)) & 3;
365 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
367 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
368 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
369 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
370 fname, *major, *minor,
371 (*major>>16)&0xffff, *major&0xffff,
372 (*minor>>16)&0xffff, *minor&0xffff));
373 SAFE_FREE(buf);
374 return 1;
379 /* Version info not found, fall back to origin date/time */
380 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
381 SAFE_FREE(buf);
382 return 0;
384 } else
385 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
386 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
387 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
389 no_version_info:
390 SAFE_FREE(buf);
391 return 0;
393 error_exit:
394 SAFE_FREE(buf);
395 return -1;
398 /****************************************************************************
399 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
400 share one or more files. During the MS installation process files are checked
401 to insure that only a newer version of a shared file is installed over an
402 older version. There are several possibilities for this comparison. If there
403 is no previous version, the new one is newer (obviously). If either file is
404 missing the version info structure, compare the creation date (on Unix use
405 the modification date). Otherwise chose the numerically larger version number.
406 ****************************************************************************/
408 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
410 bool use_version = true;
412 uint32 new_major;
413 uint32 new_minor;
414 time_t new_create_time;
416 uint32 old_major;
417 uint32 old_minor;
418 time_t old_create_time;
420 struct smb_filename *smb_fname = NULL;
421 files_struct *fsp = NULL;
422 SMB_STRUCT_STAT st;
424 NTSTATUS status;
425 int ret;
427 SET_STAT_INVALID(st);
428 new_create_time = (time_t)0;
429 old_create_time = (time_t)0;
431 /* Get file version info (if available) for previous file (if it exists) */
432 status = driver_unix_convert(conn, old_file, &smb_fname);
433 if (!NT_STATUS_IS_OK(status)) {
434 goto error_exit;
437 status = SMB_VFS_CREATE_FILE(
438 conn, /* conn */
439 NULL, /* req */
440 0, /* root_dir_fid */
441 smb_fname, /* fname */
442 FILE_GENERIC_READ, /* access_mask */
443 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
444 FILE_OPEN, /* create_disposition*/
445 0, /* create_options */
446 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
447 INTERNAL_OPEN_ONLY, /* oplock_request */
448 0, /* allocation_size */
449 0, /* private_flags */
450 NULL, /* sd */
451 NULL, /* ea_list */
452 &fsp, /* result */
453 NULL); /* pinfo */
455 if (!NT_STATUS_IS_OK(status)) {
456 /* Old file not found, so by definition new file is in fact newer */
457 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
458 "errno = %d\n", smb_fname_str_dbg(smb_fname),
459 errno));
460 ret = 1;
461 goto done;
463 } else {
464 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
465 if (ret == -1) {
466 goto error_exit;
469 if (!ret) {
470 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
471 old_file));
472 use_version = false;
473 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
474 goto error_exit;
476 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
477 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
478 (long)old_create_time));
481 close_file(NULL, fsp, NORMAL_CLOSE);
482 fsp = NULL;
484 /* Get file version info (if available) for new file */
485 status = driver_unix_convert(conn, new_file, &smb_fname);
486 if (!NT_STATUS_IS_OK(status)) {
487 goto error_exit;
490 status = SMB_VFS_CREATE_FILE(
491 conn, /* conn */
492 NULL, /* req */
493 0, /* root_dir_fid */
494 smb_fname, /* fname */
495 FILE_GENERIC_READ, /* access_mask */
496 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
497 FILE_OPEN, /* create_disposition*/
498 0, /* create_options */
499 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
500 INTERNAL_OPEN_ONLY, /* oplock_request */
501 0, /* allocation_size */
502 0, /* private_flags */
503 NULL, /* sd */
504 NULL, /* ea_list */
505 &fsp, /* result */
506 NULL); /* pinfo */
508 if (!NT_STATUS_IS_OK(status)) {
509 /* New file not found, this shouldn't occur if the caller did its job */
510 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
511 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
512 goto error_exit;
514 } else {
515 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
516 if (ret == -1) {
517 goto error_exit;
520 if (!ret) {
521 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
522 new_file));
523 use_version = false;
524 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
525 goto error_exit;
527 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
528 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
529 (long)new_create_time));
532 close_file(NULL, fsp, NORMAL_CLOSE);
533 fsp = NULL;
535 if (use_version && (new_major != old_major || new_minor != old_minor)) {
536 /* Compare versions and choose the larger version number */
537 if (new_major > old_major ||
538 (new_major == old_major && new_minor > old_minor)) {
540 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
541 ret = 1;
542 goto done;
544 else {
545 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
546 ret = 0;
547 goto done;
550 } else {
551 /* Compare modification time/dates and choose the newest time/date */
552 if (new_create_time > old_create_time) {
553 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
554 ret = 1;
555 goto done;
557 else {
558 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
559 ret = 0;
560 goto done;
564 error_exit:
565 if(fsp)
566 close_file(NULL, fsp, NORMAL_CLOSE);
567 ret = -1;
568 done:
569 TALLOC_FREE(smb_fname);
570 return ret;
573 /****************************************************************************
574 Determine the correct cVersion associated with an architecture and driver
575 ****************************************************************************/
576 static uint32 get_correct_cversion(struct pipes_struct *p,
577 const char *architecture,
578 const char *driverpath_in,
579 WERROR *perr)
581 int cversion;
582 NTSTATUS nt_status;
583 struct smb_filename *smb_fname = NULL;
584 char *driverpath = NULL;
585 files_struct *fsp = NULL;
586 connection_struct *conn = NULL;
587 NTSTATUS status;
588 char *oldcwd;
589 fstring printdollar;
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 fstrcpy(printdollar, "print$");
610 printdollar_snum = find_service(printdollar);
611 if (printdollar_snum == -1) {
612 *perr = WERR_NO_SUCH_SHARE;
613 return -1;
616 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
617 lp_pathname(printdollar_snum),
618 p->server_info, &oldcwd);
619 if (!NT_STATUS_IS_OK(nt_status)) {
620 DEBUG(0,("get_correct_cversion: create_conn_struct "
621 "returned %s\n", nt_errstr(nt_status)));
622 *perr = ntstatus_to_werror(nt_status);
623 return -1;
626 /* Open the driver file (Portable Executable format) and determine the
627 * deriver the cversion. */
628 driverpath = talloc_asprintf(talloc_tos(),
629 "%s/%s",
630 architecture,
631 driverpath_in);
632 if (!driverpath) {
633 *perr = WERR_NOMEM;
634 goto error_exit;
637 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
638 if (!NT_STATUS_IS_OK(nt_status)) {
639 *perr = ntstatus_to_werror(nt_status);
640 goto error_exit;
643 nt_status = vfs_file_exist(conn, smb_fname);
644 if (!NT_STATUS_IS_OK(nt_status)) {
645 *perr = WERR_BADFILE;
646 goto error_exit;
649 status = SMB_VFS_CREATE_FILE(
650 conn, /* conn */
651 NULL, /* req */
652 0, /* root_dir_fid */
653 smb_fname, /* fname */
654 FILE_GENERIC_READ, /* access_mask */
655 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
656 FILE_OPEN, /* create_disposition*/
657 0, /* create_options */
658 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
659 INTERNAL_OPEN_ONLY, /* oplock_request */
660 0, /* private_flags */
661 0, /* allocation_size */
662 NULL, /* sd */
663 NULL, /* ea_list */
664 &fsp, /* result */
665 NULL); /* pinfo */
667 if (!NT_STATUS_IS_OK(status)) {
668 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
669 "%d\n", smb_fname_str_dbg(smb_fname), errno));
670 *perr = WERR_ACCESS_DENIED;
671 goto error_exit;
672 } else {
673 uint32 major;
674 uint32 minor;
675 int ret;
677 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
678 if (ret == -1) goto error_exit;
680 if (!ret) {
681 DEBUG(6,("get_correct_cversion: Version info not "
682 "found [%s]\n",
683 smb_fname_str_dbg(smb_fname)));
684 goto error_exit;
688 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
689 * for more details. Version in this case is not just the version of the
690 * file, but the version in the sense of kernal mode (2) vs. user mode
691 * (3) drivers. Other bits of the version fields are the version info.
692 * JRR 010716
694 cversion = major & 0x0000ffff;
695 switch (cversion) {
696 case 2: /* WinNT drivers */
697 case 3: /* Win2K drivers */
698 break;
700 default:
701 DEBUG(6,("get_correct_cversion: cversion "
702 "invalid [%s] cversion = %d\n",
703 smb_fname_str_dbg(smb_fname),
704 cversion));
705 goto error_exit;
708 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
709 " = 0x%x minor = 0x%x\n",
710 smb_fname_str_dbg(smb_fname), major, minor));
713 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
714 smb_fname_str_dbg(smb_fname), cversion));
716 goto done;
718 error_exit:
719 cversion = -1;
720 done:
721 TALLOC_FREE(smb_fname);
722 if (fsp != NULL) {
723 close_file(NULL, fsp, NORMAL_CLOSE);
725 if (conn != NULL) {
726 vfs_ChDir(conn, oldcwd);
727 conn_free(conn);
729 if (cversion != -1) {
730 *perr = WERR_OK;
732 return cversion;
735 /****************************************************************************
736 ****************************************************************************/
738 #define strip_driver_path(_mem_ctx, _element) do { \
739 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
740 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
741 W_ERROR_HAVE_NO_MEMORY((_element)); \
743 } while (0);
745 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
746 struct pipes_struct *rpc_pipe,
747 const char *architecture,
748 const char **driver_path,
749 const char **data_file,
750 const char **config_file,
751 const char **help_file,
752 struct spoolss_StringArray *dependent_files,
753 uint32_t *version)
755 const char *short_architecture;
756 int i;
757 WERROR err;
758 char *_p;
760 if (!*driver_path || !*data_file || !*config_file) {
761 return WERR_INVALID_PARAM;
764 /* clean up the driver name.
765 * we can get .\driver.dll
766 * or worse c:\windows\system\driver.dll !
768 /* using an intermediate string to not have overlaping memcpy()'s */
770 strip_driver_path(mem_ctx, *driver_path);
771 strip_driver_path(mem_ctx, *data_file);
772 strip_driver_path(mem_ctx, *config_file);
773 if (help_file) {
774 strip_driver_path(mem_ctx, *help_file);
777 if (dependent_files && dependent_files->string) {
778 for (i=0; dependent_files->string[i]; i++) {
779 strip_driver_path(mem_ctx, dependent_files->string[i]);
783 short_architecture = get_short_archi(architecture);
784 if (!short_architecture) {
785 return WERR_UNKNOWN_PRINTER_DRIVER;
788 /* jfm:7/16/2000 the client always sends the cversion=0.
789 * The server should check which version the driver is by reading
790 * the PE header of driver->driverpath.
792 * For Windows 95/98 the version is 0 (so the value sent is correct)
793 * For Windows NT (the architecture doesn't matter)
794 * NT 3.1: cversion=0
795 * NT 3.5/3.51: cversion=1
796 * NT 4: cversion=2
797 * NT2K: cversion=3
800 *version = get_correct_cversion(rpc_pipe, short_architecture,
801 *driver_path, &err);
802 if (*version == -1) {
803 return err;
806 return WERR_OK;
809 /****************************************************************************
810 ****************************************************************************/
812 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
813 struct pipes_struct *rpc_pipe,
814 struct spoolss_AddDriverInfoCtr *r)
816 switch (r->level) {
817 case 3:
818 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
819 r->info.info3->architecture,
820 &r->info.info3->driver_path,
821 &r->info.info3->data_file,
822 &r->info.info3->config_file,
823 &r->info.info3->help_file,
824 r->info.info3->dependent_files,
825 &r->info.info3->version);
826 case 6:
827 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
828 r->info.info6->architecture,
829 &r->info.info6->driver_path,
830 &r->info.info6->data_file,
831 &r->info.info6->config_file,
832 &r->info.info6->help_file,
833 r->info.info6->dependent_files,
834 &r->info.info6->version);
835 default:
836 return WERR_NOT_SUPPORTED;
840 /****************************************************************************
841 This function sucks and should be replaced. JRA.
842 ****************************************************************************/
844 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
845 const struct spoolss_AddDriverInfo6 *src)
847 dst->version = src->version;
849 dst->driver_name = src->driver_name;
850 dst->architecture = src->architecture;
851 dst->driver_path = src->driver_path;
852 dst->data_file = src->data_file;
853 dst->config_file = src->config_file;
854 dst->help_file = src->help_file;
855 dst->monitor_name = src->monitor_name;
856 dst->default_datatype = src->default_datatype;
857 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
858 dst->dependent_files = src->dependent_files;
861 /****************************************************************************
862 ****************************************************************************/
864 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
865 connection_struct *conn,
866 const char *driver_file,
867 const char *short_architecture,
868 uint32_t driver_version,
869 uint32_t version)
871 struct smb_filename *smb_fname_old = NULL;
872 struct smb_filename *smb_fname_new = NULL;
873 char *old_name = NULL;
874 char *new_name = NULL;
875 NTSTATUS status;
876 WERROR ret;
878 old_name = talloc_asprintf(mem_ctx, "%s/%s",
879 short_architecture, driver_file);
880 W_ERROR_HAVE_NO_MEMORY(old_name);
882 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
883 short_architecture, driver_version, driver_file);
884 if (new_name == NULL) {
885 TALLOC_FREE(old_name);
886 return WERR_NOMEM;
889 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
891 status = driver_unix_convert(conn, old_name, &smb_fname_old);
892 if (!NT_STATUS_IS_OK(status)) {
893 ret = WERR_NOMEM;
894 goto out;
897 /* Setup a synthetic smb_filename struct */
898 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
899 if (!smb_fname_new) {
900 ret = WERR_NOMEM;
901 goto out;
904 smb_fname_new->base_name = new_name;
906 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
907 "'%s'\n", smb_fname_old->base_name,
908 smb_fname_new->base_name));
910 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
911 OPENX_FILE_EXISTS_TRUNCATE |
912 OPENX_FILE_CREATE_IF_NOT_EXIST,
913 0, false);
915 if (!NT_STATUS_IS_OK(status)) {
916 DEBUG(0,("move_driver_file_to_download_area: Unable "
917 "to rename [%s] to [%s]: %s\n",
918 smb_fname_old->base_name, new_name,
919 nt_errstr(status)));
920 ret = WERR_ACCESS_DENIED;
921 goto out;
925 ret = WERR_OK;
926 out:
927 TALLOC_FREE(smb_fname_old);
928 TALLOC_FREE(smb_fname_new);
929 return ret;
932 WERROR move_driver_to_download_area(struct pipes_struct *p,
933 struct spoolss_AddDriverInfoCtr *r,
934 WERROR *perr)
936 struct spoolss_AddDriverInfo3 *driver;
937 struct spoolss_AddDriverInfo3 converted_driver;
938 const char *short_architecture;
939 struct smb_filename *smb_dname = NULL;
940 char *new_dir = NULL;
941 connection_struct *conn = NULL;
942 NTSTATUS nt_status;
943 int i;
944 TALLOC_CTX *ctx = talloc_tos();
945 int ver = 0;
946 char *oldcwd;
947 fstring printdollar;
948 int printdollar_snum;
950 *perr = WERR_OK;
952 switch (r->level) {
953 case 3:
954 driver = r->info.info3;
955 break;
956 case 6:
957 convert_level_6_to_level3(&converted_driver, r->info.info6);
958 driver = &converted_driver;
959 break;
960 default:
961 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
962 return WERR_UNKNOWN_LEVEL;
965 short_architecture = get_short_archi(driver->architecture);
966 if (!short_architecture) {
967 return WERR_UNKNOWN_PRINTER_DRIVER;
970 fstrcpy(printdollar, "print$");
972 printdollar_snum = find_service(printdollar);
973 if (printdollar_snum == -1) {
974 *perr = WERR_NO_SUCH_SHARE;
975 return WERR_NO_SUCH_SHARE;
978 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
979 lp_pathname(printdollar_snum),
980 p->server_info, &oldcwd);
981 if (!NT_STATUS_IS_OK(nt_status)) {
982 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
983 "returned %s\n", nt_errstr(nt_status)));
984 *perr = ntstatus_to_werror(nt_status);
985 return *perr;
988 new_dir = talloc_asprintf(ctx,
989 "%s/%d",
990 short_architecture,
991 driver->version);
992 if (!new_dir) {
993 *perr = WERR_NOMEM;
994 goto err_exit;
996 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
997 if (!NT_STATUS_IS_OK(nt_status)) {
998 *perr = WERR_NOMEM;
999 goto err_exit;
1002 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1004 create_directory(conn, NULL, smb_dname);
1006 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1007 * listed for this driver which has already been moved, skip it (note:
1008 * drivers may list the same file name several times. Then check if the
1009 * file already exists in archi\version\, if so, check that the version
1010 * info (or time stamps if version info is unavailable) is newer (or the
1011 * date is later). If it is, move it to archi\version\filexxx.yyy.
1012 * Otherwise, delete the file.
1014 * If a file is not moved to archi\version\ because of an error, all the
1015 * rest of the 'unmoved' driver files are removed from archi\. If one or
1016 * more of the driver's files was already moved to archi\version\, it
1017 * potentially leaves the driver in a partially updated state. Version
1018 * trauma will most likely occur if an client attempts to use any printer
1019 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1020 * done is appropriate... later JRR
1023 DEBUG(5,("Moving files now !\n"));
1025 if (driver->driver_path && strlen(driver->driver_path)) {
1027 *perr = move_driver_file_to_download_area(ctx,
1028 conn,
1029 driver->driver_path,
1030 short_architecture,
1031 driver->version,
1032 ver);
1033 if (!W_ERROR_IS_OK(*perr)) {
1034 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1035 ver = -1;
1037 goto err_exit;
1041 if (driver->data_file && strlen(driver->data_file)) {
1042 if (!strequal(driver->data_file, driver->driver_path)) {
1044 *perr = move_driver_file_to_download_area(ctx,
1045 conn,
1046 driver->data_file,
1047 short_architecture,
1048 driver->version,
1049 ver);
1050 if (!W_ERROR_IS_OK(*perr)) {
1051 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1052 ver = -1;
1054 goto err_exit;
1059 if (driver->config_file && strlen(driver->config_file)) {
1060 if (!strequal(driver->config_file, driver->driver_path) &&
1061 !strequal(driver->config_file, driver->data_file)) {
1063 *perr = move_driver_file_to_download_area(ctx,
1064 conn,
1065 driver->config_file,
1066 short_architecture,
1067 driver->version,
1068 ver);
1069 if (!W_ERROR_IS_OK(*perr)) {
1070 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1071 ver = -1;
1073 goto err_exit;
1078 if (driver->help_file && strlen(driver->help_file)) {
1079 if (!strequal(driver->help_file, driver->driver_path) &&
1080 !strequal(driver->help_file, driver->data_file) &&
1081 !strequal(driver->help_file, driver->config_file)) {
1083 *perr = move_driver_file_to_download_area(ctx,
1084 conn,
1085 driver->help_file,
1086 short_architecture,
1087 driver->version,
1088 ver);
1089 if (!W_ERROR_IS_OK(*perr)) {
1090 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1091 ver = -1;
1093 goto err_exit;
1098 if (driver->dependent_files && driver->dependent_files->string) {
1099 for (i=0; driver->dependent_files->string[i]; i++) {
1100 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1101 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1102 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1103 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1104 int j;
1105 for (j=0; j < i; j++) {
1106 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1107 goto NextDriver;
1111 *perr = move_driver_file_to_download_area(ctx,
1112 conn,
1113 driver->dependent_files->string[i],
1114 short_architecture,
1115 driver->version,
1116 ver);
1117 if (!W_ERROR_IS_OK(*perr)) {
1118 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1119 ver = -1;
1121 goto err_exit;
1124 NextDriver: ;
1128 err_exit:
1129 TALLOC_FREE(smb_dname);
1131 if (conn != NULL) {
1132 vfs_ChDir(conn, oldcwd);
1133 conn_free(conn);
1136 if (W_ERROR_EQUAL(*perr, WERR_OK)) {
1137 return WERR_OK;
1139 if (ver == -1) {
1140 return WERR_UNKNOWN_PRINTER_DRIVER;
1142 return (*perr);
1145 /****************************************************************************
1146 Create and allocate a default devicemode.
1147 ****************************************************************************/
1149 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1150 const char *devicename,
1151 struct spoolss_DeviceMode **devmode)
1153 struct spoolss_DeviceMode *dm;
1154 char *dname;
1156 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1157 if (dm == NULL) {
1158 return WERR_NOMEM;
1161 dname = talloc_asprintf(dm, "%s", devicename);
1162 if (dname == NULL) {
1163 return WERR_NOMEM;
1165 if (strlen(dname) > MAXDEVICENAME) {
1166 dname[MAXDEVICENAME] = '\0';
1168 dm->devicename = dname;
1170 dm->formname = talloc_strdup(dm, "Letter");
1171 if (dm->formname == NULL) {
1172 return WERR_NOMEM;
1175 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1176 dm->driverversion = 0x0400;
1177 dm->size = 0x00DC;
1178 dm->__driverextra_length = 0;
1179 dm->fields = DEVMODE_FORMNAME |
1180 DEVMODE_TTOPTION |
1181 DEVMODE_PRINTQUALITY |
1182 DEVMODE_DEFAULTSOURCE |
1183 DEVMODE_COPIES |
1184 DEVMODE_SCALE |
1185 DEVMODE_PAPERSIZE |
1186 DEVMODE_ORIENTATION;
1187 dm->orientation = DMORIENT_PORTRAIT;
1188 dm->papersize = DMPAPER_LETTER;
1189 dm->paperlength = 0;
1190 dm->paperwidth = 0;
1191 dm->scale = 0x64;
1192 dm->copies = 1;
1193 dm->defaultsource = DMBIN_FORMSOURCE;
1194 dm->printquality = DMRES_HIGH; /* 0x0258 */
1195 dm->color = DMRES_MONOCHROME;
1196 dm->duplex = DMDUP_SIMPLEX;
1197 dm->yresolution = 0;
1198 dm->ttoption = DMTT_SUBDEV;
1199 dm->collate = DMCOLLATE_FALSE;
1200 dm->icmmethod = 0;
1201 dm->icmintent = 0;
1202 dm->mediatype = 0;
1203 dm->dithertype = 0;
1205 dm->logpixels = 0;
1206 dm->bitsperpel = 0;
1207 dm->pelswidth = 0;
1208 dm->pelsheight = 0;
1209 dm->displayflags = 0;
1210 dm->displayfrequency = 0;
1211 dm->reserved1 = 0;
1212 dm->reserved2 = 0;
1213 dm->panningwidth = 0;
1214 dm->panningheight = 0;
1216 dm->driverextra_data.data = NULL;
1217 dm->driverextra_data.length = 0;
1219 *devmode = dm;
1220 return WERR_OK;
1223 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1224 struct spoolss_security_descriptor **secdesc)
1226 struct security_ace ace[7]; /* max number of ace entries */
1227 int i = 0;
1228 uint32_t sa;
1229 struct security_acl *psa = NULL;
1230 struct security_descriptor *psd = NULL;
1231 struct dom_sid adm_sid;
1232 size_t sd_size;
1234 /* Create an ACE where Everyone is allowed to print */
1236 sa = PRINTER_ACE_PRINT;
1237 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1238 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1240 /* Add the domain admins group if we are a DC */
1242 if ( IS_DC ) {
1243 struct dom_sid domadmins_sid;
1245 sid_compose(&domadmins_sid, get_global_sam_sid(),
1246 DOMAIN_RID_ADMINS);
1248 sa = PRINTER_ACE_FULL_CONTROL;
1249 init_sec_ace(&ace[i++], &domadmins_sid,
1250 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1251 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1252 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1253 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1255 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1256 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1258 sa = PRINTER_ACE_FULL_CONTROL;
1259 init_sec_ace(&ace[i++], &adm_sid,
1260 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1261 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1262 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1263 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1266 /* add BUILTIN\Administrators as FULL CONTROL */
1268 sa = PRINTER_ACE_FULL_CONTROL;
1269 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1270 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1271 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1272 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1273 SEC_ACE_TYPE_ACCESS_ALLOWED,
1274 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1276 /* add BUILTIN\Print Operators as FULL CONTROL */
1278 sa = PRINTER_ACE_FULL_CONTROL;
1279 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1280 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1281 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1282 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1283 SEC_ACE_TYPE_ACCESS_ALLOWED,
1284 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1286 /* Make the security descriptor owned by the BUILTIN\Administrators */
1288 /* The ACL revision number in rpc_secdesc.h differs from the one
1289 created by NT when setting ACE entries in printer
1290 descriptors. NT4 complains about the property being edited by a
1291 NT5 machine. */
1293 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1294 psd = make_sec_desc(mem_ctx,
1295 SD_REVISION,
1296 SEC_DESC_SELF_RELATIVE,
1297 &global_sid_Builtin_Administrators,
1298 &global_sid_Builtin_Administrators,
1299 NULL,
1300 psa,
1301 &sd_size);
1304 if (psd == NULL) {
1305 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1306 return WERR_NOMEM;
1309 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1310 (unsigned int)sd_size));
1312 *secdesc = psd;
1314 return WERR_OK;
1317 /****************************************************************************
1318 ***************************************************************************/
1320 static char *win_driver;
1321 static char *os2_driver;
1323 static const char *get_win_driver(void)
1325 if (win_driver == NULL) {
1326 return "";
1328 return win_driver;
1331 static const char *get_os2_driver(void)
1333 if (os2_driver == NULL) {
1334 return "";
1336 return os2_driver;
1339 static bool set_driver_mapping(const char *from, const char *to)
1341 SAFE_FREE(win_driver);
1342 SAFE_FREE(os2_driver);
1344 win_driver = SMB_STRDUP(from);
1345 os2_driver = SMB_STRDUP(to);
1347 if (win_driver == NULL || os2_driver == NULL) {
1348 SAFE_FREE(win_driver);
1349 SAFE_FREE(os2_driver);
1350 return false;
1352 return true;
1356 * @internal
1358 * @brief Map a Windows driver to a OS/2 driver.
1360 * @param[in] mem_ctx The memory context to use.
1362 * @param[in,out] pdrivername The drivername of Windows to remap.
1364 * @return WERR_OK on success, a corresponding WERROR on failure.
1366 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1368 const char *mapfile = lp_os2_driver_map();
1369 char **lines = NULL;
1370 const char *drivername;
1371 int numlines = 0;
1372 int i;
1374 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1375 return WERR_INVALID_PARAMETER;
1378 drivername = *pdrivername;
1380 if (mapfile[0] == '\0') {
1381 return WERR_BADFILE;
1384 if (strequal(drivername, get_win_driver())) {
1385 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1386 drivername, get_os2_driver()));
1387 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1388 if (drivername == NULL) {
1389 return WERR_NOMEM;
1391 *pdrivername = drivername;
1392 return WERR_OK;
1395 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1396 if (numlines == 0 || lines == NULL) {
1397 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1398 TALLOC_FREE(lines);
1399 return WERR_EMPTY;
1402 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1404 for( i = 0; i < numlines; i++) {
1405 char *nt_name = lines[i];
1406 char *os2_name = strchr(nt_name, '=');
1408 if (os2_name == NULL) {
1409 continue;
1412 *os2_name++ = '\0';
1414 while (isspace(*nt_name)) {
1415 nt_name++;
1418 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1419 continue;
1423 int l = strlen(nt_name);
1424 while (l && isspace(nt_name[l - 1])) {
1425 nt_name[l - 1] = 0;
1426 l--;
1430 while (isspace(*os2_name)) {
1431 os2_name++;
1435 int l = strlen(os2_name);
1436 while (l && isspace(os2_name[l-1])) {
1437 os2_name[l-1] = 0;
1438 l--;
1442 if (strequal(nt_name, drivername)) {
1443 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1444 set_driver_mapping(drivername, os2_name);
1445 drivername = talloc_strdup(mem_ctx, os2_name);
1446 TALLOC_FREE(lines);
1447 if (drivername == NULL) {
1448 return WERR_NOMEM;
1450 *pdrivername = drivername;
1451 return WERR_OK;
1455 TALLOC_FREE(lines);
1456 return WERR_OK;
1459 /****************************************************************************
1460 ****************************************************************************/
1462 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1463 struct spoolss_DriverInfo8 *_info8)
1465 struct spoolss_DriverInfo8 info8;
1467 ZERO_STRUCT(info8);
1469 switch (r->level) {
1470 case 3:
1471 info8.version = r->info.info3->version;
1472 info8.driver_name = r->info.info3->driver_name;
1473 info8.architecture = r->info.info3->architecture;
1474 info8.driver_path = r->info.info3->driver_path;
1475 info8.data_file = r->info.info3->data_file;
1476 info8.config_file = r->info.info3->config_file;
1477 info8.help_file = r->info.info3->help_file;
1478 info8.monitor_name = r->info.info3->monitor_name;
1479 info8.default_datatype = r->info.info3->default_datatype;
1480 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1481 info8.dependent_files = r->info.info3->dependent_files->string;
1483 break;
1484 case 6:
1485 info8.version = r->info.info6->version;
1486 info8.driver_name = r->info.info6->driver_name;
1487 info8.architecture = r->info.info6->architecture;
1488 info8.driver_path = r->info.info6->driver_path;
1489 info8.data_file = r->info.info6->data_file;
1490 info8.config_file = r->info.info6->config_file;
1491 info8.help_file = r->info.info6->help_file;
1492 info8.monitor_name = r->info.info6->monitor_name;
1493 info8.default_datatype = r->info.info6->default_datatype;
1494 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1495 info8.dependent_files = r->info.info6->dependent_files->string;
1497 info8.driver_date = r->info.info6->driver_date;
1498 info8.driver_version = r->info.info6->driver_version;
1499 info8.manufacturer_name = r->info.info6->manufacturer_name;
1500 info8.manufacturer_url = r->info.info6->manufacturer_url;
1501 info8.hardware_id = r->info.info6->hardware_id;
1502 info8.provider = r->info.info6->provider;
1503 break;
1504 case 8:
1505 info8.version = r->info.info8->version;
1506 info8.driver_name = r->info.info8->driver_name;
1507 info8.architecture = r->info.info8->architecture;
1508 info8.driver_path = r->info.info8->driver_path;
1509 info8.data_file = r->info.info8->data_file;
1510 info8.config_file = r->info.info8->config_file;
1511 info8.help_file = r->info.info8->help_file;
1512 info8.monitor_name = r->info.info8->monitor_name;
1513 info8.default_datatype = r->info.info8->default_datatype;
1514 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1515 info8.dependent_files = r->info.info8->dependent_files->string;
1517 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1518 info8.previous_names = r->info.info8->previous_names->string;
1520 info8.driver_date = r->info.info8->driver_date;
1521 info8.driver_version = r->info.info8->driver_version;
1522 info8.manufacturer_name = r->info.info8->manufacturer_name;
1523 info8.manufacturer_url = r->info.info8->manufacturer_url;
1524 info8.hardware_id = r->info.info8->hardware_id;
1525 info8.provider = r->info.info8->provider;
1526 info8.print_processor = r->info.info8->print_processor;
1527 info8.vendor_setup = r->info.info8->vendor_setup;
1528 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1529 info8.color_profiles = r->info.info8->color_profiles->string;
1531 info8.inf_path = r->info.info8->inf_path;
1532 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1533 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1534 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1536 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1537 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1538 break;
1539 default:
1540 return false;
1543 *_info8 = info8;
1545 return true;
1549 /****************************************************************************
1550 Determine whether or not a particular driver is currently assigned
1551 to a printer
1552 ****************************************************************************/
1554 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1555 struct auth_serversupplied_info *server_info,
1556 struct messaging_context *msg_ctx,
1557 const struct spoolss_DriverInfo8 *r)
1559 int snum;
1560 int n_services = lp_numservices();
1561 bool in_use = False;
1562 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1563 WERROR result;
1565 if (!r) {
1566 return false;
1569 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1571 /* loop through the printers.tdb and check for the drivername */
1573 for (snum=0; snum<n_services && !in_use; snum++) {
1574 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1575 continue;
1578 result = winreg_get_printer(mem_ctx, server_info, msg_ctx,
1579 NULL, lp_servicename(snum),
1580 &pinfo2);
1581 if (!W_ERROR_IS_OK(result)) {
1582 continue; /* skip */
1585 if (strequal(r->driver_name, pinfo2->drivername)) {
1586 in_use = True;
1589 TALLOC_FREE(pinfo2);
1592 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1594 if ( in_use ) {
1595 struct spoolss_DriverInfo8 *driver;
1596 WERROR werr;
1598 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1600 /* we can still remove the driver if there is one of
1601 "Windows NT x86" version 2 or 3 left */
1603 if (!strequal("Windows NT x86", r->architecture)) {
1604 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1605 "Windows NT x86",
1606 r->driver_name,
1607 DRIVER_ANY_VERSION,
1608 &driver);
1609 } else if (r->version == 2) {
1610 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1611 "Windows NT x86",
1612 r->driver_name,
1613 3, &driver);
1614 } else if (r->version == 3) {
1615 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1616 "Windows NT x86",
1617 r->driver_name,
1618 2, &driver);
1619 } else {
1620 DEBUG(0, ("printer_driver_in_use: ERROR!"
1621 " unknown driver version (%d)\n",
1622 r->version));
1623 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1626 /* now check the error code */
1628 if ( W_ERROR_IS_OK(werr) ) {
1629 /* it's ok to remove the driver, we have other architctures left */
1630 in_use = False;
1631 talloc_free(driver);
1635 /* report that the driver is not in use by default */
1637 return in_use;
1641 /**********************************************************************
1642 Check to see if a ogiven file is in use by *info
1643 *********************************************************************/
1645 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1647 int i = 0;
1649 if ( !info )
1650 return False;
1652 /* mz: skip files that are in the list but already deleted */
1653 if (!file || !file[0]) {
1654 return false;
1657 if (strequal(file, info->driver_path))
1658 return True;
1660 if (strequal(file, info->data_file))
1661 return True;
1663 if (strequal(file, info->config_file))
1664 return True;
1666 if (strequal(file, info->help_file))
1667 return True;
1669 /* see of there are any dependent files to examine */
1671 if (!info->dependent_files)
1672 return False;
1674 while (info->dependent_files[i] && *info->dependent_files[i]) {
1675 if (strequal(file, info->dependent_files[i]))
1676 return True;
1677 i++;
1680 return False;
1684 /**********************************************************************
1685 Utility function to remove the dependent file pointed to by the
1686 input parameter from the list
1687 *********************************************************************/
1689 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1692 /* bump everything down a slot */
1694 while (files && files[idx+1]) {
1695 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1696 idx++;
1699 files[idx] = NULL;
1701 return;
1704 /**********************************************************************
1705 Check if any of the files used by src are also used by drv
1706 *********************************************************************/
1708 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1709 struct spoolss_DriverInfo8 *src,
1710 const struct spoolss_DriverInfo8 *drv)
1712 bool in_use = False;
1713 int i = 0;
1715 if ( !src || !drv )
1716 return False;
1718 /* check each file. Remove it from the src structure if it overlaps */
1720 if (drv_file_in_use(src->driver_path, drv)) {
1721 in_use = True;
1722 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1723 src->driver_path = talloc_strdup(mem_ctx, "");
1724 if (!src->driver_path) { return false; }
1727 if (drv_file_in_use(src->data_file, drv)) {
1728 in_use = True;
1729 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1730 src->data_file = talloc_strdup(mem_ctx, "");
1731 if (!src->data_file) { return false; }
1734 if (drv_file_in_use(src->config_file, drv)) {
1735 in_use = True;
1736 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1737 src->config_file = talloc_strdup(mem_ctx, "");
1738 if (!src->config_file) { return false; }
1741 if (drv_file_in_use(src->help_file, drv)) {
1742 in_use = True;
1743 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1744 src->help_file = talloc_strdup(mem_ctx, "");
1745 if (!src->help_file) { return false; }
1748 /* are there any dependentfiles to examine? */
1750 if (!src->dependent_files)
1751 return in_use;
1753 while (src->dependent_files[i] && *src->dependent_files[i]) {
1754 if (drv_file_in_use(src->dependent_files[i], drv)) {
1755 in_use = True;
1756 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1757 trim_dependent_file(mem_ctx, src->dependent_files, i);
1758 } else
1759 i++;
1762 return in_use;
1765 /****************************************************************************
1766 Determine whether or not a particular driver files are currently being
1767 used by any other driver.
1769 Return value is True if any files were in use by other drivers
1770 and False otherwise.
1772 Upon return, *info has been modified to only contain the driver files
1773 which are not in use
1775 Fix from mz:
1777 This needs to check all drivers to ensure that all files in use
1778 have been removed from *info, not just the ones in the first
1779 match.
1780 ****************************************************************************/
1782 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1783 struct auth_serversupplied_info *server_info,
1784 struct messaging_context *msg_ctx,
1785 struct spoolss_DriverInfo8 *info)
1787 int i;
1788 uint32 version;
1789 struct spoolss_DriverInfo8 *driver;
1790 bool in_use = false;
1791 uint32_t num_drivers;
1792 const char **drivers;
1793 WERROR result;
1795 if ( !info )
1796 return False;
1798 version = info->version;
1800 /* loop over all driver versions */
1802 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1804 /* get the list of drivers */
1806 result = winreg_get_driver_list(mem_ctx, server_info, msg_ctx,
1807 info->architecture, version,
1808 &num_drivers, &drivers);
1809 if (!W_ERROR_IS_OK(result)) {
1810 return true;
1813 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1814 num_drivers, info->architecture, version));
1816 /* check each driver for overlap in files */
1818 for (i = 0; i < num_drivers; i++) {
1819 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1821 driver = NULL;
1823 result = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1824 info->architecture, drivers[i],
1825 version, &driver);
1826 if (!W_ERROR_IS_OK(result)) {
1827 talloc_free(drivers);
1828 return True;
1831 /* check if d2 uses any files from d1 */
1832 /* only if this is a different driver than the one being deleted */
1834 if (!strequal(info->driver_name, driver->driver_name)) {
1835 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1836 /* mz: Do not instantly return -
1837 * we need to ensure this file isn't
1838 * also in use by other drivers. */
1839 in_use = true;
1843 talloc_free(driver);
1846 talloc_free(drivers);
1848 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1850 return in_use;
1853 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1854 const char *name)
1856 struct smb_filename *smb_fname = NULL;
1857 NTSTATUS status;
1859 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1860 &smb_fname);
1861 if (!NT_STATUS_IS_OK(status)) {
1862 return status;
1865 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1867 TALLOC_FREE(smb_fname);
1868 return status;
1871 /****************************************************************************
1872 Actually delete the driver files. Make sure that
1873 printer_driver_files_in_use() return False before calling
1874 this.
1875 ****************************************************************************/
1877 bool delete_driver_files(struct auth_serversupplied_info *server_info,
1878 const struct spoolss_DriverInfo8 *r)
1880 int i = 0;
1881 char *s;
1882 const char *file;
1883 connection_struct *conn;
1884 NTSTATUS nt_status;
1885 char *oldcwd;
1886 fstring printdollar;
1887 int printdollar_snum;
1888 bool ret = false;
1890 if (!r) {
1891 return false;
1894 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1895 r->driver_name, r->version));
1897 fstrcpy(printdollar, "print$");
1899 printdollar_snum = find_service(printdollar);
1900 if (printdollar_snum == -1) {
1901 return false;
1904 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1905 lp_pathname(printdollar_snum),
1906 server_info, &oldcwd);
1907 if (!NT_STATUS_IS_OK(nt_status)) {
1908 DEBUG(0,("delete_driver_files: create_conn_struct "
1909 "returned %s\n", nt_errstr(nt_status)));
1910 return false;
1913 if ( !CAN_WRITE(conn) ) {
1914 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1915 goto fail;
1918 /* now delete the files; must strip the '\print$' string from
1919 fron of path */
1921 if (r->driver_path && r->driver_path[0]) {
1922 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1923 file = s;
1924 DEBUG(10,("deleting driverfile [%s]\n", s));
1925 driver_unlink_internals(conn, file);
1929 if (r->config_file && r->config_file[0]) {
1930 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1931 file = s;
1932 DEBUG(10,("deleting configfile [%s]\n", s));
1933 driver_unlink_internals(conn, file);
1937 if (r->data_file && r->data_file[0]) {
1938 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1939 file = s;
1940 DEBUG(10,("deleting datafile [%s]\n", s));
1941 driver_unlink_internals(conn, file);
1945 if (r->help_file && r->help_file[0]) {
1946 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1947 file = s;
1948 DEBUG(10,("deleting helpfile [%s]\n", s));
1949 driver_unlink_internals(conn, file);
1953 /* check if we are done removing files */
1955 if (r->dependent_files) {
1956 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1957 char *p;
1959 /* bypass the "\print$" portion of the path */
1961 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1962 file = p;
1963 DEBUG(10,("deleting dependent file [%s]\n", file));
1964 driver_unlink_internals(conn, file);
1967 i++;
1971 goto done;
1972 fail:
1973 ret = false;
1974 done:
1975 if (conn != NULL) {
1976 vfs_ChDir(conn, oldcwd);
1977 conn_free(conn);
1979 return ret;
1982 /* error code:
1983 0: everything OK
1984 1: level not implemented
1985 2: file doesn't exist
1986 3: can't allocate memory
1987 4: can't free memory
1988 5: non existant struct
1992 A printer and a printer driver are 2 different things.
1993 NT manages them separatelly, Samba does the same.
1994 Why ? Simply because it's easier and it makes sense !
1996 Now explanation: You have 3 printers behind your samba server,
1997 2 of them are the same make and model (laser A and B). But laser B
1998 has an 3000 sheet feeder and laser A doesn't such an option.
1999 Your third printer is an old dot-matrix model for the accounting :-).
2001 If the /usr/local/samba/lib directory (default dir), you will have
2002 5 files to describe all of this.
2004 3 files for the printers (1 by printer):
2005 NTprinter_laser A
2006 NTprinter_laser B
2007 NTprinter_accounting
2008 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2009 NTdriver_printer model X
2010 NTdriver_printer model Y
2012 jfm: I should use this comment for the text file to explain
2013 same thing for the forms BTW.
2014 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2018 /* Convert generic access rights to printer object specific access rights.
2019 It turns out that NT4 security descriptors use generic access rights and
2020 NT5 the object specific ones. */
2022 void map_printer_permissions(struct security_descriptor *sd)
2024 int i;
2026 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2027 se_map_generic(&sd->dacl->aces[i].access_mask,
2028 &printer_generic_mapping);
2032 void map_job_permissions(struct security_descriptor *sd)
2034 int i;
2036 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2037 se_map_generic(&sd->dacl->aces[i].access_mask,
2038 &job_generic_mapping);
2043 /****************************************************************************
2044 Check a user has permissions to perform the given operation. We use the
2045 permission constants defined in include/rpc_spoolss.h to check the various
2046 actions we perform when checking printer access.
2048 PRINTER_ACCESS_ADMINISTER:
2049 print_queue_pause, print_queue_resume, update_printer_sec,
2050 update_printer, spoolss_addprinterex_level_2,
2051 _spoolss_setprinterdata
2053 PRINTER_ACCESS_USE:
2054 print_job_start
2056 JOB_ACCESS_ADMINISTER:
2057 print_job_delete, print_job_pause, print_job_resume,
2058 print_queue_purge
2060 Try access control in the following order (for performance reasons):
2061 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2062 2) check security descriptor (bit comparisons in memory)
2063 3) "printer admins" (may result in numerous calls to winbind)
2065 ****************************************************************************/
2066 bool print_access_check(struct auth_serversupplied_info *server_info,
2067 struct messaging_context *msg_ctx, int snum,
2068 int access_type)
2070 struct spoolss_security_descriptor *secdesc = NULL;
2071 uint32 access_granted;
2072 size_t sd_size;
2073 NTSTATUS status;
2074 WERROR result;
2075 const char *pname;
2076 TALLOC_CTX *mem_ctx = NULL;
2077 SE_PRIV se_printop = SE_PRINT_OPERATOR;
2079 /* If user is NULL then use the current_user structure */
2081 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2083 if (server_info->utok.uid == sec_initial_uid()
2084 || user_has_privileges(server_info->ptok, &se_printop ) ) {
2085 return True;
2088 /* Get printer name */
2090 pname = lp_printername(snum);
2092 if (!pname || !*pname) {
2093 errno = EACCES;
2094 return False;
2097 /* Get printer security descriptor */
2099 if(!(mem_ctx = talloc_init("print_access_check"))) {
2100 errno = ENOMEM;
2101 return False;
2104 result = winreg_get_printer_secdesc(mem_ctx,
2105 server_info,
2106 msg_ctx,
2107 pname,
2108 &secdesc);
2109 if (!W_ERROR_IS_OK(result)) {
2110 talloc_destroy(mem_ctx);
2111 errno = ENOMEM;
2112 return False;
2115 if (access_type == JOB_ACCESS_ADMINISTER) {
2116 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2118 /* Create a child security descriptor to check permissions
2119 against. This is because print jobs are child objects
2120 objects of a printer. */
2121 status = se_create_child_secdesc(mem_ctx,
2122 &secdesc,
2123 &sd_size,
2124 parent_secdesc,
2125 parent_secdesc->owner_sid,
2126 parent_secdesc->group_sid,
2127 false);
2128 if (!NT_STATUS_IS_OK(status)) {
2129 talloc_destroy(mem_ctx);
2130 errno = map_errno_from_nt_status(status);
2131 return False;
2134 map_job_permissions(secdesc);
2135 } else {
2136 map_printer_permissions(secdesc);
2139 /* Check access */
2140 status = se_access_check(secdesc, server_info->ptok, access_type,
2141 &access_granted);
2143 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2145 /* see if we need to try the printer admin list */
2147 if (!NT_STATUS_IS_OK(status) &&
2148 (token_contains_name_in_list(uidtoname(server_info->utok.uid),
2149 server_info->info3->base.domain.string,
2150 NULL, server_info->ptok,
2151 lp_printer_admin(snum)))) {
2152 talloc_destroy(mem_ctx);
2153 return True;
2156 talloc_destroy(mem_ctx);
2158 if (!NT_STATUS_IS_OK(status)) {
2159 errno = EACCES;
2162 return NT_STATUS_IS_OK(status);
2165 /****************************************************************************
2166 Check the time parameters allow a print operation.
2167 *****************************************************************************/
2169 bool print_time_access_check(struct auth_serversupplied_info *server_info,
2170 struct messaging_context *msg_ctx,
2171 const char *servicename)
2173 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2174 WERROR result;
2175 bool ok = False;
2176 time_t now = time(NULL);
2177 struct tm *t;
2178 uint32 mins;
2180 result = winreg_get_printer(NULL, server_info, msg_ctx,
2181 NULL, servicename, &pinfo2);
2182 if (!W_ERROR_IS_OK(result)) {
2183 return False;
2186 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2187 ok = True;
2190 t = gmtime(&now);
2191 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2193 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2194 ok = True;
2197 TALLOC_FREE(pinfo2);
2199 if (!ok) {
2200 errno = EACCES;
2203 return ok;
2206 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2207 struct auth_serversupplied_info *server_info,
2208 struct messaging_context *msg_ctx,
2209 const char *printer)
2211 WERROR result;
2213 result = winreg_delete_printer_key(mem_ctx, server_info, msg_ctx,
2214 printer, "");
2215 if (!W_ERROR_IS_OK(result)) {
2216 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2217 printer));