s3-printing: follow force user/group for driver IO
[Samba.git] / source3 / printing / nt_printing.c
blob1d075e794e06e4212bc7a15170fef3c324f73c76
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 nt_status = set_conn_force_user_group(conn, printdollar_snum);
629 if (!NT_STATUS_IS_OK(nt_status)) {
630 DEBUG(0, ("failed set force user / group\n"));
631 *perr = ntstatus_to_werror(nt_status);
632 goto error_free_conn;
635 if (!become_user(conn, get_current_vuid(conn))) {
636 DEBUG(0, ("failed to become user\n"));
637 *perr = WERR_ACCESS_DENIED;
638 goto error_free_conn;
641 /* Open the driver file (Portable Executable format) and determine the
642 * deriver the cversion. */
643 driverpath = talloc_asprintf(talloc_tos(),
644 "%s/%s",
645 architecture,
646 driverpath_in);
647 if (!driverpath) {
648 *perr = WERR_NOMEM;
649 goto error_exit;
652 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
653 if (!NT_STATUS_IS_OK(nt_status)) {
654 *perr = ntstatus_to_werror(nt_status);
655 goto error_exit;
658 nt_status = vfs_file_exist(conn, smb_fname);
659 if (!NT_STATUS_IS_OK(nt_status)) {
660 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
661 *perr = WERR_BADFILE;
662 goto error_exit;
665 nt_status = SMB_VFS_CREATE_FILE(
666 conn, /* conn */
667 NULL, /* req */
668 0, /* root_dir_fid */
669 smb_fname, /* fname */
670 FILE_GENERIC_READ, /* access_mask */
671 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
672 FILE_OPEN, /* create_disposition*/
673 0, /* create_options */
674 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
675 INTERNAL_OPEN_ONLY, /* oplock_request */
676 0, /* private_flags */
677 0, /* allocation_size */
678 NULL, /* sd */
679 NULL, /* ea_list */
680 &fsp, /* result */
681 NULL); /* pinfo */
683 if (!NT_STATUS_IS_OK(nt_status)) {
684 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
685 "%d\n", smb_fname_str_dbg(smb_fname), errno));
686 *perr = WERR_ACCESS_DENIED;
687 goto error_exit;
688 } else {
689 uint32 major;
690 uint32 minor;
691 int ret;
693 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
694 if (ret == -1) {
695 *perr = WERR_INVALID_PARAM;
696 goto error_exit;
697 } else if (!ret) {
698 DEBUG(6,("get_correct_cversion: Version info not "
699 "found [%s]\n",
700 smb_fname_str_dbg(smb_fname)));
701 *perr = WERR_INVALID_PARAM;
702 goto error_exit;
706 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
707 * for more details. Version in this case is not just the version of the
708 * file, but the version in the sense of kernal mode (2) vs. user mode
709 * (3) drivers. Other bits of the version fields are the version info.
710 * JRR 010716
712 cversion = major & 0x0000ffff;
713 switch (cversion) {
714 case 2: /* WinNT drivers */
715 case 3: /* Win2K drivers */
716 break;
718 default:
719 DEBUG(6,("get_correct_cversion: cversion "
720 "invalid [%s] cversion = %d\n",
721 smb_fname_str_dbg(smb_fname),
722 cversion));
723 goto error_exit;
726 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
727 " = 0x%x minor = 0x%x\n",
728 smb_fname_str_dbg(smb_fname), major, minor));
731 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
732 smb_fname_str_dbg(smb_fname), cversion));
733 *perr = WERR_OK;
735 error_exit:
736 unbecome_user();
737 error_free_conn:
738 TALLOC_FREE(smb_fname);
739 if (fsp != NULL) {
740 close_file(NULL, fsp, NORMAL_CLOSE);
742 if (conn != NULL) {
743 vfs_ChDir(conn, oldcwd);
744 SMB_VFS_DISCONNECT(conn);
745 conn_free(conn);
747 if (!NT_STATUS_IS_OK(*perr)) {
748 cversion = -1;
751 return cversion;
754 /****************************************************************************
755 ****************************************************************************/
757 #define strip_driver_path(_mem_ctx, _element) do { \
758 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
759 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
760 W_ERROR_HAVE_NO_MEMORY((_element)); \
762 } while (0);
764 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
765 struct pipes_struct *rpc_pipe,
766 const char *architecture,
767 const char **driver_path,
768 const char **data_file,
769 const char **config_file,
770 const char **help_file,
771 struct spoolss_StringArray *dependent_files,
772 enum spoolss_DriverOSVersion *version)
774 const char *short_architecture;
775 int i;
776 WERROR err;
777 char *_p;
779 if (!*driver_path || !*data_file) {
780 return WERR_INVALID_PARAM;
783 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
784 return WERR_INVALID_PARAM;
787 /* clean up the driver name.
788 * we can get .\driver.dll
789 * or worse c:\windows\system\driver.dll !
791 /* using an intermediate string to not have overlaping memcpy()'s */
793 strip_driver_path(mem_ctx, *driver_path);
794 strip_driver_path(mem_ctx, *data_file);
795 if (*config_file) {
796 strip_driver_path(mem_ctx, *config_file);
798 if (help_file) {
799 strip_driver_path(mem_ctx, *help_file);
802 if (dependent_files && dependent_files->string) {
803 for (i=0; dependent_files->string[i]; i++) {
804 strip_driver_path(mem_ctx, dependent_files->string[i]);
808 short_architecture = get_short_archi(architecture);
809 if (!short_architecture) {
810 return WERR_UNKNOWN_PRINTER_DRIVER;
813 /* jfm:7/16/2000 the client always sends the cversion=0.
814 * The server should check which version the driver is by reading
815 * the PE header of driver->driverpath.
817 * For Windows 95/98 the version is 0 (so the value sent is correct)
818 * For Windows NT (the architecture doesn't matter)
819 * NT 3.1: cversion=0
820 * NT 3.5/3.51: cversion=1
821 * NT 4: cversion=2
822 * NT2K: cversion=3
825 *version = get_correct_cversion(rpc_pipe, short_architecture,
826 *driver_path, &err);
827 if (*version == -1) {
828 return err;
831 return WERR_OK;
834 /****************************************************************************
835 ****************************************************************************/
837 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
838 struct pipes_struct *rpc_pipe,
839 struct spoolss_AddDriverInfoCtr *r)
841 switch (r->level) {
842 case 3:
843 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
844 r->info.info3->architecture,
845 &r->info.info3->driver_path,
846 &r->info.info3->data_file,
847 &r->info.info3->config_file,
848 &r->info.info3->help_file,
849 r->info.info3->dependent_files,
850 &r->info.info3->version);
851 case 6:
852 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
853 r->info.info6->architecture,
854 &r->info.info6->driver_path,
855 &r->info.info6->data_file,
856 &r->info.info6->config_file,
857 &r->info.info6->help_file,
858 r->info.info6->dependent_files,
859 &r->info.info6->version);
860 default:
861 return WERR_NOT_SUPPORTED;
865 /****************************************************************************
866 This function sucks and should be replaced. JRA.
867 ****************************************************************************/
869 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
870 const struct spoolss_AddDriverInfo6 *src)
872 dst->version = src->version;
874 dst->driver_name = src->driver_name;
875 dst->architecture = src->architecture;
876 dst->driver_path = src->driver_path;
877 dst->data_file = src->data_file;
878 dst->config_file = src->config_file;
879 dst->help_file = src->help_file;
880 dst->monitor_name = src->monitor_name;
881 dst->default_datatype = src->default_datatype;
882 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
883 dst->dependent_files = src->dependent_files;
886 /****************************************************************************
887 ****************************************************************************/
889 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
890 connection_struct *conn,
891 const char *driver_file,
892 const char *short_architecture,
893 uint32_t driver_version,
894 uint32_t version)
896 struct smb_filename *smb_fname_old = NULL;
897 struct smb_filename *smb_fname_new = NULL;
898 char *old_name = NULL;
899 char *new_name = NULL;
900 NTSTATUS status;
901 WERROR ret;
903 old_name = talloc_asprintf(mem_ctx, "%s/%s",
904 short_architecture, driver_file);
905 W_ERROR_HAVE_NO_MEMORY(old_name);
907 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
908 short_architecture, driver_version, driver_file);
909 if (new_name == NULL) {
910 TALLOC_FREE(old_name);
911 return WERR_NOMEM;
914 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
916 status = driver_unix_convert(conn, old_name, &smb_fname_old);
917 if (!NT_STATUS_IS_OK(status)) {
918 ret = WERR_NOMEM;
919 goto out;
922 /* Setup a synthetic smb_filename struct */
923 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
924 if (!smb_fname_new) {
925 ret = WERR_NOMEM;
926 goto out;
929 smb_fname_new->base_name = new_name;
931 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
932 "'%s'\n", smb_fname_old->base_name,
933 smb_fname_new->base_name));
935 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
936 OPENX_FILE_EXISTS_TRUNCATE |
937 OPENX_FILE_CREATE_IF_NOT_EXIST,
938 0, false);
940 if (!NT_STATUS_IS_OK(status)) {
941 DEBUG(0,("move_driver_file_to_download_area: Unable "
942 "to rename [%s] to [%s]: %s\n",
943 smb_fname_old->base_name, new_name,
944 nt_errstr(status)));
945 ret = WERR_ACCESS_DENIED;
946 goto out;
950 ret = WERR_OK;
951 out:
952 TALLOC_FREE(smb_fname_old);
953 TALLOC_FREE(smb_fname_new);
954 return ret;
957 WERROR move_driver_to_download_area(struct pipes_struct *p,
958 struct spoolss_AddDriverInfoCtr *r)
960 struct spoolss_AddDriverInfo3 *driver;
961 struct spoolss_AddDriverInfo3 converted_driver;
962 const char *short_architecture;
963 struct smb_filename *smb_dname = NULL;
964 char *new_dir = NULL;
965 connection_struct *conn = NULL;
966 NTSTATUS nt_status;
967 int i;
968 TALLOC_CTX *ctx = talloc_tos();
969 int ver = 0;
970 char *oldcwd;
971 char *printdollar = NULL;
972 int printdollar_snum;
973 WERROR err = WERR_OK;
975 switch (r->level) {
976 case 3:
977 driver = r->info.info3;
978 break;
979 case 6:
980 convert_level_6_to_level3(&converted_driver, r->info.info6);
981 driver = &converted_driver;
982 break;
983 default:
984 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
985 return WERR_UNKNOWN_LEVEL;
988 short_architecture = get_short_archi(driver->architecture);
989 if (!short_architecture) {
990 return WERR_UNKNOWN_PRINTER_DRIVER;
993 printdollar_snum = find_service(ctx, "print$", &printdollar);
994 if (!printdollar) {
995 return WERR_NOMEM;
997 if (printdollar_snum == -1) {
998 return WERR_NO_SUCH_SHARE;
1001 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1002 lp_pathname(printdollar_snum),
1003 p->session_info, &oldcwd);
1004 if (!NT_STATUS_IS_OK(nt_status)) {
1005 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1006 "returned %s\n", nt_errstr(nt_status)));
1007 err = ntstatus_to_werror(nt_status);
1008 return err;
1011 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1012 if (!NT_STATUS_IS_OK(nt_status)) {
1013 DEBUG(0, ("failed set force user / group\n"));
1014 err = ntstatus_to_werror(nt_status);
1015 goto err_free_conn;
1018 if (!become_user(conn, get_current_vuid(conn))) {
1019 DEBUG(0, ("failed to become user\n"));
1020 err = WERR_ACCESS_DENIED;
1021 goto err_free_conn;
1024 new_dir = talloc_asprintf(ctx,
1025 "%s/%d",
1026 short_architecture,
1027 driver->version);
1028 if (!new_dir) {
1029 err = WERR_NOMEM;
1030 goto err_exit;
1032 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1033 if (!NT_STATUS_IS_OK(nt_status)) {
1034 err = WERR_NOMEM;
1035 goto err_exit;
1038 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1040 nt_status = create_directory(conn, NULL, smb_dname);
1041 if (!NT_STATUS_IS_OK(nt_status)
1042 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1043 DEBUG(0, ("failed to create driver destination directory: %s\n",
1044 nt_errstr(nt_status)));
1045 err = ntstatus_to_werror(nt_status);
1046 goto err_exit;
1049 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1050 * listed for this driver which has already been moved, skip it (note:
1051 * drivers may list the same file name several times. Then check if the
1052 * file already exists in archi\version\, if so, check that the version
1053 * info (or time stamps if version info is unavailable) is newer (or the
1054 * date is later). If it is, move it to archi\version\filexxx.yyy.
1055 * Otherwise, delete the file.
1057 * If a file is not moved to archi\version\ because of an error, all the
1058 * rest of the 'unmoved' driver files are removed from archi\. If one or
1059 * more of the driver's files was already moved to archi\version\, it
1060 * potentially leaves the driver in a partially updated state. Version
1061 * trauma will most likely occur if an client attempts to use any printer
1062 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1063 * done is appropriate... later JRR
1066 DEBUG(5,("Moving files now !\n"));
1068 if (driver->driver_path && strlen(driver->driver_path)) {
1070 err = move_driver_file_to_download_area(ctx,
1071 conn,
1072 driver->driver_path,
1073 short_architecture,
1074 driver->version,
1075 ver);
1076 if (!W_ERROR_IS_OK(err)) {
1077 goto err_exit;
1081 if (driver->data_file && strlen(driver->data_file)) {
1082 if (!strequal(driver->data_file, driver->driver_path)) {
1084 err = move_driver_file_to_download_area(ctx,
1085 conn,
1086 driver->data_file,
1087 short_architecture,
1088 driver->version,
1089 ver);
1090 if (!W_ERROR_IS_OK(err)) {
1091 goto err_exit;
1096 if (driver->config_file && strlen(driver->config_file)) {
1097 if (!strequal(driver->config_file, driver->driver_path) &&
1098 !strequal(driver->config_file, driver->data_file)) {
1100 err = move_driver_file_to_download_area(ctx,
1101 conn,
1102 driver->config_file,
1103 short_architecture,
1104 driver->version,
1105 ver);
1106 if (!W_ERROR_IS_OK(err)) {
1107 goto err_exit;
1112 if (driver->help_file && strlen(driver->help_file)) {
1113 if (!strequal(driver->help_file, driver->driver_path) &&
1114 !strequal(driver->help_file, driver->data_file) &&
1115 !strequal(driver->help_file, driver->config_file)) {
1117 err = move_driver_file_to_download_area(ctx,
1118 conn,
1119 driver->help_file,
1120 short_architecture,
1121 driver->version,
1122 ver);
1123 if (!W_ERROR_IS_OK(err)) {
1124 goto err_exit;
1129 if (driver->dependent_files && driver->dependent_files->string) {
1130 for (i=0; driver->dependent_files->string[i]; i++) {
1131 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1132 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1133 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1134 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1135 int j;
1136 for (j=0; j < i; j++) {
1137 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1138 goto NextDriver;
1142 err = move_driver_file_to_download_area(ctx,
1143 conn,
1144 driver->dependent_files->string[i],
1145 short_architecture,
1146 driver->version,
1147 ver);
1148 if (!W_ERROR_IS_OK(err)) {
1149 goto err_exit;
1152 NextDriver: ;
1156 err = WERR_OK;
1157 err_exit:
1158 unbecome_user();
1159 err_free_conn:
1160 TALLOC_FREE(smb_dname);
1162 if (conn != NULL) {
1163 vfs_ChDir(conn, oldcwd);
1164 SMB_VFS_DISCONNECT(conn);
1165 conn_free(conn);
1168 return err;
1171 /****************************************************************************
1172 Create and allocate a default devicemode.
1173 ****************************************************************************/
1175 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1176 const char *devicename,
1177 struct spoolss_DeviceMode **devmode)
1179 struct spoolss_DeviceMode *dm;
1180 char *dname;
1182 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1183 if (dm == NULL) {
1184 return WERR_NOMEM;
1187 dname = talloc_asprintf(dm, "%s", devicename);
1188 if (dname == NULL) {
1189 return WERR_NOMEM;
1191 if (strlen(dname) > MAXDEVICENAME) {
1192 dname[MAXDEVICENAME] = '\0';
1194 dm->devicename = dname;
1196 dm->formname = talloc_strdup(dm, "Letter");
1197 if (dm->formname == NULL) {
1198 return WERR_NOMEM;
1201 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1202 dm->driverversion = 0x0400;
1203 dm->size = 0x00DC;
1204 dm->__driverextra_length = 0;
1205 dm->fields = DEVMODE_FORMNAME |
1206 DEVMODE_TTOPTION |
1207 DEVMODE_PRINTQUALITY |
1208 DEVMODE_DEFAULTSOURCE |
1209 DEVMODE_COPIES |
1210 DEVMODE_SCALE |
1211 DEVMODE_PAPERSIZE |
1212 DEVMODE_ORIENTATION;
1213 dm->orientation = DMORIENT_PORTRAIT;
1214 dm->papersize = DMPAPER_LETTER;
1215 dm->paperlength = 0;
1216 dm->paperwidth = 0;
1217 dm->scale = 0x64;
1218 dm->copies = 1;
1219 dm->defaultsource = DMBIN_FORMSOURCE;
1220 dm->printquality = DMRES_HIGH; /* 0x0258 */
1221 dm->color = DMRES_MONOCHROME;
1222 dm->duplex = DMDUP_SIMPLEX;
1223 dm->yresolution = 0;
1224 dm->ttoption = DMTT_SUBDEV;
1225 dm->collate = DMCOLLATE_FALSE;
1226 dm->icmmethod = 0;
1227 dm->icmintent = 0;
1228 dm->mediatype = 0;
1229 dm->dithertype = 0;
1231 dm->logpixels = 0;
1232 dm->bitsperpel = 0;
1233 dm->pelswidth = 0;
1234 dm->pelsheight = 0;
1235 dm->displayflags = 0;
1236 dm->displayfrequency = 0;
1237 dm->reserved1 = 0;
1238 dm->reserved2 = 0;
1239 dm->panningwidth = 0;
1240 dm->panningheight = 0;
1242 dm->driverextra_data.data = NULL;
1243 dm->driverextra_data.length = 0;
1245 *devmode = dm;
1246 return WERR_OK;
1249 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1250 struct spoolss_security_descriptor **secdesc)
1252 struct security_ace ace[7]; /* max number of ace entries */
1253 int i = 0;
1254 uint32_t sa;
1255 struct security_acl *psa = NULL;
1256 struct security_descriptor *psd = NULL;
1257 struct dom_sid adm_sid;
1258 size_t sd_size;
1260 /* Create an ACE where Everyone is allowed to print */
1262 sa = PRINTER_ACE_PRINT;
1263 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1264 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1266 /* Add the domain admins group if we are a DC */
1268 if ( IS_DC ) {
1269 struct dom_sid domadmins_sid;
1271 sid_compose(&domadmins_sid, get_global_sam_sid(),
1272 DOMAIN_RID_ADMINS);
1274 sa = PRINTER_ACE_FULL_CONTROL;
1275 init_sec_ace(&ace[i++], &domadmins_sid,
1276 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1277 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1278 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1279 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1281 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1282 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1284 sa = PRINTER_ACE_FULL_CONTROL;
1285 init_sec_ace(&ace[i++], &adm_sid,
1286 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1287 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1288 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1289 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1292 /* add BUILTIN\Administrators as FULL CONTROL */
1294 sa = PRINTER_ACE_FULL_CONTROL;
1295 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1296 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1297 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1298 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1299 SEC_ACE_TYPE_ACCESS_ALLOWED,
1300 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1302 /* add BUILTIN\Print Operators as FULL CONTROL */
1304 sa = PRINTER_ACE_FULL_CONTROL;
1305 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1306 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1307 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1308 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1309 SEC_ACE_TYPE_ACCESS_ALLOWED,
1310 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1312 /* Make the security descriptor owned by the BUILTIN\Administrators */
1314 /* The ACL revision number in rpc_secdesc.h differs from the one
1315 created by NT when setting ACE entries in printer
1316 descriptors. NT4 complains about the property being edited by a
1317 NT5 machine. */
1319 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1320 psd = make_sec_desc(mem_ctx,
1321 SD_REVISION,
1322 SEC_DESC_SELF_RELATIVE,
1323 &global_sid_Builtin_Administrators,
1324 &global_sid_Builtin_Administrators,
1325 NULL,
1326 psa,
1327 &sd_size);
1330 if (psd == NULL) {
1331 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1332 return WERR_NOMEM;
1335 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1336 (unsigned int)sd_size));
1338 *secdesc = psd;
1340 return WERR_OK;
1343 /****************************************************************************
1344 ***************************************************************************/
1346 static char *win_driver;
1347 static char *os2_driver;
1349 static const char *get_win_driver(void)
1351 if (win_driver == NULL) {
1352 return "";
1354 return win_driver;
1357 static const char *get_os2_driver(void)
1359 if (os2_driver == NULL) {
1360 return "";
1362 return os2_driver;
1365 static bool set_driver_mapping(const char *from, const char *to)
1367 SAFE_FREE(win_driver);
1368 SAFE_FREE(os2_driver);
1370 win_driver = SMB_STRDUP(from);
1371 os2_driver = SMB_STRDUP(to);
1373 if (win_driver == NULL || os2_driver == NULL) {
1374 SAFE_FREE(win_driver);
1375 SAFE_FREE(os2_driver);
1376 return false;
1378 return true;
1382 * @internal
1384 * @brief Map a Windows driver to a OS/2 driver.
1386 * @param[in] mem_ctx The memory context to use.
1388 * @param[in,out] pdrivername The drivername of Windows to remap.
1390 * @return WERR_OK on success, a corresponding WERROR on failure.
1392 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1394 const char *mapfile = lp_os2_driver_map();
1395 char **lines = NULL;
1396 const char *drivername;
1397 int numlines = 0;
1398 int i;
1400 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1401 return WERR_INVALID_PARAMETER;
1404 drivername = *pdrivername;
1406 if (mapfile[0] == '\0') {
1407 return WERR_BADFILE;
1410 if (strequal(drivername, get_win_driver())) {
1411 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1412 drivername, get_os2_driver()));
1413 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1414 if (drivername == NULL) {
1415 return WERR_NOMEM;
1417 *pdrivername = drivername;
1418 return WERR_OK;
1421 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1422 if (numlines == 0 || lines == NULL) {
1423 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1424 TALLOC_FREE(lines);
1425 return WERR_EMPTY;
1428 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1430 for( i = 0; i < numlines; i++) {
1431 char *nt_name = lines[i];
1432 char *os2_name = strchr(nt_name, '=');
1434 if (os2_name == NULL) {
1435 continue;
1438 *os2_name++ = '\0';
1440 while (isspace(*nt_name)) {
1441 nt_name++;
1444 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1445 continue;
1449 int l = strlen(nt_name);
1450 while (l && isspace(nt_name[l - 1])) {
1451 nt_name[l - 1] = 0;
1452 l--;
1456 while (isspace(*os2_name)) {
1457 os2_name++;
1461 int l = strlen(os2_name);
1462 while (l && isspace(os2_name[l-1])) {
1463 os2_name[l-1] = 0;
1464 l--;
1468 if (strequal(nt_name, drivername)) {
1469 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1470 set_driver_mapping(drivername, os2_name);
1471 drivername = talloc_strdup(mem_ctx, os2_name);
1472 TALLOC_FREE(lines);
1473 if (drivername == NULL) {
1474 return WERR_NOMEM;
1476 *pdrivername = drivername;
1477 return WERR_OK;
1481 TALLOC_FREE(lines);
1482 return WERR_OK;
1485 /****************************************************************************
1486 ****************************************************************************/
1488 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1489 struct spoolss_DriverInfo8 *_info8)
1491 struct spoolss_DriverInfo8 info8;
1493 ZERO_STRUCT(info8);
1495 switch (r->level) {
1496 case 3:
1497 info8.version = r->info.info3->version;
1498 info8.driver_name = r->info.info3->driver_name;
1499 info8.architecture = r->info.info3->architecture;
1500 info8.driver_path = r->info.info3->driver_path;
1501 info8.data_file = r->info.info3->data_file;
1502 info8.config_file = r->info.info3->config_file;
1503 info8.help_file = r->info.info3->help_file;
1504 info8.monitor_name = r->info.info3->monitor_name;
1505 info8.default_datatype = r->info.info3->default_datatype;
1506 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1507 info8.dependent_files = r->info.info3->dependent_files->string;
1509 break;
1510 case 6:
1511 info8.version = r->info.info6->version;
1512 info8.driver_name = r->info.info6->driver_name;
1513 info8.architecture = r->info.info6->architecture;
1514 info8.driver_path = r->info.info6->driver_path;
1515 info8.data_file = r->info.info6->data_file;
1516 info8.config_file = r->info.info6->config_file;
1517 info8.help_file = r->info.info6->help_file;
1518 info8.monitor_name = r->info.info6->monitor_name;
1519 info8.default_datatype = r->info.info6->default_datatype;
1520 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1521 info8.dependent_files = r->info.info6->dependent_files->string;
1523 info8.driver_date = r->info.info6->driver_date;
1524 info8.driver_version = r->info.info6->driver_version;
1525 info8.manufacturer_name = r->info.info6->manufacturer_name;
1526 info8.manufacturer_url = r->info.info6->manufacturer_url;
1527 info8.hardware_id = r->info.info6->hardware_id;
1528 info8.provider = r->info.info6->provider;
1529 break;
1530 case 8:
1531 info8.version = r->info.info8->version;
1532 info8.driver_name = r->info.info8->driver_name;
1533 info8.architecture = r->info.info8->architecture;
1534 info8.driver_path = r->info.info8->driver_path;
1535 info8.data_file = r->info.info8->data_file;
1536 info8.config_file = r->info.info8->config_file;
1537 info8.help_file = r->info.info8->help_file;
1538 info8.monitor_name = r->info.info8->monitor_name;
1539 info8.default_datatype = r->info.info8->default_datatype;
1540 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1541 info8.dependent_files = r->info.info8->dependent_files->string;
1543 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1544 info8.previous_names = r->info.info8->previous_names->string;
1546 info8.driver_date = r->info.info8->driver_date;
1547 info8.driver_version = r->info.info8->driver_version;
1548 info8.manufacturer_name = r->info.info8->manufacturer_name;
1549 info8.manufacturer_url = r->info.info8->manufacturer_url;
1550 info8.hardware_id = r->info.info8->hardware_id;
1551 info8.provider = r->info.info8->provider;
1552 info8.print_processor = r->info.info8->print_processor;
1553 info8.vendor_setup = r->info.info8->vendor_setup;
1554 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1555 info8.color_profiles = r->info.info8->color_profiles->string;
1557 info8.inf_path = r->info.info8->inf_path;
1558 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1559 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1560 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1562 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1563 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1564 break;
1565 default:
1566 return false;
1569 *_info8 = info8;
1571 return true;
1575 /****************************************************************************
1576 Determine whether or not a particular driver is currently assigned
1577 to a printer
1578 ****************************************************************************/
1580 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1581 const struct auth_serversupplied_info *session_info,
1582 struct messaging_context *msg_ctx,
1583 const struct spoolss_DriverInfo8 *r)
1585 int snum;
1586 int n_services = lp_numservices();
1587 bool in_use = False;
1588 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1589 WERROR result;
1591 if (!r) {
1592 return false;
1595 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1597 /* loop through the printers.tdb and check for the drivername */
1599 for (snum=0; snum<n_services && !in_use; snum++) {
1600 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1601 continue;
1604 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
1605 lp_servicename(snum),
1606 &pinfo2);
1607 if (!W_ERROR_IS_OK(result)) {
1608 continue; /* skip */
1611 if (strequal(r->driver_name, pinfo2->drivername)) {
1612 in_use = True;
1615 TALLOC_FREE(pinfo2);
1618 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1620 if ( in_use ) {
1621 struct spoolss_DriverInfo8 *driver;
1622 WERROR werr;
1624 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1626 /* we can still remove the driver if there is one of
1627 "Windows NT x86" version 2 or 3 left */
1629 if (!strequal("Windows NT x86", r->architecture)) {
1630 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1631 "Windows NT x86",
1632 r->driver_name,
1633 DRIVER_ANY_VERSION,
1634 &driver);
1635 } else if (r->version == 2) {
1636 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1637 "Windows NT x86",
1638 r->driver_name,
1639 3, &driver);
1640 } else if (r->version == 3) {
1641 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1642 "Windows NT x86",
1643 r->driver_name,
1644 2, &driver);
1645 } else {
1646 DEBUG(0, ("printer_driver_in_use: ERROR!"
1647 " unknown driver version (%d)\n",
1648 r->version));
1649 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1652 /* now check the error code */
1654 if ( W_ERROR_IS_OK(werr) ) {
1655 /* it's ok to remove the driver, we have other architctures left */
1656 in_use = False;
1657 talloc_free(driver);
1661 /* report that the driver is not in use by default */
1663 return in_use;
1667 /**********************************************************************
1668 Check to see if a ogiven file is in use by *info
1669 *********************************************************************/
1671 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1673 int i = 0;
1675 if ( !info )
1676 return False;
1678 /* mz: skip files that are in the list but already deleted */
1679 if (!file || !file[0]) {
1680 return false;
1683 if (strequal(file, info->driver_path))
1684 return True;
1686 if (strequal(file, info->data_file))
1687 return True;
1689 if (strequal(file, info->config_file))
1690 return True;
1692 if (strequal(file, info->help_file))
1693 return True;
1695 /* see of there are any dependent files to examine */
1697 if (!info->dependent_files)
1698 return False;
1700 while (info->dependent_files[i] && *info->dependent_files[i]) {
1701 if (strequal(file, info->dependent_files[i]))
1702 return True;
1703 i++;
1706 return False;
1710 /**********************************************************************
1711 Utility function to remove the dependent file pointed to by the
1712 input parameter from the list
1713 *********************************************************************/
1715 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1718 /* bump everything down a slot */
1720 while (files && files[idx+1]) {
1721 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1722 idx++;
1725 files[idx] = NULL;
1727 return;
1730 /**********************************************************************
1731 Check if any of the files used by src are also used by drv
1732 *********************************************************************/
1734 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1735 struct spoolss_DriverInfo8 *src,
1736 const struct spoolss_DriverInfo8 *drv)
1738 bool in_use = False;
1739 int i = 0;
1741 if ( !src || !drv )
1742 return False;
1744 /* check each file. Remove it from the src structure if it overlaps */
1746 if (drv_file_in_use(src->driver_path, drv)) {
1747 in_use = True;
1748 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1749 src->driver_path = talloc_strdup(mem_ctx, "");
1750 if (!src->driver_path) { return false; }
1753 if (drv_file_in_use(src->data_file, drv)) {
1754 in_use = True;
1755 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1756 src->data_file = talloc_strdup(mem_ctx, "");
1757 if (!src->data_file) { return false; }
1760 if (drv_file_in_use(src->config_file, drv)) {
1761 in_use = True;
1762 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1763 src->config_file = talloc_strdup(mem_ctx, "");
1764 if (!src->config_file) { return false; }
1767 if (drv_file_in_use(src->help_file, drv)) {
1768 in_use = True;
1769 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1770 src->help_file = talloc_strdup(mem_ctx, "");
1771 if (!src->help_file) { return false; }
1774 /* are there any dependentfiles to examine? */
1776 if (!src->dependent_files)
1777 return in_use;
1779 while (src->dependent_files[i] && *src->dependent_files[i]) {
1780 if (drv_file_in_use(src->dependent_files[i], drv)) {
1781 in_use = True;
1782 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1783 trim_dependent_file(mem_ctx, src->dependent_files, i);
1784 } else
1785 i++;
1788 return in_use;
1791 /****************************************************************************
1792 Determine whether or not a particular driver files are currently being
1793 used by any other driver.
1795 Return value is True if any files were in use by other drivers
1796 and False otherwise.
1798 Upon return, *info has been modified to only contain the driver files
1799 which are not in use
1801 Fix from mz:
1803 This needs to check all drivers to ensure that all files in use
1804 have been removed from *info, not just the ones in the first
1805 match.
1806 ****************************************************************************/
1808 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1809 const struct auth_serversupplied_info *session_info,
1810 struct messaging_context *msg_ctx,
1811 struct spoolss_DriverInfo8 *info)
1813 int i;
1814 uint32 version;
1815 struct spoolss_DriverInfo8 *driver;
1816 bool in_use = false;
1817 uint32_t num_drivers;
1818 const char **drivers;
1819 WERROR result;
1821 if ( !info )
1822 return False;
1824 version = info->version;
1826 /* loop over all driver versions */
1828 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1830 /* get the list of drivers */
1832 result = winreg_get_driver_list(mem_ctx, session_info, msg_ctx,
1833 info->architecture, version,
1834 &num_drivers, &drivers);
1835 if (!W_ERROR_IS_OK(result)) {
1836 return true;
1839 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1840 num_drivers, info->architecture, version));
1842 /* check each driver for overlap in files */
1844 for (i = 0; i < num_drivers; i++) {
1845 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1847 driver = NULL;
1849 result = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1850 info->architecture, drivers[i],
1851 version, &driver);
1852 if (!W_ERROR_IS_OK(result)) {
1853 talloc_free(drivers);
1854 return True;
1857 /* check if d2 uses any files from d1 */
1858 /* only if this is a different driver than the one being deleted */
1860 if (!strequal(info->driver_name, driver->driver_name)) {
1861 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1862 /* mz: Do not instantly return -
1863 * we need to ensure this file isn't
1864 * also in use by other drivers. */
1865 in_use = true;
1869 talloc_free(driver);
1872 talloc_free(drivers);
1874 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1876 return in_use;
1879 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1880 const char *name)
1882 struct smb_filename *smb_fname = NULL;
1883 NTSTATUS status;
1885 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1886 &smb_fname);
1887 if (!NT_STATUS_IS_OK(status)) {
1888 return status;
1891 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1893 TALLOC_FREE(smb_fname);
1894 return status;
1897 /****************************************************************************
1898 Actually delete the driver files. Make sure that
1899 printer_driver_files_in_use() return False before calling
1900 this.
1901 ****************************************************************************/
1903 bool delete_driver_files(const struct auth_serversupplied_info *session_info,
1904 const struct spoolss_DriverInfo8 *r)
1906 int i = 0;
1907 char *s;
1908 const char *file;
1909 connection_struct *conn;
1910 NTSTATUS nt_status;
1911 char *oldcwd;
1912 char *printdollar = NULL;
1913 int printdollar_snum;
1914 bool ret = false;
1916 if (!r) {
1917 return false;
1920 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1921 r->driver_name, r->version));
1923 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1924 if (!printdollar) {
1925 return false;
1927 if (printdollar_snum == -1) {
1928 return false;
1931 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1932 lp_pathname(printdollar_snum),
1933 session_info, &oldcwd);
1934 if (!NT_STATUS_IS_OK(nt_status)) {
1935 DEBUG(0,("delete_driver_files: create_conn_struct "
1936 "returned %s\n", nt_errstr(nt_status)));
1937 return false;
1940 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1941 if (!NT_STATUS_IS_OK(nt_status)) {
1942 DEBUG(0, ("failed set force user / group\n"));
1943 ret = false;
1944 goto err_free_conn;
1947 if (!become_user(conn, get_current_vuid(conn))) {
1948 DEBUG(0, ("failed to become user\n"));
1949 ret = false;
1950 goto err_free_conn;
1953 if ( !CAN_WRITE(conn) ) {
1954 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1955 ret = false;
1956 goto err_out;
1959 /* now delete the files; must strip the '\print$' string from
1960 fron of path */
1962 if (r->driver_path && r->driver_path[0]) {
1963 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1964 file = s;
1965 DEBUG(10,("deleting driverfile [%s]\n", s));
1966 driver_unlink_internals(conn, file);
1970 if (r->config_file && r->config_file[0]) {
1971 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1972 file = s;
1973 DEBUG(10,("deleting configfile [%s]\n", s));
1974 driver_unlink_internals(conn, file);
1978 if (r->data_file && r->data_file[0]) {
1979 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1980 file = s;
1981 DEBUG(10,("deleting datafile [%s]\n", s));
1982 driver_unlink_internals(conn, file);
1986 if (r->help_file && r->help_file[0]) {
1987 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1988 file = s;
1989 DEBUG(10,("deleting helpfile [%s]\n", s));
1990 driver_unlink_internals(conn, file);
1994 /* check if we are done removing files */
1996 if (r->dependent_files) {
1997 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1998 char *p;
2000 /* bypass the "\print$" portion of the path */
2002 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
2003 file = p;
2004 DEBUG(10,("deleting dependent file [%s]\n", file));
2005 driver_unlink_internals(conn, file);
2008 i++;
2012 ret = true;
2013 err_out:
2014 unbecome_user();
2015 err_free_conn:
2016 if (conn != NULL) {
2017 vfs_ChDir(conn, oldcwd);
2018 SMB_VFS_DISCONNECT(conn);
2019 conn_free(conn);
2021 return ret;
2024 /* error code:
2025 0: everything OK
2026 1: level not implemented
2027 2: file doesn't exist
2028 3: can't allocate memory
2029 4: can't free memory
2030 5: non existant struct
2034 A printer and a printer driver are 2 different things.
2035 NT manages them separatelly, Samba does the same.
2036 Why ? Simply because it's easier and it makes sense !
2038 Now explanation: You have 3 printers behind your samba server,
2039 2 of them are the same make and model (laser A and B). But laser B
2040 has an 3000 sheet feeder and laser A doesn't such an option.
2041 Your third printer is an old dot-matrix model for the accounting :-).
2043 If the /usr/local/samba/lib directory (default dir), you will have
2044 5 files to describe all of this.
2046 3 files for the printers (1 by printer):
2047 NTprinter_laser A
2048 NTprinter_laser B
2049 NTprinter_accounting
2050 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2051 NTdriver_printer model X
2052 NTdriver_printer model Y
2054 jfm: I should use this comment for the text file to explain
2055 same thing for the forms BTW.
2056 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2060 /* Convert generic access rights to printer object specific access rights.
2061 It turns out that NT4 security descriptors use generic access rights and
2062 NT5 the object specific ones. */
2064 void map_printer_permissions(struct security_descriptor *sd)
2066 int i;
2068 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2069 se_map_generic(&sd->dacl->aces[i].access_mask,
2070 &printer_generic_mapping);
2074 void map_job_permissions(struct security_descriptor *sd)
2076 int i;
2078 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2079 se_map_generic(&sd->dacl->aces[i].access_mask,
2080 &job_generic_mapping);
2085 /****************************************************************************
2086 Check a user has permissions to perform the given operation. We use the
2087 permission constants defined in include/rpc_spoolss.h to check the various
2088 actions we perform when checking printer access.
2090 PRINTER_ACCESS_ADMINISTER:
2091 print_queue_pause, print_queue_resume, update_printer_sec,
2092 update_printer, spoolss_addprinterex_level_2,
2093 _spoolss_setprinterdata
2095 PRINTER_ACCESS_USE:
2096 print_job_start
2098 JOB_ACCESS_ADMINISTER:
2099 print_job_delete, print_job_pause, print_job_resume,
2100 print_queue_purge
2102 Try access control in the following order (for performance reasons):
2103 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2104 2) check security descriptor (bit comparisons in memory)
2105 3) "printer admins" (may result in numerous calls to winbind)
2107 ****************************************************************************/
2108 bool print_access_check(const struct auth_serversupplied_info *session_info,
2109 struct messaging_context *msg_ctx, int snum,
2110 int access_type)
2112 struct spoolss_security_descriptor *secdesc = NULL;
2113 uint32 access_granted;
2114 size_t sd_size;
2115 NTSTATUS status;
2116 WERROR result;
2117 const char *pname;
2118 TALLOC_CTX *mem_ctx = NULL;
2120 /* If user is NULL then use the current_user structure */
2122 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2124 if (session_info->utok.uid == sec_initial_uid()
2125 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
2126 return True;
2129 /* Get printer name */
2131 pname = lp_printername(snum);
2133 if (!pname || !*pname) {
2134 errno = EACCES;
2135 return False;
2138 /* Get printer security descriptor */
2140 if(!(mem_ctx = talloc_init("print_access_check"))) {
2141 errno = ENOMEM;
2142 return False;
2145 result = winreg_get_printer_secdesc(mem_ctx,
2146 get_session_info_system(),
2147 msg_ctx,
2148 pname,
2149 &secdesc);
2150 if (!W_ERROR_IS_OK(result)) {
2151 talloc_destroy(mem_ctx);
2152 errno = ENOMEM;
2153 return False;
2156 if (access_type == JOB_ACCESS_ADMINISTER) {
2157 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2159 /* Create a child security descriptor to check permissions
2160 against. This is because print jobs are child objects
2161 objects of a printer. */
2162 status = se_create_child_secdesc(mem_ctx,
2163 &secdesc,
2164 &sd_size,
2165 parent_secdesc,
2166 parent_secdesc->owner_sid,
2167 parent_secdesc->group_sid,
2168 false);
2169 if (!NT_STATUS_IS_OK(status)) {
2170 talloc_destroy(mem_ctx);
2171 errno = map_errno_from_nt_status(status);
2172 return False;
2175 map_job_permissions(secdesc);
2176 } else {
2177 map_printer_permissions(secdesc);
2180 /* Check access */
2181 status = se_access_check(secdesc, session_info->security_token, access_type,
2182 &access_granted);
2184 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2186 /* see if we need to try the printer admin list */
2188 if (!NT_STATUS_IS_OK(status) &&
2189 (token_contains_name_in_list(uidtoname(session_info->utok.uid),
2190 session_info->info3->base.domain.string,
2191 NULL, session_info->security_token,
2192 lp_printer_admin(snum)))) {
2193 talloc_destroy(mem_ctx);
2194 return True;
2197 talloc_destroy(mem_ctx);
2199 if (!NT_STATUS_IS_OK(status)) {
2200 errno = EACCES;
2203 return NT_STATUS_IS_OK(status);
2206 /****************************************************************************
2207 Check the time parameters allow a print operation.
2208 *****************************************************************************/
2210 bool print_time_access_check(const struct auth_serversupplied_info *session_info,
2211 struct messaging_context *msg_ctx,
2212 const char *servicename)
2214 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2215 WERROR result;
2216 bool ok = False;
2217 time_t now = time(NULL);
2218 struct tm *t;
2219 uint32 mins;
2221 result = winreg_get_printer(NULL, session_info, msg_ctx,
2222 servicename, &pinfo2);
2223 if (!W_ERROR_IS_OK(result)) {
2224 return False;
2227 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2228 ok = True;
2231 t = gmtime(&now);
2232 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2234 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2235 ok = True;
2238 TALLOC_FREE(pinfo2);
2240 if (!ok) {
2241 errno = EACCES;
2244 return ok;
2247 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2248 const struct auth_serversupplied_info *session_info,
2249 struct messaging_context *msg_ctx,
2250 const char *printer)
2252 WERROR result;
2254 result = winreg_delete_printer_key(mem_ctx, session_info, msg_ctx,
2255 printer, "");
2256 if (!W_ERROR_IS_OK(result)) {
2257 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2258 printer));