samba-tool tests: add test-case for 'group list --base-dn'
[Samba.git] / source3 / printing / nt_printing.c
blob98536017b5b1836a6c154c676b066c1ad2479f43
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 static bool print_driver_directories_init(void)
79 int service, i;
80 char *driver_path;
81 bool ok;
82 TALLOC_CTX *mem_ctx = talloc_stackframe();
83 const struct loadparm_substitution *lp_sub =
84 loadparm_s3_global_substitution();
86 const char *dir_list[] = {
87 "W32X86/PCC",
88 "x64/PCC",
89 "color"
92 service = lp_servicenumber("print$");
93 if (service < 0) {
94 /* We don't have a print$ share */
95 DEBUG(5, ("No print$ share has been configured.\n"));
96 talloc_free(mem_ctx);
97 return true;
100 driver_path = lp_path(mem_ctx, lp_sub, service);
101 if (driver_path == NULL) {
102 talloc_free(mem_ctx);
103 return false;
106 ok = directory_create_or_exist(driver_path, 0755);
107 if (!ok) {
108 DEBUG(1, ("Failed to create printer driver directory %s\n",
109 driver_path));
110 talloc_free(mem_ctx);
111 return false;
114 for (i = 0; archi_table[i].long_archi != NULL; i++) {
115 const char *arch_path;
117 arch_path = talloc_asprintf(mem_ctx,
118 "%s/%s",
119 driver_path,
120 archi_table[i].short_archi);
121 if (arch_path == NULL) {
122 talloc_free(mem_ctx);
123 return false;
126 ok = directory_create_or_exist(arch_path, 0755);
127 if (!ok) {
128 DEBUG(1, ("Failed to create printer driver "
129 "architecture directory %s\n",
130 arch_path));
131 talloc_free(mem_ctx);
132 return false;
136 for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
137 const char *path;
139 path = talloc_asprintf(mem_ctx,
140 "%s/%s",
141 driver_path,
142 dir_list[i]);
143 if (path == NULL) {
144 talloc_free(mem_ctx);
145 return false;
148 ok = directory_create_or_exist(path, 0755);
149 if (!ok) {
150 DEBUG(1, ("Failed to create printer driver "
151 "architecture directory %s\n",
152 path));
153 talloc_free(mem_ctx);
154 return false;
158 driver_path = state_path(talloc_tos(), "DriverStore");
159 if (driver_path == NULL) {
160 talloc_free(mem_ctx);
161 return false;
164 ok = directory_create_or_exist(driver_path, 0755);
165 if (!ok) {
166 DEBUG(1,("failed to create path %s\n", driver_path));
167 talloc_free(mem_ctx);
168 return false;
171 driver_path = state_path(talloc_tos(), "DriverStore/FileRepository");
172 if (driver_path == NULL) {
173 talloc_free(mem_ctx);
174 return false;
177 ok = directory_create_or_exist(driver_path, 0755);
178 if (!ok) {
179 DEBUG(1,("failed to create path %s\n", driver_path));
180 talloc_free(mem_ctx);
181 return false;
184 driver_path = state_path(talloc_tos(), "DriverStore/Temp");
185 if (driver_path == NULL) {
186 talloc_free(mem_ctx);
187 return false;
190 ok = directory_create_or_exist(driver_path, 0755);
191 if (!ok) {
192 DEBUG(1,("failed to create path %s\n", driver_path));
193 talloc_free(mem_ctx);
194 return false;
197 talloc_free(mem_ctx);
198 return true;
201 /****************************************************************************
202 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
203 background lpq updater.
204 ****************************************************************************/
206 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
207 void *private_data,
208 uint32_t msg_type,
209 struct server_id server_id,
210 DATA_BLOB *data)
212 extern pid_t background_lpq_updater_pid;
214 if (background_lpq_updater_pid == -1) {
215 DEBUG(3,("no background lpq queue updater\n"));
216 return;
219 messaging_send_buf(msg,
220 pid_to_procid(background_lpq_updater_pid),
221 MSG_PRINTER_DRVUPGRADE,
222 data->data,
223 data->length);
226 /****************************************************************************
227 Open the NT printing tdbs. Done once before fork().
228 ****************************************************************************/
230 bool nt_printing_init(struct messaging_context *msg_ctx)
232 WERROR win_rc;
234 if (!print_driver_directories_init()) {
235 return false;
238 if (!nt_printing_tdb_upgrade()) {
239 return false;
243 * register callback to handle updating printers as new
244 * drivers are installed. Forwards to background lpq updater.
246 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
247 forward_drv_upgrade_printer_msg);
249 if ( lp_security() == SEC_ADS ) {
250 win_rc = check_published_printers(msg_ctx);
251 if (!W_ERROR_IS_OK(win_rc))
252 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
255 return true;
258 /*******************************************************************
259 Function to allow filename parsing "the old way".
260 ********************************************************************/
262 static NTSTATUS driver_unix_convert(connection_struct *conn,
263 const char *old_name,
264 struct smb_filename **smb_fname)
266 NTSTATUS status;
267 TALLOC_CTX *ctx = talloc_tos();
268 char *name = talloc_strdup(ctx, old_name);
270 if (!name) {
271 return NT_STATUS_NO_MEMORY;
273 unix_format(name);
274 name = unix_clean_name(ctx, name);
275 if (!name) {
276 return NT_STATUS_NO_MEMORY;
278 trim_string(name,"/","/");
280 status = unix_convert(ctx, conn, name, smb_fname, 0);
281 if (!NT_STATUS_IS_OK(status)) {
282 return NT_STATUS_NO_MEMORY;
285 return NT_STATUS_OK;
288 /****************************************************************************
289 Function to do the mapping between the long architecture name and
290 the short one.
291 ****************************************************************************/
293 const char *get_short_archi(const char *long_archi)
295 int i=-1;
297 DEBUG(107,("Getting architecture dependent directory\n"));
298 do {
299 i++;
300 } while ( (archi_table[i].long_archi!=NULL ) &&
301 strcasecmp_m(long_archi, archi_table[i].long_archi) );
303 if (archi_table[i].long_archi==NULL) {
304 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
305 return NULL;
308 /* this might be client code - but shouldn't this be an fstrcpy etc? */
310 DEBUGADD(108,("index: [%d]\n", i));
311 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
312 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
314 return archi_table[i].short_archi;
317 /****************************************************************************
318 Read data from fsp on the vfs.
319 ****************************************************************************/
321 static ssize_t printing_pread_data(files_struct *fsp,
322 char *buf,
323 off_t *poff,
324 size_t byte_count)
326 size_t total=0;
327 off_t in_pos = *poff;
329 /* Don't allow integer wrap on read. */
330 if (in_pos + byte_count < in_pos) {
331 return -1;
334 while (total < byte_count) {
335 ssize_t ret = read_file(fsp,
336 buf + total,
337 in_pos,
338 byte_count - total);
340 if (ret == 0) {
341 *poff = in_pos;
342 return total;
344 if (ret == -1) {
345 if (errno == EINTR) {
346 continue;
347 } else {
348 return -1;
351 in_pos += ret;
352 total += ret;
354 *poff = in_pos;
355 return (ssize_t)total;
358 /****************************************************************************
359 Detect the major and minor version of a PE file.
360 Returns:
362 1 if file is a PE file and we got version numbers,
363 0 if this file is a PE file and we couldn't get the version numbers,
364 -1 on error.
366 NB. buf is passed into and freed inside this function. This is a
367 bad API design, but fixing this is a task for another day.
368 ****************************************************************************/
370 static int handle_pe_file(files_struct *fsp,
371 off_t in_pos,
372 char *fname,
373 char *buf,
374 uint32_t *major,
375 uint32_t *minor)
377 unsigned int i;
378 unsigned int num_sections;
379 unsigned int section_table_bytes;
380 ssize_t byte_count;
381 off_t rel_pos;
382 int ret = -1;
384 /* Just skip over optional header to get to section table */
385 rel_pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-
386 (NE_HEADER_SIZE-PE_HEADER_SIZE);
388 if (in_pos + rel_pos < in_pos) {
389 /* Integer wrap. */
390 goto out;
392 in_pos = rel_pos + in_pos;
394 /* get the section table */
395 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
397 if (num_sections >= (UINT_MAX / PE_HEADER_SECT_HEADER_SIZE)) {
398 /* Integer wrap. */
399 goto out;
402 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
403 if (section_table_bytes == 0) {
404 goto out;
407 SAFE_FREE(buf);
408 buf = (char *)SMB_MALLOC(section_table_bytes);
409 if (buf == NULL) {
410 DBG_ERR("PE file [%s] section table malloc "
411 "failed bytes = %d\n",
412 fname,
413 section_table_bytes);
414 goto out;
417 byte_count = printing_pread_data(fsp, buf, &in_pos, section_table_bytes);
418 if (byte_count < section_table_bytes) {
419 DBG_NOTICE("PE file [%s] Section header too short, "
420 "bytes read = %lu\n",
421 fname,
422 (unsigned long)byte_count);
423 goto out;
427 * Iterate the section table looking for
428 * the resource section ".rsrc"
430 for (i = 0; i < num_sections; i++) {
431 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
433 if (strcmp(".rsrc",
434 &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) {
435 unsigned int section_pos = IVAL(buf,
436 sec_offset+
437 PE_HEADER_SECT_PTR_DATA_OFFSET);
438 unsigned int section_bytes = IVAL(buf,
439 sec_offset+
440 PE_HEADER_SECT_SIZE_DATA_OFFSET);
442 if (section_bytes == 0) {
443 goto out;
446 SAFE_FREE(buf);
447 buf=(char *)SMB_MALLOC(section_bytes);
448 if (buf == NULL) {
449 DBG_ERR("PE file [%s] version malloc "
450 "failed bytes = %d\n",
451 fname,
452 section_bytes);
453 goto out;
457 * Read from the start of the .rsrc
458 * section info
460 in_pos = section_pos;
462 byte_count = printing_pread_data(fsp,
463 buf,
464 &in_pos,
465 section_bytes);
466 if (byte_count < section_bytes) {
467 DBG_NOTICE("PE file "
468 "[%s] .rsrc section too short, "
469 "bytes read = %lu\n",
470 fname,
471 (unsigned long)byte_count);
472 goto out;
475 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) {
476 goto out;
479 for (i=0;
480 i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE;
481 i++) {
483 * Scan for 1st 3 unicoded bytes
484 * followed by word aligned magic
485 * value.
487 int mpos;
488 bool magic_match = false;
490 if (buf[i] == 'V' &&
491 buf[i+1] == '\0' &&
492 buf[i+2] == 'S') {
493 magic_match = true;
496 if (magic_match == false) {
497 continue;
500 /* Align to next long address */
501 mpos = (i + sizeof(VS_SIGNATURE)*2 +
502 3) & 0xfffffffc;
504 if (IVAL(buf,mpos) == VS_MAGIC_VALUE) {
505 *major = IVAL(buf,
506 mpos+ VS_MAJOR_OFFSET);
507 *minor = IVAL(buf,
508 mpos+ VS_MINOR_OFFSET);
510 DBG_INFO("PE file [%s] Version = "
511 "%08x:%08x (%d.%d.%d.%d)\n",
512 fname,
513 *major,
514 *minor,
515 (*major>>16)&0xffff,
516 *major&0xffff,
517 (*minor>>16)&0xffff,
518 *minor&0xffff);
519 ret = 1;
520 goto out;
526 /* Version info not found, fall back to origin date/time */
527 DBG_DEBUG("PE file [%s] has no version info\n", fname);
528 ret = 0;
530 out:
532 SAFE_FREE(buf);
533 return ret;
536 /****************************************************************************
537 Detect the major and minor version of an NE file.
538 Returns:
540 1 if file is an NE file and we got version numbers,
541 0 if this file is an NE file and we couldn't get the version numbers,
542 -1 on error.
544 NB. buf is passed into and freed inside this function. This is a
545 bad API design, but fixing this is a task for another day.
546 ****************************************************************************/
548 static int handle_ne_file(files_struct *fsp,
549 off_t in_pos,
550 char *fname,
551 char *buf,
552 uint32_t *major,
553 uint32_t *minor)
555 unsigned int i;
556 ssize_t byte_count;
557 int ret = -1;
559 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
560 DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n",
561 fname,
562 CVAL(buf,NE_HEADER_TARGET_OS_OFFSET));
564 * At this point, we assume the file is in error.
565 * It still could be something else besides a NE file,
566 * but it unlikely at this point.
568 goto out;
571 /* Allocate a bit more space to speed up things */
572 SAFE_FREE(buf);
573 buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE);
574 if (buf == NULL) {
575 DBG_ERR("NE file [%s] malloc failed bytes = %d\n",
576 fname,
577 PE_HEADER_SIZE);
578 goto out;
582 * This is a HACK! I got tired of trying to sort through the
583 * messy 'NE' file format. If anyone wants to clean this up
584 * please have at it, but this works. 'NE' files will
585 * eventually fade away. JRR
587 byte_count = printing_pread_data(fsp, buf, &in_pos, VS_NE_BUF_SIZE);
588 while (byte_count > 0) {
590 * Cover case that should not occur in a well
591 * formed 'NE' .dll file
593 if (byte_count-VS_VERSION_INFO_SIZE <= 0) {
594 break;
597 for(i=0; i<byte_count; i++) {
599 * Fast skip past data that can't
600 * possibly match
602 if (buf[i] != 'V') {
603 byte_count = printing_pread_data(fsp,
604 buf,
605 &in_pos,
606 VS_NE_BUF_SIZE);
607 continue;
611 * Potential match data crosses buf boundry,
612 * move it to beginning of buf, and fill the
613 * buf with as much as it will hold.
615 if (i>byte_count-VS_VERSION_INFO_SIZE) {
616 ssize_t amount_read;
617 ssize_t amount_unused = byte_count-i;
619 memmove(buf, &buf[i], amount_unused);
620 amount_read = printing_pread_data(fsp,
621 &buf[amount_unused],
622 &in_pos,
623 VS_NE_BUF_SIZE- amount_unused);
624 if (amount_read < 0) {
625 DBG_ERR("NE file [%s] Read "
626 "error, errno=%d\n",
627 fname,
628 errno);
629 goto out;
632 if (amount_read + amount_unused <
633 amount_read) {
634 /* Check for integer wrap. */
635 break;
638 byte_count = amount_read +
639 amount_unused;
640 if (byte_count < VS_VERSION_INFO_SIZE) {
641 break;
644 i = 0;
648 * Check that the full signature string and
649 * the magic number that follows exist (not
650 * a perfect solution, but the chances that this
651 * occurs in code is, well, remote. Yes I know
652 * I'm comparing the 'V' twice, as it is
653 * simpler to read the code.
655 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
657 * Compute skip alignment to next
658 * long address.
660 off_t cpos = in_pos;
661 int skip = -(cpos - (byte_count - i) +
662 sizeof(VS_SIGNATURE)) & 3;
663 if (IVAL(buf,
664 i+sizeof(VS_SIGNATURE)+skip)
665 != 0xfeef04bd) {
666 byte_count = printing_pread_data(fsp,
667 buf,
668 &in_pos,
669 VS_NE_BUF_SIZE);
670 continue;
673 *major = IVAL(buf,
674 i+sizeof(VS_SIGNATURE)+
675 skip+VS_MAJOR_OFFSET);
676 *minor = IVAL(buf,
677 i+sizeof(VS_SIGNATURE)+
678 skip+VS_MINOR_OFFSET);
679 DBG_INFO("NE file [%s] Version "
680 "= %08x:%08x (%d.%d.%d.%d)\n",
681 fname,
682 *major,
683 *minor,
684 (*major>>16)&0xffff,
685 *major&0xffff,
686 (*minor>>16)&0xffff,
687 *minor&0xffff);
688 ret = 1;
689 goto out;
694 /* Version info not found, fall back to origin date/time */
695 DBG_ERR("NE file [%s] Version info not found\n", fname);
696 ret = 0;
698 out:
700 SAFE_FREE(buf);
701 return ret;
704 /****************************************************************************
705 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
706 There are two case to be covered here: PE (Portable Executable) and NE (New
707 Executable) files. Both files support the same INFO structure, but PE files
708 store the signature in unicode, and NE files store it as !unicode.
709 returns -1 on error, 1 on version info found, and 0 on no version info found.
710 ****************************************************************************/
712 static int get_file_version(files_struct *fsp,
713 char *fname,
714 uint32_t *major,
715 uint32_t *minor)
717 char *buf = NULL;
718 ssize_t byte_count;
719 off_t in_pos = fsp->fh->pos;
721 buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE);
722 if (buf == NULL) {
723 DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n",
724 fname,
725 DOS_HEADER_SIZE);
726 goto error_exit;
729 byte_count = printing_pread_data(fsp, buf, &in_pos, DOS_HEADER_SIZE);
730 if (byte_count < DOS_HEADER_SIZE) {
731 DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n",
732 fname,
733 (unsigned long)byte_count);
734 goto no_version_info;
737 /* Is this really a DOS header? */
738 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
739 DBG_INFO("File [%s] bad DOS magic = 0x%x\n",
740 fname,
741 SVAL(buf,DOS_HEADER_MAGIC_OFFSET));
742 goto no_version_info;
746 * Skip OEM header (if any) and the
747 * DOS stub to start of Windows header.
749 in_pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET);
751 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
752 byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE);
753 if (byte_count < NE_HEADER_SIZE) {
754 DBG_NOTICE("File [%s] Windows header too short, "
755 "bytes read = %lu\n",
756 fname,
757 (unsigned long)byte_count);
759 * Assume this isn't an error...
760 * the file just looks sort of like a PE/NE file
762 goto no_version_info;
766 * The header may be a PE (Portable Executable)
767 * or an NE (New Executable).
769 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
770 return handle_pe_file(fsp,
771 in_pos,
772 fname,
773 buf,
774 major,
775 minor);
776 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) ==
777 NE_HEADER_SIGNATURE) {
778 return handle_ne_file(fsp,
779 in_pos,
780 fname,
781 buf,
782 major,
783 minor);
784 } else {
786 * Assume this isn't an error... the file just
787 * looks sort of like a PE/NE file.
789 DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n",
790 fname,
791 IVAL(buf,PE_HEADER_SIGNATURE_OFFSET));
792 /* Fallthrough into no_version_info: */
795 no_version_info:
796 SAFE_FREE(buf);
797 return 0;
799 error_exit:
800 SAFE_FREE(buf);
801 return -1;
804 /****************************************************************************
805 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
806 share one or more files. During the MS installation process files are checked
807 to insure that only a newer version of a shared file is installed over an
808 older version. There are several possibilities for this comparison. If there
809 is no previous version, the new one is newer (obviously). If either file is
810 missing the version info structure, compare the creation date (on Unix use
811 the modification date). Otherwise chose the numerically larger version number.
812 ****************************************************************************/
814 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
816 bool use_version = true;
818 uint32_t new_major;
819 uint32_t new_minor;
820 time_t new_create_time;
822 uint32_t old_major;
823 uint32_t old_minor;
824 time_t old_create_time;
826 struct smb_filename *smb_fname = NULL;
827 files_struct *fsp = NULL;
828 SMB_STRUCT_STAT st;
830 NTSTATUS status;
831 int ret;
833 SET_STAT_INVALID(st);
834 new_create_time = (time_t)0;
835 old_create_time = (time_t)0;
837 /* Get file version info (if available) for previous file (if it exists) */
838 status = driver_unix_convert(conn, old_file, &smb_fname);
839 if (!NT_STATUS_IS_OK(status)) {
840 goto error_exit;
843 status = SMB_VFS_CREATE_FILE(
844 conn, /* conn */
845 NULL, /* req */
846 0, /* root_dir_fid */
847 smb_fname, /* fname */
848 FILE_GENERIC_READ, /* access_mask */
849 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
850 FILE_OPEN, /* create_disposition*/
851 0, /* create_options */
852 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
853 INTERNAL_OPEN_ONLY, /* oplock_request */
854 NULL, /* lease */
855 0, /* allocation_size */
856 0, /* private_flags */
857 NULL, /* sd */
858 NULL, /* ea_list */
859 &fsp, /* result */
860 NULL, /* pinfo */
861 NULL, NULL); /* create context */
863 if (!NT_STATUS_IS_OK(status)) {
864 /* Old file not found, so by definition new file is in fact newer */
865 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
866 "errno = %d\n", smb_fname_str_dbg(smb_fname),
867 errno));
868 ret = 1;
869 goto done;
871 } else {
872 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
873 if (ret == -1) {
874 goto error_exit;
877 if (!ret) {
878 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
879 old_file));
880 use_version = false;
881 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
882 goto error_exit;
884 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
885 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
886 (long)old_create_time));
889 close_file(NULL, fsp, NORMAL_CLOSE);
890 fsp = NULL;
892 /* Get file version info (if available) for new file */
893 status = driver_unix_convert(conn, new_file, &smb_fname);
894 if (!NT_STATUS_IS_OK(status)) {
895 goto error_exit;
898 status = SMB_VFS_CREATE_FILE(
899 conn, /* conn */
900 NULL, /* req */
901 0, /* root_dir_fid */
902 smb_fname, /* fname */
903 FILE_GENERIC_READ, /* access_mask */
904 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
905 FILE_OPEN, /* create_disposition*/
906 0, /* create_options */
907 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
908 INTERNAL_OPEN_ONLY, /* oplock_request */
909 NULL, /* lease */
910 0, /* allocation_size */
911 0, /* private_flags */
912 NULL, /* sd */
913 NULL, /* ea_list */
914 &fsp, /* result */
915 NULL, /* pinfo */
916 NULL, NULL); /* create context */
918 if (!NT_STATUS_IS_OK(status)) {
919 /* New file not found, this shouldn't occur if the caller did its job */
920 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
921 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
922 goto error_exit;
924 } else {
925 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
926 if (ret == -1) {
927 goto error_exit;
930 if (!ret) {
931 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
932 new_file));
933 use_version = false;
934 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
935 goto error_exit;
937 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
938 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
939 (long)new_create_time));
942 close_file(NULL, fsp, NORMAL_CLOSE);
943 fsp = NULL;
945 if (use_version && (new_major != old_major || new_minor != old_minor)) {
946 /* Compare versions and choose the larger version number */
947 if (new_major > old_major ||
948 (new_major == old_major && new_minor > old_minor)) {
950 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
951 ret = 1;
952 goto done;
954 else {
955 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
956 ret = 0;
957 goto done;
960 } else {
961 /* Compare modification time/dates and choose the newest time/date */
962 if (new_create_time > old_create_time) {
963 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
964 ret = 1;
965 goto done;
967 else {
968 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
969 ret = 0;
970 goto done;
974 error_exit:
975 if(fsp)
976 close_file(NULL, fsp, NORMAL_CLOSE);
977 ret = -1;
978 done:
979 TALLOC_FREE(smb_fname);
980 return ret;
983 /****************************************************************************
984 Determine the correct cVersion associated with an architecture and driver
985 ****************************************************************************/
986 static uint32_t get_correct_cversion(const struct auth_session_info *session_info,
987 const char *architecture,
988 const char *driverpath_in,
989 const char *driver_directory,
990 WERROR *perr)
992 TALLOC_CTX *frame = talloc_stackframe();
993 const struct loadparm_substitution *lp_sub =
994 loadparm_s3_global_substitution();
995 int cversion = -1;
996 NTSTATUS nt_status;
997 struct smb_filename *smb_fname = NULL;
998 files_struct *fsp = NULL;
999 struct conn_struct_tos *c = NULL;
1000 connection_struct *conn = NULL;
1001 char *printdollar = NULL;
1002 char *printdollar_path = NULL;
1003 char *working_dir = NULL;
1004 int printdollar_snum;
1006 *perr = WERR_INVALID_PARAMETER;
1008 /* If architecture is Windows 95/98/ME, the version is always 0. */
1009 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
1010 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1011 *perr = WERR_OK;
1012 TALLOC_FREE(frame);
1013 return 0;
1016 /* If architecture is Windows x64, the version is always 3. */
1017 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
1018 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
1019 *perr = WERR_OK;
1020 TALLOC_FREE(frame);
1021 return 3;
1024 printdollar_snum = find_service(frame, "print$", &printdollar);
1025 if (!printdollar) {
1026 *perr = WERR_NOT_ENOUGH_MEMORY;
1027 TALLOC_FREE(frame);
1028 return -1;
1030 if (printdollar_snum == -1) {
1031 *perr = WERR_BAD_NET_NAME;
1032 TALLOC_FREE(frame);
1033 return -1;
1036 printdollar_path = lp_path(frame, lp_sub, printdollar_snum);
1037 if (printdollar_path == NULL) {
1038 *perr = WERR_NOT_ENOUGH_MEMORY;
1039 TALLOC_FREE(frame);
1040 return -1;
1043 working_dir = talloc_asprintf(frame,
1044 "%s/%s",
1045 printdollar_path,
1046 architecture);
1048 * If the driver has been uploaded into a temorpary driver
1049 * directory, switch to the driver directory.
1051 if (driver_directory != NULL) {
1052 working_dir = talloc_asprintf(frame, "%s/%s/%s",
1053 printdollar_path,
1054 architecture,
1055 driver_directory);
1058 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1059 printdollar_snum,
1060 working_dir,
1061 session_info,
1062 &c);
1063 if (!NT_STATUS_IS_OK(nt_status)) {
1064 DEBUG(0,("get_correct_cversion: create_conn_struct "
1065 "returned %s\n", nt_errstr(nt_status)));
1066 *perr = ntstatus_to_werror(nt_status);
1067 TALLOC_FREE(frame);
1068 return -1;
1070 conn = c->conn;
1072 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1073 if (!NT_STATUS_IS_OK(nt_status)) {
1074 DEBUG(0, ("failed set force user / group\n"));
1075 *perr = ntstatus_to_werror(nt_status);
1076 goto error_free_conn;
1079 if (!become_user_without_service_by_session(conn, session_info)) {
1080 DEBUG(0, ("failed to become user\n"));
1081 *perr = WERR_ACCESS_DENIED;
1082 goto error_free_conn;
1086 * We switch to the directory where the driver files are located,
1087 * so only work on the file names
1089 nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
1090 if (!NT_STATUS_IS_OK(nt_status)) {
1091 *perr = ntstatus_to_werror(nt_status);
1092 goto error_exit;
1095 nt_status = vfs_file_exist(conn, smb_fname);
1096 if (!NT_STATUS_IS_OK(nt_status)) {
1097 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
1098 *perr = WERR_FILE_NOT_FOUND;
1099 goto error_exit;
1102 nt_status = SMB_VFS_CREATE_FILE(
1103 conn, /* conn */
1104 NULL, /* req */
1105 0, /* root_dir_fid */
1106 smb_fname, /* fname */
1107 FILE_GENERIC_READ, /* access_mask */
1108 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1109 FILE_OPEN, /* create_disposition*/
1110 0, /* create_options */
1111 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1112 INTERNAL_OPEN_ONLY, /* oplock_request */
1113 NULL, /* lease */
1114 0, /* private_flags */
1115 0, /* allocation_size */
1116 NULL, /* sd */
1117 NULL, /* ea_list */
1118 &fsp, /* result */
1119 NULL, /* pinfo */
1120 NULL, NULL); /* create context */
1122 if (!NT_STATUS_IS_OK(nt_status)) {
1123 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
1124 "%d\n", smb_fname_str_dbg(smb_fname), errno));
1125 *perr = WERR_ACCESS_DENIED;
1126 goto error_exit;
1127 } else {
1128 uint32_t major;
1129 uint32_t minor;
1130 int ret;
1132 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
1133 if (ret == -1) {
1134 *perr = WERR_INVALID_PARAMETER;
1135 goto error_exit;
1136 } else if (!ret) {
1137 DEBUG(6,("get_correct_cversion: Version info not "
1138 "found [%s]\n",
1139 smb_fname_str_dbg(smb_fname)));
1140 *perr = WERR_INVALID_PARAMETER;
1141 goto error_exit;
1145 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1146 * for more details. Version in this case is not just the version of the
1147 * file, but the version in the sense of kernal mode (2) vs. user mode
1148 * (3) drivers. Other bits of the version fields are the version info.
1149 * JRR 010716
1151 cversion = major & 0x0000ffff;
1152 switch (cversion) {
1153 case 2: /* WinNT drivers */
1154 case 3: /* Win2K drivers */
1155 break;
1157 default:
1158 DEBUG(6,("get_correct_cversion: cversion "
1159 "invalid [%s] cversion = %d\n",
1160 smb_fname_str_dbg(smb_fname),
1161 cversion));
1162 goto error_exit;
1165 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
1166 " = 0x%x minor = 0x%x\n",
1167 smb_fname_str_dbg(smb_fname), major, minor));
1170 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1171 smb_fname_str_dbg(smb_fname), cversion));
1172 *perr = WERR_OK;
1174 error_exit:
1175 unbecome_user_without_service();
1176 error_free_conn:
1177 if (fsp != NULL) {
1178 close_file(NULL, fsp, NORMAL_CLOSE);
1180 if (!W_ERROR_IS_OK(*perr)) {
1181 cversion = -1;
1184 TALLOC_FREE(frame);
1185 return cversion;
1188 /****************************************************************************
1189 ****************************************************************************/
1191 #define strip_driver_path(_mem_ctx, _element) do { \
1192 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
1193 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
1194 W_ERROR_HAVE_NO_MEMORY((_element)); \
1196 } while (0);
1198 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
1199 const struct auth_session_info *session_info,
1200 const char *architecture,
1201 const char **driver_path,
1202 const char **data_file,
1203 const char **config_file,
1204 const char **help_file,
1205 struct spoolss_StringArray *dependent_files,
1206 enum spoolss_DriverOSVersion *version,
1207 uint32_t flags,
1208 const char **driver_directory)
1210 const char *short_architecture;
1211 int i;
1212 WERROR err;
1213 char *_p;
1215 if (!*driver_path || !*data_file) {
1216 return WERR_INVALID_PARAMETER;
1219 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
1220 return WERR_INVALID_PARAMETER;
1223 if (flags & APD_COPY_FROM_DIRECTORY) {
1224 char *path;
1225 char *q;
1228 * driver_path is set to:
1230 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
1232 path = talloc_strdup(mem_ctx, *driver_path);
1233 if (path == NULL) {
1234 return WERR_NOT_ENOUGH_MEMORY;
1237 /* Remove pscript5.dll */
1238 q = strrchr_m(path, '\\');
1239 if (q == NULL) {
1240 return WERR_INVALID_PARAMETER;
1242 *q = '\0';
1244 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
1245 q = strrchr_m(path, '\\');
1246 if (q == NULL) {
1247 return WERR_INVALID_PARAMETER;
1251 * Set driver_directory to:
1253 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1255 * This is the directory where all the files have been uploaded
1257 *driver_directory = q + 1;
1260 /* clean up the driver name.
1261 * we can get .\driver.dll
1262 * or worse c:\windows\system\driver.dll !
1264 /* using an intermediate string to not have overlaping memcpy()'s */
1266 strip_driver_path(mem_ctx, *driver_path);
1267 strip_driver_path(mem_ctx, *data_file);
1268 if (*config_file) {
1269 strip_driver_path(mem_ctx, *config_file);
1271 if (help_file) {
1272 strip_driver_path(mem_ctx, *help_file);
1275 if (dependent_files && dependent_files->string) {
1276 for (i=0; dependent_files->string[i]; i++) {
1277 strip_driver_path(mem_ctx, dependent_files->string[i]);
1281 short_architecture = get_short_archi(architecture);
1282 if (!short_architecture) {
1283 return WERR_UNKNOWN_PRINTER_DRIVER;
1286 /* jfm:7/16/2000 the client always sends the cversion=0.
1287 * The server should check which version the driver is by reading
1288 * the PE header of driver->driverpath.
1290 * For Windows 95/98 the version is 0 (so the value sent is correct)
1291 * For Windows NT (the architecture doesn't matter)
1292 * NT 3.1: cversion=0
1293 * NT 3.5/3.51: cversion=1
1294 * NT 4: cversion=2
1295 * NT2K: cversion=3
1298 *version = get_correct_cversion(session_info,
1299 short_architecture,
1300 *driver_path,
1301 *driver_directory,
1302 &err);
1303 if (*version == -1) {
1304 return err;
1307 return WERR_OK;
1310 /****************************************************************************
1311 ****************************************************************************/
1313 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1314 const struct auth_session_info *session_info,
1315 const struct spoolss_AddDriverInfoCtr *r,
1316 uint32_t flags,
1317 const char **driver_directory)
1319 switch (r->level) {
1320 case 3:
1321 return clean_up_driver_struct_level(mem_ctx, session_info,
1322 r->info.info3->architecture,
1323 &r->info.info3->driver_path,
1324 &r->info.info3->data_file,
1325 &r->info.info3->config_file,
1326 &r->info.info3->help_file,
1327 r->info.info3->dependent_files,
1328 &r->info.info3->version,
1329 flags,
1330 driver_directory);
1331 case 6:
1332 return clean_up_driver_struct_level(mem_ctx, session_info,
1333 r->info.info6->architecture,
1334 &r->info.info6->driver_path,
1335 &r->info.info6->data_file,
1336 &r->info.info6->config_file,
1337 &r->info.info6->help_file,
1338 r->info.info6->dependent_files,
1339 &r->info.info6->version,
1340 flags,
1341 driver_directory);
1342 case 8:
1343 return clean_up_driver_struct_level(mem_ctx, session_info,
1344 r->info.info8->architecture,
1345 &r->info.info8->driver_path,
1346 &r->info.info8->data_file,
1347 &r->info.info8->config_file,
1348 &r->info.info8->help_file,
1349 r->info.info8->dependent_files,
1350 &r->info.info8->version,
1351 flags,
1352 driver_directory);
1353 default:
1354 return WERR_NOT_SUPPORTED;
1358 /****************************************************************************
1359 This function sucks and should be replaced. JRA.
1360 ****************************************************************************/
1362 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1363 const struct spoolss_AddDriverInfo6 *src)
1365 dst->version = src->version;
1367 dst->driver_name = src->driver_name;
1368 dst->architecture = src->architecture;
1369 dst->driver_path = src->driver_path;
1370 dst->data_file = src->data_file;
1371 dst->config_file = src->config_file;
1372 dst->help_file = src->help_file;
1373 dst->monitor_name = src->monitor_name;
1374 dst->default_datatype = src->default_datatype;
1375 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1376 dst->dependent_files = src->dependent_files;
1379 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1380 const struct spoolss_AddDriverInfo8 *src)
1382 dst->version = src->version;
1384 dst->driver_name = src->driver_name;
1385 dst->architecture = src->architecture;
1386 dst->driver_path = src->driver_path;
1387 dst->data_file = src->data_file;
1388 dst->config_file = src->config_file;
1389 dst->help_file = src->help_file;
1390 dst->monitor_name = src->monitor_name;
1391 dst->default_datatype = src->default_datatype;
1392 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1393 dst->dependent_files = src->dependent_files;
1396 /****************************************************************************
1397 ****************************************************************************/
1399 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1400 connection_struct *conn,
1401 const char *driver_file,
1402 const char *short_architecture,
1403 uint32_t driver_version,
1404 uint32_t version,
1405 const char *driver_directory)
1407 struct smb_filename *smb_fname_old = NULL;
1408 struct smb_filename *smb_fname_new = NULL;
1409 char *old_name = NULL;
1410 char *new_name = NULL;
1411 NTSTATUS status;
1412 WERROR ret;
1414 if (driver_directory != NULL) {
1415 old_name = talloc_asprintf(mem_ctx,
1416 "%s/%s/%s",
1417 short_architecture,
1418 driver_directory,
1419 driver_file);
1420 } else {
1421 old_name = talloc_asprintf(mem_ctx,
1422 "%s/%s",
1423 short_architecture,
1424 driver_file);
1426 if (old_name == NULL) {
1427 return WERR_NOT_ENOUGH_MEMORY;
1430 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1431 short_architecture, driver_version, driver_file);
1432 if (new_name == NULL) {
1433 TALLOC_FREE(old_name);
1434 return WERR_NOT_ENOUGH_MEMORY;
1437 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1439 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1440 if (!NT_STATUS_IS_OK(status)) {
1441 ret = WERR_NOT_ENOUGH_MEMORY;
1442 goto out;
1445 /* Setup a synthetic smb_filename struct */
1446 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1447 if (!smb_fname_new) {
1448 ret = WERR_NOT_ENOUGH_MEMORY;
1449 goto out;
1452 smb_fname_new->base_name = new_name;
1454 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1455 "'%s'\n", smb_fname_old->base_name,
1456 smb_fname_new->base_name));
1458 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1459 OPENX_FILE_EXISTS_TRUNCATE |
1460 OPENX_FILE_CREATE_IF_NOT_EXIST,
1461 0, false);
1463 if (!NT_STATUS_IS_OK(status)) {
1464 DEBUG(0,("move_driver_file_to_download_area: Unable "
1465 "to rename [%s] to [%s]: %s\n",
1466 smb_fname_old->base_name, new_name,
1467 nt_errstr(status)));
1468 ret = WERR_APP_INIT_FAILURE;
1469 goto out;
1473 ret = WERR_OK;
1474 out:
1475 TALLOC_FREE(smb_fname_old);
1476 TALLOC_FREE(smb_fname_new);
1477 return ret;
1480 WERROR move_driver_to_download_area(const struct auth_session_info *session_info,
1481 const struct spoolss_AddDriverInfoCtr *r,
1482 const char *driver_directory)
1484 TALLOC_CTX *frame = talloc_stackframe();
1485 const struct loadparm_substitution *lp_sub =
1486 loadparm_s3_global_substitution();
1487 struct spoolss_AddDriverInfo3 *driver;
1488 struct spoolss_AddDriverInfo3 converted_driver;
1489 const char *short_architecture;
1490 struct smb_filename *smb_dname = NULL;
1491 char *new_dir = NULL;
1492 struct conn_struct_tos *c = NULL;
1493 connection_struct *conn = NULL;
1494 NTSTATUS nt_status;
1495 int i;
1496 int ver = 0;
1497 char *printdollar = NULL;
1498 int printdollar_snum;
1499 WERROR err = WERR_OK;
1501 switch (r->level) {
1502 case 3:
1503 driver = r->info.info3;
1504 break;
1505 case 6:
1506 convert_level_6_to_level3(&converted_driver, r->info.info6);
1507 driver = &converted_driver;
1508 break;
1509 case 8:
1510 convert_level_8_to_level3(&converted_driver, r->info.info8);
1511 driver = &converted_driver;
1512 break;
1513 default:
1514 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1515 TALLOC_FREE(frame);
1516 return WERR_INVALID_LEVEL;
1519 short_architecture = get_short_archi(driver->architecture);
1520 if (!short_architecture) {
1521 TALLOC_FREE(frame);
1522 return WERR_UNKNOWN_PRINTER_DRIVER;
1525 printdollar_snum = find_service(frame, "print$", &printdollar);
1526 if (!printdollar) {
1527 TALLOC_FREE(frame);
1528 return WERR_NOT_ENOUGH_MEMORY;
1530 if (printdollar_snum == -1) {
1531 TALLOC_FREE(frame);
1532 return WERR_BAD_NET_NAME;
1535 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1536 printdollar_snum,
1537 lp_path(frame, lp_sub, printdollar_snum),
1538 session_info,
1539 &c);
1540 if (!NT_STATUS_IS_OK(nt_status)) {
1541 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1542 "returned %s\n", nt_errstr(nt_status)));
1543 err = ntstatus_to_werror(nt_status);
1544 TALLOC_FREE(frame);
1545 return err;
1547 conn = c->conn;
1549 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1550 if (!NT_STATUS_IS_OK(nt_status)) {
1551 DEBUG(0, ("failed set force user / group\n"));
1552 err = ntstatus_to_werror(nt_status);
1553 goto err_free_conn;
1556 if (!become_user_without_service_by_session(conn, session_info)) {
1557 DEBUG(0, ("failed to become user\n"));
1558 err = WERR_ACCESS_DENIED;
1559 goto err_free_conn;
1562 new_dir = talloc_asprintf(frame,
1563 "%s/%d",
1564 short_architecture,
1565 driver->version);
1566 if (!new_dir) {
1567 err = WERR_NOT_ENOUGH_MEMORY;
1568 goto err_exit;
1570 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1571 if (!NT_STATUS_IS_OK(nt_status)) {
1572 err = WERR_NOT_ENOUGH_MEMORY;
1573 goto err_exit;
1576 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1578 nt_status = create_directory(conn, NULL, smb_dname);
1579 if (!NT_STATUS_IS_OK(nt_status)
1580 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1581 DEBUG(0, ("failed to create driver destination directory: %s\n",
1582 nt_errstr(nt_status)));
1583 err = ntstatus_to_werror(nt_status);
1584 goto err_exit;
1587 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1588 * listed for this driver which has already been moved, skip it (note:
1589 * drivers may list the same file name several times. Then check if the
1590 * file already exists in archi\version\, if so, check that the version
1591 * info (or time stamps if version info is unavailable) is newer (or the
1592 * date is later). If it is, move it to archi\version\filexxx.yyy.
1593 * Otherwise, delete the file.
1595 * If a file is not moved to archi\version\ because of an error, all the
1596 * rest of the 'unmoved' driver files are removed from archi\. If one or
1597 * more of the driver's files was already moved to archi\version\, it
1598 * potentially leaves the driver in a partially updated state. Version
1599 * trauma will most likely occur if an client attempts to use any printer
1600 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1601 * done is appropriate... later JRR
1604 DEBUG(5,("Moving files now !\n"));
1606 if (driver->driver_path && strlen(driver->driver_path)) {
1608 err = move_driver_file_to_download_area(frame,
1609 conn,
1610 driver->driver_path,
1611 short_architecture,
1612 driver->version,
1613 ver,
1614 driver_directory);
1615 if (!W_ERROR_IS_OK(err)) {
1616 goto err_exit;
1620 if (driver->data_file && strlen(driver->data_file)) {
1621 if (!strequal(driver->data_file, driver->driver_path)) {
1623 err = move_driver_file_to_download_area(frame,
1624 conn,
1625 driver->data_file,
1626 short_architecture,
1627 driver->version,
1628 ver,
1629 driver_directory);
1630 if (!W_ERROR_IS_OK(err)) {
1631 goto err_exit;
1636 if (driver->config_file && strlen(driver->config_file)) {
1637 if (!strequal(driver->config_file, driver->driver_path) &&
1638 !strequal(driver->config_file, driver->data_file)) {
1640 err = move_driver_file_to_download_area(frame,
1641 conn,
1642 driver->config_file,
1643 short_architecture,
1644 driver->version,
1645 ver,
1646 driver_directory);
1647 if (!W_ERROR_IS_OK(err)) {
1648 goto err_exit;
1653 if (driver->help_file && strlen(driver->help_file)) {
1654 if (!strequal(driver->help_file, driver->driver_path) &&
1655 !strequal(driver->help_file, driver->data_file) &&
1656 !strequal(driver->help_file, driver->config_file)) {
1658 err = move_driver_file_to_download_area(frame,
1659 conn,
1660 driver->help_file,
1661 short_architecture,
1662 driver->version,
1663 ver,
1664 driver_directory);
1665 if (!W_ERROR_IS_OK(err)) {
1666 goto err_exit;
1671 if (driver->dependent_files && driver->dependent_files->string) {
1672 for (i=0; driver->dependent_files->string[i]; i++) {
1673 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1674 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1675 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1676 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1677 int j;
1678 for (j=0; j < i; j++) {
1679 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1680 goto NextDriver;
1684 err = move_driver_file_to_download_area(frame,
1685 conn,
1686 driver->dependent_files->string[i],
1687 short_architecture,
1688 driver->version,
1689 ver,
1690 driver_directory);
1691 if (!W_ERROR_IS_OK(err)) {
1692 goto err_exit;
1695 NextDriver: ;
1699 err = WERR_OK;
1700 err_exit:
1701 unbecome_user_without_service();
1702 err_free_conn:
1703 TALLOC_FREE(frame);
1704 return err;
1707 /****************************************************************************
1708 Determine whether or not a particular driver is currently assigned
1709 to a printer
1710 ****************************************************************************/
1712 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1713 struct dcerpc_binding_handle *b,
1714 const struct spoolss_DriverInfo8 *r)
1716 const struct loadparm_substitution *lp_sub =
1717 loadparm_s3_global_substitution();
1718 int snum;
1719 int n_services = lp_numservices();
1720 bool in_use = false;
1721 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1722 WERROR result;
1724 if (!r) {
1725 return false;
1728 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1730 /* loop through the printers.tdb and check for the drivername */
1732 for (snum=0; snum<n_services && !in_use; snum++) {
1733 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1734 continue;
1737 result = winreg_get_printer(mem_ctx, b,
1738 lp_servicename(talloc_tos(), lp_sub, snum),
1739 &pinfo2);
1740 if (!W_ERROR_IS_OK(result)) {
1741 continue; /* skip */
1744 if (strequal(r->driver_name, pinfo2->drivername)) {
1745 in_use = true;
1748 TALLOC_FREE(pinfo2);
1751 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1753 if ( in_use ) {
1754 struct spoolss_DriverInfo8 *driver = NULL;
1755 WERROR werr;
1757 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1759 /* we can still remove the driver if there is one of
1760 "Windows NT x86" version 2 or 3 left */
1762 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1763 if (r->version == 2) {
1764 werr = winreg_get_driver(mem_ctx, b,
1765 r->architecture,
1766 r->driver_name,
1767 3, &driver);
1768 } else if (r->version == 3) {
1769 werr = winreg_get_driver(mem_ctx, b,
1770 r->architecture,
1771 r->driver_name,
1772 2, &driver);
1773 } else {
1774 DBG_ERR("Unknown driver version (%d)\n",
1775 r->version);
1776 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1778 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1779 werr = winreg_get_driver(mem_ctx, b,
1780 SPOOLSS_ARCHITECTURE_NT_X86,
1781 r->driver_name,
1782 DRIVER_ANY_VERSION,
1783 &driver);
1784 } else {
1785 DBG_ERR("Unknown driver architecture: %s\n",
1786 r->architecture);
1787 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1790 /* now check the error code */
1792 if ( W_ERROR_IS_OK(werr) ) {
1793 /* it's ok to remove the driver, we have other architctures left */
1794 in_use = false;
1795 talloc_free(driver);
1799 /* report that the driver is not in use by default */
1801 return in_use;
1805 /**********************************************************************
1806 Check to see if a ogiven file is in use by *info
1807 *********************************************************************/
1809 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1811 int i = 0;
1813 if ( !info )
1814 return False;
1816 /* mz: skip files that are in the list but already deleted */
1817 if (!file || !file[0]) {
1818 return false;
1821 if (strequal(file, info->driver_path))
1822 return True;
1824 if (strequal(file, info->data_file))
1825 return True;
1827 if (strequal(file, info->config_file))
1828 return True;
1830 if (strequal(file, info->help_file))
1831 return True;
1833 /* see of there are any dependent files to examine */
1835 if (!info->dependent_files)
1836 return False;
1838 while (info->dependent_files[i] && *info->dependent_files[i]) {
1839 if (strequal(file, info->dependent_files[i]))
1840 return True;
1841 i++;
1844 return False;
1848 /**********************************************************************
1849 Utility function to remove the dependent file pointed to by the
1850 input parameter from the list
1851 *********************************************************************/
1853 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1856 /* bump everything down a slot */
1858 while (files && files[idx+1]) {
1859 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1860 idx++;
1863 files[idx] = NULL;
1865 return;
1868 /**********************************************************************
1869 Check if any of the files used by src are also used by drv
1870 *********************************************************************/
1872 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1873 struct spoolss_DriverInfo8 *src,
1874 const struct spoolss_DriverInfo8 *drv)
1876 bool in_use = False;
1877 int i = 0;
1879 if ( !src || !drv )
1880 return False;
1882 /* check each file. Remove it from the src structure if it overlaps */
1884 if (drv_file_in_use(src->driver_path, drv)) {
1885 in_use = True;
1886 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1887 src->driver_path = talloc_strdup(mem_ctx, "");
1888 if (!src->driver_path) { return false; }
1891 if (drv_file_in_use(src->data_file, drv)) {
1892 in_use = True;
1893 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1894 src->data_file = talloc_strdup(mem_ctx, "");
1895 if (!src->data_file) { return false; }
1898 if (drv_file_in_use(src->config_file, drv)) {
1899 in_use = True;
1900 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1901 src->config_file = talloc_strdup(mem_ctx, "");
1902 if (!src->config_file) { return false; }
1905 if (drv_file_in_use(src->help_file, drv)) {
1906 in_use = True;
1907 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1908 src->help_file = talloc_strdup(mem_ctx, "");
1909 if (!src->help_file) { return false; }
1912 /* are there any dependentfiles to examine? */
1914 if (!src->dependent_files)
1915 return in_use;
1917 while (src->dependent_files[i] && *src->dependent_files[i]) {
1918 if (drv_file_in_use(src->dependent_files[i], drv)) {
1919 in_use = True;
1920 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1921 trim_dependent_file(mem_ctx, src->dependent_files, i);
1922 } else
1923 i++;
1926 return in_use;
1929 /****************************************************************************
1930 Determine whether or not a particular driver files are currently being
1931 used by any other driver.
1933 Return value is True if any files were in use by other drivers
1934 and False otherwise.
1936 Upon return, *info has been modified to only contain the driver files
1937 which are not in use
1939 Fix from mz:
1941 This needs to check all drivers to ensure that all files in use
1942 have been removed from *info, not just the ones in the first
1943 match.
1944 ****************************************************************************/
1946 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1947 struct dcerpc_binding_handle *b,
1948 struct spoolss_DriverInfo8 *info)
1950 int i;
1951 uint32_t version;
1952 struct spoolss_DriverInfo8 *driver;
1953 bool in_use = false;
1954 uint32_t num_drivers;
1955 const char **drivers;
1956 WERROR result;
1958 if ( !info )
1959 return False;
1961 version = info->version;
1963 /* loop over all driver versions */
1965 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1967 /* get the list of drivers */
1969 result = winreg_get_driver_list(mem_ctx, b,
1970 info->architecture, version,
1971 &num_drivers, &drivers);
1972 if (!W_ERROR_IS_OK(result)) {
1973 return true;
1976 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1977 num_drivers, info->architecture, version));
1979 /* check each driver for overlap in files */
1981 for (i = 0; i < num_drivers; i++) {
1982 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1984 driver = NULL;
1986 result = winreg_get_driver(mem_ctx, b,
1987 info->architecture, drivers[i],
1988 version, &driver);
1989 if (!W_ERROR_IS_OK(result)) {
1990 talloc_free(drivers);
1991 return True;
1994 /* check if d2 uses any files from d1 */
1995 /* only if this is a different driver than the one being deleted */
1997 if (!strequal(info->driver_name, driver->driver_name)) {
1998 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1999 /* mz: Do not instantly return -
2000 * we need to ensure this file isn't
2001 * also in use by other drivers. */
2002 in_use = true;
2006 talloc_free(driver);
2009 talloc_free(drivers);
2011 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2013 return in_use;
2016 static NTSTATUS driver_unlink_internals(connection_struct *conn,
2017 const char *short_arch,
2018 int vers,
2019 const char *fname)
2021 TALLOC_CTX *tmp_ctx = talloc_new(conn);
2022 struct smb_filename *smb_fname = NULL;
2023 char *print_dlr_path;
2024 NTSTATUS status = NT_STATUS_NO_MEMORY;
2026 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
2027 short_arch, vers, fname);
2028 if (print_dlr_path == NULL) {
2029 goto err_out;
2032 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
2033 if (smb_fname == NULL) {
2034 goto err_out;
2037 status = unlink_internals(conn, NULL, 0, smb_fname, false);
2038 err_out:
2039 talloc_free(tmp_ctx);
2040 return status;
2043 /****************************************************************************
2044 Actually delete the driver files. Make sure that
2045 printer_driver_files_in_use() return False before calling
2046 this.
2047 ****************************************************************************/
2049 bool delete_driver_files(const struct auth_session_info *session_info,
2050 const struct spoolss_DriverInfo8 *r)
2052 TALLOC_CTX *frame = talloc_stackframe();
2053 const struct loadparm_substitution *lp_sub =
2054 loadparm_s3_global_substitution();
2055 const char *short_arch;
2056 struct conn_struct_tos *c = NULL;
2057 connection_struct *conn = NULL;
2058 NTSTATUS nt_status;
2059 char *printdollar = NULL;
2060 int printdollar_snum;
2061 bool ret = false;
2063 if (!r) {
2064 TALLOC_FREE(frame);
2065 return false;
2068 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2069 r->driver_name, r->version));
2071 printdollar_snum = find_service(frame, "print$", &printdollar);
2072 if (!printdollar) {
2073 TALLOC_FREE(frame);
2074 return false;
2076 if (printdollar_snum == -1) {
2077 TALLOC_FREE(frame);
2078 return false;
2081 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
2082 printdollar_snum,
2083 lp_path(frame, lp_sub, printdollar_snum),
2084 session_info,
2085 &c);
2086 if (!NT_STATUS_IS_OK(nt_status)) {
2087 DEBUG(0,("delete_driver_files: create_conn_struct "
2088 "returned %s\n", nt_errstr(nt_status)));
2089 TALLOC_FREE(frame);
2090 return false;
2092 conn = c->conn;
2094 nt_status = set_conn_force_user_group(conn, printdollar_snum);
2095 if (!NT_STATUS_IS_OK(nt_status)) {
2096 DEBUG(0, ("failed set force user / group\n"));
2097 ret = false;
2098 goto err_free_conn;
2101 if (!become_user_without_service_by_session(conn, session_info)) {
2102 DEBUG(0, ("failed to become user\n"));
2103 ret = false;
2104 goto err_free_conn;
2107 if ( !CAN_WRITE(conn) ) {
2108 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2109 ret = false;
2110 goto err_out;
2113 short_arch = get_short_archi(r->architecture);
2114 if (short_arch == NULL) {
2115 DEBUG(0, ("bad architecture %s\n", r->architecture));
2116 ret = false;
2117 goto err_out;
2120 /* now delete the files */
2122 if (r->driver_path && r->driver_path[0]) {
2123 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
2124 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
2127 if (r->config_file && r->config_file[0]) {
2128 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
2129 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
2132 if (r->data_file && r->data_file[0]) {
2133 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
2134 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
2137 if (r->help_file && r->help_file[0]) {
2138 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
2139 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
2142 if (r->dependent_files) {
2143 int i = 0;
2144 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2145 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
2146 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
2147 i++;
2151 ret = true;
2152 err_out:
2153 unbecome_user_without_service();
2154 err_free_conn:
2155 TALLOC_FREE(frame);
2156 return ret;
2159 /* error code:
2160 0: everything OK
2161 1: level not implemented
2162 2: file doesn't exist
2163 3: can't allocate memory
2164 4: can't free memory
2165 5: non existent struct
2169 A printer and a printer driver are 2 different things.
2170 NT manages them separatelly, Samba does the same.
2171 Why ? Simply because it's easier and it makes sense !
2173 Now explanation: You have 3 printers behind your samba server,
2174 2 of them are the same make and model (laser A and B). But laser B
2175 has an 3000 sheet feeder and laser A doesn't such an option.
2176 Your third printer is an old dot-matrix model for the accounting :-).
2178 If the /usr/local/samba/lib directory (default dir), you will have
2179 5 files to describe all of this.
2181 3 files for the printers (1 by printer):
2182 NTprinter_laser A
2183 NTprinter_laser B
2184 NTprinter_accounting
2185 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2186 NTdriver_printer model X
2187 NTdriver_printer model Y
2189 jfm: I should use this comment for the text file to explain
2190 same thing for the forms BTW.
2191 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2195 /* Convert generic access rights to printer object specific access rights.
2196 It turns out that NT4 security descriptors use generic access rights and
2197 NT5 the object specific ones. */
2199 void map_printer_permissions(struct security_descriptor *sd)
2201 int i;
2203 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2204 se_map_generic(&sd->dacl->aces[i].access_mask,
2205 &printer_generic_mapping);
2209 void map_job_permissions(struct security_descriptor *sd)
2211 int i;
2213 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2214 se_map_generic(&sd->dacl->aces[i].access_mask,
2215 &job_generic_mapping);
2220 /****************************************************************************
2221 Check a user has permissions to perform the given operation. We use the
2222 permission constants defined in include/rpc_spoolss.h to check the various
2223 actions we perform when checking printer access.
2225 PRINTER_ACCESS_ADMINISTER:
2226 print_queue_pause, print_queue_resume, update_printer_sec,
2227 update_printer, spoolss_addprinterex_level_2,
2228 _spoolss_setprinterdata
2230 PRINTER_ACCESS_USE:
2231 print_job_start
2233 JOB_ACCESS_ADMINISTER:
2234 print_job_delete, print_job_pause, print_job_resume,
2235 print_queue_purge
2237 Try access control in the following order (for performance reasons):
2238 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2239 2) check security descriptor (bit comparisons in memory)
2240 3) "printer admins" (may result in numerous calls to winbind)
2242 ****************************************************************************/
2243 WERROR print_access_check(const struct auth_session_info *session_info,
2244 struct messaging_context *msg_ctx, int snum,
2245 int access_type)
2247 struct spoolss_security_descriptor *secdesc = NULL;
2248 const struct loadparm_substitution *lp_sub =
2249 loadparm_s3_global_substitution();
2250 uint32_t access_granted;
2251 size_t sd_size;
2252 NTSTATUS status;
2253 WERROR result;
2254 const char *pname;
2255 TALLOC_CTX *mem_ctx = NULL;
2257 /* If user is NULL then use the current_user structure */
2259 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2261 if ((session_info->unix_token->uid == sec_initial_uid())
2262 || security_token_has_privilege(session_info->security_token,
2263 SEC_PRIV_PRINT_OPERATOR)) {
2264 return WERR_OK;
2267 /* Get printer name */
2269 pname = lp_printername(talloc_tos(), lp_sub, snum);
2271 if (!pname || !*pname) {
2272 return WERR_ACCESS_DENIED;
2275 /* Get printer security descriptor */
2277 if(!(mem_ctx = talloc_init("print_access_check"))) {
2278 return WERR_NOT_ENOUGH_MEMORY;
2281 result = winreg_get_printer_secdesc_internal(mem_ctx,
2282 get_session_info_system(),
2283 msg_ctx,
2284 pname,
2285 &secdesc);
2286 if (!W_ERROR_IS_OK(result)) {
2287 talloc_destroy(mem_ctx);
2288 return WERR_NOT_ENOUGH_MEMORY;
2291 if (access_type == JOB_ACCESS_ADMINISTER) {
2292 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2294 /* Create a child security descriptor to check permissions
2295 against. This is because print jobs are child objects
2296 objects of a printer. */
2297 status = se_create_child_secdesc(mem_ctx,
2298 &secdesc,
2299 &sd_size,
2300 parent_secdesc,
2301 parent_secdesc->owner_sid,
2302 parent_secdesc->group_sid,
2303 false);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 talloc_destroy(mem_ctx);
2306 return ntstatus_to_werror(status);
2309 map_job_permissions(secdesc);
2310 } else {
2311 map_printer_permissions(secdesc);
2314 /* Check access */
2315 status = se_access_check(secdesc, session_info->security_token, access_type,
2316 &access_granted);
2318 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2320 talloc_destroy(mem_ctx);
2322 return ntstatus_to_werror(status);
2325 /****************************************************************************
2326 Check the time parameters allow a print operation.
2327 *****************************************************************************/
2329 bool print_time_access_check(const struct auth_session_info *session_info,
2330 struct messaging_context *msg_ctx,
2331 const char *servicename)
2333 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2334 WERROR result;
2335 bool ok = False;
2336 time_t now = time(NULL);
2337 struct tm *t;
2338 uint32_t mins;
2340 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2341 servicename, &pinfo2);
2342 if (!W_ERROR_IS_OK(result)) {
2343 return False;
2346 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2347 ok = True;
2350 t = gmtime(&now);
2351 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2353 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2354 ok = True;
2357 TALLOC_FREE(pinfo2);
2359 if (!ok) {
2360 errno = EACCES;
2363 return ok;
2366 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2367 const struct auth_session_info *session_info,
2368 struct messaging_context *msg_ctx,
2369 const char *printer)
2371 WERROR result;
2373 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2374 printer, "");
2375 if (!W_ERROR_IS_OK(result)) {
2376 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2377 "%s\n", printer, win_errstr(result)));
2381 void nt_printer_add(TALLOC_CTX *mem_ctx,
2382 const struct auth_session_info *session_info,
2383 struct messaging_context *msg_ctx,
2384 const char *printer)
2386 WERROR result;
2388 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2389 printer);
2390 if (!W_ERROR_IS_OK(result)) {
2391 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2392 printer, win_errstr(result)));