s3:smbd/trans2: make use of BVAL() and remove ugly LARGE_SMB_OFF_T ifdef's
[Samba.git] / source3 / printing / nt_printing.c
bloba7539f6478fa4ee239454edf88266e243062717d
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/pcap.h"
24 #include "printing/nt_printing_tdb.h"
25 #include "printing/nt_printing_migrate.h"
26 #include "registry.h"
27 #include "registry/reg_objects.h"
28 #include "../librpc/gen_ndr/ndr_security.h"
29 #include "../librpc/gen_ndr/ndr_spoolss.h"
30 #include "rpc_server/spoolss/srv_spoolss_util.h"
31 #include "nt_printing.h"
32 #include "secrets.h"
33 #include "../librpc/gen_ndr/netlogon.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
36 #include "smbd/smbd.h"
37 #include "auth.h"
38 #include "messages.h"
39 #include "ntdomain.h"
41 /* Map generic permissions to printer object specific permissions */
43 const struct generic_mapping printer_generic_mapping = {
44 PRINTER_READ,
45 PRINTER_WRITE,
46 PRINTER_EXECUTE,
47 PRINTER_ALL_ACCESS
50 /* Map generic permissions to print server object specific permissions */
52 const struct generic_mapping printserver_generic_mapping = {
53 SERVER_READ,
54 SERVER_WRITE,
55 SERVER_EXECUTE,
56 SERVER_ALL_ACCESS
59 /* Map generic permissions to job object specific permissions */
61 const struct generic_mapping job_generic_mapping = {
62 JOB_READ,
63 JOB_WRITE,
64 JOB_EXECUTE,
65 JOB_ALL_ACCESS
68 static const struct print_architecture_table_node archi_table[]= {
70 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
71 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
72 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
73 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
74 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
75 {"Windows IA64", SPL_ARCH_IA64, 3 },
76 {"Windows x64", SPL_ARCH_X64, 3 },
77 {NULL, "", -1 }
80 /****************************************************************************
81 Open the NT printing tdbs. Done once before fork().
82 ****************************************************************************/
84 bool nt_printing_init(struct messaging_context *msg_ctx)
86 WERROR win_rc;
88 if (!nt_printing_tdb_upgrade()) {
89 return false;
93 * register callback to handle updating printers as new
94 * drivers are installed
96 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
97 do_drv_upgrade_printer);
99 /* of course, none of the message callbacks matter if you don't
100 tell messages.c that you interested in receiving PRINT_GENERAL
101 msgs. This is done in serverid_register() */
103 if ( lp_security() == SEC_ADS ) {
104 win_rc = check_published_printers(msg_ctx);
105 if (!W_ERROR_IS_OK(win_rc))
106 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
109 return true;
112 /*******************************************************************
113 Function to allow filename parsing "the old way".
114 ********************************************************************/
116 static NTSTATUS driver_unix_convert(connection_struct *conn,
117 const char *old_name,
118 struct smb_filename **smb_fname)
120 NTSTATUS status;
121 TALLOC_CTX *ctx = talloc_tos();
122 char *name = talloc_strdup(ctx, old_name);
124 if (!name) {
125 return NT_STATUS_NO_MEMORY;
127 unix_format(name);
128 name = unix_clean_name(ctx, name);
129 if (!name) {
130 return NT_STATUS_NO_MEMORY;
132 trim_string(name,"/","/");
134 status = unix_convert(ctx, conn, name, smb_fname, 0);
135 if (!NT_STATUS_IS_OK(status)) {
136 return NT_STATUS_NO_MEMORY;
139 return NT_STATUS_OK;
142 /****************************************************************************
143 Function to do the mapping between the long architecture name and
144 the short one.
145 ****************************************************************************/
147 const char *get_short_archi(const char *long_archi)
149 int i=-1;
151 DEBUG(107,("Getting architecture dependent directory\n"));
152 do {
153 i++;
154 } while ( (archi_table[i].long_archi!=NULL ) &&
155 StrCaseCmp(long_archi, archi_table[i].long_archi) );
157 if (archi_table[i].long_archi==NULL) {
158 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
159 return NULL;
162 /* this might be client code - but shouldn't this be an fstrcpy etc? */
164 DEBUGADD(108,("index: [%d]\n", i));
165 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
166 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
168 return archi_table[i].short_archi;
171 /****************************************************************************
172 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
173 There are two case to be covered here: PE (Portable Executable) and NE (New
174 Executable) files. Both files support the same INFO structure, but PE files
175 store the signature in unicode, and NE files store it as !unicode.
176 returns -1 on error, 1 on version info found, and 0 on no version info found.
177 ****************************************************************************/
179 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
181 int i;
182 char *buf = NULL;
183 ssize_t byte_count;
185 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
186 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
187 fname, DOS_HEADER_SIZE));
188 goto error_exit;
191 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
192 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
193 fname, (unsigned long)byte_count));
194 goto no_version_info;
197 /* Is this really a DOS header? */
198 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
199 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
200 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
201 goto no_version_info;
204 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
205 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
206 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
207 fname, errno));
208 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
209 goto no_version_info;
212 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
213 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
214 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
215 fname, (unsigned long)byte_count));
216 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
217 goto no_version_info;
220 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
221 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
222 unsigned int num_sections;
223 unsigned int section_table_bytes;
225 /* Just skip over optional header to get to section table */
226 if (SMB_VFS_LSEEK(fsp,
227 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
228 SEEK_CUR) == (SMB_OFF_T)-1) {
229 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
230 fname, errno));
231 goto error_exit;
234 /* get the section table */
235 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
236 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
237 if (section_table_bytes == 0)
238 goto error_exit;
240 SAFE_FREE(buf);
241 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
242 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
243 fname, section_table_bytes));
244 goto error_exit;
247 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
248 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
249 fname, (unsigned long)byte_count));
250 goto error_exit;
253 /* Iterate the section table looking for the resource section ".rsrc" */
254 for (i = 0; i < num_sections; i++) {
255 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
257 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
258 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
259 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
261 if (section_bytes == 0)
262 goto error_exit;
264 SAFE_FREE(buf);
265 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
266 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
267 fname, section_bytes));
268 goto error_exit;
271 /* Seek to the start of the .rsrc section info */
272 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
273 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
274 fname, errno));
275 goto error_exit;
278 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
279 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
280 fname, (unsigned long)byte_count));
281 goto error_exit;
284 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
285 goto error_exit;
287 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
288 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
289 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
290 /* Align to next long address */
291 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
293 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
294 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
295 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
297 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
298 fname, *major, *minor,
299 (*major>>16)&0xffff, *major&0xffff,
300 (*minor>>16)&0xffff, *minor&0xffff));
301 SAFE_FREE(buf);
302 return 1;
309 /* Version info not found, fall back to origin date/time */
310 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
311 SAFE_FREE(buf);
312 return 0;
314 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
315 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
316 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
317 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
318 /* At this point, we assume the file is in error. It still could be somthing
319 * else besides a NE file, but it unlikely at this point. */
320 goto error_exit;
323 /* Allocate a bit more space to speed up things */
324 SAFE_FREE(buf);
325 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
326 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
327 fname, PE_HEADER_SIZE));
328 goto error_exit;
331 /* This is a HACK! I got tired of trying to sort through the messy
332 * 'NE' file format. If anyone wants to clean this up please have at
333 * it, but this works. 'NE' files will eventually fade away. JRR */
334 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
335 /* Cover case that should not occur in a well formed 'NE' .dll file */
336 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
338 for(i=0; i<byte_count; i++) {
339 /* Fast skip past data that can't possibly match */
340 if (buf[i] != 'V') continue;
342 /* Potential match data crosses buf boundry, move it to beginning
343 * of buf, and fill the buf with as much as it will hold. */
344 if (i>byte_count-VS_VERSION_INFO_SIZE) {
345 int bc;
347 memcpy(buf, &buf[i], byte_count-i);
348 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
349 (byte_count-i))) < 0) {
351 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
352 fname, errno));
353 goto error_exit;
356 byte_count = bc + (byte_count - i);
357 if (byte_count<VS_VERSION_INFO_SIZE) break;
359 i = 0;
362 /* Check that the full signature string and the magic number that
363 * follows exist (not a perfect solution, but the chances that this
364 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
365 * twice, as it is simpler to read the code. */
366 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
367 /* Compute skip alignment to next long address */
368 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
369 sizeof(VS_SIGNATURE)) & 3;
370 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
372 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
373 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
374 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
375 fname, *major, *minor,
376 (*major>>16)&0xffff, *major&0xffff,
377 (*minor>>16)&0xffff, *minor&0xffff));
378 SAFE_FREE(buf);
379 return 1;
384 /* Version info not found, fall back to origin date/time */
385 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
386 SAFE_FREE(buf);
387 return 0;
389 } else
390 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
391 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
392 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
394 no_version_info:
395 SAFE_FREE(buf);
396 return 0;
398 error_exit:
399 SAFE_FREE(buf);
400 return -1;
403 /****************************************************************************
404 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
405 share one or more files. During the MS installation process files are checked
406 to insure that only a newer version of a shared file is installed over an
407 older version. There are several possibilities for this comparison. If there
408 is no previous version, the new one is newer (obviously). If either file is
409 missing the version info structure, compare the creation date (on Unix use
410 the modification date). Otherwise chose the numerically larger version number.
411 ****************************************************************************/
413 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
415 bool use_version = true;
417 uint32 new_major;
418 uint32 new_minor;
419 time_t new_create_time;
421 uint32 old_major;
422 uint32 old_minor;
423 time_t old_create_time;
425 struct smb_filename *smb_fname = NULL;
426 files_struct *fsp = NULL;
427 SMB_STRUCT_STAT st;
429 NTSTATUS status;
430 int ret;
432 SET_STAT_INVALID(st);
433 new_create_time = (time_t)0;
434 old_create_time = (time_t)0;
436 /* Get file version info (if available) for previous file (if it exists) */
437 status = driver_unix_convert(conn, old_file, &smb_fname);
438 if (!NT_STATUS_IS_OK(status)) {
439 goto error_exit;
442 status = SMB_VFS_CREATE_FILE(
443 conn, /* conn */
444 NULL, /* req */
445 0, /* root_dir_fid */
446 smb_fname, /* fname */
447 FILE_GENERIC_READ, /* access_mask */
448 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
449 FILE_OPEN, /* create_disposition*/
450 0, /* create_options */
451 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
452 INTERNAL_OPEN_ONLY, /* oplock_request */
453 0, /* allocation_size */
454 0, /* private_flags */
455 NULL, /* sd */
456 NULL, /* ea_list */
457 &fsp, /* result */
458 NULL); /* pinfo */
460 if (!NT_STATUS_IS_OK(status)) {
461 /* Old file not found, so by definition new file is in fact newer */
462 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
463 "errno = %d\n", smb_fname_str_dbg(smb_fname),
464 errno));
465 ret = 1;
466 goto done;
468 } else {
469 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
470 if (ret == -1) {
471 goto error_exit;
474 if (!ret) {
475 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
476 old_file));
477 use_version = false;
478 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
479 goto error_exit;
481 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
482 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
483 (long)old_create_time));
486 close_file(NULL, fsp, NORMAL_CLOSE);
487 fsp = NULL;
489 /* Get file version info (if available) for new file */
490 status = driver_unix_convert(conn, new_file, &smb_fname);
491 if (!NT_STATUS_IS_OK(status)) {
492 goto error_exit;
495 status = SMB_VFS_CREATE_FILE(
496 conn, /* conn */
497 NULL, /* req */
498 0, /* root_dir_fid */
499 smb_fname, /* fname */
500 FILE_GENERIC_READ, /* access_mask */
501 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
502 FILE_OPEN, /* create_disposition*/
503 0, /* create_options */
504 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
505 INTERNAL_OPEN_ONLY, /* oplock_request */
506 0, /* allocation_size */
507 0, /* private_flags */
508 NULL, /* sd */
509 NULL, /* ea_list */
510 &fsp, /* result */
511 NULL); /* pinfo */
513 if (!NT_STATUS_IS_OK(status)) {
514 /* New file not found, this shouldn't occur if the caller did its job */
515 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
516 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
517 goto error_exit;
519 } else {
520 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
521 if (ret == -1) {
522 goto error_exit;
525 if (!ret) {
526 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
527 new_file));
528 use_version = false;
529 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
530 goto error_exit;
532 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
533 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
534 (long)new_create_time));
537 close_file(NULL, fsp, NORMAL_CLOSE);
538 fsp = NULL;
540 if (use_version && (new_major != old_major || new_minor != old_minor)) {
541 /* Compare versions and choose the larger version number */
542 if (new_major > old_major ||
543 (new_major == old_major && new_minor > old_minor)) {
545 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
546 ret = 1;
547 goto done;
549 else {
550 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
551 ret = 0;
552 goto done;
555 } else {
556 /* Compare modification time/dates and choose the newest time/date */
557 if (new_create_time > old_create_time) {
558 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
559 ret = 1;
560 goto done;
562 else {
563 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
564 ret = 0;
565 goto done;
569 error_exit:
570 if(fsp)
571 close_file(NULL, fsp, NORMAL_CLOSE);
572 ret = -1;
573 done:
574 TALLOC_FREE(smb_fname);
575 return ret;
578 /****************************************************************************
579 Determine the correct cVersion associated with an architecture and driver
580 ****************************************************************************/
581 static uint32 get_correct_cversion(struct pipes_struct *p,
582 const char *architecture,
583 const char *driverpath_in,
584 WERROR *perr)
586 int cversion = -1;
587 NTSTATUS nt_status;
588 struct smb_filename *smb_fname = NULL;
589 char *driverpath = NULL;
590 files_struct *fsp = NULL;
591 connection_struct *conn = NULL;
592 char *oldcwd;
593 char *printdollar = NULL;
594 int printdollar_snum;
596 *perr = WERR_INVALID_PARAM;
598 /* If architecture is Windows 95/98/ME, the version is always 0. */
599 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
600 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
601 *perr = WERR_OK;
602 return 0;
605 /* If architecture is Windows x64, the version is always 3. */
606 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
607 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
608 *perr = WERR_OK;
609 return 3;
612 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
613 if (!printdollar) {
614 *perr = WERR_NOMEM;
615 return -1;
617 if (printdollar_snum == -1) {
618 *perr = WERR_NO_SUCH_SHARE;
619 return -1;
622 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
623 lp_pathname(printdollar_snum),
624 p->session_info, &oldcwd);
625 if (!NT_STATUS_IS_OK(nt_status)) {
626 DEBUG(0,("get_correct_cversion: create_conn_struct "
627 "returned %s\n", nt_errstr(nt_status)));
628 *perr = ntstatus_to_werror(nt_status);
629 return -1;
632 nt_status = set_conn_force_user_group(conn, printdollar_snum);
633 if (!NT_STATUS_IS_OK(nt_status)) {
634 DEBUG(0, ("failed set force user / group\n"));
635 *perr = ntstatus_to_werror(nt_status);
636 goto error_free_conn;
639 if (!become_user_by_session(conn, p->session_info)) {
640 DEBUG(0, ("failed to become user\n"));
641 *perr = WERR_ACCESS_DENIED;
642 goto error_free_conn;
645 /* Open the driver file (Portable Executable format) and determine the
646 * deriver the cversion. */
647 driverpath = talloc_asprintf(talloc_tos(),
648 "%s/%s",
649 architecture,
650 driverpath_in);
651 if (!driverpath) {
652 *perr = WERR_NOMEM;
653 goto error_exit;
656 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
657 if (!NT_STATUS_IS_OK(nt_status)) {
658 *perr = ntstatus_to_werror(nt_status);
659 goto error_exit;
662 nt_status = vfs_file_exist(conn, smb_fname);
663 if (!NT_STATUS_IS_OK(nt_status)) {
664 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
665 *perr = WERR_BADFILE;
666 goto error_exit;
669 nt_status = SMB_VFS_CREATE_FILE(
670 conn, /* conn */
671 NULL, /* req */
672 0, /* root_dir_fid */
673 smb_fname, /* fname */
674 FILE_GENERIC_READ, /* access_mask */
675 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
676 FILE_OPEN, /* create_disposition*/
677 0, /* create_options */
678 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
679 INTERNAL_OPEN_ONLY, /* oplock_request */
680 0, /* private_flags */
681 0, /* allocation_size */
682 NULL, /* sd */
683 NULL, /* ea_list */
684 &fsp, /* result */
685 NULL); /* pinfo */
687 if (!NT_STATUS_IS_OK(nt_status)) {
688 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
689 "%d\n", smb_fname_str_dbg(smb_fname), errno));
690 *perr = WERR_ACCESS_DENIED;
691 goto error_exit;
692 } else {
693 uint32 major;
694 uint32 minor;
695 int ret;
697 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
698 if (ret == -1) {
699 *perr = WERR_INVALID_PARAM;
700 goto error_exit;
701 } else if (!ret) {
702 DEBUG(6,("get_correct_cversion: Version info not "
703 "found [%s]\n",
704 smb_fname_str_dbg(smb_fname)));
705 *perr = WERR_INVALID_PARAM;
706 goto error_exit;
710 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
711 * for more details. Version in this case is not just the version of the
712 * file, but the version in the sense of kernal mode (2) vs. user mode
713 * (3) drivers. Other bits of the version fields are the version info.
714 * JRR 010716
716 cversion = major & 0x0000ffff;
717 switch (cversion) {
718 case 2: /* WinNT drivers */
719 case 3: /* Win2K drivers */
720 break;
722 default:
723 DEBUG(6,("get_correct_cversion: cversion "
724 "invalid [%s] cversion = %d\n",
725 smb_fname_str_dbg(smb_fname),
726 cversion));
727 goto error_exit;
730 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
731 " = 0x%x minor = 0x%x\n",
732 smb_fname_str_dbg(smb_fname), major, minor));
735 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
736 smb_fname_str_dbg(smb_fname), cversion));
737 *perr = WERR_OK;
739 error_exit:
740 unbecome_user();
741 error_free_conn:
742 TALLOC_FREE(smb_fname);
743 if (fsp != NULL) {
744 close_file(NULL, fsp, NORMAL_CLOSE);
746 if (conn != NULL) {
747 vfs_ChDir(conn, oldcwd);
748 SMB_VFS_DISCONNECT(conn);
749 conn_free(conn);
751 if (!NT_STATUS_IS_OK(*perr)) {
752 cversion = -1;
755 return cversion;
758 /****************************************************************************
759 ****************************************************************************/
761 #define strip_driver_path(_mem_ctx, _element) do { \
762 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
763 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
764 W_ERROR_HAVE_NO_MEMORY((_element)); \
766 } while (0);
768 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
769 struct pipes_struct *rpc_pipe,
770 const char *architecture,
771 const char **driver_path,
772 const char **data_file,
773 const char **config_file,
774 const char **help_file,
775 struct spoolss_StringArray *dependent_files,
776 enum spoolss_DriverOSVersion *version)
778 const char *short_architecture;
779 int i;
780 WERROR err;
781 char *_p;
783 if (!*driver_path || !*data_file) {
784 return WERR_INVALID_PARAM;
787 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
788 return WERR_INVALID_PARAM;
791 /* clean up the driver name.
792 * we can get .\driver.dll
793 * or worse c:\windows\system\driver.dll !
795 /* using an intermediate string to not have overlaping memcpy()'s */
797 strip_driver_path(mem_ctx, *driver_path);
798 strip_driver_path(mem_ctx, *data_file);
799 if (*config_file) {
800 strip_driver_path(mem_ctx, *config_file);
802 if (help_file) {
803 strip_driver_path(mem_ctx, *help_file);
806 if (dependent_files && dependent_files->string) {
807 for (i=0; dependent_files->string[i]; i++) {
808 strip_driver_path(mem_ctx, dependent_files->string[i]);
812 short_architecture = get_short_archi(architecture);
813 if (!short_architecture) {
814 return WERR_UNKNOWN_PRINTER_DRIVER;
817 /* jfm:7/16/2000 the client always sends the cversion=0.
818 * The server should check which version the driver is by reading
819 * the PE header of driver->driverpath.
821 * For Windows 95/98 the version is 0 (so the value sent is correct)
822 * For Windows NT (the architecture doesn't matter)
823 * NT 3.1: cversion=0
824 * NT 3.5/3.51: cversion=1
825 * NT 4: cversion=2
826 * NT2K: cversion=3
829 *version = get_correct_cversion(rpc_pipe, short_architecture,
830 *driver_path, &err);
831 if (*version == -1) {
832 return err;
835 return WERR_OK;
838 /****************************************************************************
839 ****************************************************************************/
841 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
842 struct pipes_struct *rpc_pipe,
843 struct spoolss_AddDriverInfoCtr *r)
845 switch (r->level) {
846 case 3:
847 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
848 r->info.info3->architecture,
849 &r->info.info3->driver_path,
850 &r->info.info3->data_file,
851 &r->info.info3->config_file,
852 &r->info.info3->help_file,
853 r->info.info3->dependent_files,
854 &r->info.info3->version);
855 case 6:
856 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
857 r->info.info6->architecture,
858 &r->info.info6->driver_path,
859 &r->info.info6->data_file,
860 &r->info.info6->config_file,
861 &r->info.info6->help_file,
862 r->info.info6->dependent_files,
863 &r->info.info6->version);
864 default:
865 return WERR_NOT_SUPPORTED;
869 /****************************************************************************
870 This function sucks and should be replaced. JRA.
871 ****************************************************************************/
873 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
874 const struct spoolss_AddDriverInfo6 *src)
876 dst->version = src->version;
878 dst->driver_name = src->driver_name;
879 dst->architecture = src->architecture;
880 dst->driver_path = src->driver_path;
881 dst->data_file = src->data_file;
882 dst->config_file = src->config_file;
883 dst->help_file = src->help_file;
884 dst->monitor_name = src->monitor_name;
885 dst->default_datatype = src->default_datatype;
886 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
887 dst->dependent_files = src->dependent_files;
890 /****************************************************************************
891 ****************************************************************************/
893 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
894 connection_struct *conn,
895 const char *driver_file,
896 const char *short_architecture,
897 uint32_t driver_version,
898 uint32_t version)
900 struct smb_filename *smb_fname_old = NULL;
901 struct smb_filename *smb_fname_new = NULL;
902 char *old_name = NULL;
903 char *new_name = NULL;
904 NTSTATUS status;
905 WERROR ret;
907 old_name = talloc_asprintf(mem_ctx, "%s/%s",
908 short_architecture, driver_file);
909 W_ERROR_HAVE_NO_MEMORY(old_name);
911 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
912 short_architecture, driver_version, driver_file);
913 if (new_name == NULL) {
914 TALLOC_FREE(old_name);
915 return WERR_NOMEM;
918 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
920 status = driver_unix_convert(conn, old_name, &smb_fname_old);
921 if (!NT_STATUS_IS_OK(status)) {
922 ret = WERR_NOMEM;
923 goto out;
926 /* Setup a synthetic smb_filename struct */
927 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
928 if (!smb_fname_new) {
929 ret = WERR_NOMEM;
930 goto out;
933 smb_fname_new->base_name = new_name;
935 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
936 "'%s'\n", smb_fname_old->base_name,
937 smb_fname_new->base_name));
939 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
940 OPENX_FILE_EXISTS_TRUNCATE |
941 OPENX_FILE_CREATE_IF_NOT_EXIST,
942 0, false);
944 if (!NT_STATUS_IS_OK(status)) {
945 DEBUG(0,("move_driver_file_to_download_area: Unable "
946 "to rename [%s] to [%s]: %s\n",
947 smb_fname_old->base_name, new_name,
948 nt_errstr(status)));
949 ret = WERR_ACCESS_DENIED;
950 goto out;
954 ret = WERR_OK;
955 out:
956 TALLOC_FREE(smb_fname_old);
957 TALLOC_FREE(smb_fname_new);
958 return ret;
961 WERROR move_driver_to_download_area(struct pipes_struct *p,
962 struct spoolss_AddDriverInfoCtr *r)
964 struct spoolss_AddDriverInfo3 *driver;
965 struct spoolss_AddDriverInfo3 converted_driver;
966 const char *short_architecture;
967 struct smb_filename *smb_dname = NULL;
968 char *new_dir = NULL;
969 connection_struct *conn = NULL;
970 NTSTATUS nt_status;
971 int i;
972 TALLOC_CTX *ctx = talloc_tos();
973 int ver = 0;
974 char *oldcwd;
975 char *printdollar = NULL;
976 int printdollar_snum;
977 WERROR err = WERR_OK;
979 switch (r->level) {
980 case 3:
981 driver = r->info.info3;
982 break;
983 case 6:
984 convert_level_6_to_level3(&converted_driver, r->info.info6);
985 driver = &converted_driver;
986 break;
987 default:
988 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
989 return WERR_UNKNOWN_LEVEL;
992 short_architecture = get_short_archi(driver->architecture);
993 if (!short_architecture) {
994 return WERR_UNKNOWN_PRINTER_DRIVER;
997 printdollar_snum = find_service(ctx, "print$", &printdollar);
998 if (!printdollar) {
999 return WERR_NOMEM;
1001 if (printdollar_snum == -1) {
1002 return WERR_NO_SUCH_SHARE;
1005 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1006 lp_pathname(printdollar_snum),
1007 p->session_info, &oldcwd);
1008 if (!NT_STATUS_IS_OK(nt_status)) {
1009 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1010 "returned %s\n", nt_errstr(nt_status)));
1011 err = ntstatus_to_werror(nt_status);
1012 return err;
1015 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1016 if (!NT_STATUS_IS_OK(nt_status)) {
1017 DEBUG(0, ("failed set force user / group\n"));
1018 err = ntstatus_to_werror(nt_status);
1019 goto err_free_conn;
1022 if (!become_user_by_session(conn, p->session_info)) {
1023 DEBUG(0, ("failed to become user\n"));
1024 err = WERR_ACCESS_DENIED;
1025 goto err_free_conn;
1028 new_dir = talloc_asprintf(ctx,
1029 "%s/%d",
1030 short_architecture,
1031 driver->version);
1032 if (!new_dir) {
1033 err = WERR_NOMEM;
1034 goto err_exit;
1036 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1037 if (!NT_STATUS_IS_OK(nt_status)) {
1038 err = WERR_NOMEM;
1039 goto err_exit;
1042 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1044 nt_status = create_directory(conn, NULL, smb_dname);
1045 if (!NT_STATUS_IS_OK(nt_status)
1046 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1047 DEBUG(0, ("failed to create driver destination directory: %s\n",
1048 nt_errstr(nt_status)));
1049 err = ntstatus_to_werror(nt_status);
1050 goto err_exit;
1053 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1054 * listed for this driver which has already been moved, skip it (note:
1055 * drivers may list the same file name several times. Then check if the
1056 * file already exists in archi\version\, if so, check that the version
1057 * info (or time stamps if version info is unavailable) is newer (or the
1058 * date is later). If it is, move it to archi\version\filexxx.yyy.
1059 * Otherwise, delete the file.
1061 * If a file is not moved to archi\version\ because of an error, all the
1062 * rest of the 'unmoved' driver files are removed from archi\. If one or
1063 * more of the driver's files was already moved to archi\version\, it
1064 * potentially leaves the driver in a partially updated state. Version
1065 * trauma will most likely occur if an client attempts to use any printer
1066 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1067 * done is appropriate... later JRR
1070 DEBUG(5,("Moving files now !\n"));
1072 if (driver->driver_path && strlen(driver->driver_path)) {
1074 err = move_driver_file_to_download_area(ctx,
1075 conn,
1076 driver->driver_path,
1077 short_architecture,
1078 driver->version,
1079 ver);
1080 if (!W_ERROR_IS_OK(err)) {
1081 goto err_exit;
1085 if (driver->data_file && strlen(driver->data_file)) {
1086 if (!strequal(driver->data_file, driver->driver_path)) {
1088 err = move_driver_file_to_download_area(ctx,
1089 conn,
1090 driver->data_file,
1091 short_architecture,
1092 driver->version,
1093 ver);
1094 if (!W_ERROR_IS_OK(err)) {
1095 goto err_exit;
1100 if (driver->config_file && strlen(driver->config_file)) {
1101 if (!strequal(driver->config_file, driver->driver_path) &&
1102 !strequal(driver->config_file, driver->data_file)) {
1104 err = move_driver_file_to_download_area(ctx,
1105 conn,
1106 driver->config_file,
1107 short_architecture,
1108 driver->version,
1109 ver);
1110 if (!W_ERROR_IS_OK(err)) {
1111 goto err_exit;
1116 if (driver->help_file && strlen(driver->help_file)) {
1117 if (!strequal(driver->help_file, driver->driver_path) &&
1118 !strequal(driver->help_file, driver->data_file) &&
1119 !strequal(driver->help_file, driver->config_file)) {
1121 err = move_driver_file_to_download_area(ctx,
1122 conn,
1123 driver->help_file,
1124 short_architecture,
1125 driver->version,
1126 ver);
1127 if (!W_ERROR_IS_OK(err)) {
1128 goto err_exit;
1133 if (driver->dependent_files && driver->dependent_files->string) {
1134 for (i=0; driver->dependent_files->string[i]; i++) {
1135 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1136 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1137 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1138 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1139 int j;
1140 for (j=0; j < i; j++) {
1141 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1142 goto NextDriver;
1146 err = move_driver_file_to_download_area(ctx,
1147 conn,
1148 driver->dependent_files->string[i],
1149 short_architecture,
1150 driver->version,
1151 ver);
1152 if (!W_ERROR_IS_OK(err)) {
1153 goto err_exit;
1156 NextDriver: ;
1160 err = WERR_OK;
1161 err_exit:
1162 unbecome_user();
1163 err_free_conn:
1164 TALLOC_FREE(smb_dname);
1166 if (conn != NULL) {
1167 vfs_ChDir(conn, oldcwd);
1168 SMB_VFS_DISCONNECT(conn);
1169 conn_free(conn);
1172 return err;
1175 /****************************************************************************
1176 Create and allocate a default devicemode.
1177 ****************************************************************************/
1179 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1180 const char *devicename,
1181 struct spoolss_DeviceMode **devmode)
1183 struct spoolss_DeviceMode *dm;
1184 char *dname;
1186 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1187 if (dm == NULL) {
1188 return WERR_NOMEM;
1191 dname = talloc_asprintf(dm, "%s", devicename);
1192 if (dname == NULL) {
1193 return WERR_NOMEM;
1195 if (strlen(dname) > MAXDEVICENAME) {
1196 dname[MAXDEVICENAME] = '\0';
1198 dm->devicename = dname;
1200 dm->formname = talloc_strdup(dm, "Letter");
1201 if (dm->formname == NULL) {
1202 return WERR_NOMEM;
1205 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1206 dm->driverversion = 0x0400;
1207 dm->size = 0x00DC;
1208 dm->__driverextra_length = 0;
1209 dm->fields = DEVMODE_FORMNAME |
1210 DEVMODE_TTOPTION |
1211 DEVMODE_PRINTQUALITY |
1212 DEVMODE_DEFAULTSOURCE |
1213 DEVMODE_COPIES |
1214 DEVMODE_SCALE |
1215 DEVMODE_PAPERSIZE |
1216 DEVMODE_ORIENTATION;
1217 dm->orientation = DMORIENT_PORTRAIT;
1218 dm->papersize = DMPAPER_LETTER;
1219 dm->paperlength = 0;
1220 dm->paperwidth = 0;
1221 dm->scale = 0x64;
1222 dm->copies = 1;
1223 dm->defaultsource = DMBIN_FORMSOURCE;
1224 dm->printquality = DMRES_HIGH; /* 0x0258 */
1225 dm->color = DMRES_MONOCHROME;
1226 dm->duplex = DMDUP_SIMPLEX;
1227 dm->yresolution = 0;
1228 dm->ttoption = DMTT_SUBDEV;
1229 dm->collate = DMCOLLATE_FALSE;
1230 dm->icmmethod = 0;
1231 dm->icmintent = 0;
1232 dm->mediatype = 0;
1233 dm->dithertype = 0;
1235 dm->logpixels = 0;
1236 dm->bitsperpel = 0;
1237 dm->pelswidth = 0;
1238 dm->pelsheight = 0;
1239 dm->displayflags = 0;
1240 dm->displayfrequency = 0;
1241 dm->reserved1 = 0;
1242 dm->reserved2 = 0;
1243 dm->panningwidth = 0;
1244 dm->panningheight = 0;
1246 dm->driverextra_data.data = NULL;
1247 dm->driverextra_data.length = 0;
1249 *devmode = dm;
1250 return WERR_OK;
1253 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1254 struct spoolss_security_descriptor **secdesc)
1256 struct security_ace ace[7]; /* max number of ace entries */
1257 int i = 0;
1258 uint32_t sa;
1259 struct security_acl *psa = NULL;
1260 struct security_descriptor *psd = NULL;
1261 struct dom_sid adm_sid;
1262 size_t sd_size;
1264 /* Create an ACE where Everyone is allowed to print */
1266 sa = PRINTER_ACE_PRINT;
1267 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1268 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1270 /* Add the domain admins group if we are a DC */
1272 if ( IS_DC ) {
1273 struct dom_sid domadmins_sid;
1275 sid_compose(&domadmins_sid, get_global_sam_sid(),
1276 DOMAIN_RID_ADMINS);
1278 sa = PRINTER_ACE_FULL_CONTROL;
1279 init_sec_ace(&ace[i++], &domadmins_sid,
1280 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1281 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1282 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1283 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1285 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1286 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1288 sa = PRINTER_ACE_FULL_CONTROL;
1289 init_sec_ace(&ace[i++], &adm_sid,
1290 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1291 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1292 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1293 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1296 /* add BUILTIN\Administrators as FULL CONTROL */
1298 sa = PRINTER_ACE_FULL_CONTROL;
1299 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1300 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1301 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1302 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1303 SEC_ACE_TYPE_ACCESS_ALLOWED,
1304 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1306 /* add BUILTIN\Print Operators as FULL CONTROL */
1308 sa = PRINTER_ACE_FULL_CONTROL;
1309 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1310 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1311 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1312 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1313 SEC_ACE_TYPE_ACCESS_ALLOWED,
1314 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1316 /* Make the security descriptor owned by the BUILTIN\Administrators */
1318 /* The ACL revision number in rpc_secdesc.h differs from the one
1319 created by NT when setting ACE entries in printer
1320 descriptors. NT4 complains about the property being edited by a
1321 NT5 machine. */
1323 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1324 psd = make_sec_desc(mem_ctx,
1325 SD_REVISION,
1326 SEC_DESC_SELF_RELATIVE,
1327 &global_sid_Builtin_Administrators,
1328 &global_sid_Builtin_Administrators,
1329 NULL,
1330 psa,
1331 &sd_size);
1334 if (psd == NULL) {
1335 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1336 return WERR_NOMEM;
1339 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1340 (unsigned int)sd_size));
1342 *secdesc = psd;
1344 return WERR_OK;
1347 /****************************************************************************
1348 ***************************************************************************/
1350 static char *win_driver;
1351 static char *os2_driver;
1353 static const char *get_win_driver(void)
1355 if (win_driver == NULL) {
1356 return "";
1358 return win_driver;
1361 static const char *get_os2_driver(void)
1363 if (os2_driver == NULL) {
1364 return "";
1366 return os2_driver;
1369 static bool set_driver_mapping(const char *from, const char *to)
1371 SAFE_FREE(win_driver);
1372 SAFE_FREE(os2_driver);
1374 win_driver = SMB_STRDUP(from);
1375 os2_driver = SMB_STRDUP(to);
1377 if (win_driver == NULL || os2_driver == NULL) {
1378 SAFE_FREE(win_driver);
1379 SAFE_FREE(os2_driver);
1380 return false;
1382 return true;
1386 * @internal
1388 * @brief Map a Windows driver to a OS/2 driver.
1390 * @param[in] mem_ctx The memory context to use.
1392 * @param[in,out] pdrivername The drivername of Windows to remap.
1394 * @return WERR_OK on success, a corresponding WERROR on failure.
1396 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1398 const char *mapfile = lp_os2_driver_map();
1399 char **lines = NULL;
1400 const char *drivername;
1401 int numlines = 0;
1402 int i;
1404 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1405 return WERR_INVALID_PARAMETER;
1408 drivername = *pdrivername;
1410 if (mapfile[0] == '\0') {
1411 return WERR_BADFILE;
1414 if (strequal(drivername, get_win_driver())) {
1415 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1416 drivername, get_os2_driver()));
1417 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1418 if (drivername == NULL) {
1419 return WERR_NOMEM;
1421 *pdrivername = drivername;
1422 return WERR_OK;
1425 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1426 if (numlines == 0 || lines == NULL) {
1427 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1428 TALLOC_FREE(lines);
1429 return WERR_EMPTY;
1432 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1434 for( i = 0; i < numlines; i++) {
1435 char *nt_name = lines[i];
1436 char *os2_name = strchr(nt_name, '=');
1438 if (os2_name == NULL) {
1439 continue;
1442 *os2_name++ = '\0';
1444 while (isspace(*nt_name)) {
1445 nt_name++;
1448 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1449 continue;
1453 int l = strlen(nt_name);
1454 while (l && isspace(nt_name[l - 1])) {
1455 nt_name[l - 1] = 0;
1456 l--;
1460 while (isspace(*os2_name)) {
1461 os2_name++;
1465 int l = strlen(os2_name);
1466 while (l && isspace(os2_name[l-1])) {
1467 os2_name[l-1] = 0;
1468 l--;
1472 if (strequal(nt_name, drivername)) {
1473 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1474 set_driver_mapping(drivername, os2_name);
1475 drivername = talloc_strdup(mem_ctx, os2_name);
1476 TALLOC_FREE(lines);
1477 if (drivername == NULL) {
1478 return WERR_NOMEM;
1480 *pdrivername = drivername;
1481 return WERR_OK;
1485 TALLOC_FREE(lines);
1486 return WERR_OK;
1489 /****************************************************************************
1490 ****************************************************************************/
1492 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1493 struct spoolss_DriverInfo8 *_info8)
1495 struct spoolss_DriverInfo8 info8;
1497 ZERO_STRUCT(info8);
1499 switch (r->level) {
1500 case 3:
1501 info8.version = r->info.info3->version;
1502 info8.driver_name = r->info.info3->driver_name;
1503 info8.architecture = r->info.info3->architecture;
1504 info8.driver_path = r->info.info3->driver_path;
1505 info8.data_file = r->info.info3->data_file;
1506 info8.config_file = r->info.info3->config_file;
1507 info8.help_file = r->info.info3->help_file;
1508 info8.monitor_name = r->info.info3->monitor_name;
1509 info8.default_datatype = r->info.info3->default_datatype;
1510 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1511 info8.dependent_files = r->info.info3->dependent_files->string;
1513 break;
1514 case 6:
1515 info8.version = r->info.info6->version;
1516 info8.driver_name = r->info.info6->driver_name;
1517 info8.architecture = r->info.info6->architecture;
1518 info8.driver_path = r->info.info6->driver_path;
1519 info8.data_file = r->info.info6->data_file;
1520 info8.config_file = r->info.info6->config_file;
1521 info8.help_file = r->info.info6->help_file;
1522 info8.monitor_name = r->info.info6->monitor_name;
1523 info8.default_datatype = r->info.info6->default_datatype;
1524 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1525 info8.dependent_files = r->info.info6->dependent_files->string;
1527 info8.driver_date = r->info.info6->driver_date;
1528 info8.driver_version = r->info.info6->driver_version;
1529 info8.manufacturer_name = r->info.info6->manufacturer_name;
1530 info8.manufacturer_url = r->info.info6->manufacturer_url;
1531 info8.hardware_id = r->info.info6->hardware_id;
1532 info8.provider = r->info.info6->provider;
1533 break;
1534 case 8:
1535 info8.version = r->info.info8->version;
1536 info8.driver_name = r->info.info8->driver_name;
1537 info8.architecture = r->info.info8->architecture;
1538 info8.driver_path = r->info.info8->driver_path;
1539 info8.data_file = r->info.info8->data_file;
1540 info8.config_file = r->info.info8->config_file;
1541 info8.help_file = r->info.info8->help_file;
1542 info8.monitor_name = r->info.info8->monitor_name;
1543 info8.default_datatype = r->info.info8->default_datatype;
1544 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1545 info8.dependent_files = r->info.info8->dependent_files->string;
1547 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1548 info8.previous_names = r->info.info8->previous_names->string;
1550 info8.driver_date = r->info.info8->driver_date;
1551 info8.driver_version = r->info.info8->driver_version;
1552 info8.manufacturer_name = r->info.info8->manufacturer_name;
1553 info8.manufacturer_url = r->info.info8->manufacturer_url;
1554 info8.hardware_id = r->info.info8->hardware_id;
1555 info8.provider = r->info.info8->provider;
1556 info8.print_processor = r->info.info8->print_processor;
1557 info8.vendor_setup = r->info.info8->vendor_setup;
1558 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1559 info8.color_profiles = r->info.info8->color_profiles->string;
1561 info8.inf_path = r->info.info8->inf_path;
1562 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1563 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1564 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1566 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1567 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1568 break;
1569 default:
1570 return false;
1573 *_info8 = info8;
1575 return true;
1579 /****************************************************************************
1580 Determine whether or not a particular driver is currently assigned
1581 to a printer
1582 ****************************************************************************/
1584 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1585 const struct auth_serversupplied_info *session_info,
1586 struct messaging_context *msg_ctx,
1587 const struct spoolss_DriverInfo8 *r)
1589 int snum;
1590 int n_services = lp_numservices();
1591 bool in_use = False;
1592 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1593 WERROR result;
1595 if (!r) {
1596 return false;
1599 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1601 /* loop through the printers.tdb and check for the drivername */
1603 for (snum=0; snum<n_services && !in_use; snum++) {
1604 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1605 continue;
1608 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
1609 lp_servicename(snum),
1610 &pinfo2);
1611 if (!W_ERROR_IS_OK(result)) {
1612 continue; /* skip */
1615 if (strequal(r->driver_name, pinfo2->drivername)) {
1616 in_use = True;
1619 TALLOC_FREE(pinfo2);
1622 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1624 if ( in_use ) {
1625 struct spoolss_DriverInfo8 *driver;
1626 WERROR werr;
1628 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1630 /* we can still remove the driver if there is one of
1631 "Windows NT x86" version 2 or 3 left */
1633 if (!strequal("Windows NT x86", r->architecture)) {
1634 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1635 "Windows NT x86",
1636 r->driver_name,
1637 DRIVER_ANY_VERSION,
1638 &driver);
1639 } else if (r->version == 2) {
1640 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1641 "Windows NT x86",
1642 r->driver_name,
1643 3, &driver);
1644 } else if (r->version == 3) {
1645 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1646 "Windows NT x86",
1647 r->driver_name,
1648 2, &driver);
1649 } else {
1650 DEBUG(0, ("printer_driver_in_use: ERROR!"
1651 " unknown driver version (%d)\n",
1652 r->version));
1653 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1656 /* now check the error code */
1658 if ( W_ERROR_IS_OK(werr) ) {
1659 /* it's ok to remove the driver, we have other architctures left */
1660 in_use = False;
1661 talloc_free(driver);
1665 /* report that the driver is not in use by default */
1667 return in_use;
1671 /**********************************************************************
1672 Check to see if a ogiven file is in use by *info
1673 *********************************************************************/
1675 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1677 int i = 0;
1679 if ( !info )
1680 return False;
1682 /* mz: skip files that are in the list but already deleted */
1683 if (!file || !file[0]) {
1684 return false;
1687 if (strequal(file, info->driver_path))
1688 return True;
1690 if (strequal(file, info->data_file))
1691 return True;
1693 if (strequal(file, info->config_file))
1694 return True;
1696 if (strequal(file, info->help_file))
1697 return True;
1699 /* see of there are any dependent files to examine */
1701 if (!info->dependent_files)
1702 return False;
1704 while (info->dependent_files[i] && *info->dependent_files[i]) {
1705 if (strequal(file, info->dependent_files[i]))
1706 return True;
1707 i++;
1710 return False;
1714 /**********************************************************************
1715 Utility function to remove the dependent file pointed to by the
1716 input parameter from the list
1717 *********************************************************************/
1719 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1722 /* bump everything down a slot */
1724 while (files && files[idx+1]) {
1725 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1726 idx++;
1729 files[idx] = NULL;
1731 return;
1734 /**********************************************************************
1735 Check if any of the files used by src are also used by drv
1736 *********************************************************************/
1738 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1739 struct spoolss_DriverInfo8 *src,
1740 const struct spoolss_DriverInfo8 *drv)
1742 bool in_use = False;
1743 int i = 0;
1745 if ( !src || !drv )
1746 return False;
1748 /* check each file. Remove it from the src structure if it overlaps */
1750 if (drv_file_in_use(src->driver_path, drv)) {
1751 in_use = True;
1752 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1753 src->driver_path = talloc_strdup(mem_ctx, "");
1754 if (!src->driver_path) { return false; }
1757 if (drv_file_in_use(src->data_file, drv)) {
1758 in_use = True;
1759 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1760 src->data_file = talloc_strdup(mem_ctx, "");
1761 if (!src->data_file) { return false; }
1764 if (drv_file_in_use(src->config_file, drv)) {
1765 in_use = True;
1766 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1767 src->config_file = talloc_strdup(mem_ctx, "");
1768 if (!src->config_file) { return false; }
1771 if (drv_file_in_use(src->help_file, drv)) {
1772 in_use = True;
1773 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1774 src->help_file = talloc_strdup(mem_ctx, "");
1775 if (!src->help_file) { return false; }
1778 /* are there any dependentfiles to examine? */
1780 if (!src->dependent_files)
1781 return in_use;
1783 while (src->dependent_files[i] && *src->dependent_files[i]) {
1784 if (drv_file_in_use(src->dependent_files[i], drv)) {
1785 in_use = True;
1786 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1787 trim_dependent_file(mem_ctx, src->dependent_files, i);
1788 } else
1789 i++;
1792 return in_use;
1795 /****************************************************************************
1796 Determine whether or not a particular driver files are currently being
1797 used by any other driver.
1799 Return value is True if any files were in use by other drivers
1800 and False otherwise.
1802 Upon return, *info has been modified to only contain the driver files
1803 which are not in use
1805 Fix from mz:
1807 This needs to check all drivers to ensure that all files in use
1808 have been removed from *info, not just the ones in the first
1809 match.
1810 ****************************************************************************/
1812 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1813 const struct auth_serversupplied_info *session_info,
1814 struct messaging_context *msg_ctx,
1815 struct spoolss_DriverInfo8 *info)
1817 int i;
1818 uint32 version;
1819 struct spoolss_DriverInfo8 *driver;
1820 bool in_use = false;
1821 uint32_t num_drivers;
1822 const char **drivers;
1823 WERROR result;
1825 if ( !info )
1826 return False;
1828 version = info->version;
1830 /* loop over all driver versions */
1832 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1834 /* get the list of drivers */
1836 result = winreg_get_driver_list(mem_ctx, session_info, msg_ctx,
1837 info->architecture, version,
1838 &num_drivers, &drivers);
1839 if (!W_ERROR_IS_OK(result)) {
1840 return true;
1843 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1844 num_drivers, info->architecture, version));
1846 /* check each driver for overlap in files */
1848 for (i = 0; i < num_drivers; i++) {
1849 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1851 driver = NULL;
1853 result = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1854 info->architecture, drivers[i],
1855 version, &driver);
1856 if (!W_ERROR_IS_OK(result)) {
1857 talloc_free(drivers);
1858 return True;
1861 /* check if d2 uses any files from d1 */
1862 /* only if this is a different driver than the one being deleted */
1864 if (!strequal(info->driver_name, driver->driver_name)) {
1865 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1866 /* mz: Do not instantly return -
1867 * we need to ensure this file isn't
1868 * also in use by other drivers. */
1869 in_use = true;
1873 talloc_free(driver);
1876 talloc_free(drivers);
1878 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1880 return in_use;
1883 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1884 const char *name)
1886 struct smb_filename *smb_fname = NULL;
1887 NTSTATUS status;
1889 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1890 &smb_fname);
1891 if (!NT_STATUS_IS_OK(status)) {
1892 return status;
1895 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1897 TALLOC_FREE(smb_fname);
1898 return status;
1901 /****************************************************************************
1902 Actually delete the driver files. Make sure that
1903 printer_driver_files_in_use() return False before calling
1904 this.
1905 ****************************************************************************/
1907 bool delete_driver_files(const struct auth_serversupplied_info *session_info,
1908 const struct spoolss_DriverInfo8 *r)
1910 int i = 0;
1911 char *s;
1912 const char *file;
1913 connection_struct *conn;
1914 NTSTATUS nt_status;
1915 char *oldcwd;
1916 char *printdollar = NULL;
1917 int printdollar_snum;
1918 bool ret = false;
1920 if (!r) {
1921 return false;
1924 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1925 r->driver_name, r->version));
1927 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1928 if (!printdollar) {
1929 return false;
1931 if (printdollar_snum == -1) {
1932 return false;
1935 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1936 lp_pathname(printdollar_snum),
1937 session_info, &oldcwd);
1938 if (!NT_STATUS_IS_OK(nt_status)) {
1939 DEBUG(0,("delete_driver_files: create_conn_struct "
1940 "returned %s\n", nt_errstr(nt_status)));
1941 return false;
1944 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1945 if (!NT_STATUS_IS_OK(nt_status)) {
1946 DEBUG(0, ("failed set force user / group\n"));
1947 ret = false;
1948 goto err_free_conn;
1951 if (!become_user_by_session(conn, session_info)) {
1952 DEBUG(0, ("failed to become user\n"));
1953 ret = false;
1954 goto err_free_conn;
1957 if ( !CAN_WRITE(conn) ) {
1958 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1959 ret = false;
1960 goto err_out;
1963 /* now delete the files; must strip the '\print$' string from
1964 fron of path */
1966 if (r->driver_path && r->driver_path[0]) {
1967 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1968 file = s;
1969 DEBUG(10,("deleting driverfile [%s]\n", s));
1970 driver_unlink_internals(conn, file);
1974 if (r->config_file && r->config_file[0]) {
1975 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1976 file = s;
1977 DEBUG(10,("deleting configfile [%s]\n", s));
1978 driver_unlink_internals(conn, file);
1982 if (r->data_file && r->data_file[0]) {
1983 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1984 file = s;
1985 DEBUG(10,("deleting datafile [%s]\n", s));
1986 driver_unlink_internals(conn, file);
1990 if (r->help_file && r->help_file[0]) {
1991 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1992 file = s;
1993 DEBUG(10,("deleting helpfile [%s]\n", s));
1994 driver_unlink_internals(conn, file);
1998 /* check if we are done removing files */
2000 if (r->dependent_files) {
2001 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2002 char *p;
2004 /* bypass the "\print$" portion of the path */
2006 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
2007 file = p;
2008 DEBUG(10,("deleting dependent file [%s]\n", file));
2009 driver_unlink_internals(conn, file);
2012 i++;
2016 ret = true;
2017 err_out:
2018 unbecome_user();
2019 err_free_conn:
2020 if (conn != NULL) {
2021 vfs_ChDir(conn, oldcwd);
2022 SMB_VFS_DISCONNECT(conn);
2023 conn_free(conn);
2025 return ret;
2028 /* error code:
2029 0: everything OK
2030 1: level not implemented
2031 2: file doesn't exist
2032 3: can't allocate memory
2033 4: can't free memory
2034 5: non existant struct
2038 A printer and a printer driver are 2 different things.
2039 NT manages them separatelly, Samba does the same.
2040 Why ? Simply because it's easier and it makes sense !
2042 Now explanation: You have 3 printers behind your samba server,
2043 2 of them are the same make and model (laser A and B). But laser B
2044 has an 3000 sheet feeder and laser A doesn't such an option.
2045 Your third printer is an old dot-matrix model for the accounting :-).
2047 If the /usr/local/samba/lib directory (default dir), you will have
2048 5 files to describe all of this.
2050 3 files for the printers (1 by printer):
2051 NTprinter_laser A
2052 NTprinter_laser B
2053 NTprinter_accounting
2054 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2055 NTdriver_printer model X
2056 NTdriver_printer model Y
2058 jfm: I should use this comment for the text file to explain
2059 same thing for the forms BTW.
2060 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2064 /* Convert generic access rights to printer object specific access rights.
2065 It turns out that NT4 security descriptors use generic access rights and
2066 NT5 the object specific ones. */
2068 void map_printer_permissions(struct security_descriptor *sd)
2070 int i;
2072 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2073 se_map_generic(&sd->dacl->aces[i].access_mask,
2074 &printer_generic_mapping);
2078 void map_job_permissions(struct security_descriptor *sd)
2080 int i;
2082 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2083 se_map_generic(&sd->dacl->aces[i].access_mask,
2084 &job_generic_mapping);
2089 /****************************************************************************
2090 Check a user has permissions to perform the given operation. We use the
2091 permission constants defined in include/rpc_spoolss.h to check the various
2092 actions we perform when checking printer access.
2094 PRINTER_ACCESS_ADMINISTER:
2095 print_queue_pause, print_queue_resume, update_printer_sec,
2096 update_printer, spoolss_addprinterex_level_2,
2097 _spoolss_setprinterdata
2099 PRINTER_ACCESS_USE:
2100 print_job_start
2102 JOB_ACCESS_ADMINISTER:
2103 print_job_delete, print_job_pause, print_job_resume,
2104 print_queue_purge
2106 Try access control in the following order (for performance reasons):
2107 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2108 2) check security descriptor (bit comparisons in memory)
2109 3) "printer admins" (may result in numerous calls to winbind)
2111 ****************************************************************************/
2112 bool print_access_check(const struct auth_serversupplied_info *session_info,
2113 struct messaging_context *msg_ctx, int snum,
2114 int access_type)
2116 struct spoolss_security_descriptor *secdesc = NULL;
2117 uint32 access_granted;
2118 size_t sd_size;
2119 NTSTATUS status;
2120 WERROR result;
2121 const char *pname;
2122 TALLOC_CTX *mem_ctx = NULL;
2124 /* If user is NULL then use the current_user structure */
2126 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2128 if (session_info->utok.uid == sec_initial_uid()
2129 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
2130 return True;
2133 /* Get printer name */
2135 pname = lp_printername(snum);
2137 if (!pname || !*pname) {
2138 errno = EACCES;
2139 return False;
2142 /* Get printer security descriptor */
2144 if(!(mem_ctx = talloc_init("print_access_check"))) {
2145 errno = ENOMEM;
2146 return False;
2149 result = winreg_get_printer_secdesc(mem_ctx,
2150 get_session_info_system(),
2151 msg_ctx,
2152 pname,
2153 &secdesc);
2154 if (!W_ERROR_IS_OK(result)) {
2155 talloc_destroy(mem_ctx);
2156 errno = ENOMEM;
2157 return False;
2160 if (access_type == JOB_ACCESS_ADMINISTER) {
2161 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2163 /* Create a child security descriptor to check permissions
2164 against. This is because print jobs are child objects
2165 objects of a printer. */
2166 status = se_create_child_secdesc(mem_ctx,
2167 &secdesc,
2168 &sd_size,
2169 parent_secdesc,
2170 parent_secdesc->owner_sid,
2171 parent_secdesc->group_sid,
2172 false);
2173 if (!NT_STATUS_IS_OK(status)) {
2174 talloc_destroy(mem_ctx);
2175 errno = map_errno_from_nt_status(status);
2176 return False;
2179 map_job_permissions(secdesc);
2180 } else {
2181 map_printer_permissions(secdesc);
2184 /* Check access */
2185 status = se_access_check(secdesc, session_info->security_token, access_type,
2186 &access_granted);
2188 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2190 /* see if we need to try the printer admin list */
2192 if (!NT_STATUS_IS_OK(status) &&
2193 (token_contains_name_in_list(uidtoname(session_info->utok.uid),
2194 session_info->info3->base.domain.string,
2195 NULL, session_info->security_token,
2196 lp_printer_admin(snum)))) {
2197 talloc_destroy(mem_ctx);
2198 return True;
2201 talloc_destroy(mem_ctx);
2203 if (!NT_STATUS_IS_OK(status)) {
2204 errno = EACCES;
2207 return NT_STATUS_IS_OK(status);
2210 /****************************************************************************
2211 Check the time parameters allow a print operation.
2212 *****************************************************************************/
2214 bool print_time_access_check(const struct auth_serversupplied_info *session_info,
2215 struct messaging_context *msg_ctx,
2216 const char *servicename)
2218 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2219 WERROR result;
2220 bool ok = False;
2221 time_t now = time(NULL);
2222 struct tm *t;
2223 uint32 mins;
2225 result = winreg_get_printer(NULL, session_info, msg_ctx,
2226 servicename, &pinfo2);
2227 if (!W_ERROR_IS_OK(result)) {
2228 return False;
2231 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2232 ok = True;
2235 t = gmtime(&now);
2236 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2238 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2239 ok = True;
2242 TALLOC_FREE(pinfo2);
2244 if (!ok) {
2245 errno = EACCES;
2248 return ok;
2251 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2252 const struct auth_serversupplied_info *session_info,
2253 struct messaging_context *msg_ctx,
2254 const char *printer)
2256 WERROR result;
2258 result = winreg_delete_printer_key(mem_ctx, session_info, msg_ctx,
2259 printer, "");
2260 if (!W_ERROR_IS_OK(result)) {
2261 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2262 printer));