s3: Fix an uninitialized variable
[Samba/gebeck_regimport.git] / source3 / printing / nt_printing.c
blobc9ce969b8893a182dafd1962d02a728daa6bf615
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 "../rpc_server/srv_spoolss_util.h"
35 /* Map generic permissions to printer object specific permissions */
37 const struct generic_mapping printer_generic_mapping = {
38 PRINTER_READ,
39 PRINTER_WRITE,
40 PRINTER_EXECUTE,
41 PRINTER_ALL_ACCESS
44 /* Map generic permissions to print server object specific permissions */
46 const struct generic_mapping printserver_generic_mapping = {
47 SERVER_READ,
48 SERVER_WRITE,
49 SERVER_EXECUTE,
50 SERVER_ALL_ACCESS
53 /* Map generic permissions to job object specific permissions */
55 const struct generic_mapping job_generic_mapping = {
56 JOB_READ,
57 JOB_WRITE,
58 JOB_EXECUTE,
59 JOB_ALL_ACCESS
62 static const struct print_architecture_table_node archi_table[]= {
64 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
65 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
66 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
67 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
68 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
69 {"Windows IA64", SPL_ARCH_IA64, 3 },
70 {"Windows x64", SPL_ARCH_X64, 3 },
71 {NULL, "", -1 }
74 /****************************************************************************
75 Open the NT printing tdbs. Done once before fork().
76 ****************************************************************************/
78 bool nt_printing_init(struct messaging_context *msg_ctx)
80 WERROR win_rc;
82 if (!nt_printing_tdb_upgrade()) {
83 return false;
87 * register callback to handle updating printers as new
88 * drivers are installed
90 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
91 do_drv_upgrade_printer);
93 /* of course, none of the message callbacks matter if you don't
94 tell messages.c that you interested in receiving PRINT_GENERAL
95 msgs. This is done in serverid_register() */
97 if ( lp_security() == SEC_ADS ) {
98 win_rc = check_published_printers();
99 if (!W_ERROR_IS_OK(win_rc))
100 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
103 return true;
106 /*******************************************************************
107 Function to allow filename parsing "the old way".
108 ********************************************************************/
110 static NTSTATUS driver_unix_convert(connection_struct *conn,
111 const char *old_name,
112 struct smb_filename **smb_fname)
114 NTSTATUS status;
115 TALLOC_CTX *ctx = talloc_tos();
116 char *name = talloc_strdup(ctx, old_name);
118 if (!name) {
119 return NT_STATUS_NO_MEMORY;
121 unix_format(name);
122 name = unix_clean_name(ctx, name);
123 if (!name) {
124 return NT_STATUS_NO_MEMORY;
126 trim_string(name,"/","/");
128 status = unix_convert(ctx, conn, name, smb_fname, 0);
129 if (!NT_STATUS_IS_OK(status)) {
130 return NT_STATUS_NO_MEMORY;
133 return NT_STATUS_OK;
136 /****************************************************************************
137 Function to do the mapping between the long architecture name and
138 the short one.
139 ****************************************************************************/
141 const char *get_short_archi(const char *long_archi)
143 int i=-1;
145 DEBUG(107,("Getting architecture dependant directory\n"));
146 do {
147 i++;
148 } while ( (archi_table[i].long_archi!=NULL ) &&
149 StrCaseCmp(long_archi, archi_table[i].long_archi) );
151 if (archi_table[i].long_archi==NULL) {
152 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
153 return NULL;
156 /* this might be client code - but shouldn't this be an fstrcpy etc? */
158 DEBUGADD(108,("index: [%d]\n", i));
159 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
160 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
162 return archi_table[i].short_archi;
165 /****************************************************************************
166 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
167 There are two case to be covered here: PE (Portable Executable) and NE (New
168 Executable) files. Both files support the same INFO structure, but PE files
169 store the signature in unicode, and NE files store it as !unicode.
170 returns -1 on error, 1 on version info found, and 0 on no version info found.
171 ****************************************************************************/
173 static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
175 int i;
176 char *buf = NULL;
177 ssize_t byte_count;
179 if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
180 DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
181 fname, DOS_HEADER_SIZE));
182 goto error_exit;
185 if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
186 DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
187 fname, (unsigned long)byte_count));
188 goto no_version_info;
191 /* Is this really a DOS header? */
192 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
193 DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
194 fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
195 goto no_version_info;
198 /* Skip OEM header (if any) and the DOS stub to start of Windows header */
199 if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
200 DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
201 fname, errno));
202 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
203 goto no_version_info;
206 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
207 if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
208 DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
209 fname, (unsigned long)byte_count));
210 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
211 goto no_version_info;
214 /* The header may be a PE (Portable Executable) or an NE (New Executable) */
215 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
216 unsigned int num_sections;
217 unsigned int section_table_bytes;
219 /* Just skip over optional header to get to section table */
220 if (SMB_VFS_LSEEK(fsp,
221 SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
222 SEEK_CUR) == (SMB_OFF_T)-1) {
223 DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
224 fname, errno));
225 goto error_exit;
228 /* get the section table */
229 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
230 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
231 if (section_table_bytes == 0)
232 goto error_exit;
234 SAFE_FREE(buf);
235 if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
236 DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
237 fname, section_table_bytes));
238 goto error_exit;
241 if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
242 DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
243 fname, (unsigned long)byte_count));
244 goto error_exit;
247 /* Iterate the section table looking for the resource section ".rsrc" */
248 for (i = 0; i < num_sections; i++) {
249 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
251 if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
252 unsigned int section_pos = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
253 unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
255 if (section_bytes == 0)
256 goto error_exit;
258 SAFE_FREE(buf);
259 if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
260 DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
261 fname, section_bytes));
262 goto error_exit;
265 /* Seek to the start of the .rsrc section info */
266 if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
267 DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
268 fname, errno));
269 goto error_exit;
272 if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
273 DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
274 fname, (unsigned long)byte_count));
275 goto error_exit;
278 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
279 goto error_exit;
281 for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
282 /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
283 if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
284 /* Align to next long address */
285 int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
287 if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
288 *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
289 *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
291 DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
292 fname, *major, *minor,
293 (*major>>16)&0xffff, *major&0xffff,
294 (*minor>>16)&0xffff, *minor&0xffff));
295 SAFE_FREE(buf);
296 return 1;
303 /* Version info not found, fall back to origin date/time */
304 DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
305 SAFE_FREE(buf);
306 return 0;
308 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
309 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
310 DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
311 fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
312 /* At this point, we assume the file is in error. It still could be somthing
313 * else besides a NE file, but it unlikely at this point. */
314 goto error_exit;
317 /* Allocate a bit more space to speed up things */
318 SAFE_FREE(buf);
319 if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
320 DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes = %d\n",
321 fname, PE_HEADER_SIZE));
322 goto error_exit;
325 /* This is a HACK! I got tired of trying to sort through the messy
326 * 'NE' file format. If anyone wants to clean this up please have at
327 * it, but this works. 'NE' files will eventually fade away. JRR */
328 while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
329 /* Cover case that should not occur in a well formed 'NE' .dll file */
330 if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
332 for(i=0; i<byte_count; i++) {
333 /* Fast skip past data that can't possibly match */
334 if (buf[i] != 'V') continue;
336 /* Potential match data crosses buf boundry, move it to beginning
337 * of buf, and fill the buf with as much as it will hold. */
338 if (i>byte_count-VS_VERSION_INFO_SIZE) {
339 int bc;
341 memcpy(buf, &buf[i], byte_count-i);
342 if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
343 (byte_count-i))) < 0) {
345 DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
346 fname, errno));
347 goto error_exit;
350 byte_count = bc + (byte_count - i);
351 if (byte_count<VS_VERSION_INFO_SIZE) break;
353 i = 0;
356 /* Check that the full signature string and the magic number that
357 * follows exist (not a perfect solution, but the chances that this
358 * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
359 * twice, as it is simpler to read the code. */
360 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
361 /* Compute skip alignment to next long address */
362 int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
363 sizeof(VS_SIGNATURE)) & 3;
364 if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
366 *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
367 *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
368 DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
369 fname, *major, *minor,
370 (*major>>16)&0xffff, *major&0xffff,
371 (*minor>>16)&0xffff, *minor&0xffff));
372 SAFE_FREE(buf);
373 return 1;
378 /* Version info not found, fall back to origin date/time */
379 DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
380 SAFE_FREE(buf);
381 return 0;
383 } else
384 /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
385 DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
386 fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
388 no_version_info:
389 SAFE_FREE(buf);
390 return 0;
392 error_exit:
393 SAFE_FREE(buf);
394 return -1;
397 /****************************************************************************
398 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
399 share one or more files. During the MS installation process files are checked
400 to insure that only a newer version of a shared file is installed over an
401 older version. There are several possibilities for this comparison. If there
402 is no previous version, the new one is newer (obviously). If either file is
403 missing the version info structure, compare the creation date (on Unix use
404 the modification date). Otherwise chose the numerically larger version number.
405 ****************************************************************************/
407 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
409 bool use_version = true;
411 uint32 new_major;
412 uint32 new_minor;
413 time_t new_create_time;
415 uint32 old_major;
416 uint32 old_minor;
417 time_t old_create_time;
419 struct smb_filename *smb_fname = NULL;
420 files_struct *fsp = NULL;
421 SMB_STRUCT_STAT st;
423 NTSTATUS status;
424 int ret;
426 SET_STAT_INVALID(st);
427 new_create_time = (time_t)0;
428 old_create_time = (time_t)0;
430 /* Get file version info (if available) for previous file (if it exists) */
431 status = driver_unix_convert(conn, old_file, &smb_fname);
432 if (!NT_STATUS_IS_OK(status)) {
433 goto error_exit;
436 status = SMB_VFS_CREATE_FILE(
437 conn, /* conn */
438 NULL, /* req */
439 0, /* root_dir_fid */
440 smb_fname, /* fname */
441 FILE_GENERIC_READ, /* access_mask */
442 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
443 FILE_OPEN, /* create_disposition*/
444 0, /* create_options */
445 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
446 INTERNAL_OPEN_ONLY, /* oplock_request */
447 0, /* allocation_size */
448 0, /* private_flags */
449 NULL, /* sd */
450 NULL, /* ea_list */
451 &fsp, /* result */
452 NULL); /* pinfo */
454 if (!NT_STATUS_IS_OK(status)) {
455 /* Old file not found, so by definition new file is in fact newer */
456 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
457 "errno = %d\n", smb_fname_str_dbg(smb_fname),
458 errno));
459 ret = 1;
460 goto done;
462 } else {
463 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
464 if (ret == -1) {
465 goto error_exit;
468 if (!ret) {
469 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
470 old_file));
471 use_version = false;
472 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
473 goto error_exit;
475 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
476 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
477 (long)old_create_time));
480 close_file(NULL, fsp, NORMAL_CLOSE);
481 fsp = NULL;
483 /* Get file version info (if available) for new file */
484 status = driver_unix_convert(conn, new_file, &smb_fname);
485 if (!NT_STATUS_IS_OK(status)) {
486 goto error_exit;
489 status = SMB_VFS_CREATE_FILE(
490 conn, /* conn */
491 NULL, /* req */
492 0, /* root_dir_fid */
493 smb_fname, /* fname */
494 FILE_GENERIC_READ, /* access_mask */
495 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
496 FILE_OPEN, /* create_disposition*/
497 0, /* create_options */
498 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
499 INTERNAL_OPEN_ONLY, /* oplock_request */
500 0, /* allocation_size */
501 0, /* private_flags */
502 NULL, /* sd */
503 NULL, /* ea_list */
504 &fsp, /* result */
505 NULL); /* pinfo */
507 if (!NT_STATUS_IS_OK(status)) {
508 /* New file not found, this shouldn't occur if the caller did its job */
509 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
510 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
511 goto error_exit;
513 } else {
514 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
515 if (ret == -1) {
516 goto error_exit;
519 if (!ret) {
520 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
521 new_file));
522 use_version = false;
523 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
524 goto error_exit;
526 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
527 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
528 (long)new_create_time));
531 close_file(NULL, fsp, NORMAL_CLOSE);
532 fsp = NULL;
534 if (use_version && (new_major != old_major || new_minor != old_minor)) {
535 /* Compare versions and choose the larger version number */
536 if (new_major > old_major ||
537 (new_major == old_major && new_minor > old_minor)) {
539 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
540 ret = 1;
541 goto done;
543 else {
544 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
545 ret = 0;
546 goto done;
549 } else {
550 /* Compare modification time/dates and choose the newest time/date */
551 if (new_create_time > old_create_time) {
552 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
553 ret = 1;
554 goto done;
556 else {
557 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
558 ret = 0;
559 goto done;
563 error_exit:
564 if(fsp)
565 close_file(NULL, fsp, NORMAL_CLOSE);
566 ret = -1;
567 done:
568 TALLOC_FREE(smb_fname);
569 return ret;
572 /****************************************************************************
573 Determine the correct cVersion associated with an architecture and driver
574 ****************************************************************************/
575 static uint32 get_correct_cversion(struct pipes_struct *p,
576 const char *architecture,
577 const char *driverpath_in,
578 WERROR *perr)
580 int cversion;
581 NTSTATUS nt_status;
582 struct smb_filename *smb_fname = NULL;
583 char *driverpath = NULL;
584 files_struct *fsp = NULL;
585 connection_struct *conn = NULL;
586 NTSTATUS status;
587 char *oldcwd;
588 fstring printdollar;
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 fstrcpy(printdollar, "print$");
609 printdollar_snum = find_service(printdollar);
610 if (printdollar_snum == -1) {
611 *perr = WERR_NO_SUCH_SHARE;
612 return -1;
615 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
616 lp_pathname(printdollar_snum),
617 p->server_info, &oldcwd);
618 if (!NT_STATUS_IS_OK(nt_status)) {
619 DEBUG(0,("get_correct_cversion: create_conn_struct "
620 "returned %s\n", nt_errstr(nt_status)));
621 *perr = ntstatus_to_werror(nt_status);
622 return -1;
625 /* Open the driver file (Portable Executable format) and determine the
626 * deriver the cversion. */
627 driverpath = talloc_asprintf(talloc_tos(),
628 "%s/%s",
629 architecture,
630 driverpath_in);
631 if (!driverpath) {
632 *perr = WERR_NOMEM;
633 goto error_exit;
636 nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
637 if (!NT_STATUS_IS_OK(nt_status)) {
638 *perr = ntstatus_to_werror(nt_status);
639 goto error_exit;
642 nt_status = vfs_file_exist(conn, smb_fname);
643 if (!NT_STATUS_IS_OK(nt_status)) {
644 *perr = WERR_BADFILE;
645 goto error_exit;
648 status = SMB_VFS_CREATE_FILE(
649 conn, /* conn */
650 NULL, /* req */
651 0, /* root_dir_fid */
652 smb_fname, /* fname */
653 FILE_GENERIC_READ, /* access_mask */
654 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
655 FILE_OPEN, /* create_disposition*/
656 0, /* create_options */
657 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
658 INTERNAL_OPEN_ONLY, /* oplock_request */
659 0, /* private_flags */
660 0, /* allocation_size */
661 NULL, /* sd */
662 NULL, /* ea_list */
663 &fsp, /* result */
664 NULL); /* pinfo */
666 if (!NT_STATUS_IS_OK(status)) {
667 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
668 "%d\n", smb_fname_str_dbg(smb_fname), errno));
669 *perr = WERR_ACCESS_DENIED;
670 goto error_exit;
671 } else {
672 uint32 major;
673 uint32 minor;
674 int ret;
676 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
677 if (ret == -1) goto error_exit;
679 if (!ret) {
680 DEBUG(6,("get_correct_cversion: Version info not "
681 "found [%s]\n",
682 smb_fname_str_dbg(smb_fname)));
683 goto error_exit;
687 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
688 * for more details. Version in this case is not just the version of the
689 * file, but the version in the sense of kernal mode (2) vs. user mode
690 * (3) drivers. Other bits of the version fields are the version info.
691 * JRR 010716
693 cversion = major & 0x0000ffff;
694 switch (cversion) {
695 case 2: /* WinNT drivers */
696 case 3: /* Win2K drivers */
697 break;
699 default:
700 DEBUG(6,("get_correct_cversion: cversion "
701 "invalid [%s] cversion = %d\n",
702 smb_fname_str_dbg(smb_fname),
703 cversion));
704 goto error_exit;
707 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
708 " = 0x%x minor = 0x%x\n",
709 smb_fname_str_dbg(smb_fname), major, minor));
712 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
713 smb_fname_str_dbg(smb_fname), cversion));
715 goto done;
717 error_exit:
718 cversion = -1;
719 done:
720 TALLOC_FREE(smb_fname);
721 if (fsp != NULL) {
722 close_file(NULL, fsp, NORMAL_CLOSE);
724 if (conn != NULL) {
725 vfs_ChDir(conn, oldcwd);
726 conn_free(conn);
728 if (cversion != -1) {
729 *perr = WERR_OK;
731 return cversion;
734 /****************************************************************************
735 ****************************************************************************/
737 #define strip_driver_path(_mem_ctx, _element) do { \
738 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
739 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
740 W_ERROR_HAVE_NO_MEMORY((_element)); \
742 } while (0);
744 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
745 struct pipes_struct *rpc_pipe,
746 const char *architecture,
747 const char **driver_path,
748 const char **data_file,
749 const char **config_file,
750 const char **help_file,
751 struct spoolss_StringArray *dependent_files,
752 uint32_t *version)
754 const char *short_architecture;
755 int i;
756 WERROR err;
757 char *_p;
759 if (!*driver_path || !*data_file || !*config_file) {
760 return WERR_INVALID_PARAM;
763 /* clean up the driver name.
764 * we can get .\driver.dll
765 * or worse c:\windows\system\driver.dll !
767 /* using an intermediate string to not have overlaping memcpy()'s */
769 strip_driver_path(mem_ctx, *driver_path);
770 strip_driver_path(mem_ctx, *data_file);
771 strip_driver_path(mem_ctx, *config_file);
772 if (help_file) {
773 strip_driver_path(mem_ctx, *help_file);
776 if (dependent_files && dependent_files->string) {
777 for (i=0; dependent_files->string[i]; i++) {
778 strip_driver_path(mem_ctx, dependent_files->string[i]);
782 short_architecture = get_short_archi(architecture);
783 if (!short_architecture) {
784 return WERR_UNKNOWN_PRINTER_DRIVER;
787 /* jfm:7/16/2000 the client always sends the cversion=0.
788 * The server should check which version the driver is by reading
789 * the PE header of driver->driverpath.
791 * For Windows 95/98 the version is 0 (so the value sent is correct)
792 * For Windows NT (the architecture doesn't matter)
793 * NT 3.1: cversion=0
794 * NT 3.5/3.51: cversion=1
795 * NT 4: cversion=2
796 * NT2K: cversion=3
799 *version = get_correct_cversion(rpc_pipe, short_architecture,
800 *driver_path, &err);
801 if (*version == -1) {
802 return err;
805 return WERR_OK;
808 /****************************************************************************
809 ****************************************************************************/
811 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
812 struct pipes_struct *rpc_pipe,
813 struct spoolss_AddDriverInfoCtr *r)
815 switch (r->level) {
816 case 3:
817 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
818 r->info.info3->architecture,
819 &r->info.info3->driver_path,
820 &r->info.info3->data_file,
821 &r->info.info3->config_file,
822 &r->info.info3->help_file,
823 r->info.info3->dependent_files,
824 &r->info.info3->version);
825 case 6:
826 return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
827 r->info.info6->architecture,
828 &r->info.info6->driver_path,
829 &r->info.info6->data_file,
830 &r->info.info6->config_file,
831 &r->info.info6->help_file,
832 r->info.info6->dependent_files,
833 &r->info.info6->version);
834 default:
835 return WERR_NOT_SUPPORTED;
839 /****************************************************************************
840 This function sucks and should be replaced. JRA.
841 ****************************************************************************/
843 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
844 const struct spoolss_AddDriverInfo6 *src)
846 dst->version = src->version;
848 dst->driver_name = src->driver_name;
849 dst->architecture = src->architecture;
850 dst->driver_path = src->driver_path;
851 dst->data_file = src->data_file;
852 dst->config_file = src->config_file;
853 dst->help_file = src->help_file;
854 dst->monitor_name = src->monitor_name;
855 dst->default_datatype = src->default_datatype;
856 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
857 dst->dependent_files = src->dependent_files;
860 /****************************************************************************
861 ****************************************************************************/
863 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
864 connection_struct *conn,
865 const char *driver_file,
866 const char *short_architecture,
867 uint32_t driver_version,
868 uint32_t version)
870 struct smb_filename *smb_fname_old = NULL;
871 struct smb_filename *smb_fname_new = NULL;
872 char *old_name = NULL;
873 char *new_name = NULL;
874 NTSTATUS status;
875 WERROR ret;
877 old_name = talloc_asprintf(mem_ctx, "%s/%s",
878 short_architecture, driver_file);
879 W_ERROR_HAVE_NO_MEMORY(old_name);
881 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
882 short_architecture, driver_version, driver_file);
883 if (new_name == NULL) {
884 TALLOC_FREE(old_name);
885 return WERR_NOMEM;
888 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
890 status = driver_unix_convert(conn, old_name, &smb_fname_old);
891 if (!NT_STATUS_IS_OK(status)) {
892 ret = WERR_NOMEM;
893 goto out;
896 /* Setup a synthetic smb_filename struct */
897 smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
898 if (!smb_fname_new) {
899 ret = WERR_NOMEM;
900 goto out;
903 smb_fname_new->base_name = new_name;
905 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
906 "'%s'\n", smb_fname_old->base_name,
907 smb_fname_new->base_name));
909 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
910 OPENX_FILE_EXISTS_TRUNCATE |
911 OPENX_FILE_CREATE_IF_NOT_EXIST,
912 0, false);
914 if (!NT_STATUS_IS_OK(status)) {
915 DEBUG(0,("move_driver_file_to_download_area: Unable "
916 "to rename [%s] to [%s]: %s\n",
917 smb_fname_old->base_name, new_name,
918 nt_errstr(status)));
919 ret = WERR_ACCESS_DENIED;
920 goto out;
924 ret = WERR_OK;
925 out:
926 TALLOC_FREE(smb_fname_old);
927 TALLOC_FREE(smb_fname_new);
928 return ret;
931 WERROR move_driver_to_download_area(struct pipes_struct *p,
932 struct spoolss_AddDriverInfoCtr *r,
933 WERROR *perr)
935 struct spoolss_AddDriverInfo3 *driver;
936 struct spoolss_AddDriverInfo3 converted_driver;
937 const char *short_architecture;
938 struct smb_filename *smb_dname = NULL;
939 char *new_dir = NULL;
940 connection_struct *conn = NULL;
941 NTSTATUS nt_status;
942 int i;
943 TALLOC_CTX *ctx = talloc_tos();
944 int ver = 0;
945 char *oldcwd;
946 fstring printdollar;
947 int printdollar_snum;
949 *perr = WERR_OK;
951 switch (r->level) {
952 case 3:
953 driver = r->info.info3;
954 break;
955 case 6:
956 convert_level_6_to_level3(&converted_driver, r->info.info6);
957 driver = &converted_driver;
958 break;
959 default:
960 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
961 return WERR_UNKNOWN_LEVEL;
964 short_architecture = get_short_archi(driver->architecture);
965 if (!short_architecture) {
966 return WERR_UNKNOWN_PRINTER_DRIVER;
969 fstrcpy(printdollar, "print$");
971 printdollar_snum = find_service(printdollar);
972 if (printdollar_snum == -1) {
973 *perr = WERR_NO_SUCH_SHARE;
974 return WERR_NO_SUCH_SHARE;
977 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
978 lp_pathname(printdollar_snum),
979 p->server_info, &oldcwd);
980 if (!NT_STATUS_IS_OK(nt_status)) {
981 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
982 "returned %s\n", nt_errstr(nt_status)));
983 *perr = ntstatus_to_werror(nt_status);
984 return *perr;
987 new_dir = talloc_asprintf(ctx,
988 "%s/%d",
989 short_architecture,
990 driver->version);
991 if (!new_dir) {
992 *perr = WERR_NOMEM;
993 goto err_exit;
995 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
996 if (!NT_STATUS_IS_OK(nt_status)) {
997 *perr = WERR_NOMEM;
998 goto err_exit;
1001 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1003 create_directory(conn, NULL, smb_dname);
1005 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1006 * listed for this driver which has already been moved, skip it (note:
1007 * drivers may list the same file name several times. Then check if the
1008 * file already exists in archi\version\, if so, check that the version
1009 * info (or time stamps if version info is unavailable) is newer (or the
1010 * date is later). If it is, move it to archi\version\filexxx.yyy.
1011 * Otherwise, delete the file.
1013 * If a file is not moved to archi\version\ because of an error, all the
1014 * rest of the 'unmoved' driver files are removed from archi\. If one or
1015 * more of the driver's files was already moved to archi\version\, it
1016 * potentially leaves the driver in a partially updated state. Version
1017 * trauma will most likely occur if an client attempts to use any printer
1018 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1019 * done is appropriate... later JRR
1022 DEBUG(5,("Moving files now !\n"));
1024 if (driver->driver_path && strlen(driver->driver_path)) {
1026 *perr = move_driver_file_to_download_area(ctx,
1027 conn,
1028 driver->driver_path,
1029 short_architecture,
1030 driver->version,
1031 ver);
1032 if (!W_ERROR_IS_OK(*perr)) {
1033 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1034 ver = -1;
1036 goto err_exit;
1040 if (driver->data_file && strlen(driver->data_file)) {
1041 if (!strequal(driver->data_file, driver->driver_path)) {
1043 *perr = move_driver_file_to_download_area(ctx,
1044 conn,
1045 driver->data_file,
1046 short_architecture,
1047 driver->version,
1048 ver);
1049 if (!W_ERROR_IS_OK(*perr)) {
1050 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1051 ver = -1;
1053 goto err_exit;
1058 if (driver->config_file && strlen(driver->config_file)) {
1059 if (!strequal(driver->config_file, driver->driver_path) &&
1060 !strequal(driver->config_file, driver->data_file)) {
1062 *perr = move_driver_file_to_download_area(ctx,
1063 conn,
1064 driver->config_file,
1065 short_architecture,
1066 driver->version,
1067 ver);
1068 if (!W_ERROR_IS_OK(*perr)) {
1069 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1070 ver = -1;
1072 goto err_exit;
1077 if (driver->help_file && strlen(driver->help_file)) {
1078 if (!strequal(driver->help_file, driver->driver_path) &&
1079 !strequal(driver->help_file, driver->data_file) &&
1080 !strequal(driver->help_file, driver->config_file)) {
1082 *perr = move_driver_file_to_download_area(ctx,
1083 conn,
1084 driver->help_file,
1085 short_architecture,
1086 driver->version,
1087 ver);
1088 if (!W_ERROR_IS_OK(*perr)) {
1089 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1090 ver = -1;
1092 goto err_exit;
1097 if (driver->dependent_files && driver->dependent_files->string) {
1098 for (i=0; driver->dependent_files->string[i]; i++) {
1099 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1100 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1101 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1102 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1103 int j;
1104 for (j=0; j < i; j++) {
1105 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1106 goto NextDriver;
1110 *perr = move_driver_file_to_download_area(ctx,
1111 conn,
1112 driver->dependent_files->string[i],
1113 short_architecture,
1114 driver->version,
1115 ver);
1116 if (!W_ERROR_IS_OK(*perr)) {
1117 if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
1118 ver = -1;
1120 goto err_exit;
1123 NextDriver: ;
1127 err_exit:
1128 TALLOC_FREE(smb_dname);
1130 if (conn != NULL) {
1131 vfs_ChDir(conn, oldcwd);
1132 conn_free(conn);
1135 if (W_ERROR_EQUAL(*perr, WERR_OK)) {
1136 return WERR_OK;
1138 if (ver == -1) {
1139 return WERR_UNKNOWN_PRINTER_DRIVER;
1141 return (*perr);
1144 /****************************************************************************
1145 Create and allocate a default devicemode.
1146 ****************************************************************************/
1148 WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
1149 const char *devicename,
1150 struct spoolss_DeviceMode **devmode)
1152 struct spoolss_DeviceMode *dm;
1153 char *dname;
1155 dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
1156 if (dm == NULL) {
1157 return WERR_NOMEM;
1160 dname = talloc_asprintf(dm, "%s", devicename);
1161 if (dname == NULL) {
1162 return WERR_NOMEM;
1164 if (strlen(dname) > MAXDEVICENAME) {
1165 dname[MAXDEVICENAME] = '\0';
1167 dm->devicename = dname;
1169 dm->formname = talloc_strdup(dm, "Letter");
1170 if (dm->formname == NULL) {
1171 return WERR_NOMEM;
1174 dm->specversion = DMSPEC_NT4_AND_ABOVE;
1175 dm->driverversion = 0x0400;
1176 dm->size = 0x00DC;
1177 dm->__driverextra_length = 0;
1178 dm->fields = DEVMODE_FORMNAME |
1179 DEVMODE_TTOPTION |
1180 DEVMODE_PRINTQUALITY |
1181 DEVMODE_DEFAULTSOURCE |
1182 DEVMODE_COPIES |
1183 DEVMODE_SCALE |
1184 DEVMODE_PAPERSIZE |
1185 DEVMODE_ORIENTATION;
1186 dm->orientation = DMORIENT_PORTRAIT;
1187 dm->papersize = DMPAPER_LETTER;
1188 dm->paperlength = 0;
1189 dm->paperwidth = 0;
1190 dm->scale = 0x64;
1191 dm->copies = 1;
1192 dm->defaultsource = DMBIN_FORMSOURCE;
1193 dm->printquality = DMRES_HIGH; /* 0x0258 */
1194 dm->color = DMRES_MONOCHROME;
1195 dm->duplex = DMDUP_SIMPLEX;
1196 dm->yresolution = 0;
1197 dm->ttoption = DMTT_SUBDEV;
1198 dm->collate = DMCOLLATE_FALSE;
1199 dm->icmmethod = 0;
1200 dm->icmintent = 0;
1201 dm->mediatype = 0;
1202 dm->dithertype = 0;
1204 dm->logpixels = 0;
1205 dm->bitsperpel = 0;
1206 dm->pelswidth = 0;
1207 dm->pelsheight = 0;
1208 dm->displayflags = 0;
1209 dm->displayfrequency = 0;
1210 dm->reserved1 = 0;
1211 dm->reserved2 = 0;
1212 dm->panningwidth = 0;
1213 dm->panningheight = 0;
1215 dm->driverextra_data.data = NULL;
1216 dm->driverextra_data.length = 0;
1218 *devmode = dm;
1219 return WERR_OK;
1222 WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
1223 struct spoolss_security_descriptor **secdesc)
1225 struct security_ace ace[7]; /* max number of ace entries */
1226 int i = 0;
1227 uint32_t sa;
1228 struct security_acl *psa = NULL;
1229 struct security_descriptor *psd = NULL;
1230 struct dom_sid adm_sid;
1231 size_t sd_size;
1233 /* Create an ACE where Everyone is allowed to print */
1235 sa = PRINTER_ACE_PRINT;
1236 init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
1237 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1239 /* Add the domain admins group if we are a DC */
1241 if ( IS_DC ) {
1242 struct dom_sid domadmins_sid;
1244 sid_compose(&domadmins_sid, get_global_sam_sid(),
1245 DOMAIN_RID_ADMINS);
1247 sa = PRINTER_ACE_FULL_CONTROL;
1248 init_sec_ace(&ace[i++], &domadmins_sid,
1249 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1250 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1251 init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1252 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1254 else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
1255 sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
1257 sa = PRINTER_ACE_FULL_CONTROL;
1258 init_sec_ace(&ace[i++], &adm_sid,
1259 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1260 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1261 init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
1262 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1265 /* add BUILTIN\Administrators as FULL CONTROL */
1267 sa = PRINTER_ACE_FULL_CONTROL;
1268 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1269 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1270 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1271 init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
1272 SEC_ACE_TYPE_ACCESS_ALLOWED,
1273 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1275 /* add BUILTIN\Print Operators as FULL CONTROL */
1277 sa = PRINTER_ACE_FULL_CONTROL;
1278 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1279 SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
1280 SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
1281 init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
1282 SEC_ACE_TYPE_ACCESS_ALLOWED,
1283 sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
1285 /* Make the security descriptor owned by the BUILTIN\Administrators */
1287 /* The ACL revision number in rpc_secdesc.h differs from the one
1288 created by NT when setting ACE entries in printer
1289 descriptors. NT4 complains about the property being edited by a
1290 NT5 machine. */
1292 if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
1293 psd = make_sec_desc(mem_ctx,
1294 SD_REVISION,
1295 SEC_DESC_SELF_RELATIVE,
1296 &global_sid_Builtin_Administrators,
1297 &global_sid_Builtin_Administrators,
1298 NULL,
1299 psa,
1300 &sd_size);
1303 if (psd == NULL) {
1304 DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
1305 return WERR_NOMEM;
1308 DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
1309 (unsigned int)sd_size));
1311 *secdesc = psd;
1313 return WERR_OK;
1316 #ifdef HAVE_ADS
1317 /*****************************************************************
1318 ****************************************************************/
1320 static void store_printer_guid(const char *printer, struct GUID guid)
1322 TALLOC_CTX *tmp_ctx;
1323 struct auth_serversupplied_info *server_info = NULL;
1324 const char *guid_str;
1325 DATA_BLOB blob;
1326 NTSTATUS status;
1327 WERROR result;
1329 tmp_ctx = talloc_new(NULL);
1330 if (!tmp_ctx) {
1331 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
1332 return;
1335 status = make_server_info_system(tmp_ctx, &server_info);
1336 if (!NT_STATUS_IS_OK(status)) {
1337 DEBUG(0, ("store_printer_guid: "
1338 "Could not create system server_info\n"));
1339 goto done;
1342 guid_str = GUID_string(tmp_ctx, &guid);
1343 if (!guid_str) {
1344 DEBUG(0, ("store_printer_guid: Out of memory?!\n"));
1345 goto done;
1348 /* We used to store this as a REG_BINARY but that causes
1349 Vista to whine */
1351 if (!push_reg_sz(tmp_ctx, &blob, guid_str)) {
1352 DEBUG(0, ("store_printer_guid: "
1353 "Could not marshall string %s for objectGUID\n",
1354 guid_str));
1355 goto done;
1358 result = winreg_set_printer_dataex(tmp_ctx, server_info, printer,
1359 SPOOL_DSSPOOLER_KEY, "objectGUID",
1360 REG_SZ, blob.data, blob.length);
1361 if (!W_ERROR_IS_OK(result)) {
1362 DEBUG(0, ("store_printer_guid: "
1363 "Failed to store GUID for printer %s\n", printer));
1366 done:
1367 talloc_free(tmp_ctx);
1370 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
1371 struct spoolss_PrinterInfo2 *pinfo2)
1373 ADS_STATUS ads_rc;
1374 LDAPMessage *res;
1375 char *prt_dn = NULL, *srv_dn, *srv_cn_0, *srv_cn_escaped, *sharename_escaped;
1376 char *srv_dn_utf8, **srv_cn_utf8;
1377 TALLOC_CTX *ctx;
1378 ADS_MODLIST mods;
1379 const char *attrs[] = {"objectGUID", NULL};
1380 struct GUID guid;
1381 WERROR win_rc = WERR_OK;
1382 size_t converted_size;
1383 const char *printer = pinfo2->sharename;
1385 /* build the ads mods */
1386 ctx = talloc_init("nt_printer_publish_ads");
1387 if (ctx == NULL) {
1388 return WERR_NOMEM;
1391 DEBUG(5, ("publishing printer %s\n", printer));
1393 /* figure out where to publish */
1394 ads_find_machine_acct(ads, &res, global_myname());
1396 /* We use ldap_get_dn here as we need the answer
1397 * in utf8 to call ldap_explode_dn(). JRA. */
1399 srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1400 if (!srv_dn_utf8) {
1401 TALLOC_FREE(ctx);
1402 return WERR_SERVER_UNAVAILABLE;
1404 ads_msgfree(ads, res);
1405 srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
1406 if (!srv_cn_utf8) {
1407 TALLOC_FREE(ctx);
1408 ldap_memfree(srv_dn_utf8);
1409 return WERR_SERVER_UNAVAILABLE;
1411 /* Now convert to CH_UNIX. */
1412 if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
1413 TALLOC_FREE(ctx);
1414 ldap_memfree(srv_dn_utf8);
1415 ldap_memfree(srv_cn_utf8);
1416 return WERR_SERVER_UNAVAILABLE;
1418 if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
1419 TALLOC_FREE(ctx);
1420 ldap_memfree(srv_dn_utf8);
1421 ldap_memfree(srv_cn_utf8);
1422 TALLOC_FREE(srv_dn);
1423 return WERR_SERVER_UNAVAILABLE;
1426 ldap_memfree(srv_dn_utf8);
1427 ldap_memfree(srv_cn_utf8);
1429 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
1430 if (!srv_cn_escaped) {
1431 TALLOC_FREE(ctx);
1432 return WERR_SERVER_UNAVAILABLE;
1434 sharename_escaped = escape_rdn_val_string_alloc(printer);
1435 if (!sharename_escaped) {
1436 SAFE_FREE(srv_cn_escaped);
1437 TALLOC_FREE(ctx);
1438 return WERR_SERVER_UNAVAILABLE;
1441 prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
1443 SAFE_FREE(srv_cn_escaped);
1444 SAFE_FREE(sharename_escaped);
1446 mods = ads_init_mods(ctx);
1448 if (mods == NULL) {
1449 SAFE_FREE(prt_dn);
1450 TALLOC_FREE(ctx);
1451 return WERR_NOMEM;
1454 ads_mod_str(ctx, &mods, SPOOL_REG_PRINTERNAME, printer);
1456 /* publish it */
1457 ads_rc = ads_mod_printer_entry(ads, prt_dn, ctx, &mods);
1458 if (ads_rc.err.rc == LDAP_NO_SUCH_OBJECT) {
1459 int i;
1460 for (i=0; mods[i] != 0; i++)
1462 mods[i] = (LDAPMod *)-1;
1463 ads_rc = ads_add_printer_entry(ads, prt_dn, ctx, &mods);
1466 if (!ADS_ERR_OK(ads_rc)) {
1467 DEBUG(3, ("error publishing %s: %s\n",
1468 printer, ads_errstr(ads_rc)));
1471 /* retreive the guid and store it locally */
1472 if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
1473 ZERO_STRUCT(guid);
1474 ads_pull_guid(ads, res, &guid);
1475 ads_msgfree(ads, res);
1476 store_printer_guid(printer, guid);
1478 TALLOC_FREE(ctx);
1480 return win_rc;
1483 static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
1484 const char *printer)
1486 ADS_STATUS ads_rc;
1487 LDAPMessage *res = NULL;
1488 char *prt_dn = NULL;
1490 DEBUG(5, ("unpublishing printer %s\n", printer));
1492 /* remove the printer from the directory */
1493 ads_rc = ads_find_printer_on_server(ads, &res,
1494 printer, global_myname());
1496 if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
1497 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1498 if (!prt_dn) {
1499 ads_msgfree(ads, res);
1500 return WERR_NOMEM;
1502 ads_rc = ads_del_dn(ads, prt_dn);
1503 TALLOC_FREE(prt_dn);
1506 if (res) {
1507 ads_msgfree(ads, res);
1509 return WERR_OK;
1512 /****************************************************************************
1513 * Publish a printer in the directory
1515 * @param mem_ctx memory context
1516 * @param server_info server_info to access winreg pipe
1517 * @param pinfo2 printer information
1518 * @param action publish/unpublish action
1519 * @return WERROR indicating status of publishing
1520 ***************************************************************************/
1522 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
1523 struct auth_serversupplied_info *server_info,
1524 struct spoolss_PrinterInfo2 *pinfo2,
1525 int action)
1527 uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES;
1528 struct spoolss_SetPrinterInfo2 *sinfo2;
1529 ADS_STATUS ads_rc;
1530 ADS_STRUCT *ads = NULL;
1531 WERROR win_rc;
1533 sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2);
1534 if (!sinfo2) {
1535 return WERR_NOMEM;
1538 switch (action) {
1539 case DSPRINT_PUBLISH:
1540 case DSPRINT_UPDATE:
1541 pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
1542 break;
1543 case DSPRINT_UNPUBLISH:
1544 pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED;
1545 break;
1546 default:
1547 win_rc = WERR_NOT_SUPPORTED;
1548 goto done;
1551 sinfo2->attributes = pinfo2->attributes;
1553 win_rc = winreg_update_printer(mem_ctx, server_info,
1554 pinfo2->sharename, info2_mask,
1555 sinfo2, NULL, NULL);
1556 if (!W_ERROR_IS_OK(win_rc)) {
1557 DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc)));
1558 goto done;
1561 TALLOC_FREE(sinfo2);
1563 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
1564 if (!ads) {
1565 DEBUG(3, ("ads_init() failed\n"));
1566 win_rc = WERR_SERVER_UNAVAILABLE;
1567 goto done;
1569 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
1570 SAFE_FREE(ads->auth.password);
1571 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
1572 NULL, NULL);
1574 /* ads_connect() will find the DC for us */
1575 ads_rc = ads_connect(ads);
1576 if (!ADS_ERR_OK(ads_rc)) {
1577 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
1578 win_rc = WERR_ACCESS_DENIED;
1579 goto done;
1582 switch (action) {
1583 case DSPRINT_PUBLISH:
1584 case DSPRINT_UPDATE:
1585 win_rc = nt_printer_publish_ads(ads, pinfo2);
1586 break;
1587 case DSPRINT_UNPUBLISH:
1588 win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename);
1589 break;
1592 done:
1593 ads_destroy(&ads);
1594 return win_rc;
1597 WERROR check_published_printers(void)
1599 ADS_STATUS ads_rc;
1600 ADS_STRUCT *ads = NULL;
1601 int snum;
1602 int n_services = lp_numservices();
1603 TALLOC_CTX *tmp_ctx = NULL;
1604 struct auth_serversupplied_info *server_info = NULL;
1605 struct spoolss_PrinterInfo2 *pinfo2;
1606 NTSTATUS status;
1607 WERROR result;
1609 tmp_ctx = talloc_new(NULL);
1610 if (!tmp_ctx) return WERR_NOMEM;
1612 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
1613 if (!ads) {
1614 DEBUG(3, ("ads_init() failed\n"));
1615 return WERR_SERVER_UNAVAILABLE;
1617 setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1);
1618 SAFE_FREE(ads->auth.password);
1619 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(),
1620 NULL, NULL);
1622 /* ads_connect() will find the DC for us */
1623 ads_rc = ads_connect(ads);
1624 if (!ADS_ERR_OK(ads_rc)) {
1625 DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc)));
1626 result = WERR_ACCESS_DENIED;
1627 goto done;
1630 status = make_server_info_system(tmp_ctx, &server_info);
1631 if (!NT_STATUS_IS_OK(status)) {
1632 DEBUG(0, ("check_published_printers: "
1633 "Could not create system server_info\n"));
1634 result = WERR_ACCESS_DENIED;
1635 goto done;
1638 for (snum = 0; snum < n_services; snum++) {
1639 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
1640 continue;
1643 result = winreg_get_printer(tmp_ctx, server_info, NULL,
1644 lp_servicename(snum), &pinfo2);
1645 if (!W_ERROR_IS_OK(result)) {
1646 continue;
1649 if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) {
1650 nt_printer_publish_ads(ads, pinfo2);
1653 TALLOC_FREE(pinfo2);
1656 result = WERR_OK;
1657 done:
1658 ads_destroy(&ads);
1659 ads_kdestroy("MEMORY:prtpub_cache");
1660 talloc_free(tmp_ctx);
1661 return result;
1664 bool is_printer_published(TALLOC_CTX *mem_ctx,
1665 struct auth_serversupplied_info *server_info,
1666 char *servername, char *printer, struct GUID *guid,
1667 struct spoolss_PrinterInfo2 **info2)
1669 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1670 enum winreg_Type type;
1671 uint8_t *data;
1672 uint32_t data_size;
1673 WERROR result;
1674 NTSTATUS status;
1676 result = winreg_get_printer(mem_ctx, server_info,
1677 servername, printer, &pinfo2);
1678 if (!W_ERROR_IS_OK(result)) {
1679 return false;
1682 if (!(pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
1683 TALLOC_FREE(pinfo2);
1684 return false;
1687 if (!guid) {
1688 goto done;
1691 /* fetching printer guids really ought to be a separate function. */
1693 result = winreg_get_printer_dataex(mem_ctx, server_info, printer,
1694 SPOOL_DSSPOOLER_KEY, "objectGUID",
1695 &type, &data, &data_size);
1696 if (!W_ERROR_IS_OK(result)) {
1697 TALLOC_FREE(pinfo2);
1698 return false;
1701 /* We used to store the guid as REG_BINARY, then swapped
1702 to REG_SZ for Vista compatibility so check for both */
1704 switch (type) {
1705 case REG_SZ:
1706 status = GUID_from_string((char *)data, guid);
1707 if (!NT_STATUS_IS_OK(status)) {
1708 TALLOC_FREE(pinfo2);
1709 return false;
1711 break;
1713 case REG_BINARY:
1714 if (data_size != sizeof(struct GUID)) {
1715 TALLOC_FREE(pinfo2);
1716 return false;
1718 memcpy(guid, data, sizeof(struct GUID));
1719 break;
1720 default:
1721 DEBUG(0,("is_printer_published: GUID value stored as "
1722 "invaluid type (%d)\n", type));
1723 break;
1726 done:
1727 if (info2) {
1728 *info2 = talloc_move(mem_ctx, &pinfo2);
1730 talloc_free(pinfo2);
1731 return true;
1733 #else
1734 WERROR nt_printer_publish(TALLOC_CTX *mem_ctx,
1735 struct auth_serversupplied_info *server_info,
1736 struct spoolss_PrinterInfo2 *pinfo2,
1737 int action)
1739 return WERR_OK;
1742 WERROR check_published_printers(void)
1744 return WERR_OK;
1747 bool is_printer_published(TALLOC_CTX *mem_ctx,
1748 struct auth_serversupplied_info *server_info,
1749 char *servername, char *printer, struct GUID *guid,
1750 struct spoolss_PrinterInfo2 **info2)
1752 return False;
1754 #endif /* HAVE_ADS */
1756 /****************************************************************************
1757 ***************************************************************************/
1759 static char *win_driver;
1760 static char *os2_driver;
1762 static const char *get_win_driver(void)
1764 if (win_driver == NULL) {
1765 return "";
1767 return win_driver;
1770 static const char *get_os2_driver(void)
1772 if (os2_driver == NULL) {
1773 return "";
1775 return os2_driver;
1778 static bool set_driver_mapping(const char *from, const char *to)
1780 SAFE_FREE(win_driver);
1781 SAFE_FREE(os2_driver);
1783 win_driver = SMB_STRDUP(from);
1784 os2_driver = SMB_STRDUP(to);
1786 if (win_driver == NULL || os2_driver == NULL) {
1787 SAFE_FREE(win_driver);
1788 SAFE_FREE(os2_driver);
1789 return false;
1791 return true;
1795 * @internal
1797 * @brief Map a Windows driver to a OS/2 driver.
1799 * @param[in] mem_ctx The memory context to use.
1801 * @param[in,out] pdrivername The drivername of Windows to remap.
1803 * @return WERR_OK on success, a corresponding WERROR on failure.
1805 WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
1807 const char *mapfile = lp_os2_driver_map();
1808 char **lines = NULL;
1809 const char *drivername;
1810 int numlines = 0;
1811 int i;
1813 if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
1814 return WERR_INVALID_PARAMETER;
1817 drivername = *pdrivername;
1819 if (mapfile[0] == '\0') {
1820 return WERR_BADFILE;
1823 if (strequal(drivername, get_win_driver())) {
1824 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
1825 drivername, get_os2_driver()));
1826 drivername = talloc_strdup(mem_ctx, get_os2_driver());
1827 if (drivername == NULL) {
1828 return WERR_NOMEM;
1830 *pdrivername = drivername;
1831 return WERR_OK;
1834 lines = file_lines_load(mapfile, &numlines, 0, NULL);
1835 if (numlines == 0 || lines == NULL) {
1836 DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
1837 TALLOC_FREE(lines);
1838 return WERR_EMPTY;
1841 DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
1843 for( i = 0; i < numlines; i++) {
1844 char *nt_name = lines[i];
1845 char *os2_name = strchr(nt_name, '=');
1847 if (os2_name == NULL) {
1848 continue;
1851 *os2_name++ = '\0';
1853 while (isspace(*nt_name)) {
1854 nt_name++;
1857 if (*nt_name == '\0' || strchr("#;", *nt_name)) {
1858 continue;
1862 int l = strlen(nt_name);
1863 while (l && isspace(nt_name[l - 1])) {
1864 nt_name[l - 1] = 0;
1865 l--;
1869 while (isspace(*os2_name)) {
1870 os2_name++;
1874 int l = strlen(os2_name);
1875 while (l && isspace(os2_name[l-1])) {
1876 os2_name[l-1] = 0;
1877 l--;
1881 if (strequal(nt_name, drivername)) {
1882 DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
1883 set_driver_mapping(drivername, os2_name);
1884 drivername = talloc_strdup(mem_ctx, os2_name);
1885 TALLOC_FREE(lines);
1886 if (drivername == NULL) {
1887 return WERR_NOMEM;
1889 *pdrivername = drivername;
1890 return WERR_OK;
1894 TALLOC_FREE(lines);
1895 return WERR_OK;
1898 /****************************************************************************
1899 ****************************************************************************/
1901 bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
1902 struct spoolss_DriverInfo8 *_info8)
1904 struct spoolss_DriverInfo8 info8;
1906 ZERO_STRUCT(info8);
1908 switch (r->level) {
1909 case 3:
1910 info8.version = r->info.info3->version;
1911 info8.driver_name = r->info.info3->driver_name;
1912 info8.architecture = r->info.info3->architecture;
1913 info8.driver_path = r->info.info3->driver_path;
1914 info8.data_file = r->info.info3->data_file;
1915 info8.config_file = r->info.info3->config_file;
1916 info8.help_file = r->info.info3->help_file;
1917 info8.monitor_name = r->info.info3->monitor_name;
1918 info8.default_datatype = r->info.info3->default_datatype;
1919 if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
1920 info8.dependent_files = r->info.info3->dependent_files->string;
1922 break;
1923 case 6:
1924 info8.version = r->info.info6->version;
1925 info8.driver_name = r->info.info6->driver_name;
1926 info8.architecture = r->info.info6->architecture;
1927 info8.driver_path = r->info.info6->driver_path;
1928 info8.data_file = r->info.info6->data_file;
1929 info8.config_file = r->info.info6->config_file;
1930 info8.help_file = r->info.info6->help_file;
1931 info8.monitor_name = r->info.info6->monitor_name;
1932 info8.default_datatype = r->info.info6->default_datatype;
1933 if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
1934 info8.dependent_files = r->info.info6->dependent_files->string;
1936 info8.driver_date = r->info.info6->driver_date;
1937 info8.driver_version = r->info.info6->driver_version;
1938 info8.manufacturer_name = r->info.info6->manufacturer_name;
1939 info8.manufacturer_url = r->info.info6->manufacturer_url;
1940 info8.hardware_id = r->info.info6->hardware_id;
1941 info8.provider = r->info.info6->provider;
1942 break;
1943 case 8:
1944 info8.version = r->info.info8->version;
1945 info8.driver_name = r->info.info8->driver_name;
1946 info8.architecture = r->info.info8->architecture;
1947 info8.driver_path = r->info.info8->driver_path;
1948 info8.data_file = r->info.info8->data_file;
1949 info8.config_file = r->info.info8->config_file;
1950 info8.help_file = r->info.info8->help_file;
1951 info8.monitor_name = r->info.info8->monitor_name;
1952 info8.default_datatype = r->info.info8->default_datatype;
1953 if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
1954 info8.dependent_files = r->info.info8->dependent_files->string;
1956 if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
1957 info8.previous_names = r->info.info8->previous_names->string;
1959 info8.driver_date = r->info.info8->driver_date;
1960 info8.driver_version = r->info.info8->driver_version;
1961 info8.manufacturer_name = r->info.info8->manufacturer_name;
1962 info8.manufacturer_url = r->info.info8->manufacturer_url;
1963 info8.hardware_id = r->info.info8->hardware_id;
1964 info8.provider = r->info.info8->provider;
1965 info8.print_processor = r->info.info8->print_processor;
1966 info8.vendor_setup = r->info.info8->vendor_setup;
1967 if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
1968 info8.color_profiles = r->info.info8->color_profiles->string;
1970 info8.inf_path = r->info.info8->inf_path;
1971 info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
1972 if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
1973 info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
1975 info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
1976 info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
1977 break;
1978 default:
1979 return false;
1982 *_info8 = info8;
1984 return true;
1988 /****************************************************************************
1989 Determine whether or not a particular driver is currently assigned
1990 to a printer
1991 ****************************************************************************/
1993 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1994 struct auth_serversupplied_info *server_info,
1995 const struct spoolss_DriverInfo8 *r)
1997 int snum;
1998 int n_services = lp_numservices();
1999 bool in_use = False;
2000 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2001 WERROR result;
2003 if (!r) {
2004 return false;
2007 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
2009 /* loop through the printers.tdb and check for the drivername */
2011 for (snum=0; snum<n_services && !in_use; snum++) {
2012 if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
2013 continue;
2016 result = winreg_get_printer(mem_ctx, server_info, NULL,
2017 lp_servicename(snum), &pinfo2);
2018 if (!W_ERROR_IS_OK(result)) {
2019 continue; /* skip */
2022 if (strequal(r->driver_name, pinfo2->drivername)) {
2023 in_use = True;
2026 TALLOC_FREE(pinfo2);
2029 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
2031 if ( in_use ) {
2032 struct spoolss_DriverInfo8 *driver;
2033 WERROR werr;
2035 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
2037 /* we can still remove the driver if there is one of
2038 "Windows NT x86" version 2 or 3 left */
2040 if (!strequal("Windows NT x86", r->architecture)) {
2041 werr = winreg_get_driver(mem_ctx, server_info,
2042 "Windows NT x86",
2043 r->driver_name,
2044 DRIVER_ANY_VERSION,
2045 &driver);
2046 } else if (r->version == 2) {
2047 werr = winreg_get_driver(mem_ctx, server_info,
2048 "Windows NT x86",
2049 r->driver_name,
2050 3, &driver);
2051 } else if (r->version == 3) {
2052 werr = winreg_get_driver(mem_ctx, server_info,
2053 "Windows NT x86",
2054 r->driver_name,
2055 2, &driver);
2056 } else {
2057 DEBUG(0, ("printer_driver_in_use: ERROR!"
2058 " unknown driver version (%d)\n",
2059 r->version));
2060 werr = WERR_UNKNOWN_PRINTER_DRIVER;
2063 /* now check the error code */
2065 if ( W_ERROR_IS_OK(werr) ) {
2066 /* it's ok to remove the driver, we have other architctures left */
2067 in_use = False;
2068 talloc_free(driver);
2072 /* report that the driver is not in use by default */
2074 return in_use;
2078 /**********************************************************************
2079 Check to see if a ogiven file is in use by *info
2080 *********************************************************************/
2082 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
2084 int i = 0;
2086 if ( !info )
2087 return False;
2089 /* mz: skip files that are in the list but already deleted */
2090 if (!file || !file[0]) {
2091 return false;
2094 if (strequal(file, info->driver_path))
2095 return True;
2097 if (strequal(file, info->data_file))
2098 return True;
2100 if (strequal(file, info->config_file))
2101 return True;
2103 if (strequal(file, info->help_file))
2104 return True;
2106 /* see of there are any dependent files to examine */
2108 if (!info->dependent_files)
2109 return False;
2111 while (info->dependent_files[i] && *info->dependent_files[i]) {
2112 if (strequal(file, info->dependent_files[i]))
2113 return True;
2114 i++;
2117 return False;
2121 /**********************************************************************
2122 Utility function to remove the dependent file pointed to by the
2123 input parameter from the list
2124 *********************************************************************/
2126 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
2129 /* bump everything down a slot */
2131 while (files && files[idx+1]) {
2132 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
2133 idx++;
2136 files[idx] = NULL;
2138 return;
2141 /**********************************************************************
2142 Check if any of the files used by src are also used by drv
2143 *********************************************************************/
2145 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
2146 struct spoolss_DriverInfo8 *src,
2147 const struct spoolss_DriverInfo8 *drv)
2149 bool in_use = False;
2150 int i = 0;
2152 if ( !src || !drv )
2153 return False;
2155 /* check each file. Remove it from the src structure if it overlaps */
2157 if (drv_file_in_use(src->driver_path, drv)) {
2158 in_use = True;
2159 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
2160 src->driver_path = talloc_strdup(mem_ctx, "");
2161 if (!src->driver_path) { return false; }
2164 if (drv_file_in_use(src->data_file, drv)) {
2165 in_use = True;
2166 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
2167 src->data_file = talloc_strdup(mem_ctx, "");
2168 if (!src->data_file) { return false; }
2171 if (drv_file_in_use(src->config_file, drv)) {
2172 in_use = True;
2173 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
2174 src->config_file = talloc_strdup(mem_ctx, "");
2175 if (!src->config_file) { return false; }
2178 if (drv_file_in_use(src->help_file, drv)) {
2179 in_use = True;
2180 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
2181 src->help_file = talloc_strdup(mem_ctx, "");
2182 if (!src->help_file) { return false; }
2185 /* are there any dependentfiles to examine? */
2187 if (!src->dependent_files)
2188 return in_use;
2190 while (src->dependent_files[i] && *src->dependent_files[i]) {
2191 if (drv_file_in_use(src->dependent_files[i], drv)) {
2192 in_use = True;
2193 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
2194 trim_dependent_file(mem_ctx, src->dependent_files, i);
2195 } else
2196 i++;
2199 return in_use;
2202 /****************************************************************************
2203 Determine whether or not a particular driver files are currently being
2204 used by any other driver.
2206 Return value is True if any files were in use by other drivers
2207 and False otherwise.
2209 Upon return, *info has been modified to only contain the driver files
2210 which are not in use
2212 Fix from mz:
2214 This needs to check all drivers to ensure that all files in use
2215 have been removed from *info, not just the ones in the first
2216 match.
2217 ****************************************************************************/
2219 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
2220 struct auth_serversupplied_info *server_info,
2221 struct spoolss_DriverInfo8 *info)
2223 int i;
2224 uint32 version;
2225 struct spoolss_DriverInfo8 *driver;
2226 bool in_use = false;
2227 uint32_t num_drivers;
2228 const char **drivers;
2229 WERROR result;
2231 if ( !info )
2232 return False;
2234 version = info->version;
2236 /* loop over all driver versions */
2238 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
2240 /* get the list of drivers */
2242 result = winreg_get_driver_list(mem_ctx, server_info,
2243 info->architecture, version,
2244 &num_drivers, &drivers);
2245 if (!W_ERROR_IS_OK(result)) {
2246 return true;
2249 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
2250 num_drivers, info->architecture, version));
2252 /* check each driver for overlap in files */
2254 for (i = 0; i < num_drivers; i++) {
2255 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
2257 driver = NULL;
2259 result = winreg_get_driver(mem_ctx, server_info,
2260 info->architecture, drivers[i],
2261 version, &driver);
2262 if (!W_ERROR_IS_OK(result)) {
2263 talloc_free(drivers);
2264 return True;
2267 /* check if d2 uses any files from d1 */
2268 /* only if this is a different driver than the one being deleted */
2270 if (!strequal(info->driver_name, driver->driver_name)) {
2271 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
2272 /* mz: Do not instantly return -
2273 * we need to ensure this file isn't
2274 * also in use by other drivers. */
2275 in_use = true;
2279 talloc_free(driver);
2282 talloc_free(drivers);
2284 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2286 return in_use;
2289 static NTSTATUS driver_unlink_internals(connection_struct *conn,
2290 const char *name)
2292 struct smb_filename *smb_fname = NULL;
2293 NTSTATUS status;
2295 status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
2296 &smb_fname);
2297 if (!NT_STATUS_IS_OK(status)) {
2298 return status;
2301 status = unlink_internals(conn, NULL, 0, smb_fname, false);
2303 TALLOC_FREE(smb_fname);
2304 return status;
2307 /****************************************************************************
2308 Actually delete the driver files. Make sure that
2309 printer_driver_files_in_use() return False before calling
2310 this.
2311 ****************************************************************************/
2313 bool delete_driver_files(struct auth_serversupplied_info *server_info,
2314 const struct spoolss_DriverInfo8 *r)
2316 int i = 0;
2317 char *s;
2318 const char *file;
2319 connection_struct *conn;
2320 NTSTATUS nt_status;
2321 char *oldcwd;
2322 fstring printdollar;
2323 int printdollar_snum;
2324 bool ret = false;
2326 if (!r) {
2327 return false;
2330 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2331 r->driver_name, r->version));
2333 fstrcpy(printdollar, "print$");
2335 printdollar_snum = find_service(printdollar);
2336 if (printdollar_snum == -1) {
2337 return false;
2340 nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
2341 lp_pathname(printdollar_snum),
2342 server_info, &oldcwd);
2343 if (!NT_STATUS_IS_OK(nt_status)) {
2344 DEBUG(0,("delete_driver_files: create_conn_struct "
2345 "returned %s\n", nt_errstr(nt_status)));
2346 return false;
2349 if ( !CAN_WRITE(conn) ) {
2350 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2351 goto fail;
2354 /* now delete the files; must strip the '\print$' string from
2355 fron of path */
2357 if (r->driver_path && r->driver_path[0]) {
2358 if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
2359 file = s;
2360 DEBUG(10,("deleting driverfile [%s]\n", s));
2361 driver_unlink_internals(conn, file);
2365 if (r->config_file && r->config_file[0]) {
2366 if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
2367 file = s;
2368 DEBUG(10,("deleting configfile [%s]\n", s));
2369 driver_unlink_internals(conn, file);
2373 if (r->data_file && r->data_file[0]) {
2374 if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
2375 file = s;
2376 DEBUG(10,("deleting datafile [%s]\n", s));
2377 driver_unlink_internals(conn, file);
2381 if (r->help_file && r->help_file[0]) {
2382 if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
2383 file = s;
2384 DEBUG(10,("deleting helpfile [%s]\n", s));
2385 driver_unlink_internals(conn, file);
2389 /* check if we are done removing files */
2391 if (r->dependent_files) {
2392 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2393 char *p;
2395 /* bypass the "\print$" portion of the path */
2397 if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
2398 file = p;
2399 DEBUG(10,("deleting dependent file [%s]\n", file));
2400 driver_unlink_internals(conn, file);
2403 i++;
2407 goto done;
2408 fail:
2409 ret = false;
2410 done:
2411 if (conn != NULL) {
2412 vfs_ChDir(conn, oldcwd);
2413 conn_free(conn);
2415 return ret;
2418 /* error code:
2419 0: everything OK
2420 1: level not implemented
2421 2: file doesn't exist
2422 3: can't allocate memory
2423 4: can't free memory
2424 5: non existant struct
2428 A printer and a printer driver are 2 different things.
2429 NT manages them separatelly, Samba does the same.
2430 Why ? Simply because it's easier and it makes sense !
2432 Now explanation: You have 3 printers behind your samba server,
2433 2 of them are the same make and model (laser A and B). But laser B
2434 has an 3000 sheet feeder and laser A doesn't such an option.
2435 Your third printer is an old dot-matrix model for the accounting :-).
2437 If the /usr/local/samba/lib directory (default dir), you will have
2438 5 files to describe all of this.
2440 3 files for the printers (1 by printer):
2441 NTprinter_laser A
2442 NTprinter_laser B
2443 NTprinter_accounting
2444 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2445 NTdriver_printer model X
2446 NTdriver_printer model Y
2448 jfm: I should use this comment for the text file to explain
2449 same thing for the forms BTW.
2450 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2454 /* Convert generic access rights to printer object specific access rights.
2455 It turns out that NT4 security descriptors use generic access rights and
2456 NT5 the object specific ones. */
2458 void map_printer_permissions(struct security_descriptor *sd)
2460 int i;
2462 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2463 se_map_generic(&sd->dacl->aces[i].access_mask,
2464 &printer_generic_mapping);
2468 void map_job_permissions(struct security_descriptor *sd)
2470 int i;
2472 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2473 se_map_generic(&sd->dacl->aces[i].access_mask,
2474 &job_generic_mapping);
2479 /****************************************************************************
2480 Check a user has permissions to perform the given operation. We use the
2481 permission constants defined in include/rpc_spoolss.h to check the various
2482 actions we perform when checking printer access.
2484 PRINTER_ACCESS_ADMINISTER:
2485 print_queue_pause, print_queue_resume, update_printer_sec,
2486 update_printer, spoolss_addprinterex_level_2,
2487 _spoolss_setprinterdata
2489 PRINTER_ACCESS_USE:
2490 print_job_start
2492 JOB_ACCESS_ADMINISTER:
2493 print_job_delete, print_job_pause, print_job_resume,
2494 print_queue_purge
2496 Try access control in the following order (for performance reasons):
2497 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2498 2) check security descriptor (bit comparisons in memory)
2499 3) "printer admins" (may result in numerous calls to winbind)
2501 ****************************************************************************/
2502 bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
2503 int access_type)
2505 struct spoolss_security_descriptor *secdesc = NULL;
2506 uint32 access_granted;
2507 size_t sd_size;
2508 NTSTATUS status;
2509 WERROR result;
2510 const char *pname;
2511 TALLOC_CTX *mem_ctx = NULL;
2512 SE_PRIV se_printop = SE_PRINT_OPERATOR;
2514 /* If user is NULL then use the current_user structure */
2516 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2518 if (server_info->utok.uid == sec_initial_uid()
2519 || user_has_privileges(server_info->ptok, &se_printop ) ) {
2520 return True;
2523 /* Get printer name */
2525 pname = lp_printername(snum);
2527 if (!pname || !*pname) {
2528 errno = EACCES;
2529 return False;
2532 /* Get printer security descriptor */
2534 if(!(mem_ctx = talloc_init("print_access_check"))) {
2535 errno = ENOMEM;
2536 return False;
2539 result = winreg_get_printer_secdesc(mem_ctx,
2540 server_info,
2541 pname,
2542 &secdesc);
2543 if (!W_ERROR_IS_OK(result)) {
2544 talloc_destroy(mem_ctx);
2545 errno = ENOMEM;
2546 return False;
2549 if (access_type == JOB_ACCESS_ADMINISTER) {
2550 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2552 /* Create a child security descriptor to check permissions
2553 against. This is because print jobs are child objects
2554 objects of a printer. */
2555 status = se_create_child_secdesc(mem_ctx,
2556 &secdesc,
2557 &sd_size,
2558 parent_secdesc,
2559 parent_secdesc->owner_sid,
2560 parent_secdesc->group_sid,
2561 false);
2562 if (!NT_STATUS_IS_OK(status)) {
2563 talloc_destroy(mem_ctx);
2564 errno = map_errno_from_nt_status(status);
2565 return False;
2568 map_job_permissions(secdesc);
2569 } else {
2570 map_printer_permissions(secdesc);
2573 /* Check access */
2574 status = se_access_check(secdesc, server_info->ptok, access_type,
2575 &access_granted);
2577 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2579 /* see if we need to try the printer admin list */
2581 if (!NT_STATUS_IS_OK(status) &&
2582 (token_contains_name_in_list(uidtoname(server_info->utok.uid),
2583 server_info->info3->base.domain.string,
2584 NULL, server_info->ptok,
2585 lp_printer_admin(snum)))) {
2586 talloc_destroy(mem_ctx);
2587 return True;
2590 talloc_destroy(mem_ctx);
2592 if (!NT_STATUS_IS_OK(status)) {
2593 errno = EACCES;
2596 return NT_STATUS_IS_OK(status);
2599 /****************************************************************************
2600 Check the time parameters allow a print operation.
2601 *****************************************************************************/
2603 bool print_time_access_check(struct auth_serversupplied_info *server_info,
2604 const char *servicename)
2606 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2607 WERROR result;
2608 bool ok = False;
2609 time_t now = time(NULL);
2610 struct tm *t;
2611 uint32 mins;
2613 result = winreg_get_printer(NULL, server_info,
2614 NULL, servicename, &pinfo2);
2615 if (!W_ERROR_IS_OK(result)) {
2616 return False;
2619 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2620 ok = True;
2623 t = gmtime(&now);
2624 mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
2626 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2627 ok = True;
2630 TALLOC_FREE(pinfo2);
2632 if (!ok) {
2633 errno = EACCES;
2636 return ok;
2639 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2640 struct auth_serversupplied_info *server_info,
2641 const char *printer)
2643 WERROR result;
2645 result = winreg_delete_printer_key(mem_ctx, server_info, printer, "");
2646 if (!W_ERROR_IS_OK(result)) {
2647 DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
2648 printer));