s3:vfs_commit: fix build
[Samba.git] / source3 / printing / nt_printing.c
blob6d4bebbdf5776d95176a5e3835d5e2e9fc167087
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "auth.h"
33 #include "messages.h"
34 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 /* Map generic permissions to printer object specific permissions */
38 const struct generic_mapping printer_generic_mapping = {
39 PRINTER_READ,
40 PRINTER_WRITE,
41 PRINTER_EXECUTE,
42 PRINTER_ALL_ACCESS
45 /* Map generic permissions to print server object specific permissions */
47 const struct generic_mapping printserver_generic_mapping = {
48 SERVER_READ,
49 SERVER_WRITE,
50 SERVER_EXECUTE,
51 SERVER_ALL_ACCESS
54 /* Map generic permissions to job object specific permissions */
56 const struct generic_mapping job_generic_mapping = {
57 JOB_READ,
58 JOB_WRITE,
59 JOB_EXECUTE,
60 JOB_ALL_ACCESS
63 static const struct print_architecture_table_node archi_table[]= {
65 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
66 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
67 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
68 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
69 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
70 {"Windows IA64", SPL_ARCH_IA64, 3 },
71 {"Windows x64", SPL_ARCH_X64, 3 },
72 {NULL, "", -1 }
75 /****************************************************************************
76 Open the NT printing tdbs. Done once before fork().
77 ****************************************************************************/
79 bool nt_printing_init(struct messaging_context *msg_ctx)
81 WERROR win_rc;
83 if (!nt_printing_tdb_upgrade()) {
84 return false;
88 * register callback to handle updating printers as new
89 * drivers are installed
91 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
92 do_drv_upgrade_printer);
94 /* of course, none of the message callbacks matter if you don't
95 tell messages.c that you interested in receiving PRINT_GENERAL
96 msgs. This is done in serverid_register() */
98 if ( lp_security() == SEC_ADS ) {
99 win_rc = check_published_printers(msg_ctx);
100 if (!W_ERROR_IS_OK(win_rc))
101 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
104 return true;
107 /*******************************************************************
108 Function to allow filename parsing "the old way".
109 ********************************************************************/
111 static NTSTATUS driver_unix_convert(connection_struct *conn,
112 const char *old_name,
113 struct smb_filename **smb_fname)
115 NTSTATUS status;
116 TALLOC_CTX *ctx = talloc_tos();
117 char *name = talloc_strdup(ctx, old_name);
119 if (!name) {
120 return NT_STATUS_NO_MEMORY;
122 unix_format(name);
123 name = unix_clean_name(ctx, name);
124 if (!name) {
125 return NT_STATUS_NO_MEMORY;
127 trim_string(name,"/","/");
129 status = unix_convert(ctx, conn, name, smb_fname, 0);
130 if (!NT_STATUS_IS_OK(status)) {
131 return NT_STATUS_NO_MEMORY;
134 return NT_STATUS_OK;
137 /****************************************************************************
138 Function to do the mapping between the long architecture name and
139 the short one.
140 ****************************************************************************/
142 const char *get_short_archi(const char *long_archi)
144 int i=-1;
146 DEBUG(107,("Getting architecture dependent directory\n"));
147 do {
148 i++;
149 } while ( (archi_table[i].long_archi!=NULL ) &&
150 StrCaseCmp(long_archi, archi_table[i].long_archi) );
152 if (archi_table[i].long_archi==NULL) {
153 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
154 return NULL;
157 /* this might be client code - but shouldn't this be an fstrcpy etc? */
159 DEBUGADD(108,("index: [%d]\n", i));
160 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
161 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
163 return archi_table[i].short_archi;
166 /****************************************************************************
167 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
168 There are two case to be covered here: PE (Portable Executable) and NE (New
169 Executable) files. Both files support the same INFO structure, but PE files
170 store the signature in unicode, and NE files store it as !unicode.
171 returns -1 on error, 1 on version info found, and 0 on no version info found.
172 ****************************************************************************/
174 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
176 int i;
177 char *buf = NULL;
178 ssize_t byte_count;
180 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
181 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
182 fname, DOS_HEADER_SIZE));
183 goto error_exit;
186 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
187 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
188 fname, (unsigned long)byte_count));
189 goto no_version_info;
192 /* Is this really a DOS header? */
193 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
194 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
195 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
196 goto no_version_info;
199 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
200 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
201 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
202 fname, errno));
203 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
204 goto no_version_info;
207 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
208 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
209 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
210 fname, (unsigned long)byte_count));
211 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
212 goto no_version_info;
215 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
216 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
217 unsigned int num_sections;
218 unsigned int section_table_bytes;
220 /* Just skip over optional header to get to section table */
221 if (SMB_VFS_LSEEK(fsp,
222 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
223 SEEK_CUR) == (SMB_OFF_T)-1) {
224 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
225 fname, errno));
226 goto error_exit;
229 /* get the section table */
230 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
231 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
232 if (section_table_bytes == 0)
233 goto error_exit;
235 SAFE_FREE(buf);
236 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
237 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
238 fname, section_table_bytes));
239 goto error_exit;
242 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
243 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
244 fname, (unsigned long)byte_count));
245 goto error_exit;
248 /* Iterate the section table looking for the resource section ".rsrc" */
249 for (i = 0; i < num_sections; i++) {
250 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
252 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
253 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
254 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
256 if (section_bytes == 0)
257 goto error_exit;
259 SAFE_FREE(buf);
260 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
261 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
262 fname, section_bytes));
263 goto error_exit;
266 /* Seek to the start of the .rsrc section info */
267 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
268 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
269 fname, errno));
270 goto error_exit;
273 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
274 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
275 fname, (unsigned long)byte_count));
276 goto error_exit;
279 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
280 goto error_exit;
282 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
283 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
284 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
285 /* Align to next long address */
286 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
288 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
289 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
290 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
292 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
293 fname, *major, *minor,
294 (*major>>16)&0xffff, *major&0xffff,
295 (*minor>>16)&0xffff, *minor&0xffff));
296 SAFE_FREE(buf);
297 return 1;
304 /* Version info not found, fall back to origin date/time */
305 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
306 SAFE_FREE(buf);
307 return 0;
309 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
310 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
311 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
312 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
313 /* At this point, we assume the file is in error. It still could be somthing
314 * else besides a NE file, but it unlikely at this point. */
315 goto error_exit;
318 /* Allocate a bit more space to speed up things */
319 SAFE_FREE(buf);
320 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
321 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
322 fname, PE_HEADER_SIZE));
323 goto error_exit;
326 /* This is a HACK! I got tired of trying to sort through the messy
327 * 'NE' file format. If anyone wants to clean this up please have at
328 * it, but this works. 'NE' files will eventually fade away. JRR */
329 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
330 /* Cover case that should not occur in a well formed 'NE' .dll file */
331 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
333 for(i=0; i<byte_count; i++) {
334 /* Fast skip past data that can't possibly match */
335 if (buf[i] != 'V') continue;
337 /* Potential match data crosses buf boundry, move it to beginning
338 * of buf, and fill the buf with as much as it will hold. */
339 if (i>byte_count-VS_VERSION_INFO_SIZE) {
340 int bc;
342 memcpy(buf, &buf[i], byte_count-i);
343 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
344 (byte_count-i))) < 0) {
346 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
347 fname, errno));
348 goto error_exit;
351 byte_count = bc + (byte_count - i);
352 if (byte_count<VS_VERSION_INFO_SIZE) break;
354 i = 0;
357 /* Check that the full signature string and the magic number that
358 * follows exist (not a perfect solution, but the chances that this
359 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
360 * twice, as it is simpler to read the code. */
361 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
362 /* Compute skip alignment to next long address */
363 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
364 sizeof(VS_SIGNATURE)) & 3;
365 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
367 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
368 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
369 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
370 fname, *major, *minor,
371 (*major>>16)&0xffff, *major&0xffff,
372 (*minor>>16)&0xffff, *minor&0xffff));
373 SAFE_FREE(buf);
374 return 1;
379 /* Version info not found, fall back to origin date/time */
380 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
381 SAFE_FREE(buf);
382 return 0;
384 } else
385 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
386 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
387 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
389 no_version_info:
390 SAFE_FREE(buf);
391 return 0;
393 error_exit:
394 SAFE_FREE(buf);
395 return -1;
398 /****************************************************************************
399 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
400 share one or more files. During the MS installation process files are checked
401 to insure that only a newer version of a shared file is installed over an
402 older version. There are several possibilities for this comparison. If there
403 is no previous version, the new one is newer (obviously). If either file is
404 missing the version info structure, compare the creation date (on Unix use
405 the modification date). Otherwise chose the numerically larger version number.
406 ****************************************************************************/
408 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
410 bool use_version = true;
412 uint32 new_major;
413 uint32 new_minor;
414 time_t new_create_time;
416 uint32 old_major;
417 uint32 old_minor;
418 time_t old_create_time;
420 struct smb_filename *smb_fname = NULL;
421 files_struct *fsp = NULL;
422 SMB_STRUCT_STAT st;
424 NTSTATUS status;
425 int ret;
427 SET_STAT_INVALID(st);
428 new_create_time = (time_t)0;
429 old_create_time = (time_t)0;
431 /* Get file version info (if available) for previous file (if it exists) */
432 status = driver_unix_convert(conn, old_file, &smb_fname);
433 if (!NT_STATUS_IS_OK(status)) {
434 goto error_exit;
437 status = SMB_VFS_CREATE_FILE(
438 conn, /* conn */
439 NULL, /* req */
440 0, /* root_dir_fid */
441 smb_fname, /* fname */
442 FILE_GENERIC_READ, /* access_mask */
443 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
444 FILE_OPEN, /* create_disposition*/
445 0, /* create_options */
446 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
447 INTERNAL_OPEN_ONLY, /* oplock_request */
448 0, /* allocation_size */
449 0, /* private_flags */
450 NULL, /* sd */
451 NULL, /* ea_list */
452 &fsp, /* result */
453 NULL); /* pinfo */
455 if (!NT_STATUS_IS_OK(status)) {
456 /* Old file not found, so by definition new file is in fact newer */
457 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
458 "errno = %d\n", smb_fname_str_dbg(smb_fname),
459 errno));
460 ret = 1;
461 goto done;
463 } else {
464 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
465 if (ret == -1) {
466 goto error_exit;
469 if (!ret) {
470 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
471 old_file));
472 use_version = false;
473 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
474 goto error_exit;
476 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
477 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
478 (long)old_create_time));
481 close_file(NULL, fsp, NORMAL_CLOSE);
482 fsp = NULL;
484 /* Get file version info (if available) for new file */
485 status = driver_unix_convert(conn, new_file, &smb_fname);
486 if (!NT_STATUS_IS_OK(status)) {
487 goto error_exit;
490 status = SMB_VFS_CREATE_FILE(
491 conn, /* conn */
492 NULL, /* req */
493 0, /* root_dir_fid */
494 smb_fname, /* fname */
495 FILE_GENERIC_READ, /* access_mask */
496 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
497 FILE_OPEN, /* create_disposition*/
498 0, /* create_options */
499 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
500 INTERNAL_OPEN_ONLY, /* oplock_request */
501 0, /* allocation_size */
502 0, /* private_flags */
503 NULL, /* sd */
504 NULL, /* ea_list */
505 &fsp, /* result */
506 NULL); /* pinfo */
508 if (!NT_STATUS_IS_OK(status)) {
509 /* New file not found, this shouldn't occur if the caller did its job */
510 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
511 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
512 goto error_exit;
514 } else {
515 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
516 if (ret == -1) {
517 goto error_exit;
520 if (!ret) {
521 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
522 new_file));
523 use_version = false;
524 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
525 goto error_exit;
527 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
528 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
529 (long)new_create_time));
532 close_file(NULL, fsp, NORMAL_CLOSE);
533 fsp = NULL;
535 if (use_version && (new_major != old_major || new_minor != old_minor)) {
536 /* Compare versions and choose the larger version number */
537 if (new_major > old_major ||
538 (new_major == old_major && new_minor > old_minor)) {
540 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
541 ret = 1;
542 goto done;
544 else {
545 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
546 ret = 0;
547 goto done;
550 } else {
551 /* Compare modification time/dates and choose the newest time/date */
552 if (new_create_time > old_create_time) {
553 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
554 ret = 1;
555 goto done;
557 else {
558 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
559 ret = 0;
560 goto done;
564 error_exit:
565 if(fsp)
566 close_file(NULL, fsp, NORMAL_CLOSE);
567 ret = -1;
568 done:
569 TALLOC_FREE(smb_fname);
570 return ret;
573 /****************************************************************************
574 Determine the correct cVersion associated with an architecture and driver
575 ****************************************************************************/
576 static uint32 get_correct_cversion(struct auth_serversupplied_info *session_info,
577 const char *architecture,
578 const char *driverpath_in,
579 WERROR *perr)
581 int cversion = -1;
582 NTSTATUS nt_status;
583 struct smb_filename *smb_fname = NULL;
584 char *driverpath = NULL;
585 files_struct *fsp = NULL;
586 connection_struct *conn = NULL;
587 char *oldcwd;
588 char *printdollar = NULL;
589 int printdollar_snum;
591 *perr = WERR_INVALID_PARAM;
593 /* If architecture is Windows 95/98/ME, the version is always 0. */
594 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
595 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
596 *perr = WERR_OK;
597 return 0;
600 /* If architecture is Windows x64, the version is always 3. */
601 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
602 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
603 *perr = WERR_OK;
604 return 3;
607 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
608 if (!printdollar) {
609 *perr = WERR_NOMEM;
610 return -1;
612 if (printdollar_snum == -1) {
613 *perr = WERR_NO_SUCH_SHARE;
614 return -1;
617 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
618 lp_pathname(printdollar_snum),
619 session_info, &oldcwd);
620 if (!NT_STATUS_IS_OK(nt_status)) {
621 DEBUG(0,("get_correct_cversion: create_conn_struct "
622 "returned %s\n", nt_errstr(nt_status)));
623 *perr = ntstatus_to_werror(nt_status);
624 return -1;
627 nt_status = set_conn_force_user_group(conn, printdollar_snum);
628 if (!NT_STATUS_IS_OK(nt_status)) {
629 DEBUG(0, ("failed set force user / group\n"));
630 *perr = ntstatus_to_werror(nt_status);
631 goto error_free_conn;
634 if (!become_user_by_session(conn, session_info)) {
635 DEBUG(0, ("failed to become user\n"));
636 *perr = WERR_ACCESS_DENIED;
637 goto error_free_conn;
640 /* Open the driver file (Portable Executable format) and determine the
641 * deriver the cversion. */
642 driverpath = talloc_asprintf(talloc_tos(),
643 "%s/%s",
644 architecture,
645 driverpath_in);
646 if (!driverpath) {
647 *perr = WERR_NOMEM;
648 goto error_exit;
651 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
652 if (!NT_STATUS_IS_OK(nt_status)) {
653 *perr = ntstatus_to_werror(nt_status);
654 goto error_exit;
657 nt_status = vfs_file_exist(conn, smb_fname);
658 if (!NT_STATUS_IS_OK(nt_status)) {
659 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
660 *perr = WERR_BADFILE;
661 goto error_exit;
664 nt_status = SMB_VFS_CREATE_FILE(
665 conn, /* conn */
666 NULL, /* req */
667 0, /* root_dir_fid */
668 smb_fname, /* fname */
669 FILE_GENERIC_READ, /* access_mask */
670 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
671 FILE_OPEN, /* create_disposition*/
672 0, /* create_options */
673 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
674 INTERNAL_OPEN_ONLY, /* oplock_request */
675 0, /* private_flags */
676 0, /* allocation_size */
677 NULL, /* sd */
678 NULL, /* ea_list */
679 &fsp, /* result */
680 NULL); /* pinfo */
682 if (!NT_STATUS_IS_OK(nt_status)) {
683 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
684 "%d\n", smb_fname_str_dbg(smb_fname), errno));
685 *perr = WERR_ACCESS_DENIED;
686 goto error_exit;
687 } else {
688 uint32 major;
689 uint32 minor;
690 int ret;
692 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
693 if (ret == -1) {
694 *perr = WERR_INVALID_PARAM;
695 goto error_exit;
696 } else if (!ret) {
697 DEBUG(6,("get_correct_cversion: Version info not "
698 "found [%s]\n",
699 smb_fname_str_dbg(smb_fname)));
700 *perr = WERR_INVALID_PARAM;
701 goto error_exit;
705 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
706 * for more details. Version in this case is not just the version of the
707 * file, but the version in the sense of kernal mode (2) vs. user mode
708 * (3) drivers. Other bits of the version fields are the version info.
709 * JRR 010716
711 cversion = major & 0x0000ffff;
712 switch (cversion) {
713 case 2: /* WinNT drivers */
714 case 3: /* Win2K drivers */
715 break;
717 default:
718 DEBUG(6,("get_correct_cversion: cversion "
719 "invalid [%s] cversion = %d\n",
720 smb_fname_str_dbg(smb_fname),
721 cversion));
722 goto error_exit;
725 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
726 " = 0x%x minor = 0x%x\n",
727 smb_fname_str_dbg(smb_fname), major, minor));
730 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
731 smb_fname_str_dbg(smb_fname), cversion));
732 *perr = WERR_OK;
734 error_exit:
735 unbecome_user();
736 error_free_conn:
737 TALLOC_FREE(smb_fname);
738 if (fsp != NULL) {
739 close_file(NULL, fsp, NORMAL_CLOSE);
741 if (conn != NULL) {
742 vfs_ChDir(conn, oldcwd);
743 SMB_VFS_DISCONNECT(conn);
744 conn_free(conn);
746 if (!NT_STATUS_IS_OK(*perr)) {
747 cversion = -1;
750 return cversion;
753 /****************************************************************************
754 ****************************************************************************/
756 #define strip_driver_path(_mem_ctx, _element) do { \
757 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
758 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
759 W_ERROR_HAVE_NO_MEMORY((_element)); \
761 } while (0);
763 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
764 struct auth_serversupplied_info *session_info,
765 const char *architecture,
766 const char **driver_path,
767 const char **data_file,
768 const char **config_file,
769 const char **help_file,
770 struct spoolss_StringArray *dependent_files,
771 enum spoolss_DriverOSVersion *version)
773 const char *short_architecture;
774 int i;
775 WERROR err;
776 char *_p;
778 if (!*driver_path || !*data_file) {
779 return WERR_INVALID_PARAM;
782 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
783 return WERR_INVALID_PARAM;
786 /* clean up the driver name.
787 * we can get .\driver.dll
788 * or worse c:\windows\system\driver.dll !
790 /* using an intermediate string to not have overlaping memcpy()'s */
792 strip_driver_path(mem_ctx, *driver_path);
793 strip_driver_path(mem_ctx, *data_file);
794 if (*config_file) {
795 strip_driver_path(mem_ctx, *config_file);
797 if (help_file) {
798 strip_driver_path(mem_ctx, *help_file);
801 if (dependent_files && dependent_files->string) {
802 for (i=0; dependent_files->string[i]; i++) {
803 strip_driver_path(mem_ctx, dependent_files->string[i]);
807 short_architecture = get_short_archi(architecture);
808 if (!short_architecture) {
809 return WERR_UNKNOWN_PRINTER_DRIVER;
812 /* jfm:7/16/2000 the client always sends the cversion=0.
813 * The server should check which version the driver is by reading
814 * the PE header of driver->driverpath.
816 * For Windows 95/98 the version is 0 (so the value sent is correct)
817 * For Windows NT (the architecture doesn't matter)
818 * NT 3.1: cversion=0
819 * NT 3.5/3.51: cversion=1
820 * NT 4: cversion=2
821 * NT2K: cversion=3
824 *version = get_correct_cversion(session_info, short_architecture,
825 *driver_path, &err);
826 if (*version == -1) {
827 return err;
830 return WERR_OK;
833 /****************************************************************************
834 ****************************************************************************/
836 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
837 struct auth_serversupplied_info *session_info,
838 struct spoolss_AddDriverInfoCtr *r)
840 switch (r->level) {
841 case 3:
842 return clean_up_driver_struct_level(mem_ctx, session_info,
843 r->info.info3->architecture,
844 &r->info.info3->driver_path,
845 &r->info.info3->data_file,
846 &r->info.info3->config_file,
847 &r->info.info3->help_file,
848 r->info.info3->dependent_files,
849 &r->info.info3->version);
850 case 6:
851 return clean_up_driver_struct_level(mem_ctx, session_info,
852 r->info.info6->architecture,
853 &r->info.info6->driver_path,
854 &r->info.info6->data_file,
855 &r->info.info6->config_file,
856 &r->info.info6->help_file,
857 r->info.info6->dependent_files,
858 &r->info.info6->version);
859 default:
860 return WERR_NOT_SUPPORTED;
864 /****************************************************************************
865 This function sucks and should be replaced. JRA.
866 ****************************************************************************/
868 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
869 const struct spoolss_AddDriverInfo6 *src)
871 dst->version = src->version;
873 dst->driver_name = src->driver_name;
874 dst->architecture = src->architecture;
875 dst->driver_path = src->driver_path;
876 dst->data_file = src->data_file;
877 dst->config_file = src->config_file;
878 dst->help_file = src->help_file;
879 dst->monitor_name = src->monitor_name;
880 dst->default_datatype = src->default_datatype;
881 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
882 dst->dependent_files = src->dependent_files;
885 /****************************************************************************
886 ****************************************************************************/
888 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
889 connection_struct *conn,
890 const char *driver_file,
891 const char *short_architecture,
892 uint32_t driver_version,
893 uint32_t version)
895 struct smb_filename *smb_fname_old = NULL;
896 struct smb_filename *smb_fname_new = NULL;
897 char *old_name = NULL;
898 char *new_name = NULL;
899 NTSTATUS status;
900 WERROR ret;
902 old_name = talloc_asprintf(mem_ctx, "%s/%s",
903 short_architecture, driver_file);
904 W_ERROR_HAVE_NO_MEMORY(old_name);
906 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
907 short_architecture, driver_version, driver_file);
908 if (new_name == NULL) {
909 TALLOC_FREE(old_name);
910 return WERR_NOMEM;
913 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
915 status = driver_unix_convert(conn, old_name, &smb_fname_old);
916 if (!NT_STATUS_IS_OK(status)) {
917 ret = WERR_NOMEM;
918 goto out;
921 /* Setup a synthetic smb_filename struct */
922 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
923 if (!smb_fname_new) {
924 ret = WERR_NOMEM;
925 goto out;
928 smb_fname_new->base_name = new_name;
930 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
931 "'%s'\n", smb_fname_old->base_name,
932 smb_fname_new->base_name));
934 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
935 OPENX_FILE_EXISTS_TRUNCATE |
936 OPENX_FILE_CREATE_IF_NOT_EXIST,
937 0, false);
939 if (!NT_STATUS_IS_OK(status)) {
940 DEBUG(0,("move_driver_file_to_download_area: Unable "
941 "to rename [%s] to [%s]: %s\n",
942 smb_fname_old->base_name, new_name,
943 nt_errstr(status)));
944 ret = WERR_ACCESS_DENIED;
945 goto out;
949 ret = WERR_OK;
950 out:
951 TALLOC_FREE(smb_fname_old);
952 TALLOC_FREE(smb_fname_new);
953 return ret;
956 WERROR move_driver_to_download_area(struct auth_serversupplied_info *session_info,
957 struct spoolss_AddDriverInfoCtr *r)
959 struct spoolss_AddDriverInfo3 *driver;
960 struct spoolss_AddDriverInfo3 converted_driver;
961 const char *short_architecture;
962 struct smb_filename *smb_dname = NULL;
963 char *new_dir = NULL;
964 connection_struct *conn = NULL;
965 NTSTATUS nt_status;
966 int i;
967 TALLOC_CTX *ctx = talloc_tos();
968 int ver = 0;
969 char *oldcwd;
970 char *printdollar = NULL;
971 int printdollar_snum;
972 WERROR err = WERR_OK;
974 switch (r->level) {
975 case 3:
976 driver = r->info.info3;
977 break;
978 case 6:
979 convert_level_6_to_level3(&converted_driver, r->info.info6);
980 driver = &converted_driver;
981 break;
982 default:
983 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
984 return WERR_UNKNOWN_LEVEL;
987 short_architecture = get_short_archi(driver->architecture);
988 if (!short_architecture) {
989 return WERR_UNKNOWN_PRINTER_DRIVER;
992 printdollar_snum = find_service(ctx, "print$", &printdollar);
993 if (!printdollar) {
994 return WERR_NOMEM;
996 if (printdollar_snum == -1) {
997 return WERR_NO_SUCH_SHARE;
1000 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1001 lp_pathname(printdollar_snum),
1002 session_info, &oldcwd);
1003 if (!NT_STATUS_IS_OK(nt_status)) {
1004 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1005 "returned %s\n", nt_errstr(nt_status)));
1006 err = ntstatus_to_werror(nt_status);
1007 return err;
1010 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1011 if (!NT_STATUS_IS_OK(nt_status)) {
1012 DEBUG(0, ("failed set force user / group\n"));
1013 err = ntstatus_to_werror(nt_status);
1014 goto err_free_conn;
1017 if (!become_user_by_session(conn, session_info)) {
1018 DEBUG(0, ("failed to become user\n"));
1019 err = WERR_ACCESS_DENIED;
1020 goto err_free_conn;
1023 new_dir = talloc_asprintf(ctx,
1024 "%s/%d",
1025 short_architecture,
1026 driver->version);
1027 if (!new_dir) {
1028 err = WERR_NOMEM;
1029 goto err_exit;
1031 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1032 if (!NT_STATUS_IS_OK(nt_status)) {
1033 err = WERR_NOMEM;
1034 goto err_exit;
1037 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1039 nt_status = create_directory(conn, NULL, smb_dname);
1040 if (!NT_STATUS_IS_OK(nt_status)
1041 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1042 DEBUG(0, ("failed to create driver destination directory: %s\n",
1043 nt_errstr(nt_status)));
1044 err = ntstatus_to_werror(nt_status);
1045 goto err_exit;
1048 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1049 * listed for this driver which has already been moved, skip it (note:
1050 * drivers may list the same file name several times. Then check if the
1051 * file already exists in archi\version\, if so, check that the version
1052 * info (or time stamps if version info is unavailable) is newer (or the
1053 * date is later). If it is, move it to archi\version\filexxx.yyy.
1054 * Otherwise, delete the file.
1056 * If a file is not moved to archi\version\ because of an error, all the
1057 * rest of the 'unmoved' driver files are removed from archi\. If one or
1058 * more of the driver's files was already moved to archi\version\, it
1059 * potentially leaves the driver in a partially updated state. Version
1060 * trauma will most likely occur if an client attempts to use any printer
1061 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1062 * done is appropriate... later JRR
1065 DEBUG(5,("Moving files now !\n"));
1067 if (driver->driver_path && strlen(driver->driver_path)) {
1069 err = move_driver_file_to_download_area(ctx,
1070 conn,
1071 driver->driver_path,
1072 short_architecture,
1073 driver->version,
1074 ver);
1075 if (!W_ERROR_IS_OK(err)) {
1076 goto err_exit;
1080 if (driver->data_file && strlen(driver->data_file)) {
1081 if (!strequal(driver->data_file, driver->driver_path)) {
1083 err = move_driver_file_to_download_area(ctx,
1084 conn,
1085 driver->data_file,
1086 short_architecture,
1087 driver->version,
1088 ver);
1089 if (!W_ERROR_IS_OK(err)) {
1090 goto err_exit;
1095 if (driver->config_file && strlen(driver->config_file)) {
1096 if (!strequal(driver->config_file, driver->driver_path) &&
1097 !strequal(driver->config_file, driver->data_file)) {
1099 err = move_driver_file_to_download_area(ctx,
1100 conn,
1101 driver->config_file,
1102 short_architecture,
1103 driver->version,
1104 ver);
1105 if (!W_ERROR_IS_OK(err)) {
1106 goto err_exit;
1111 if (driver->help_file && strlen(driver->help_file)) {
1112 if (!strequal(driver->help_file, driver->driver_path) &&
1113 !strequal(driver->help_file, driver->data_file) &&
1114 !strequal(driver->help_file, driver->config_file)) {
1116 err = move_driver_file_to_download_area(ctx,
1117 conn,
1118 driver->help_file,
1119 short_architecture,
1120 driver->version,
1121 ver);
1122 if (!W_ERROR_IS_OK(err)) {
1123 goto err_exit;
1128 if (driver->dependent_files && driver->dependent_files->string) {
1129 for (i=0; driver->dependent_files->string[i]; i++) {
1130 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1131 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1132 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1133 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1134 int j;
1135 for (j=0; j < i; j++) {
1136 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1137 goto NextDriver;
1141 err = move_driver_file_to_download_area(ctx,
1142 conn,
1143 driver->dependent_files->string[i],
1144 short_architecture,
1145 driver->version,
1146 ver);
1147 if (!W_ERROR_IS_OK(err)) {
1148 goto err_exit;
1151 NextDriver: ;
1155 err = WERR_OK;
1156 err_exit:
1157 unbecome_user();
1158 err_free_conn:
1159 TALLOC_FREE(smb_dname);
1161 if (conn != NULL) {
1162 vfs_ChDir(conn, oldcwd);
1163 SMB_VFS_DISCONNECT(conn);
1164 conn_free(conn);
1167 return err;
1170 /****************************************************************************
1171 Create and allocate a default devicemode.
1172 ****************************************************************************/
1174 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1175 const char *devicename,
1176 struct spoolss_DeviceMode **devmode)
1178 struct spoolss_DeviceMode *dm;
1179 char *dname;
1181 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1182 if (dm == NULL) {
1183 return WERR_NOMEM;
1186 dname = talloc_asprintf(dm, "%s", devicename);
1187 if (dname == NULL) {
1188 return WERR_NOMEM;
1190 if (strlen(dname) > MAXDEVICENAME) {
1191 dname[MAXDEVICENAME] = '\0';
1193 dm->devicename = dname;
1195 dm->formname = talloc_strdup(dm, "Letter");
1196 if (dm->formname == NULL) {
1197 return WERR_NOMEM;
1200 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1201 dm->driverversion = 0x0400;
1202 dm->size = 0x00DC;
1203 dm->__driverextra_length = 0;
1204 dm->fields = DEVMODE_FORMNAME |
1205 DEVMODE_TTOPTION |
1206 DEVMODE_PRINTQUALITY |
1207 DEVMODE_DEFAULTSOURCE |
1208 DEVMODE_COPIES |
1209 DEVMODE_SCALE |
1210 DEVMODE_PAPERSIZE |
1211 DEVMODE_ORIENTATION;
1212 dm->orientation = DMORIENT_PORTRAIT;
1213 dm->papersize = DMPAPER_LETTER;
1214 dm->paperlength = 0;
1215 dm->paperwidth = 0;
1216 dm->scale = 0x64;
1217 dm->copies = 1;
1218 dm->defaultsource = DMBIN_FORMSOURCE;
1219 dm->printquality = DMRES_HIGH; /* 0x0258 */
1220 dm->color = DMRES_MONOCHROME;
1221 dm->duplex = DMDUP_SIMPLEX;
1222 dm->yresolution = 0;
1223 dm->ttoption = DMTT_SUBDEV;
1224 dm->collate = DMCOLLATE_FALSE;
1225 dm->icmmethod = 0;
1226 dm->icmintent = 0;
1227 dm->mediatype = 0;
1228 dm->dithertype = 0;
1230 dm->logpixels = 0;
1231 dm->bitsperpel = 0;
1232 dm->pelswidth = 0;
1233 dm->pelsheight = 0;
1234 dm->displayflags = 0;
1235 dm->displayfrequency = 0;
1236 dm->reserved1 = 0;
1237 dm->reserved2 = 0;
1238 dm->panningwidth = 0;
1239 dm->panningheight = 0;
1241 dm->driverextra_data.data = NULL;
1242 dm->driverextra_data.length = 0;
1244 *devmode = dm;
1245 return WERR_OK;
1248 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1249 struct spoolss_security_descriptor **secdesc)
1251 struct security_ace ace[7]; /* max number of ace entries */
1252 int i = 0;
1253 uint32_t sa;
1254 struct security_acl *psa = NULL;
1255 struct security_descriptor *psd = NULL;
1256 struct dom_sid adm_sid;
1257 size_t sd_size;
1259 /* Create an ACE where Everyone is allowed to print */
1261 sa = PRINTER_ACE_PRINT;
1262 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1263 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1265 /* Add the domain admins group if we are a DC */
1267 if ( IS_DC ) {
1268 struct dom_sid domadmins_sid;
1270 sid_compose(&domadmins_sid, get_global_sam_sid(),
1271 DOMAIN_RID_ADMINS);
1273 sa = PRINTER_ACE_FULL_CONTROL;
1274 init_sec_ace(&ace[i++], &domadmins_sid,
1275 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1276 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1277 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1278 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1280 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1281 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1283 sa = PRINTER_ACE_FULL_CONTROL;
1284 init_sec_ace(&ace[i++], &adm_sid,
1285 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1286 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1287 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1288 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1291 /* add BUILTIN\Administrators as FULL CONTROL */
1293 sa = PRINTER_ACE_FULL_CONTROL;
1294 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1295 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1296 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1297 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1298 SEC_ACE_TYPE_ACCESS_ALLOWED,
1299 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1301 /* add BUILTIN\Print Operators as FULL CONTROL */
1303 sa = PRINTER_ACE_FULL_CONTROL;
1304 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1305 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1306 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1307 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1308 SEC_ACE_TYPE_ACCESS_ALLOWED,
1309 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1311 /* Make the security descriptor owned by the BUILTIN\Administrators */
1313 /* The ACL revision number in rpc_secdesc.h differs from the one
1314 created by NT when setting ACE entries in printer
1315 descriptors. NT4 complains about the property being edited by a
1316 NT5 machine. */
1318 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1319 psd = make_sec_desc(mem_ctx,
1320 SD_REVISION,
1321 SEC_DESC_SELF_RELATIVE,
1322 &global_sid_Builtin_Administrators,
1323 &global_sid_Builtin_Administrators,
1324 NULL,
1325 psa,
1326 &sd_size);
1329 if (psd == NULL) {
1330 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1331 return WERR_NOMEM;
1334 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1335 (unsigned int)sd_size));
1337 *secdesc = psd;
1339 return WERR_OK;
1342 /****************************************************************************
1343 ***************************************************************************/
1345 static char *win_driver;
1346 static char *os2_driver;
1348 static const char *get_win_driver(void)
1350 if (win_driver == NULL) {
1351 return "";
1353 return win_driver;
1356 static const char *get_os2_driver(void)
1358 if (os2_driver == NULL) {
1359 return "";
1361 return os2_driver;
1364 static bool set_driver_mapping(const char *from, const char *to)
1366 SAFE_FREE(win_driver);
1367 SAFE_FREE(os2_driver);
1369 win_driver = SMB_STRDUP(from);
1370 os2_driver = SMB_STRDUP(to);
1372 if (win_driver == NULL || os2_driver == NULL) {
1373 SAFE_FREE(win_driver);
1374 SAFE_FREE(os2_driver);
1375 return false;
1377 return true;
1381 * @internal
1383 * @brief Map a Windows driver to a OS/2 driver.
1385 * @param[in] mem_ctx The memory context to use.
1387 * @param[in,out] pdrivername The drivername of Windows to remap.
1389 * @return WERR_OK on success, a corresponding WERROR on failure.
1391 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1393 const char *mapfile = lp_os2_driver_map();
1394 char **lines = NULL;
1395 const char *drivername;
1396 int numlines = 0;
1397 int i;
1399 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1400 return WERR_INVALID_PARAMETER;
1403 drivername = *pdrivername;
1405 if (mapfile[0] == '\0') {
1406 return WERR_BADFILE;
1409 if (strequal(drivername, get_win_driver())) {
1410 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1411 drivername, get_os2_driver()));
1412 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1413 if (drivername == NULL) {
1414 return WERR_NOMEM;
1416 *pdrivername = drivername;
1417 return WERR_OK;
1420 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1421 if (numlines == 0 || lines == NULL) {
1422 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1423 TALLOC_FREE(lines);
1424 return WERR_EMPTY;
1427 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1429 for( i = 0; i < numlines; i++) {
1430 char *nt_name = lines[i];
1431 char *os2_name = strchr(nt_name, '=');
1433 if (os2_name == NULL) {
1434 continue;
1437 *os2_name++ = '\0';
1439 while (isspace(*nt_name)) {
1440 nt_name++;
1443 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1444 continue;
1448 int l = strlen(nt_name);
1449 while (l && isspace(nt_name[l - 1])) {
1450 nt_name[l - 1] = 0;
1451 l--;
1455 while (isspace(*os2_name)) {
1456 os2_name++;
1460 int l = strlen(os2_name);
1461 while (l && isspace(os2_name[l-1])) {
1462 os2_name[l-1] = 0;
1463 l--;
1467 if (strequal(nt_name, drivername)) {
1468 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1469 set_driver_mapping(drivername, os2_name);
1470 drivername = talloc_strdup(mem_ctx, os2_name);
1471 TALLOC_FREE(lines);
1472 if (drivername == NULL) {
1473 return WERR_NOMEM;
1475 *pdrivername = drivername;
1476 return WERR_OK;
1480 TALLOC_FREE(lines);
1481 return WERR_OK;
1484 /****************************************************************************
1485 ****************************************************************************/
1487 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1488 struct spoolss_DriverInfo8 *_info8)
1490 struct spoolss_DriverInfo8 info8;
1492 ZERO_STRUCT(info8);
1494 switch (r->level) {
1495 case 3:
1496 info8.version = r->info.info3->version;
1497 info8.driver_name = r->info.info3->driver_name;
1498 info8.architecture = r->info.info3->architecture;
1499 info8.driver_path = r->info.info3->driver_path;
1500 info8.data_file = r->info.info3->data_file;
1501 info8.config_file = r->info.info3->config_file;
1502 info8.help_file = r->info.info3->help_file;
1503 info8.monitor_name = r->info.info3->monitor_name;
1504 info8.default_datatype = r->info.info3->default_datatype;
1505 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1506 info8.dependent_files = r->info.info3->dependent_files->string;
1508 break;
1509 case 6:
1510 info8.version = r->info.info6->version;
1511 info8.driver_name = r->info.info6->driver_name;
1512 info8.architecture = r->info.info6->architecture;
1513 info8.driver_path = r->info.info6->driver_path;
1514 info8.data_file = r->info.info6->data_file;
1515 info8.config_file = r->info.info6->config_file;
1516 info8.help_file = r->info.info6->help_file;
1517 info8.monitor_name = r->info.info6->monitor_name;
1518 info8.default_datatype = r->info.info6->default_datatype;
1519 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1520 info8.dependent_files = r->info.info6->dependent_files->string;
1522 info8.driver_date = r->info.info6->driver_date;
1523 info8.driver_version = r->info.info6->driver_version;
1524 info8.manufacturer_name = r->info.info6->manufacturer_name;
1525 info8.manufacturer_url = r->info.info6->manufacturer_url;
1526 info8.hardware_id = r->info.info6->hardware_id;
1527 info8.provider = r->info.info6->provider;
1528 break;
1529 case 8:
1530 info8.version = r->info.info8->version;
1531 info8.driver_name = r->info.info8->driver_name;
1532 info8.architecture = r->info.info8->architecture;
1533 info8.driver_path = r->info.info8->driver_path;
1534 info8.data_file = r->info.info8->data_file;
1535 info8.config_file = r->info.info8->config_file;
1536 info8.help_file = r->info.info8->help_file;
1537 info8.monitor_name = r->info.info8->monitor_name;
1538 info8.default_datatype = r->info.info8->default_datatype;
1539 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1540 info8.dependent_files = r->info.info8->dependent_files->string;
1542 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1543 info8.previous_names = r->info.info8->previous_names->string;
1545 info8.driver_date = r->info.info8->driver_date;
1546 info8.driver_version = r->info.info8->driver_version;
1547 info8.manufacturer_name = r->info.info8->manufacturer_name;
1548 info8.manufacturer_url = r->info.info8->manufacturer_url;
1549 info8.hardware_id = r->info.info8->hardware_id;
1550 info8.provider = r->info.info8->provider;
1551 info8.print_processor = r->info.info8->print_processor;
1552 info8.vendor_setup = r->info.info8->vendor_setup;
1553 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1554 info8.color_profiles = r->info.info8->color_profiles->string;
1556 info8.inf_path = r->info.info8->inf_path;
1557 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1558 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1559 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1561 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1562 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1563 break;
1564 default:
1565 return false;
1568 *_info8 = info8;
1570 return true;
1574 /****************************************************************************
1575 Determine whether or not a particular driver is currently assigned
1576 to a printer
1577 ****************************************************************************/
1579 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1580 const struct auth_serversupplied_info *session_info,
1581 struct messaging_context *msg_ctx,
1582 const struct spoolss_DriverInfo8 *r)
1584 int snum;
1585 int n_services = lp_numservices();
1586 bool in_use = False;
1587 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1588 WERROR result;
1590 if (!r) {
1591 return false;
1594 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1596 /* loop through the printers.tdb and check for the drivername */
1598 for (snum=0; snum<n_services && !in_use; snum++) {
1599 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1600 continue;
1603 result = winreg_get_printer(mem_ctx, session_info, msg_ctx,
1604 lp_servicename(snum),
1605 &pinfo2);
1606 if (!W_ERROR_IS_OK(result)) {
1607 continue; /* skip */
1610 if (strequal(r->driver_name, pinfo2->drivername)) {
1611 in_use = True;
1614 TALLOC_FREE(pinfo2);
1617 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1619 if ( in_use ) {
1620 struct spoolss_DriverInfo8 *driver;
1621 WERROR werr;
1623 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1625 /* we can still remove the driver if there is one of
1626 "Windows NT x86" version 2 or 3 left */
1628 if (!strequal("Windows NT x86", r->architecture)) {
1629 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1630 "Windows NT x86",
1631 r->driver_name,
1632 DRIVER_ANY_VERSION,
1633 &driver);
1634 } else if (r->version == 2) {
1635 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1636 "Windows NT x86",
1637 r->driver_name,
1638 3, &driver);
1639 } else if (r->version == 3) {
1640 werr = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1641 "Windows NT x86",
1642 r->driver_name,
1643 2, &driver);
1644 } else {
1645 DEBUG(0, ("printer_driver_in_use: ERROR!"
1646 " unknown driver version (%d)\n",
1647 r->version));
1648 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1651 /* now check the error code */
1653 if ( W_ERROR_IS_OK(werr) ) {
1654 /* it's ok to remove the driver, we have other architctures left */
1655 in_use = False;
1656 talloc_free(driver);
1660 /* report that the driver is not in use by default */
1662 return in_use;
1666 /**********************************************************************
1667 Check to see if a ogiven file is in use by *info
1668 *********************************************************************/
1670 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1672 int i = 0;
1674 if ( !info )
1675 return False;
1677 /* mz: skip files that are in the list but already deleted */
1678 if (!file || !file[0]) {
1679 return false;
1682 if (strequal(file, info->driver_path))
1683 return True;
1685 if (strequal(file, info->data_file))
1686 return True;
1688 if (strequal(file, info->config_file))
1689 return True;
1691 if (strequal(file, info->help_file))
1692 return True;
1694 /* see of there are any dependent files to examine */
1696 if (!info->dependent_files)
1697 return False;
1699 while (info->dependent_files[i] && *info->dependent_files[i]) {
1700 if (strequal(file, info->dependent_files[i]))
1701 return True;
1702 i++;
1705 return False;
1709 /**********************************************************************
1710 Utility function to remove the dependent file pointed to by the
1711 input parameter from the list
1712 *********************************************************************/
1714 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1717 /* bump everything down a slot */
1719 while (files && files[idx+1]) {
1720 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1721 idx++;
1724 files[idx] = NULL;
1726 return;
1729 /**********************************************************************
1730 Check if any of the files used by src are also used by drv
1731 *********************************************************************/
1733 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1734 struct spoolss_DriverInfo8 *src,
1735 const struct spoolss_DriverInfo8 *drv)
1737 bool in_use = False;
1738 int i = 0;
1740 if ( !src || !drv )
1741 return False;
1743 /* check each file. Remove it from the src structure if it overlaps */
1745 if (drv_file_in_use(src->driver_path, drv)) {
1746 in_use = True;
1747 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1748 src->driver_path = talloc_strdup(mem_ctx, "");
1749 if (!src->driver_path) { return false; }
1752 if (drv_file_in_use(src->data_file, drv)) {
1753 in_use = True;
1754 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1755 src->data_file = talloc_strdup(mem_ctx, "");
1756 if (!src->data_file) { return false; }
1759 if (drv_file_in_use(src->config_file, drv)) {
1760 in_use = True;
1761 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1762 src->config_file = talloc_strdup(mem_ctx, "");
1763 if (!src->config_file) { return false; }
1766 if (drv_file_in_use(src->help_file, drv)) {
1767 in_use = True;
1768 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1769 src->help_file = talloc_strdup(mem_ctx, "");
1770 if (!src->help_file) { return false; }
1773 /* are there any dependentfiles to examine? */
1775 if (!src->dependent_files)
1776 return in_use;
1778 while (src->dependent_files[i] && *src->dependent_files[i]) {
1779 if (drv_file_in_use(src->dependent_files[i], drv)) {
1780 in_use = True;
1781 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1782 trim_dependent_file(mem_ctx, src->dependent_files, i);
1783 } else
1784 i++;
1787 return in_use;
1790 /****************************************************************************
1791 Determine whether or not a particular driver files are currently being
1792 used by any other driver.
1794 Return value is True if any files were in use by other drivers
1795 and False otherwise.
1797 Upon return, *info has been modified to only contain the driver files
1798 which are not in use
1800 Fix from mz:
1802 This needs to check all drivers to ensure that all files in use
1803 have been removed from *info, not just the ones in the first
1804 match.
1805 ****************************************************************************/
1807 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1808 const struct auth_serversupplied_info *session_info,
1809 struct messaging_context *msg_ctx,
1810 struct spoolss_DriverInfo8 *info)
1812 int i;
1813 uint32 version;
1814 struct spoolss_DriverInfo8 *driver;
1815 bool in_use = false;
1816 uint32_t num_drivers;
1817 const char **drivers;
1818 WERROR result;
1820 if ( !info )
1821 return False;
1823 version = info->version;
1825 /* loop over all driver versions */
1827 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1829 /* get the list of drivers */
1831 result = winreg_get_driver_list(mem_ctx, session_info, msg_ctx,
1832 info->architecture, version,
1833 &num_drivers, &drivers);
1834 if (!W_ERROR_IS_OK(result)) {
1835 return true;
1838 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1839 num_drivers, info->architecture, version));
1841 /* check each driver for overlap in files */
1843 for (i = 0; i < num_drivers; i++) {
1844 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1846 driver = NULL;
1848 result = winreg_get_driver(mem_ctx, session_info, msg_ctx,
1849 info->architecture, drivers[i],
1850 version, &driver);
1851 if (!W_ERROR_IS_OK(result)) {
1852 talloc_free(drivers);
1853 return True;
1856 /* check if d2 uses any files from d1 */
1857 /* only if this is a different driver than the one being deleted */
1859 if (!strequal(info->driver_name, driver->driver_name)) {
1860 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1861 /* mz: Do not instantly return -
1862 * we need to ensure this file isn't
1863 * also in use by other drivers. */
1864 in_use = true;
1868 talloc_free(driver);
1871 talloc_free(drivers);
1873 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1875 return in_use;
1878 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1879 const char *name)
1881 struct smb_filename *smb_fname = NULL;
1882 NTSTATUS status;
1884 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1885 &smb_fname);
1886 if (!NT_STATUS_IS_OK(status)) {
1887 return status;
1890 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1892 TALLOC_FREE(smb_fname);
1893 return status;
1896 /****************************************************************************
1897 Actually delete the driver files. Make sure that
1898 printer_driver_files_in_use() return False before calling
1899 this.
1900 ****************************************************************************/
1902 bool delete_driver_files(const struct auth_serversupplied_info *session_info,
1903 const struct spoolss_DriverInfo8 *r)
1905 int i = 0;
1906 char *s;
1907 const char *file;
1908 connection_struct *conn;
1909 NTSTATUS nt_status;
1910 char *oldcwd;
1911 char *printdollar = NULL;
1912 int printdollar_snum;
1913 bool ret = false;
1915 if (!r) {
1916 return false;
1919 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1920 r->driver_name, r->version));
1922 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1923 if (!printdollar) {
1924 return false;
1926 if (printdollar_snum == -1) {
1927 return false;
1930 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1931 lp_pathname(printdollar_snum),
1932 session_info, &oldcwd);
1933 if (!NT_STATUS_IS_OK(nt_status)) {
1934 DEBUG(0,("delete_driver_files: create_conn_struct "
1935 "returned %s\n", nt_errstr(nt_status)));
1936 return false;
1939 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1940 if (!NT_STATUS_IS_OK(nt_status)) {
1941 DEBUG(0, ("failed set force user / group\n"));
1942 ret = false;
1943 goto err_free_conn;
1946 if (!become_user_by_session(conn, session_info)) {
1947 DEBUG(0, ("failed to become user\n"));
1948 ret = false;
1949 goto err_free_conn;
1952 if ( !CAN_WRITE(conn) ) {
1953 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1954 ret = false;
1955 goto err_out;
1958 /* now delete the files; must strip the '\print$' string from
1959 fron of path */
1961 if (r->driver_path && r->driver_path[0]) {
1962 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1963 file = s;
1964 DEBUG(10,("deleting driverfile [%s]\n", s));
1965 driver_unlink_internals(conn, file);
1969 if (r->config_file && r->config_file[0]) {
1970 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1971 file = s;
1972 DEBUG(10,("deleting configfile [%s]\n", s));
1973 driver_unlink_internals(conn, file);
1977 if (r->data_file && r->data_file[0]) {
1978 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1979 file = s;
1980 DEBUG(10,("deleting datafile [%s]\n", s));
1981 driver_unlink_internals(conn, file);
1985 if (r->help_file && r->help_file[0]) {
1986 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1987 file = s;
1988 DEBUG(10,("deleting helpfile [%s]\n", s));
1989 driver_unlink_internals(conn, file);
1993 /* check if we are done removing files */
1995 if (r->dependent_files) {
1996 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1997 char *p;
1999 /* bypass the "\print$" portion of the path */
2001 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
2002 file = p;
2003 DEBUG(10,("deleting dependent file [%s]\n", file));
2004 driver_unlink_internals(conn, file);
2007 i++;
2011 ret = true;
2012 err_out:
2013 unbecome_user();
2014 err_free_conn:
2015 if (conn != NULL) {
2016 vfs_ChDir(conn, oldcwd);
2017 SMB_VFS_DISCONNECT(conn);
2018 conn_free(conn);
2020 return ret;
2023 /* error code:
2024 0: everything OK
2025 1: level not implemented
2026 2: file doesn't exist
2027 3: can't allocate memory
2028 4: can't free memory
2029 5: non existant struct
2033 A printer and a printer driver are 2 different things.
2034 NT manages them separatelly, Samba does the same.
2035 Why ? Simply because it's easier and it makes sense !
2037 Now explanation: You have 3 printers behind your samba server,
2038 2 of them are the same make and model (laser A and B). But laser B
2039 has an 3000 sheet feeder and laser A doesn't such an option.
2040 Your third printer is an old dot-matrix model for the accounting :-).
2042 If the /usr/local/samba/lib directory (default dir), you will have
2043 5 files to describe all of this.
2045 3 files for the printers (1 by printer):
2046 NTprinter_laser A
2047 NTprinter_laser B
2048 NTprinter_accounting
2049 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2050 NTdriver_printer model X
2051 NTdriver_printer model Y
2053 jfm: I should use this comment for the text file to explain
2054 same thing for the forms BTW.
2055 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2059 /* Convert generic access rights to printer object specific access rights.
2060 It turns out that NT4 security descriptors use generic access rights and
2061 NT5 the object specific ones. */
2063 void map_printer_permissions(struct security_descriptor *sd)
2065 int i;
2067 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2068 se_map_generic(&sd->dacl->aces[i].access_mask,
2069 &printer_generic_mapping);
2073 void map_job_permissions(struct security_descriptor *sd)
2075 int i;
2077 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2078 se_map_generic(&sd->dacl->aces[i].access_mask,
2079 &job_generic_mapping);
2084 /****************************************************************************
2085 Check a user has permissions to perform the given operation. We use the
2086 permission constants defined in include/rpc_spoolss.h to check the various
2087 actions we perform when checking printer access.
2089 PRINTER_ACCESS_ADMINISTER:
2090 print_queue_pause, print_queue_resume, update_printer_sec,
2091 update_printer, spoolss_addprinterex_level_2,
2092 _spoolss_setprinterdata
2094 PRINTER_ACCESS_USE:
2095 print_job_start
2097 JOB_ACCESS_ADMINISTER:
2098 print_job_delete, print_job_pause, print_job_resume,
2099 print_queue_purge
2101 Try access control in the following order (for performance reasons):
2102 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2103 2) check security descriptor (bit comparisons in memory)
2104 3) "printer admins" (may result in numerous calls to winbind)
2106 ****************************************************************************/
2107 bool print_access_check(const struct auth_serversupplied_info *session_info,
2108 struct messaging_context *msg_ctx, int snum,
2109 int access_type)
2111 struct spoolss_security_descriptor *secdesc = NULL;
2112 uint32 access_granted;
2113 size_t sd_size;
2114 NTSTATUS status;
2115 WERROR result;
2116 const char *pname;
2117 TALLOC_CTX *mem_ctx = NULL;
2119 /* If user is NULL then use the current_user structure */
2121 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2123 if (session_info->utok.uid == sec_initial_uid()
2124 || security_token_has_privilege(session_info->security_token, SEC_PRIV_PRINT_OPERATOR)) {
2125 return True;
2128 /* Get printer name */
2130 pname = lp_printername(snum);
2132 if (!pname || !*pname) {
2133 errno = EACCES;
2134 return False;
2137 /* Get printer security descriptor */
2139 if(!(mem_ctx = talloc_init("print_access_check"))) {
2140 errno = ENOMEM;
2141 return False;
2144 result = winreg_get_printer_secdesc(mem_ctx,
2145 get_session_info_system(),
2146 msg_ctx,
2147 pname,
2148 &secdesc);
2149 if (!W_ERROR_IS_OK(result)) {
2150 talloc_destroy(mem_ctx);
2151 errno = ENOMEM;
2152 return False;
2155 if (access_type == JOB_ACCESS_ADMINISTER) {
2156 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2158 /* Create a child security descriptor to check permissions
2159 against. This is because print jobs are child objects
2160 objects of a printer. */
2161 status = se_create_child_secdesc(mem_ctx,
2162 &secdesc,
2163 &sd_size,
2164 parent_secdesc,
2165 parent_secdesc->owner_sid,
2166 parent_secdesc->group_sid,
2167 false);
2168 if (!NT_STATUS_IS_OK(status)) {
2169 talloc_destroy(mem_ctx);
2170 errno = map_errno_from_nt_status(status);
2171 return False;
2174 map_job_permissions(secdesc);
2175 } else {
2176 map_printer_permissions(secdesc);
2179 /* Check access */
2180 status = se_access_check(secdesc, session_info->security_token, access_type,
2181 &access_granted);
2183 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2185 /* see if we need to try the printer admin list */
2187 if (!NT_STATUS_IS_OK(status) &&
2188 (token_contains_name_in_list(uidtoname(session_info->utok.uid),
2189 session_info->info3->base.domain.string,
2190 NULL, session_info->security_token,
2191 lp_printer_admin(snum)))) {
2192 talloc_destroy(mem_ctx);
2193 return True;
2196 talloc_destroy(mem_ctx);
2198 if (!NT_STATUS_IS_OK(status)) {
2199 errno = EACCES;
2202 return NT_STATUS_IS_OK(status);
2205 /****************************************************************************
2206 Check the time parameters allow a print operation.
2207 *****************************************************************************/
2209 bool print_time_access_check(const struct auth_serversupplied_info *session_info,
2210 struct messaging_context *msg_ctx,
2211 const char *servicename)
2213 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2214 WERROR result;
2215 bool ok = False;
2216 time_t now = time(NULL);
2217 struct tm *t;
2218 uint32 mins;
2220 result = winreg_get_printer(NULL, session_info, msg_ctx,
2221 servicename, &pinfo2);
2222 if (!W_ERROR_IS_OK(result)) {
2223 return False;
2226 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2227 ok = True;
2230 t = gmtime(&now);
2231 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2233 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2234 ok = True;
2237 TALLOC_FREE(pinfo2);
2239 if (!ok) {
2240 errno = EACCES;
2243 return ok;
2246 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2247 const struct auth_serversupplied_info *session_info,
2248 struct messaging_context *msg_ctx,
2249 const char *printer)
2251 WERROR result;
2253 result = winreg_delete_printer_key(mem_ctx, session_info, msg_ctx,
2254 printer, "");
2255 if (!W_ERROR_IS_OK(result)) {
2256 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2257 printer));