s3-docs: Typos in rpcclient man page
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blob671aca6a51999b2a4a498d9d3d145ed1b573d5d7
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "librpc/gen_ndr/messaging.h"
24 #include "printing/pcap.h"
25 #include "printing/nt_printing_tdb.h"
26 #include "printing/nt_printing_migrate.h"
27 #include "registry.h"
28 #include "registry/reg_objects.h"
29 #include "../librpc/gen_ndr/ndr_security.h"
30 #include "../librpc/gen_ndr/ndr_spoolss.h"
31 #include "rpc_server/srv_spoolss_util.h"
32 #include "nt_printing.h"
33 #include "secrets.h"
34 #include "../librpc/gen_ndr/netlogon.h"
35 #include "../libcli/security/security.h"
37 /* Map generic permissions to printer object specific permissions */
39 const struct generic_mapping printer_generic_mapping = {
40 PRINTER_READ,
41 PRINTER_WRITE,
42 PRINTER_EXECUTE,
43 PRINTER_ALL_ACCESS
46 /* Map generic permissions to print server object specific permissions */
48 const struct generic_mapping printserver_generic_mapping = {
49 SERVER_READ,
50 SERVER_WRITE,
51 SERVER_EXECUTE,
52 SERVER_ALL_ACCESS
55 /* Map generic permissions to job object specific permissions */
57 const struct generic_mapping job_generic_mapping = {
58 JOB_READ,
59 JOB_WRITE,
60 JOB_EXECUTE,
61 JOB_ALL_ACCESS
64 static const struct print_architecture_table_node archi_table[]= {
66 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
67 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
68 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
69 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
70 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
71 {"Windows IA64", SPL_ARCH_IA64, 3 },
72 {"Windows x64", SPL_ARCH_X64, 3 },
73 {NULL, "", -1 }
76 /****************************************************************************
77 Open the NT printing tdbs. Done once before fork().
78 ****************************************************************************/
80 bool nt_printing_init(struct messaging_context *msg_ctx)
82 WERROR win_rc;
84 if (!nt_printing_tdb_upgrade()) {
85 return false;
89 * register callback to handle updating printers as new
90 * drivers are installed
92 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
93 do_drv_upgrade_printer);
95 /* of course, none of the message callbacks matter if you don't
96 tell messages.c that you interested in receiving PRINT_GENERAL
97 msgs. This is done in serverid_register() */
99 if ( lp_security() == SEC_ADS ) {
100 win_rc = check_published_printers(msg_ctx);
101 if (!W_ERROR_IS_OK(win_rc))
102 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
105 return true;
108 /*******************************************************************
109 Function to allow filename parsing "the old way".
110 ********************************************************************/
112 static NTSTATUS driver_unix_convert(connection_struct *conn,
113 const char *old_name,
114 struct smb_filename **smb_fname)
116 NTSTATUS status;
117 TALLOC_CTX *ctx = talloc_tos();
118 char *name = talloc_strdup(ctx, old_name);
120 if (!name) {
121 return NT_STATUS_NO_MEMORY;
123 unix_format(name);
124 name = unix_clean_name(ctx, name);
125 if (!name) {
126 return NT_STATUS_NO_MEMORY;
128 trim_string(name,"/","/");
130 status = unix_convert(ctx, conn, name, smb_fname, 0);
131 if (!NT_STATUS_IS_OK(status)) {
132 return NT_STATUS_NO_MEMORY;
135 return NT_STATUS_OK;
138 /****************************************************************************
139 Function to do the mapping between the long architecture name and
140 the short one.
141 ****************************************************************************/
143 const char *get_short_archi(const char *long_archi)
145 int i=-1;
147 DEBUG(107,("Getting architecture dependant directory\n"));
148 do {
149 i++;
150 } while ( (archi_table[i].long_archi!=NULL ) &&
151 StrCaseCmp(long_archi, archi_table[i].long_archi) );
153 if (archi_table[i].long_archi==NULL) {
154 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
155 return NULL;
158 /* this might be client code - but shouldn't this be an fstrcpy etc? */
160 DEBUGADD(108,("index: [%d]\n", i));
161 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
162 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
164 return archi_table[i].short_archi;
167 /****************************************************************************
168 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
169 There are two case to be covered here: PE (Portable Executable) and NE (New
170 Executable) files. Both files support the same INFO structure, but PE files
171 store the signature in unicode, and NE files store it as !unicode.
172 returns -1 on error, 1 on version info found, and 0 on no version info found.
173 ****************************************************************************/
175 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
177 int i;
178 char *buf = NULL;
179 ssize_t byte_count;
181 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
182 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
183 fname, DOS_HEADER_SIZE));
184 goto error_exit;
187 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
188 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
189 fname, (unsigned long)byte_count));
190 goto no_version_info;
193 /* Is this really a DOS header? */
194 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
195 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
196 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
197 goto no_version_info;
200 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
201 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
202 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
203 fname, errno));
204 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
205 goto no_version_info;
208 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
209 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
210 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
211 fname, (unsigned long)byte_count));
212 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
213 goto no_version_info;
216 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
217 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
218 unsigned int num_sections;
219 unsigned int section_table_bytes;
221 /* Just skip over optional header to get to section table */
222 if (SMB_VFS_LSEEK(fsp,
223 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
224 SEEK_CUR) == (SMB_OFF_T)-1) {
225 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
226 fname, errno));
227 goto error_exit;
230 /* get the section table */
231 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
232 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
233 if (section_table_bytes == 0)
234 goto error_exit;
236 SAFE_FREE(buf);
237 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
238 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
239 fname, section_table_bytes));
240 goto error_exit;
243 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
244 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
245 fname, (unsigned long)byte_count));
246 goto error_exit;
249 /* Iterate the section table looking for the resource section ".rsrc" */
250 for (i = 0; i < num_sections; i++) {
251 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
253 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
254 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
255 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
257 if (section_bytes == 0)
258 goto error_exit;
260 SAFE_FREE(buf);
261 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
262 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
263 fname, section_bytes));
264 goto error_exit;
267 /* Seek to the start of the .rsrc section info */
268 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
269 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
270 fname, errno));
271 goto error_exit;
274 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
275 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
276 fname, (unsigned long)byte_count));
277 goto error_exit;
280 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
281 goto error_exit;
283 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
284 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
285 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
286 /* Align to next long address */
287 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
289 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
290 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
291 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
293 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
294 fname, *major, *minor,
295 (*major>>16)&0xffff, *major&0xffff,
296 (*minor>>16)&0xffff, *minor&0xffff));
297 SAFE_FREE(buf);
298 return 1;
305 /* Version info not found, fall back to origin date/time */
306 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
307 SAFE_FREE(buf);
308 return 0;
310 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
311 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
312 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
313 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
314 /* At this point, we assume the file is in error. It still could be somthing
315 * else besides a NE file, but it unlikely at this point. */
316 goto error_exit;
319 /* Allocate a bit more space to speed up things */
320 SAFE_FREE(buf);
321 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
322 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
323 fname, PE_HEADER_SIZE));
324 goto error_exit;
327 /* This is a HACK! I got tired of trying to sort through the messy
328 * 'NE' file format. If anyone wants to clean this up please have at
329 * it, but this works. 'NE' files will eventually fade away. JRR */
330 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
331 /* Cover case that should not occur in a well formed 'NE' .dll file */
332 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
334 for(i=0; i<byte_count; i++) {
335 /* Fast skip past data that can't possibly match */
336 if (buf[i] != 'V') continue;
338 /* Potential match data crosses buf boundry, move it to beginning
339 * of buf, and fill the buf with as much as it will hold. */
340 if (i>byte_count-VS_VERSION_INFO_SIZE) {
341 int bc;
343 memcpy(buf, &buf[i], byte_count-i);
344 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
345 (byte_count-i))) < 0) {
347 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
348 fname, errno));
349 goto error_exit;
352 byte_count = bc + (byte_count - i);
353 if (byte_count<VS_VERSION_INFO_SIZE) break;
355 i = 0;
358 /* Check that the full signature string and the magic number that
359 * follows exist (not a perfect solution, but the chances that this
360 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
361 * twice, as it is simpler to read the code. */
362 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
363 /* Compute skip alignment to next long address */
364 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
365 sizeof(VS_SIGNATURE)) & 3;
366 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
368 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
369 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
370 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
371 fname, *major, *minor,
372 (*major>>16)&0xffff, *major&0xffff,
373 (*minor>>16)&0xffff, *minor&0xffff));
374 SAFE_FREE(buf);
375 return 1;
380 /* Version info not found, fall back to origin date/time */
381 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
382 SAFE_FREE(buf);
383 return 0;
385 } else
386 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
387 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
388 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
390 no_version_info:
391 SAFE_FREE(buf);
392 return 0;
394 error_exit:
395 SAFE_FREE(buf);
396 return -1;
399 /****************************************************************************
400 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
401 share one or more files. During the MS installation process files are checked
402 to insure that only a newer version of a shared file is installed over an
403 older version. There are several possibilities for this comparison. If there
404 is no previous version, the new one is newer (obviously). If either file is
405 missing the version info structure, compare the creation date (on Unix use
406 the modification date). Otherwise chose the numerically larger version number.
407 ****************************************************************************/
409 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
411 bool use_version = true;
413 uint32 new_major;
414 uint32 new_minor;
415 time_t new_create_time;
417 uint32 old_major;
418 uint32 old_minor;
419 time_t old_create_time;
421 struct smb_filename *smb_fname = NULL;
422 files_struct *fsp = NULL;
423 SMB_STRUCT_STAT st;
425 NTSTATUS status;
426 int ret;
428 SET_STAT_INVALID(st);
429 new_create_time = (time_t)0;
430 old_create_time = (time_t)0;
432 /* Get file version info (if available) for previous file (if it exists) */
433 status = driver_unix_convert(conn, old_file, &smb_fname);
434 if (!NT_STATUS_IS_OK(status)) {
435 goto error_exit;
438 status = SMB_VFS_CREATE_FILE(
439 conn, /* conn */
440 NULL, /* req */
441 0, /* root_dir_fid */
442 smb_fname, /* fname */
443 FILE_GENERIC_READ, /* access_mask */
444 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
445 FILE_OPEN, /* create_disposition*/
446 0, /* create_options */
447 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
448 INTERNAL_OPEN_ONLY, /* oplock_request */
449 0, /* allocation_size */
450 0, /* private_flags */
451 NULL, /* sd */
452 NULL, /* ea_list */
453 &fsp, /* result */
454 NULL); /* pinfo */
456 if (!NT_STATUS_IS_OK(status)) {
457 /* Old file not found, so by definition new file is in fact newer */
458 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
459 "errno = %d\n", smb_fname_str_dbg(smb_fname),
460 errno));
461 ret = 1;
462 goto done;
464 } else {
465 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
466 if (ret == -1) {
467 goto error_exit;
470 if (!ret) {
471 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
472 old_file));
473 use_version = false;
474 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
475 goto error_exit;
477 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
478 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
479 (long)old_create_time));
482 close_file(NULL, fsp, NORMAL_CLOSE);
483 fsp = NULL;
485 /* Get file version info (if available) for new file */
486 status = driver_unix_convert(conn, new_file, &smb_fname);
487 if (!NT_STATUS_IS_OK(status)) {
488 goto error_exit;
491 status = SMB_VFS_CREATE_FILE(
492 conn, /* conn */
493 NULL, /* req */
494 0, /* root_dir_fid */
495 smb_fname, /* fname */
496 FILE_GENERIC_READ, /* access_mask */
497 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
498 FILE_OPEN, /* create_disposition*/
499 0, /* create_options */
500 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
501 INTERNAL_OPEN_ONLY, /* oplock_request */
502 0, /* allocation_size */
503 0, /* private_flags */
504 NULL, /* sd */
505 NULL, /* ea_list */
506 &fsp, /* result */
507 NULL); /* pinfo */
509 if (!NT_STATUS_IS_OK(status)) {
510 /* New file not found, this shouldn't occur if the caller did its job */
511 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
512 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
513 goto error_exit;
515 } else {
516 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
517 if (ret == -1) {
518 goto error_exit;
521 if (!ret) {
522 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
523 new_file));
524 use_version = false;
525 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
526 goto error_exit;
528 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
529 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
530 (long)new_create_time));
533 close_file(NULL, fsp, NORMAL_CLOSE);
534 fsp = NULL;
536 if (use_version && (new_major != old_major || new_minor != old_minor)) {
537 /* Compare versions and choose the larger version number */
538 if (new_major > old_major ||
539 (new_major == old_major && new_minor > old_minor)) {
541 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
542 ret = 1;
543 goto done;
545 else {
546 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
547 ret = 0;
548 goto done;
551 } else {
552 /* Compare modification time/dates and choose the newest time/date */
553 if (new_create_time > old_create_time) {
554 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
555 ret = 1;
556 goto done;
558 else {
559 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
560 ret = 0;
561 goto done;
565 error_exit:
566 if(fsp)
567 close_file(NULL, fsp, NORMAL_CLOSE);
568 ret = -1;
569 done:
570 TALLOC_FREE(smb_fname);
571 return ret;
574 /****************************************************************************
575 Determine the correct cVersion associated with an architecture and driver
576 ****************************************************************************/
577 static uint32 get_correct_cversion(struct pipes_struct *p,
578 const char *architecture,
579 const char *driverpath_in,
580 WERROR *perr)
582 int cversion;
583 NTSTATUS nt_status;
584 struct smb_filename *smb_fname = NULL;
585 char *driverpath = NULL;
586 files_struct *fsp = NULL;
587 connection_struct *conn = NULL;
588 NTSTATUS status;
589 char *oldcwd;
590 char *printdollar = NULL;
591 int printdollar_snum;
593 *perr = WERR_INVALID_PARAM;
595 /* If architecture is Windows 95/98/ME, the version is always 0. */
596 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
597 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
598 *perr = WERR_OK;
599 return 0;
602 /* If architecture is Windows x64, the version is always 3. */
603 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
604 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
605 *perr = WERR_OK;
606 return 3;
609 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
610 if (!printdollar) {
611 *perr = WERR_NOMEM;
612 return -1;
614 if (printdollar_snum == -1) {
615 *perr = WERR_NO_SUCH_SHARE;
616 return -1;
619 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
620 lp_pathname(printdollar_snum),
621 p->server_info, &oldcwd);
622 if (!NT_STATUS_IS_OK(nt_status)) {
623 DEBUG(0,("get_correct_cversion: create_conn_struct "
624 "returned %s\n", nt_errstr(nt_status)));
625 *perr = ntstatus_to_werror(nt_status);
626 return -1;
629 /* Open the driver file (Portable Executable format) and determine the
630 * deriver the cversion. */
631 driverpath = talloc_asprintf(talloc_tos(),
632 "%s/%s",
633 architecture,
634 driverpath_in);
635 if (!driverpath) {
636 *perr = WERR_NOMEM;
637 goto error_exit;
640 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
641 if (!NT_STATUS_IS_OK(nt_status)) {
642 *perr = ntstatus_to_werror(nt_status);
643 goto error_exit;
646 nt_status = vfs_file_exist(conn, smb_fname);
647 if (!NT_STATUS_IS_OK(nt_status)) {
648 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
649 *perr = WERR_BADFILE;
650 goto error_exit;
653 status = SMB_VFS_CREATE_FILE(
654 conn, /* conn */
655 NULL, /* req */
656 0, /* root_dir_fid */
657 smb_fname, /* fname */
658 FILE_GENERIC_READ, /* access_mask */
659 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
660 FILE_OPEN, /* create_disposition*/
661 0, /* create_options */
662 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
663 INTERNAL_OPEN_ONLY, /* oplock_request */
664 0, /* private_flags */
665 0, /* allocation_size */
666 NULL, /* sd */
667 NULL, /* ea_list */
668 &fsp, /* result */
669 NULL); /* pinfo */
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
673 "%d\n", smb_fname_str_dbg(smb_fname), errno));
674 *perr = WERR_ACCESS_DENIED;
675 goto error_exit;
676 } else {
677 uint32 major;
678 uint32 minor;
679 int ret;
681 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
682 if (ret == -1) goto error_exit;
684 if (!ret) {
685 DEBUG(6,("get_correct_cversion: Version info not "
686 "found [%s]\n",
687 smb_fname_str_dbg(smb_fname)));
688 goto error_exit;
692 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
693 * for more details. Version in this case is not just the version of the
694 * file, but the version in the sense of kernal mode (2) vs. user mode
695 * (3) drivers. Other bits of the version fields are the version info.
696 * JRR 010716
698 cversion = major & 0x0000ffff;
699 switch (cversion) {
700 case 2: /* WinNT drivers */
701 case 3: /* Win2K drivers */
702 break;
704 default:
705 DEBUG(6,("get_correct_cversion: cversion "
706 "invalid [%s] cversion = %d\n",
707 smb_fname_str_dbg(smb_fname),
708 cversion));
709 goto error_exit;
712 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
713 " = 0x%x minor = 0x%x\n",
714 smb_fname_str_dbg(smb_fname), major, minor));
717 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
718 smb_fname_str_dbg(smb_fname), cversion));
720 goto done;
722 error_exit:
723 cversion = -1;
724 done:
725 TALLOC_FREE(smb_fname);
726 if (fsp != NULL) {
727 close_file(NULL, fsp, NORMAL_CLOSE);
729 if (conn != NULL) {
730 vfs_ChDir(conn, oldcwd);
731 conn_free(conn);
733 if (cversion != -1) {
734 *perr = WERR_OK;
736 return cversion;
739 /****************************************************************************
740 ****************************************************************************/
742 #define strip_driver_path(_mem_ctx, _element) do { \
743 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
744 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
745 W_ERROR_HAVE_NO_MEMORY((_element)); \
747 } while (0);
749 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
750 struct pipes_struct *rpc_pipe,
751 const char *architecture,
752 const char **driver_path,
753 const char **data_file,
754 const char **config_file,
755 const char **help_file,
756 struct spoolss_StringArray *dependent_files,
757 enum spoolss_DriverOSVersion *version)
759 const char *short_architecture;
760 int i;
761 WERROR err;
762 char *_p;
764 if (!*driver_path || !*data_file) {
765 return WERR_INVALID_PARAM;
768 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
769 return WERR_INVALID_PARAM;
772 /* clean up the driver name.
773 * we can get .\driver.dll
774 * or worse c:\windows\system\driver.dll !
776 /* using an intermediate string to not have overlaping memcpy()'s */
778 strip_driver_path(mem_ctx, *driver_path);
779 strip_driver_path(mem_ctx, *data_file);
780 if (*config_file) {
781 strip_driver_path(mem_ctx, *config_file);
783 if (help_file) {
784 strip_driver_path(mem_ctx, *help_file);
787 if (dependent_files && dependent_files->string) {
788 for (i=0; dependent_files->string[i]; i++) {
789 strip_driver_path(mem_ctx, dependent_files->string[i]);
793 short_architecture = get_short_archi(architecture);
794 if (!short_architecture) {
795 return WERR_UNKNOWN_PRINTER_DRIVER;
798 /* jfm:7/16/2000 the client always sends the cversion=0.
799 * The server should check which version the driver is by reading
800 * the PE header of driver->driverpath.
802 * For Windows 95/98 the version is 0 (so the value sent is correct)
803 * For Windows NT (the architecture doesn't matter)
804 * NT 3.1: cversion=0
805 * NT 3.5/3.51: cversion=1
806 * NT 4: cversion=2
807 * NT2K: cversion=3
810 *version = get_correct_cversion(rpc_pipe, short_architecture,
811 *driver_path, &err);
812 if (*version == -1) {
813 return err;
816 return WERR_OK;
819 /****************************************************************************
820 ****************************************************************************/
822 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
823 struct pipes_struct *rpc_pipe,
824 struct spoolss_AddDriverInfoCtr *r)
826 switch (r->level) {
827 case 3:
828 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
829 r->info.info3->architecture,
830 &r->info.info3->driver_path,
831 &r->info.info3->data_file,
832 &r->info.info3->config_file,
833 &r->info.info3->help_file,
834 r->info.info3->dependent_files,
835 &r->info.info3->version);
836 case 6:
837 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
838 r->info.info6->architecture,
839 &r->info.info6->driver_path,
840 &r->info.info6->data_file,
841 &r->info.info6->config_file,
842 &r->info.info6->help_file,
843 r->info.info6->dependent_files,
844 &r->info.info6->version);
845 default:
846 return WERR_NOT_SUPPORTED;
850 /****************************************************************************
851 This function sucks and should be replaced. JRA.
852 ****************************************************************************/
854 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
855 const struct spoolss_AddDriverInfo6 *src)
857 dst->version = src->version;
859 dst->driver_name = src->driver_name;
860 dst->architecture = src->architecture;
861 dst->driver_path = src->driver_path;
862 dst->data_file = src->data_file;
863 dst->config_file = src->config_file;
864 dst->help_file = src->help_file;
865 dst->monitor_name = src->monitor_name;
866 dst->default_datatype = src->default_datatype;
867 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
868 dst->dependent_files = src->dependent_files;
871 /****************************************************************************
872 ****************************************************************************/
874 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
875 connection_struct *conn,
876 const char *driver_file,
877 const char *short_architecture,
878 uint32_t driver_version,
879 uint32_t version)
881 struct smb_filename *smb_fname_old = NULL;
882 struct smb_filename *smb_fname_new = NULL;
883 char *old_name = NULL;
884 char *new_name = NULL;
885 NTSTATUS status;
886 WERROR ret;
888 old_name = talloc_asprintf(mem_ctx, "%s/%s",
889 short_architecture, driver_file);
890 W_ERROR_HAVE_NO_MEMORY(old_name);
892 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
893 short_architecture, driver_version, driver_file);
894 if (new_name == NULL) {
895 TALLOC_FREE(old_name);
896 return WERR_NOMEM;
899 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
901 status = driver_unix_convert(conn, old_name, &smb_fname_old);
902 if (!NT_STATUS_IS_OK(status)) {
903 ret = WERR_NOMEM;
904 goto out;
907 /* Setup a synthetic smb_filename struct */
908 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
909 if (!smb_fname_new) {
910 ret = WERR_NOMEM;
911 goto out;
914 smb_fname_new->base_name = new_name;
916 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
917 "'%s'\n", smb_fname_old->base_name,
918 smb_fname_new->base_name));
920 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
921 OPENX_FILE_EXISTS_TRUNCATE |
922 OPENX_FILE_CREATE_IF_NOT_EXIST,
923 0, false);
925 if (!NT_STATUS_IS_OK(status)) {
926 DEBUG(0,("move_driver_file_to_download_area: Unable "
927 "to rename [%s] to [%s]: %s\n",
928 smb_fname_old->base_name, new_name,
929 nt_errstr(status)));
930 ret = WERR_ACCESS_DENIED;
931 goto out;
935 ret = WERR_OK;
936 out:
937 TALLOC_FREE(smb_fname_old);
938 TALLOC_FREE(smb_fname_new);
939 return ret;
942 WERROR move_driver_to_download_area(struct pipes_struct *p,
943 struct spoolss_AddDriverInfoCtr *r,
944 WERROR *perr)
946 struct spoolss_AddDriverInfo3 *driver;
947 struct spoolss_AddDriverInfo3 converted_driver;
948 const char *short_architecture;
949 struct smb_filename *smb_dname = NULL;
950 char *new_dir = NULL;
951 connection_struct *conn = NULL;
952 NTSTATUS nt_status;
953 int i;
954 TALLOC_CTX *ctx = talloc_tos();
955 int ver = 0;
956 char *oldcwd;
957 char *printdollar = NULL;
958 int printdollar_snum;
960 *perr = WERR_OK;
962 switch (r->level) {
963 case 3:
964 driver = r->info.info3;
965 break;
966 case 6:
967 convert_level_6_to_level3(&converted_driver, r->info.info6);
968 driver = &converted_driver;
969 break;
970 default:
971 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
972 return WERR_UNKNOWN_LEVEL;
975 short_architecture = get_short_archi(driver->architecture);
976 if (!short_architecture) {
977 return WERR_UNKNOWN_PRINTER_DRIVER;
980 printdollar_snum = find_service(ctx, "print$", &printdollar);
981 if (!printdollar) {
982 *perr = WERR_NOMEM;
983 return WERR_NOMEM;
985 if (printdollar_snum == -1) {
986 *perr = WERR_NO_SUCH_SHARE;
987 return WERR_NO_SUCH_SHARE;
990 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
991 lp_pathname(printdollar_snum),
992 p->server_info, &oldcwd);
993 if (!NT_STATUS_IS_OK(nt_status)) {
994 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
995 "returned %s\n", nt_errstr(nt_status)));
996 *perr = ntstatus_to_werror(nt_status);
997 return *perr;
1000 new_dir = talloc_asprintf(ctx,
1001 "%s/%d",
1002 short_architecture,
1003 driver->version);
1004 if (!new_dir) {
1005 *perr = WERR_NOMEM;
1006 goto err_exit;
1008 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1009 if (!NT_STATUS_IS_OK(nt_status)) {
1010 *perr = WERR_NOMEM;
1011 goto err_exit;
1014 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1016 create_directory(conn, NULL, smb_dname);
1018 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1019 * listed for this driver which has already been moved, skip it (note:
1020 * drivers may list the same file name several times. Then check if the
1021 * file already exists in archi\version\, if so, check that the version
1022 * info (or time stamps if version info is unavailable) is newer (or the
1023 * date is later). If it is, move it to archi\version\filexxx.yyy.
1024 * Otherwise, delete the file.
1026 * If a file is not moved to archi\version\ because of an error, all the
1027 * rest of the 'unmoved' driver files are removed from archi\. If one or
1028 * more of the driver's files was already moved to archi\version\, it
1029 * potentially leaves the driver in a partially updated state. Version
1030 * trauma will most likely occur if an client attempts to use any printer
1031 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1032 * done is appropriate... later JRR
1035 DEBUG(5,("Moving files now !\n"));
1037 if (driver->driver_path && strlen(driver->driver_path)) {
1039 *perr = move_driver_file_to_download_area(ctx,
1040 conn,
1041 driver->driver_path,
1042 short_architecture,
1043 driver->version,
1044 ver);
1045 if (!W_ERROR_IS_OK(*perr)) {
1046 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1047 ver = -1;
1049 goto err_exit;
1053 if (driver->data_file && strlen(driver->data_file)) {
1054 if (!strequal(driver->data_file, driver->driver_path)) {
1056 *perr = move_driver_file_to_download_area(ctx,
1057 conn,
1058 driver->data_file,
1059 short_architecture,
1060 driver->version,
1061 ver);
1062 if (!W_ERROR_IS_OK(*perr)) {
1063 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1064 ver = -1;
1066 goto err_exit;
1071 if (driver->config_file && strlen(driver->config_file)) {
1072 if (!strequal(driver->config_file, driver->driver_path) &&
1073 !strequal(driver->config_file, driver->data_file)) {
1075 *perr = move_driver_file_to_download_area(ctx,
1076 conn,
1077 driver->config_file,
1078 short_architecture,
1079 driver->version,
1080 ver);
1081 if (!W_ERROR_IS_OK(*perr)) {
1082 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1083 ver = -1;
1085 goto err_exit;
1090 if (driver->help_file && strlen(driver->help_file)) {
1091 if (!strequal(driver->help_file, driver->driver_path) &&
1092 !strequal(driver->help_file, driver->data_file) &&
1093 !strequal(driver->help_file, driver->config_file)) {
1095 *perr = move_driver_file_to_download_area(ctx,
1096 conn,
1097 driver->help_file,
1098 short_architecture,
1099 driver->version,
1100 ver);
1101 if (!W_ERROR_IS_OK(*perr)) {
1102 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1103 ver = -1;
1105 goto err_exit;
1110 if (driver->dependent_files && driver->dependent_files->string) {
1111 for (i=0; driver->dependent_files->string[i]; i++) {
1112 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1113 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1114 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1115 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1116 int j;
1117 for (j=0; j < i; j++) {
1118 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1119 goto NextDriver;
1123 *perr = move_driver_file_to_download_area(ctx,
1124 conn,
1125 driver->dependent_files->string[i],
1126 short_architecture,
1127 driver->version,
1128 ver);
1129 if (!W_ERROR_IS_OK(*perr)) {
1130 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1131 ver = -1;
1133 goto err_exit;
1136 NextDriver: ;
1140 err_exit:
1141 TALLOC_FREE(smb_dname);
1143 if (conn != NULL) {
1144 vfs_ChDir(conn, oldcwd);
1145 conn_free(conn);
1148 if (W_ERROR_EQUAL(*perr, WERR_OK)) {
1149 return WERR_OK;
1151 if (ver == -1) {
1152 return WERR_UNKNOWN_PRINTER_DRIVER;
1154 return (*perr);
1157 /****************************************************************************
1158 Create and allocate a default devicemode.
1159 ****************************************************************************/
1161 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1162 const char *devicename,
1163 struct spoolss_DeviceMode **devmode)
1165 struct spoolss_DeviceMode *dm;
1166 char *dname;
1168 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1169 if (dm == NULL) {
1170 return WERR_NOMEM;
1173 dname = talloc_asprintf(dm, "%s", devicename);
1174 if (dname == NULL) {
1175 return WERR_NOMEM;
1177 if (strlen(dname) > MAXDEVICENAME) {
1178 dname[MAXDEVICENAME] = '\0';
1180 dm->devicename = dname;
1182 dm->formname = talloc_strdup(dm, "Letter");
1183 if (dm->formname == NULL) {
1184 return WERR_NOMEM;
1187 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1188 dm->driverversion = 0x0400;
1189 dm->size = 0x00DC;
1190 dm->__driverextra_length = 0;
1191 dm->fields = DEVMODE_FORMNAME |
1192 DEVMODE_TTOPTION |
1193 DEVMODE_PRINTQUALITY |
1194 DEVMODE_DEFAULTSOURCE |
1195 DEVMODE_COPIES |
1196 DEVMODE_SCALE |
1197 DEVMODE_PAPERSIZE |
1198 DEVMODE_ORIENTATION;
1199 dm->orientation = DMORIENT_PORTRAIT;
1200 dm->papersize = DMPAPER_LETTER;
1201 dm->paperlength = 0;
1202 dm->paperwidth = 0;
1203 dm->scale = 0x64;
1204 dm->copies = 1;
1205 dm->defaultsource = DMBIN_FORMSOURCE;
1206 dm->printquality = DMRES_HIGH; /* 0x0258 */
1207 dm->color = DMRES_MONOCHROME;
1208 dm->duplex = DMDUP_SIMPLEX;
1209 dm->yresolution = 0;
1210 dm->ttoption = DMTT_SUBDEV;
1211 dm->collate = DMCOLLATE_FALSE;
1212 dm->icmmethod = 0;
1213 dm->icmintent = 0;
1214 dm->mediatype = 0;
1215 dm->dithertype = 0;
1217 dm->logpixels = 0;
1218 dm->bitsperpel = 0;
1219 dm->pelswidth = 0;
1220 dm->pelsheight = 0;
1221 dm->displayflags = 0;
1222 dm->displayfrequency = 0;
1223 dm->reserved1 = 0;
1224 dm->reserved2 = 0;
1225 dm->panningwidth = 0;
1226 dm->panningheight = 0;
1228 dm->driverextra_data.data = NULL;
1229 dm->driverextra_data.length = 0;
1231 *devmode = dm;
1232 return WERR_OK;
1235 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1236 struct spoolss_security_descriptor **secdesc)
1238 struct security_ace ace[7]; /* max number of ace entries */
1239 int i = 0;
1240 uint32_t sa;
1241 struct security_acl *psa = NULL;
1242 struct security_descriptor *psd = NULL;
1243 struct dom_sid adm_sid;
1244 size_t sd_size;
1246 /* Create an ACE where Everyone is allowed to print */
1248 sa = PRINTER_ACE_PRINT;
1249 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1250 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1252 /* Add the domain admins group if we are a DC */
1254 if ( IS_DC ) {
1255 struct dom_sid domadmins_sid;
1257 sid_compose(&domadmins_sid, get_global_sam_sid(),
1258 DOMAIN_RID_ADMINS);
1260 sa = PRINTER_ACE_FULL_CONTROL;
1261 init_sec_ace(&ace[i++], &domadmins_sid,
1262 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1263 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1264 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1265 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1267 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1268 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1270 sa = PRINTER_ACE_FULL_CONTROL;
1271 init_sec_ace(&ace[i++], &adm_sid,
1272 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1273 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1274 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1275 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1278 /* add BUILTIN\Administrators as FULL CONTROL */
1280 sa = PRINTER_ACE_FULL_CONTROL;
1281 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1282 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1283 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1284 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1285 SEC_ACE_TYPE_ACCESS_ALLOWED,
1286 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1288 /* add BUILTIN\Print Operators as FULL CONTROL */
1290 sa = PRINTER_ACE_FULL_CONTROL;
1291 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1292 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1293 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1294 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1295 SEC_ACE_TYPE_ACCESS_ALLOWED,
1296 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1298 /* Make the security descriptor owned by the BUILTIN\Administrators */
1300 /* The ACL revision number in rpc_secdesc.h differs from the one
1301 created by NT when setting ACE entries in printer
1302 descriptors. NT4 complains about the property being edited by a
1303 NT5 machine. */
1305 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1306 psd = make_sec_desc(mem_ctx,
1307 SD_REVISION,
1308 SEC_DESC_SELF_RELATIVE,
1309 &global_sid_Builtin_Administrators,
1310 &global_sid_Builtin_Administrators,
1311 NULL,
1312 psa,
1313 &sd_size);
1316 if (psd == NULL) {
1317 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1318 return WERR_NOMEM;
1321 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1322 (unsigned int)sd_size));
1324 *secdesc = psd;
1326 return WERR_OK;
1329 /****************************************************************************
1330 ***************************************************************************/
1332 static char *win_driver;
1333 static char *os2_driver;
1335 static const char *get_win_driver(void)
1337 if (win_driver == NULL) {
1338 return "";
1340 return win_driver;
1343 static const char *get_os2_driver(void)
1345 if (os2_driver == NULL) {
1346 return "";
1348 return os2_driver;
1351 static bool set_driver_mapping(const char *from, const char *to)
1353 SAFE_FREE(win_driver);
1354 SAFE_FREE(os2_driver);
1356 win_driver = SMB_STRDUP(from);
1357 os2_driver = SMB_STRDUP(to);
1359 if (win_driver == NULL || os2_driver == NULL) {
1360 SAFE_FREE(win_driver);
1361 SAFE_FREE(os2_driver);
1362 return false;
1364 return true;
1368 * @internal
1370 * @brief Map a Windows driver to a OS/2 driver.
1372 * @param[in] mem_ctx The memory context to use.
1374 * @param[in,out] pdrivername The drivername of Windows to remap.
1376 * @return WERR_OK on success, a corresponding WERROR on failure.
1378 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1380 const char *mapfile = lp_os2_driver_map();
1381 char **lines = NULL;
1382 const char *drivername;
1383 int numlines = 0;
1384 int i;
1386 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1387 return WERR_INVALID_PARAMETER;
1390 drivername = *pdrivername;
1392 if (mapfile[0] == '\0') {
1393 return WERR_BADFILE;
1396 if (strequal(drivername, get_win_driver())) {
1397 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1398 drivername, get_os2_driver()));
1399 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1400 if (drivername == NULL) {
1401 return WERR_NOMEM;
1403 *pdrivername = drivername;
1404 return WERR_OK;
1407 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1408 if (numlines == 0 || lines == NULL) {
1409 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1410 TALLOC_FREE(lines);
1411 return WERR_EMPTY;
1414 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1416 for( i = 0; i < numlines; i++) {
1417 char *nt_name = lines[i];
1418 char *os2_name = strchr(nt_name, '=');
1420 if (os2_name == NULL) {
1421 continue;
1424 *os2_name++ = '\0';
1426 while (isspace(*nt_name)) {
1427 nt_name++;
1430 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1431 continue;
1435 int l = strlen(nt_name);
1436 while (l && isspace(nt_name[l - 1])) {
1437 nt_name[l - 1] = 0;
1438 l--;
1442 while (isspace(*os2_name)) {
1443 os2_name++;
1447 int l = strlen(os2_name);
1448 while (l && isspace(os2_name[l-1])) {
1449 os2_name[l-1] = 0;
1450 l--;
1454 if (strequal(nt_name, drivername)) {
1455 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1456 set_driver_mapping(drivername, os2_name);
1457 drivername = talloc_strdup(mem_ctx, os2_name);
1458 TALLOC_FREE(lines);
1459 if (drivername == NULL) {
1460 return WERR_NOMEM;
1462 *pdrivername = drivername;
1463 return WERR_OK;
1467 TALLOC_FREE(lines);
1468 return WERR_OK;
1471 /****************************************************************************
1472 ****************************************************************************/
1474 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1475 struct spoolss_DriverInfo8 *_info8)
1477 struct spoolss_DriverInfo8 info8;
1479 ZERO_STRUCT(info8);
1481 switch (r->level) {
1482 case 3:
1483 info8.version = r->info.info3->version;
1484 info8.driver_name = r->info.info3->driver_name;
1485 info8.architecture = r->info.info3->architecture;
1486 info8.driver_path = r->info.info3->driver_path;
1487 info8.data_file = r->info.info3->data_file;
1488 info8.config_file = r->info.info3->config_file;
1489 info8.help_file = r->info.info3->help_file;
1490 info8.monitor_name = r->info.info3->monitor_name;
1491 info8.default_datatype = r->info.info3->default_datatype;
1492 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1493 info8.dependent_files = r->info.info3->dependent_files->string;
1495 break;
1496 case 6:
1497 info8.version = r->info.info6->version;
1498 info8.driver_name = r->info.info6->driver_name;
1499 info8.architecture = r->info.info6->architecture;
1500 info8.driver_path = r->info.info6->driver_path;
1501 info8.data_file = r->info.info6->data_file;
1502 info8.config_file = r->info.info6->config_file;
1503 info8.help_file = r->info.info6->help_file;
1504 info8.monitor_name = r->info.info6->monitor_name;
1505 info8.default_datatype = r->info.info6->default_datatype;
1506 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1507 info8.dependent_files = r->info.info6->dependent_files->string;
1509 info8.driver_date = r->info.info6->driver_date;
1510 info8.driver_version = r->info.info6->driver_version;
1511 info8.manufacturer_name = r->info.info6->manufacturer_name;
1512 info8.manufacturer_url = r->info.info6->manufacturer_url;
1513 info8.hardware_id = r->info.info6->hardware_id;
1514 info8.provider = r->info.info6->provider;
1515 break;
1516 case 8:
1517 info8.version = r->info.info8->version;
1518 info8.driver_name = r->info.info8->driver_name;
1519 info8.architecture = r->info.info8->architecture;
1520 info8.driver_path = r->info.info8->driver_path;
1521 info8.data_file = r->info.info8->data_file;
1522 info8.config_file = r->info.info8->config_file;
1523 info8.help_file = r->info.info8->help_file;
1524 info8.monitor_name = r->info.info8->monitor_name;
1525 info8.default_datatype = r->info.info8->default_datatype;
1526 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1527 info8.dependent_files = r->info.info8->dependent_files->string;
1529 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1530 info8.previous_names = r->info.info8->previous_names->string;
1532 info8.driver_date = r->info.info8->driver_date;
1533 info8.driver_version = r->info.info8->driver_version;
1534 info8.manufacturer_name = r->info.info8->manufacturer_name;
1535 info8.manufacturer_url = r->info.info8->manufacturer_url;
1536 info8.hardware_id = r->info.info8->hardware_id;
1537 info8.provider = r->info.info8->provider;
1538 info8.print_processor = r->info.info8->print_processor;
1539 info8.vendor_setup = r->info.info8->vendor_setup;
1540 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1541 info8.color_profiles = r->info.info8->color_profiles->string;
1543 info8.inf_path = r->info.info8->inf_path;
1544 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1545 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1546 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1548 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1549 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1550 break;
1551 default:
1552 return false;
1555 *_info8 = info8;
1557 return true;
1561 /****************************************************************************
1562 Determine whether or not a particular driver is currently assigned
1563 to a printer
1564 ****************************************************************************/
1566 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1567 const struct auth_serversupplied_info *server_info,
1568 struct messaging_context *msg_ctx,
1569 const struct spoolss_DriverInfo8 *r)
1571 int snum;
1572 int n_services = lp_numservices();
1573 bool in_use = False;
1574 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1575 WERROR result;
1577 if (!r) {
1578 return false;
1581 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1583 /* loop through the printers.tdb and check for the drivername */
1585 for (snum=0; snum<n_services && !in_use; snum++) {
1586 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1587 continue;
1590 result = winreg_get_printer(mem_ctx, server_info, msg_ctx,
1591 lp_servicename(snum),
1592 &pinfo2);
1593 if (!W_ERROR_IS_OK(result)) {
1594 continue; /* skip */
1597 if (strequal(r->driver_name, pinfo2->drivername)) {
1598 in_use = True;
1601 TALLOC_FREE(pinfo2);
1604 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1606 if ( in_use ) {
1607 struct spoolss_DriverInfo8 *driver;
1608 WERROR werr;
1610 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1612 /* we can still remove the driver if there is one of
1613 "Windows NT x86" version 2 or 3 left */
1615 if (!strequal("Windows NT x86", r->architecture)) {
1616 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1617 "Windows NT x86",
1618 r->driver_name,
1619 DRIVER_ANY_VERSION,
1620 &driver);
1621 } else if (r->version == 2) {
1622 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1623 "Windows NT x86",
1624 r->driver_name,
1625 3, &driver);
1626 } else if (r->version == 3) {
1627 werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1628 "Windows NT x86",
1629 r->driver_name,
1630 2, &driver);
1631 } else {
1632 DEBUG(0, ("printer_driver_in_use: ERROR!"
1633 " unknown driver version (%d)\n",
1634 r->version));
1635 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1638 /* now check the error code */
1640 if ( W_ERROR_IS_OK(werr) ) {
1641 /* it's ok to remove the driver, we have other architctures left */
1642 in_use = False;
1643 talloc_free(driver);
1647 /* report that the driver is not in use by default */
1649 return in_use;
1653 /**********************************************************************
1654 Check to see if a ogiven file is in use by *info
1655 *********************************************************************/
1657 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1659 int i = 0;
1661 if ( !info )
1662 return False;
1664 /* mz: skip files that are in the list but already deleted */
1665 if (!file || !file[0]) {
1666 return false;
1669 if (strequal(file, info->driver_path))
1670 return True;
1672 if (strequal(file, info->data_file))
1673 return True;
1675 if (strequal(file, info->config_file))
1676 return True;
1678 if (strequal(file, info->help_file))
1679 return True;
1681 /* see of there are any dependent files to examine */
1683 if (!info->dependent_files)
1684 return False;
1686 while (info->dependent_files[i] && *info->dependent_files[i]) {
1687 if (strequal(file, info->dependent_files[i]))
1688 return True;
1689 i++;
1692 return False;
1696 /**********************************************************************
1697 Utility function to remove the dependent file pointed to by the
1698 input parameter from the list
1699 *********************************************************************/
1701 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1704 /* bump everything down a slot */
1706 while (files && files[idx+1]) {
1707 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1708 idx++;
1711 files[idx] = NULL;
1713 return;
1716 /**********************************************************************
1717 Check if any of the files used by src are also used by drv
1718 *********************************************************************/
1720 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1721 struct spoolss_DriverInfo8 *src,
1722 const struct spoolss_DriverInfo8 *drv)
1724 bool in_use = False;
1725 int i = 0;
1727 if ( !src || !drv )
1728 return False;
1730 /* check each file. Remove it from the src structure if it overlaps */
1732 if (drv_file_in_use(src->driver_path, drv)) {
1733 in_use = True;
1734 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1735 src->driver_path = talloc_strdup(mem_ctx, "");
1736 if (!src->driver_path) { return false; }
1739 if (drv_file_in_use(src->data_file, drv)) {
1740 in_use = True;
1741 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1742 src->data_file = talloc_strdup(mem_ctx, "");
1743 if (!src->data_file) { return false; }
1746 if (drv_file_in_use(src->config_file, drv)) {
1747 in_use = True;
1748 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1749 src->config_file = talloc_strdup(mem_ctx, "");
1750 if (!src->config_file) { return false; }
1753 if (drv_file_in_use(src->help_file, drv)) {
1754 in_use = True;
1755 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1756 src->help_file = talloc_strdup(mem_ctx, "");
1757 if (!src->help_file) { return false; }
1760 /* are there any dependentfiles to examine? */
1762 if (!src->dependent_files)
1763 return in_use;
1765 while (src->dependent_files[i] && *src->dependent_files[i]) {
1766 if (drv_file_in_use(src->dependent_files[i], drv)) {
1767 in_use = True;
1768 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1769 trim_dependent_file(mem_ctx, src->dependent_files, i);
1770 } else
1771 i++;
1774 return in_use;
1777 /****************************************************************************
1778 Determine whether or not a particular driver files are currently being
1779 used by any other driver.
1781 Return value is True if any files were in use by other drivers
1782 and False otherwise.
1784 Upon return, *info has been modified to only contain the driver files
1785 which are not in use
1787 Fix from mz:
1789 This needs to check all drivers to ensure that all files in use
1790 have been removed from *info, not just the ones in the first
1791 match.
1792 ****************************************************************************/
1794 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1795 const struct auth_serversupplied_info *server_info,
1796 struct messaging_context *msg_ctx,
1797 struct spoolss_DriverInfo8 *info)
1799 int i;
1800 uint32 version;
1801 struct spoolss_DriverInfo8 *driver;
1802 bool in_use = false;
1803 uint32_t num_drivers;
1804 const char **drivers;
1805 WERROR result;
1807 if ( !info )
1808 return False;
1810 version = info->version;
1812 /* loop over all driver versions */
1814 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1816 /* get the list of drivers */
1818 result = winreg_get_driver_list(mem_ctx, server_info, msg_ctx,
1819 info->architecture, version,
1820 &num_drivers, &drivers);
1821 if (!W_ERROR_IS_OK(result)) {
1822 return true;
1825 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1826 num_drivers, info->architecture, version));
1828 /* check each driver for overlap in files */
1830 for (i = 0; i < num_drivers; i++) {
1831 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1833 driver = NULL;
1835 result = winreg_get_driver(mem_ctx, server_info, msg_ctx,
1836 info->architecture, drivers[i],
1837 version, &driver);
1838 if (!W_ERROR_IS_OK(result)) {
1839 talloc_free(drivers);
1840 return True;
1843 /* check if d2 uses any files from d1 */
1844 /* only if this is a different driver than the one being deleted */
1846 if (!strequal(info->driver_name, driver->driver_name)) {
1847 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1848 /* mz: Do not instantly return -
1849 * we need to ensure this file isn't
1850 * also in use by other drivers. */
1851 in_use = true;
1855 talloc_free(driver);
1858 talloc_free(drivers);
1860 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
1862 return in_use;
1865 static NTSTATUS driver_unlink_internals(connection_struct *conn,
1866 const char *name)
1868 struct smb_filename *smb_fname = NULL;
1869 NTSTATUS status;
1871 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
1872 &smb_fname);
1873 if (!NT_STATUS_IS_OK(status)) {
1874 return status;
1877 status = unlink_internals(conn, NULL, 0, smb_fname, false);
1879 TALLOC_FREE(smb_fname);
1880 return status;
1883 /****************************************************************************
1884 Actually delete the driver files. Make sure that
1885 printer_driver_files_in_use() return False before calling
1886 this.
1887 ****************************************************************************/
1889 bool delete_driver_files(const struct auth_serversupplied_info *server_info,
1890 const struct spoolss_DriverInfo8 *r)
1892 int i = 0;
1893 char *s;
1894 const char *file;
1895 connection_struct *conn;
1896 NTSTATUS nt_status;
1897 char *oldcwd;
1898 char *printdollar = NULL;
1899 int printdollar_snum;
1900 bool ret = false;
1902 if (!r) {
1903 return false;
1906 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
1907 r->driver_name, r->version));
1909 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1910 if (!printdollar) {
1911 return false;
1913 if (printdollar_snum == -1) {
1914 return false;
1917 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
1918 lp_pathname(printdollar_snum),
1919 server_info, &oldcwd);
1920 if (!NT_STATUS_IS_OK(nt_status)) {
1921 DEBUG(0,("delete_driver_files: create_conn_struct "
1922 "returned %s\n", nt_errstr(nt_status)));
1923 return false;
1926 if ( !CAN_WRITE(conn) ) {
1927 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
1928 goto fail;
1931 /* now delete the files; must strip the '\print$' string from
1932 fron of path */
1934 if (r->driver_path && r->driver_path[0]) {
1935 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
1936 file = s;
1937 DEBUG(10,("deleting driverfile [%s]\n", s));
1938 driver_unlink_internals(conn, file);
1942 if (r->config_file && r->config_file[0]) {
1943 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
1944 file = s;
1945 DEBUG(10,("deleting configfile [%s]\n", s));
1946 driver_unlink_internals(conn, file);
1950 if (r->data_file && r->data_file[0]) {
1951 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
1952 file = s;
1953 DEBUG(10,("deleting datafile [%s]\n", s));
1954 driver_unlink_internals(conn, file);
1958 if (r->help_file && r->help_file[0]) {
1959 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
1960 file = s;
1961 DEBUG(10,("deleting helpfile [%s]\n", s));
1962 driver_unlink_internals(conn, file);
1966 /* check if we are done removing files */
1968 if (r->dependent_files) {
1969 while (r->dependent_files[i] && r->dependent_files[i][0]) {
1970 char *p;
1972 /* bypass the "\print$" portion of the path */
1974 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
1975 file = p;
1976 DEBUG(10,("deleting dependent file [%s]\n", file));
1977 driver_unlink_internals(conn, file);
1980 i++;
1984 goto done;
1985 fail:
1986 ret = false;
1987 done:
1988 if (conn != NULL) {
1989 vfs_ChDir(conn, oldcwd);
1990 conn_free(conn);
1992 return ret;
1995 /* error code:
1996 0: everything OK
1997 1: level not implemented
1998 2: file doesn't exist
1999 3: can't allocate memory
2000 4: can't free memory
2001 5: non existant struct
2005 A printer and a printer driver are 2 different things.
2006 NT manages them separatelly, Samba does the same.
2007 Why ? Simply because it's easier and it makes sense !
2009 Now explanation: You have 3 printers behind your samba server,
2010 2 of them are the same make and model (laser A and B). But laser B
2011 has an 3000 sheet feeder and laser A doesn't such an option.
2012 Your third printer is an old dot-matrix model for the accounting :-).
2014 If the /usr/local/samba/lib directory (default dir), you will have
2015 5 files to describe all of this.
2017 3 files for the printers (1 by printer):
2018 NTprinter_laser A
2019 NTprinter_laser B
2020 NTprinter_accounting
2021 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2022 NTdriver_printer model X
2023 NTdriver_printer model Y
2025 jfm: I should use this comment for the text file to explain
2026 same thing for the forms BTW.
2027 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2031 /* Convert generic access rights to printer object specific access rights.
2032 It turns out that NT4 security descriptors use generic access rights and
2033 NT5 the object specific ones. */
2035 void map_printer_permissions(struct security_descriptor *sd)
2037 int i;
2039 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2040 se_map_generic(&sd->dacl->aces[i].access_mask,
2041 &printer_generic_mapping);
2045 void map_job_permissions(struct security_descriptor *sd)
2047 int i;
2049 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2050 se_map_generic(&sd->dacl->aces[i].access_mask,
2051 &job_generic_mapping);
2056 /****************************************************************************
2057 Check a user has permissions to perform the given operation. We use the
2058 permission constants defined in include/rpc_spoolss.h to check the various
2059 actions we perform when checking printer access.
2061 PRINTER_ACCESS_ADMINISTER:
2062 print_queue_pause, print_queue_resume, update_printer_sec,
2063 update_printer, spoolss_addprinterex_level_2,
2064 _spoolss_setprinterdata
2066 PRINTER_ACCESS_USE:
2067 print_job_start
2069 JOB_ACCESS_ADMINISTER:
2070 print_job_delete, print_job_pause, print_job_resume,
2071 print_queue_purge
2073 Try access control in the following order (for performance reasons):
2074 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2075 2) check security descriptor (bit comparisons in memory)
2076 3) "printer admins" (may result in numerous calls to winbind)
2078 ****************************************************************************/
2079 bool print_access_check(const struct auth_serversupplied_info *server_info,
2080 struct messaging_context *msg_ctx, int snum,
2081 int access_type)
2083 struct spoolss_security_descriptor *secdesc = NULL;
2084 uint32 access_granted;
2085 size_t sd_size;
2086 NTSTATUS status;
2087 WERROR result;
2088 const char *pname;
2089 TALLOC_CTX *mem_ctx = NULL;
2091 /* If user is NULL then use the current_user structure */
2093 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2095 if (server_info->utok.uid == sec_initial_uid()
2096 || security_token_has_privilege(server_info->ptok, SEC_PRIV_PRINT_OPERATOR)) {
2097 return True;
2100 /* Get printer name */
2102 pname = lp_printername(snum);
2104 if (!pname || !*pname) {
2105 errno = EACCES;
2106 return False;
2109 /* Get printer security descriptor */
2111 if(!(mem_ctx = talloc_init("print_access_check"))) {
2112 errno = ENOMEM;
2113 return False;
2116 result = winreg_get_printer_secdesc(mem_ctx,
2117 get_server_info_system(),
2118 msg_ctx,
2119 pname,
2120 &secdesc);
2121 if (!W_ERROR_IS_OK(result)) {
2122 talloc_destroy(mem_ctx);
2123 errno = ENOMEM;
2124 return False;
2127 if (access_type == JOB_ACCESS_ADMINISTER) {
2128 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2130 /* Create a child security descriptor to check permissions
2131 against. This is because print jobs are child objects
2132 objects of a printer. */
2133 status = se_create_child_secdesc(mem_ctx,
2134 &secdesc,
2135 &sd_size,
2136 parent_secdesc,
2137 parent_secdesc->owner_sid,
2138 parent_secdesc->group_sid,
2139 false);
2140 if (!NT_STATUS_IS_OK(status)) {
2141 talloc_destroy(mem_ctx);
2142 errno = map_errno_from_nt_status(status);
2143 return False;
2146 map_job_permissions(secdesc);
2147 } else {
2148 map_printer_permissions(secdesc);
2151 /* Check access */
2152 status = se_access_check(secdesc, server_info->ptok, access_type,
2153 &access_granted);
2155 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2157 /* see if we need to try the printer admin list */
2159 if (!NT_STATUS_IS_OK(status) &&
2160 (token_contains_name_in_list(uidtoname(server_info->utok.uid),
2161 server_info->info3->base.domain.string,
2162 NULL, server_info->ptok,
2163 lp_printer_admin(snum)))) {
2164 talloc_destroy(mem_ctx);
2165 return True;
2168 talloc_destroy(mem_ctx);
2170 if (!NT_STATUS_IS_OK(status)) {
2171 errno = EACCES;
2174 return NT_STATUS_IS_OK(status);
2177 /****************************************************************************
2178 Check the time parameters allow a print operation.
2179 *****************************************************************************/
2181 bool print_time_access_check(const struct auth_serversupplied_info *server_info,
2182 struct messaging_context *msg_ctx,
2183 const char *servicename)
2185 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2186 WERROR result;
2187 bool ok = False;
2188 time_t now = time(NULL);
2189 struct tm *t;
2190 uint32 mins;
2192 result = winreg_get_printer(NULL, server_info, msg_ctx,
2193 servicename, &pinfo2);
2194 if (!W_ERROR_IS_OK(result)) {
2195 return False;
2198 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2199 ok = True;
2202 t = gmtime(&now);
2203 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2205 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2206 ok = True;
2209 TALLOC_FREE(pinfo2);
2211 if (!ok) {
2212 errno = EACCES;
2215 return ok;
2218 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2219 const struct auth_serversupplied_info *server_info,
2220 struct messaging_context *msg_ctx,
2221 const char *printer)
2223 WERROR result;
2225 result = winreg_delete_printer_key(mem_ctx, server_info, msg_ctx,
2226 printer, "");
2227 if (!W_ERROR_IS_OK(result)) {
2228 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2229 printer));