ctdb-failover: omit "restrict" optimization keyword
[Samba.git] / source3 / printing / nt_printing.c
blob7907fb4b22969aec32a606ef5c0dbbbb1fd86718
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 "printing/queue_process.h"
25 #include "../librpc/gen_ndr/ndr_spoolss.h"
26 #include "rpc_server/spoolss/srv_spoolss_util.h"
27 #include "nt_printing.h"
28 #include "secrets.h"
29 #include "../librpc/gen_ndr/netlogon.h"
30 #include "../libcli/security/security.h"
31 #include "passdb/machine_sid.h"
32 #include "smbd/smbd.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"
37 #include "lib/util/string_wrappers.h"
38 #include "lib/global_contexts.h"
40 /* Map generic permissions to printer object specific permissions */
42 const struct generic_mapping printer_generic_mapping = {
43 PRINTER_READ,
44 PRINTER_WRITE,
45 PRINTER_EXECUTE,
46 PRINTER_ALL_ACCESS
49 /* Map generic permissions to print server object specific permissions */
51 const struct generic_mapping printserver_generic_mapping = {
52 SERVER_READ,
53 SERVER_WRITE,
54 SERVER_EXECUTE,
55 SERVER_ALL_ACCESS
58 /* Map generic permissions to job object specific permissions */
60 const struct generic_mapping job_generic_mapping = {
61 JOB_READ,
62 JOB_WRITE,
63 JOB_EXECUTE,
64 JOB_ALL_ACCESS
67 static bool print_driver_directories_init(void)
69 int service;
70 size_t i;
71 char *driver_path;
72 bool ok;
73 TALLOC_CTX *mem_ctx = talloc_stackframe();
74 const struct loadparm_substitution *lp_sub =
75 loadparm_s3_global_substitution();
77 const char *dir_list[] = {
78 "W32X86/PCC",
79 "x64/PCC",
80 "ARM64",
81 "color"
84 service = lp_servicenumber("print$");
85 if (service < 0) {
86 /* We don't have a print$ share */
87 DEBUG(5, ("No print$ share has been configured.\n"));
88 talloc_free(mem_ctx);
89 return true;
92 driver_path = lp_path(mem_ctx, lp_sub, service);
93 if (driver_path == NULL) {
94 talloc_free(mem_ctx);
95 return false;
98 ok = directory_create_or_exist(driver_path, 0755);
99 if (!ok) {
100 DEBUG(1, ("Failed to create printer driver directory %s\n",
101 driver_path));
102 talloc_free(mem_ctx);
103 return false;
106 for (i = 0; archi_table[i].long_archi != NULL; i++) {
107 const char *arch_path;
109 arch_path = talloc_asprintf(mem_ctx,
110 "%s/%s",
111 driver_path,
112 archi_table[i].short_archi);
113 if (arch_path == NULL) {
114 talloc_free(mem_ctx);
115 return false;
118 ok = directory_create_or_exist(arch_path, 0755);
119 if (!ok) {
120 DEBUG(1, ("Failed to create printer driver "
121 "architecture directory %s\n",
122 arch_path));
123 talloc_free(mem_ctx);
124 return false;
128 for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
129 const char *path;
131 path = talloc_asprintf(mem_ctx,
132 "%s/%s",
133 driver_path,
134 dir_list[i]);
135 if (path == NULL) {
136 talloc_free(mem_ctx);
137 return false;
140 ok = directory_create_or_exist(path, 0755);
141 if (!ok) {
142 DEBUG(1, ("Failed to create printer driver "
143 "architecture directory %s\n",
144 path));
145 talloc_free(mem_ctx);
146 return false;
150 driver_path = state_path(talloc_tos(), "DriverStore");
151 if (driver_path == NULL) {
152 talloc_free(mem_ctx);
153 return false;
156 ok = directory_create_or_exist(driver_path, 0755);
157 if (!ok) {
158 DEBUG(1,("failed to create path %s\n", driver_path));
159 talloc_free(mem_ctx);
160 return false;
163 driver_path = state_path(talloc_tos(), "DriverStore/FileRepository");
164 if (driver_path == NULL) {
165 talloc_free(mem_ctx);
166 return false;
169 ok = directory_create_or_exist(driver_path, 0755);
170 if (!ok) {
171 DEBUG(1,("failed to create path %s\n", driver_path));
172 talloc_free(mem_ctx);
173 return false;
176 driver_path = state_path(talloc_tos(), "DriverStore/Temp");
177 if (driver_path == NULL) {
178 talloc_free(mem_ctx);
179 return false;
182 ok = directory_create_or_exist(driver_path, 0755);
183 if (!ok) {
184 DEBUG(1,("failed to create path %s\n", driver_path));
185 talloc_free(mem_ctx);
186 return false;
189 talloc_free(mem_ctx);
190 return true;
193 /****************************************************************************
194 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
195 background lpq updater.
196 ****************************************************************************/
198 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
199 void *private_data,
200 uint32_t msg_type,
201 struct server_id server_id,
202 DATA_BLOB *data)
204 send_to_bgqd(msg, msg_type, data->data, data->length);
207 /****************************************************************************
208 Open the NT printing tdbs. Done once before fork().
209 ****************************************************************************/
211 bool nt_printing_init(struct messaging_context *msg_ctx)
213 WERROR win_rc;
215 if (!print_driver_directories_init()) {
216 return false;
219 if (!nt_printing_tdb_upgrade()) {
220 return false;
224 * register callback to handle updating printers as new
225 * drivers are installed. Forwards to background lpq updater.
227 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
228 forward_drv_upgrade_printer_msg);
230 if ( lp_security() == SEC_ADS ) {
231 win_rc = check_published_printers(msg_ctx);
232 if (!W_ERROR_IS_OK(win_rc))
233 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
236 return true;
239 /*******************************************************************
240 Function to allow filename parsing "the old way".
241 ********************************************************************/
243 static NTSTATUS driver_unix_convert(connection_struct *conn,
244 const char *old_name,
245 struct files_struct **pdirfsp,
246 struct smb_filename **psmb_fname)
248 NTSTATUS status;
249 TALLOC_CTX *ctx = talloc_tos();
250 char *name = talloc_strdup(ctx, old_name);
252 if (!name) {
253 return NT_STATUS_NO_MEMORY;
255 unix_format(name);
256 name = unix_clean_name(ctx, name);
257 if (!name) {
258 return NT_STATUS_NO_MEMORY;
260 trim_string(name,"/","/");
262 status = filename_convert_dirfsp(ctx,
263 conn,
264 name,
265 0, /* ucf_flags */
266 0, /* twrp */
267 pdirfsp,
268 psmb_fname);
269 if (!NT_STATUS_IS_OK(status)) {
270 return status;
273 return NT_STATUS_OK;
276 /****************************************************************************
277 Function to do the mapping between the long architecture name and
278 the short one.
279 ****************************************************************************/
281 const char *get_short_archi(const char *long_archi)
283 int i=-1;
285 DEBUG(107,("Getting architecture dependent directory\n"));
286 do {
287 i++;
288 } while ( (archi_table[i].long_archi!=NULL ) &&
289 strcasecmp_m(long_archi, archi_table[i].long_archi) );
291 if (archi_table[i].long_archi==NULL) {
292 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
293 return NULL;
296 /* this might be client code - but shouldn't this be an fstrcpy etc? */
298 DEBUGADD(108,("index: [%d]\n", i));
299 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
300 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
302 return archi_table[i].short_archi;
305 /****************************************************************************
306 Read data from fsp on the vfs.
307 ****************************************************************************/
309 static ssize_t printing_pread_data(files_struct *fsp,
310 char *buf,
311 off_t *poff,
312 size_t byte_count)
314 size_t total=0;
315 off_t in_pos = *poff;
317 /* Don't allow integer wrap on read. */
318 if (in_pos + byte_count < in_pos) {
319 return -1;
322 while (total < byte_count) {
323 ssize_t ret = read_file(fsp,
324 buf + total,
325 in_pos,
326 byte_count - total);
328 if (ret == 0) {
329 *poff = in_pos;
330 return total;
332 if (ret == -1) {
333 if (errno == EINTR) {
334 continue;
335 } else {
336 return -1;
339 in_pos += ret;
340 total += ret;
342 *poff = in_pos;
343 return (ssize_t)total;
346 /****************************************************************************
347 Detect the major and minor version of a PE file.
348 Returns:
350 1 if file is a PE file and we got version numbers,
351 0 if this file is a PE file and we couldn't get the version numbers,
352 -1 on error.
354 NB. buf is passed into and freed inside this function. This is a
355 bad API design, but fixing this is a task for another day.
356 ****************************************************************************/
358 static int handle_pe_file(files_struct *fsp,
359 off_t in_pos,
360 char *fname,
361 char *buf,
362 uint32_t *major,
363 uint32_t *minor)
365 unsigned int i;
366 unsigned int num_sections;
367 unsigned int section_table_bytes;
368 ssize_t byte_count;
369 off_t rel_pos;
370 int ret = -1;
372 /* Just skip over optional header to get to section table */
373 rel_pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-
374 (NE_HEADER_SIZE-PE_HEADER_SIZE);
376 if (in_pos + rel_pos < in_pos) {
377 /* Integer wrap. */
378 goto out;
380 in_pos = rel_pos + in_pos;
382 /* get the section table */
383 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
385 if (num_sections >= (UINT_MAX / PE_HEADER_SECT_HEADER_SIZE)) {
386 /* Integer wrap. */
387 goto out;
390 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
391 if (section_table_bytes == 0) {
392 goto out;
395 SAFE_FREE(buf);
396 buf = (char *)SMB_MALLOC(section_table_bytes);
397 if (buf == NULL) {
398 DBG_ERR("PE file [%s] section table malloc "
399 "failed bytes = %d\n",
400 fname,
401 section_table_bytes);
402 goto out;
405 byte_count = printing_pread_data(fsp, buf, &in_pos, section_table_bytes);
406 if (byte_count < section_table_bytes) {
407 DBG_NOTICE("PE file [%s] Section header too short, "
408 "bytes read = %lu\n",
409 fname,
410 (unsigned long)byte_count);
411 goto out;
415 * Iterate the section table looking for
416 * the resource section ".rsrc"
418 for (i = 0; i < num_sections; i++) {
419 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
421 if (strcmp(".rsrc",
422 &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) {
423 unsigned int section_pos = IVAL(buf,
424 sec_offset+
425 PE_HEADER_SECT_PTR_DATA_OFFSET);
426 unsigned int section_bytes = IVAL(buf,
427 sec_offset+
428 PE_HEADER_SECT_SIZE_DATA_OFFSET);
430 if (section_bytes == 0) {
431 goto out;
434 SAFE_FREE(buf);
435 buf=(char *)SMB_MALLOC(section_bytes);
436 if (buf == NULL) {
437 DBG_ERR("PE file [%s] version malloc "
438 "failed bytes = %d\n",
439 fname,
440 section_bytes);
441 goto out;
445 * Read from the start of the .rsrc
446 * section info
448 in_pos = section_pos;
450 byte_count = printing_pread_data(fsp,
451 buf,
452 &in_pos,
453 section_bytes);
454 if (byte_count < section_bytes) {
455 DBG_NOTICE("PE file "
456 "[%s] .rsrc section too short, "
457 "bytes read = %lu\n",
458 fname,
459 (unsigned long)byte_count);
460 goto out;
463 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) {
464 goto out;
467 for (i=0;
468 i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE;
469 i++) {
471 * Scan for 1st 3 unicoded bytes
472 * followed by word aligned magic
473 * value.
475 int mpos;
476 bool magic_match = false;
478 if (buf[i] == 'V' &&
479 buf[i+1] == '\0' &&
480 buf[i+2] == 'S') {
481 magic_match = true;
484 if (magic_match == false) {
485 continue;
488 /* Align to next long address */
489 mpos = (i + sizeof(VS_SIGNATURE)*2 +
490 3) & 0xfffffffc;
492 if (IVAL(buf,mpos) == VS_MAGIC_VALUE) {
493 *major = IVAL(buf,
494 mpos+ VS_MAJOR_OFFSET);
495 *minor = IVAL(buf,
496 mpos+ VS_MINOR_OFFSET);
498 DBG_INFO("PE file [%s] Version = "
499 "%08x:%08x (%d.%d.%d.%d)\n",
500 fname,
501 *major,
502 *minor,
503 (*major>>16)&0xffff,
504 *major&0xffff,
505 (*minor>>16)&0xffff,
506 *minor&0xffff);
507 ret = 1;
508 goto out;
514 /* Version info not found, fall back to origin date/time */
515 DBG_DEBUG("PE file [%s] has no version info\n", fname);
516 ret = 0;
518 out:
520 SAFE_FREE(buf);
521 return ret;
524 /****************************************************************************
525 Detect the major and minor version of an NE file.
526 Returns:
528 1 if file is an NE file and we got version numbers,
529 0 if this file is an NE file and we couldn't get the version numbers,
530 -1 on error.
532 NB. buf is passed into and freed inside this function. This is a
533 bad API design, but fixing this is a task for another day.
534 ****************************************************************************/
536 static int handle_ne_file(files_struct *fsp,
537 off_t in_pos,
538 char *fname,
539 char *buf,
540 uint32_t *major,
541 uint32_t *minor)
543 unsigned int i;
544 ssize_t byte_count;
545 int ret = -1;
547 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
548 DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n",
549 fname,
550 CVAL(buf,NE_HEADER_TARGET_OS_OFFSET));
552 * At this point, we assume the file is in error.
553 * It still could be something else besides a NE file,
554 * but it unlikely at this point.
556 goto out;
559 /* Allocate a bit more space to speed up things */
560 SAFE_FREE(buf);
561 buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE);
562 if (buf == NULL) {
563 DBG_ERR("NE file [%s] malloc failed bytes = %d\n",
564 fname,
565 PE_HEADER_SIZE);
566 goto out;
570 * This is a HACK! I got tired of trying to sort through the
571 * messy 'NE' file format. If anyone wants to clean this up
572 * please have at it, but this works. 'NE' files will
573 * eventually fade away. JRR
575 byte_count = printing_pread_data(fsp, buf, &in_pos, VS_NE_BUF_SIZE);
576 while (byte_count > 0) {
578 * Cover case that should not occur in a well
579 * formed 'NE' .dll file
581 if (byte_count-VS_VERSION_INFO_SIZE <= 0) {
582 break;
585 for(i=0; i<byte_count; i++) {
587 * Fast skip past data that can't
588 * possibly match
590 if (buf[i] != 'V') {
591 byte_count = printing_pread_data(fsp,
592 buf,
593 &in_pos,
594 VS_NE_BUF_SIZE);
595 continue;
599 * Potential match data crosses buf boundary,
600 * move it to beginning of buf, and fill the
601 * buf with as much as it will hold.
603 if (i>byte_count-VS_VERSION_INFO_SIZE) {
604 ssize_t amount_read;
605 ssize_t amount_unused = byte_count-i;
607 memmove(buf, &buf[i], amount_unused);
608 amount_read = printing_pread_data(fsp,
609 &buf[amount_unused],
610 &in_pos,
611 VS_NE_BUF_SIZE- amount_unused);
612 if (amount_read < 0) {
613 DBG_ERR("NE file [%s] Read "
614 "error, errno=%d\n",
615 fname,
616 errno);
617 goto out;
620 if (amount_read + amount_unused <
621 amount_read) {
622 /* Check for integer wrap. */
623 break;
626 byte_count = amount_read +
627 amount_unused;
628 if (byte_count < VS_VERSION_INFO_SIZE) {
629 break;
632 i = 0;
636 * Check that the full signature string and
637 * the magic number that follows exist (not
638 * a perfect solution, but the chances that this
639 * occurs in code is, well, remote. Yes I know
640 * I'm comparing the 'V' twice, as it is
641 * simpler to read the code.
643 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
645 * Compute skip alignment to next
646 * long address.
648 off_t cpos = in_pos;
649 int skip = -(cpos - (byte_count - i) +
650 sizeof(VS_SIGNATURE)) & 3;
651 if (IVAL(buf,
652 i+sizeof(VS_SIGNATURE)+skip)
653 != 0xfeef04bd) {
654 byte_count = printing_pread_data(fsp,
655 buf,
656 &in_pos,
657 VS_NE_BUF_SIZE);
658 continue;
661 *major = IVAL(buf,
662 i+sizeof(VS_SIGNATURE)+
663 skip+VS_MAJOR_OFFSET);
664 *minor = IVAL(buf,
665 i+sizeof(VS_SIGNATURE)+
666 skip+VS_MINOR_OFFSET);
667 DBG_INFO("NE file [%s] Version "
668 "= %08x:%08x (%d.%d.%d.%d)\n",
669 fname,
670 *major,
671 *minor,
672 (*major>>16)&0xffff,
673 *major&0xffff,
674 (*minor>>16)&0xffff,
675 *minor&0xffff);
676 ret = 1;
677 goto out;
682 /* Version info not found, fall back to origin date/time */
683 DBG_ERR("NE file [%s] Version info not found\n", fname);
684 ret = 0;
686 out:
688 SAFE_FREE(buf);
689 return ret;
692 /****************************************************************************
693 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
694 There are two case to be covered here: PE (Portable Executable) and NE (New
695 Executable) files. Both files support the same INFO structure, but PE files
696 store the signature in unicode, and NE files store it as !unicode.
697 returns -1 on error, 1 on version info found, and 0 on no version info found.
698 ****************************************************************************/
700 static int get_file_version(files_struct *fsp,
701 char *fname,
702 uint32_t *major,
703 uint32_t *minor)
705 char *buf = NULL;
706 ssize_t byte_count;
707 off_t in_pos = fh_get_pos(fsp->fh);
709 buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE);
710 if (buf == NULL) {
711 DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n",
712 fname,
713 DOS_HEADER_SIZE);
714 goto error_exit;
717 byte_count = printing_pread_data(fsp, buf, &in_pos, DOS_HEADER_SIZE);
718 if (byte_count < DOS_HEADER_SIZE) {
719 DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n",
720 fname,
721 (unsigned long)byte_count);
722 goto no_version_info;
725 /* Is this really a DOS header? */
726 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
727 DBG_INFO("File [%s] bad DOS magic = 0x%x\n",
728 fname,
729 SVAL(buf,DOS_HEADER_MAGIC_OFFSET));
730 goto no_version_info;
734 * Skip OEM header (if any) and the
735 * DOS stub to start of Windows header.
737 in_pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET);
739 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
740 byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE);
741 if (byte_count < NE_HEADER_SIZE) {
742 DBG_NOTICE("File [%s] Windows header too short, "
743 "bytes read = %lu\n",
744 fname,
745 (unsigned long)byte_count);
747 * Assume this isn't an error...
748 * the file just looks sort of like a PE/NE file
750 goto no_version_info;
754 * The header may be a PE (Portable Executable)
755 * or an NE (New Executable).
757 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
758 return handle_pe_file(fsp,
759 in_pos,
760 fname,
761 buf,
762 major,
763 minor);
764 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) ==
765 NE_HEADER_SIGNATURE) {
766 return handle_ne_file(fsp,
767 in_pos,
768 fname,
769 buf,
770 major,
771 minor);
772 } else {
774 * Assume this isn't an error... the file just
775 * looks sort of like a PE/NE file.
777 DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n",
778 fname,
779 IVAL(buf,PE_HEADER_SIGNATURE_OFFSET));
780 /* Fallthrough into no_version_info: */
783 no_version_info:
784 SAFE_FREE(buf);
785 return 0;
787 error_exit:
788 SAFE_FREE(buf);
789 return -1;
792 /****************************************************************************
793 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
794 share one or more files. During the MS installation process files are checked
795 to insure that only a newer version of a shared file is installed over an
796 older version. There are several possibilities for this comparison. If there
797 is no previous version, the new one is newer (obviously). If either file is
798 missing the version info structure, compare the creation date (on Unix use
799 the modification date). Otherwise chose the numerically larger version number.
800 ****************************************************************************/
802 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
804 bool use_version = true;
806 uint32_t new_major;
807 uint32_t new_minor;
808 time_t new_create_time;
810 uint32_t old_major;
811 uint32_t old_minor;
812 time_t old_create_time;
814 struct smb_filename *smb_fname = NULL;
815 files_struct *fsp = NULL;
816 struct files_struct *dirfsp = NULL;
817 SMB_STRUCT_STAT st;
819 NTSTATUS status;
820 int ret;
822 SET_STAT_INVALID(st);
823 new_create_time = (time_t)0;
824 old_create_time = (time_t)0;
826 /* Get file version info (if available) for previous file (if it exists) */
827 status = driver_unix_convert(conn, old_file, &dirfsp, &smb_fname);
828 if (!NT_STATUS_IS_OK(status)) {
829 goto error_exit;
832 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
833 if (!NT_STATUS_IS_OK(status)) {
834 ret = 1;
835 goto done;
838 status = SMB_VFS_CREATE_FILE(
839 conn, /* conn */
840 NULL, /* req */
841 dirfsp, /* dirfsp */
842 smb_fname, /* fname */
843 FILE_GENERIC_READ, /* access_mask */
844 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
845 FILE_OPEN, /* create_disposition*/
846 0, /* create_options */
847 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
848 INTERNAL_OPEN_ONLY, /* oplock_request */
849 NULL, /* lease */
850 0, /* allocation_size */
851 0, /* private_flags */
852 NULL, /* sd */
853 NULL, /* ea_list */
854 &fsp, /* result */
855 NULL, /* pinfo */
856 NULL, NULL); /* create context */
858 if (!NT_STATUS_IS_OK(status)) {
859 /* Old file not found, so by definition new file is in fact newer */
860 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
861 "errno = %d\n", smb_fname_str_dbg(smb_fname),
862 errno));
863 ret = 1;
864 goto done;
868 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
869 if (ret == -1) {
870 goto error_exit;
873 if (!ret) {
874 DEBUG(6,("file_version_is_newer: Version info not found [%s], "
875 "use mod time\n",
876 old_file));
877 use_version = false;
878 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
879 goto error_exit;
881 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
882 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
883 (long)old_create_time));
886 close_file_free(NULL, &fsp, NORMAL_CLOSE);
888 /* Get file version info (if available) for new file */
889 status = driver_unix_convert(conn, new_file, &dirfsp, &smb_fname);
890 if (!NT_STATUS_IS_OK(status)) {
891 goto error_exit;
894 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
895 if (!NT_STATUS_IS_OK(status)) {
896 DBG_NOTICE("Can't open new file [%s], errno = %d\n",
897 smb_fname_str_dbg(smb_fname), errno);
898 goto error_exit;
901 status = SMB_VFS_CREATE_FILE(
902 conn, /* conn */
903 NULL, /* req */
904 dirfsp, /* dirfsp */
905 smb_fname, /* fname */
906 FILE_GENERIC_READ, /* access_mask */
907 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
908 FILE_OPEN, /* create_disposition*/
909 0, /* create_options */
910 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
911 INTERNAL_OPEN_ONLY, /* oplock_request */
912 NULL, /* lease */
913 0, /* allocation_size */
914 0, /* private_flags */
915 NULL, /* sd */
916 NULL, /* ea_list */
917 &fsp, /* result */
918 NULL, /* pinfo */
919 NULL, NULL); /* create context */
921 if (!NT_STATUS_IS_OK(status)) {
922 /* New file not found, this shouldn't occur if the caller did its job */
923 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
924 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
925 goto error_exit;
929 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
930 if (ret == -1) {
931 goto error_exit;
934 if (!ret) {
935 DEBUG(6,("file_version_is_newer: Version info not found [%s], "
936 "use mod time\n",
937 new_file));
938 use_version = false;
939 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
940 goto error_exit;
942 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
943 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
944 (long)new_create_time));
947 close_file_free(NULL, &fsp, NORMAL_CLOSE);
949 if (use_version && (new_major != old_major || new_minor != old_minor)) {
950 /* Compare versions and choose the larger version number */
951 if (new_major > old_major ||
952 (new_major == old_major && new_minor > old_minor)) {
954 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
955 ret = 1;
956 goto done;
958 else {
959 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
960 ret = 0;
961 goto done;
964 } else {
965 /* Compare modification time/dates and choose the newest time/date */
966 if (new_create_time > old_create_time) {
967 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
968 ret = 1;
969 goto done;
971 else {
972 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
973 ret = 0;
974 goto done;
978 error_exit:
979 if(fsp)
980 close_file_free(NULL, &fsp, NORMAL_CLOSE);
981 ret = -1;
982 done:
983 TALLOC_FREE(smb_fname);
984 return ret;
987 /****************************************************************************
988 Determine the correct cVersion associated with an architecture and driver
989 ****************************************************************************/
990 static uint32_t get_correct_cversion(const struct auth_session_info *session_info,
991 const char *architecture,
992 const char *driverpath_in,
993 const char *driver_directory,
994 WERROR *perr)
996 TALLOC_CTX *frame = talloc_stackframe();
997 const struct loadparm_substitution *lp_sub =
998 loadparm_s3_global_substitution();
999 int cversion = -1;
1000 NTSTATUS nt_status;
1001 struct smb_filename *smb_fname = NULL;
1002 files_struct *fsp = NULL;
1003 struct files_struct *dirfsp = NULL;
1004 struct conn_struct_tos *c = NULL;
1005 connection_struct *conn = NULL;
1006 char *printdollar = NULL;
1007 char *printdollar_path = NULL;
1008 char *working_dir = NULL;
1009 int printdollar_snum;
1010 uint32_t major, minor;
1011 int ret;
1013 *perr = WERR_INVALID_PARAMETER;
1015 /* If architecture is Windows 95/98/ME, the version is always 0. */
1016 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
1017 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1018 *perr = WERR_OK;
1019 TALLOC_FREE(frame);
1020 return 0;
1023 /* If architecture is Windows x64, the version is always 3. */
1024 if (strcmp(architecture, SPL_ARCH_X64) == 0 ||
1025 strcmp(architecture, SPL_ARCH_ARM64) == 0) {
1026 DBG_DEBUG("get_correct_cversion: this architecture must be, cversion = 3\n");
1027 *perr = WERR_OK;
1028 TALLOC_FREE(frame);
1029 return 3;
1032 printdollar_snum = find_service(frame, "print$", &printdollar);
1033 if (!printdollar) {
1034 *perr = WERR_NOT_ENOUGH_MEMORY;
1035 TALLOC_FREE(frame);
1036 return -1;
1038 if (printdollar_snum == -1) {
1039 *perr = WERR_BAD_NET_NAME;
1040 TALLOC_FREE(frame);
1041 return -1;
1044 printdollar_path = lp_path(frame, lp_sub, printdollar_snum);
1045 if (printdollar_path == NULL) {
1046 *perr = WERR_NOT_ENOUGH_MEMORY;
1047 TALLOC_FREE(frame);
1048 return -1;
1051 working_dir = talloc_asprintf(frame,
1052 "%s/%s",
1053 printdollar_path,
1054 architecture);
1056 * If the driver has been uploaded into a temorpary driver
1057 * directory, switch to the driver directory.
1059 if (driver_directory != NULL) {
1060 working_dir = talloc_asprintf(frame, "%s/%s/%s",
1061 printdollar_path,
1062 architecture,
1063 driver_directory);
1066 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1067 printdollar_snum,
1068 working_dir,
1069 session_info,
1070 &c);
1071 if (!NT_STATUS_IS_OK(nt_status)) {
1072 DEBUG(0,("get_correct_cversion: create_conn_struct "
1073 "returned %s\n", nt_errstr(nt_status)));
1074 *perr = ntstatus_to_werror(nt_status);
1075 TALLOC_FREE(frame);
1076 return -1;
1078 conn = c->conn;
1080 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1081 if (!NT_STATUS_IS_OK(nt_status)) {
1082 DEBUG(0, ("failed set force user / group\n"));
1083 *perr = ntstatus_to_werror(nt_status);
1084 goto error_free_conn;
1087 if (!become_user_without_service_by_session(conn, session_info)) {
1088 DEBUG(0, ("failed to become user\n"));
1089 *perr = WERR_ACCESS_DENIED;
1090 goto error_free_conn;
1094 * We switch to the directory where the driver files are located,
1095 * so only work on the file names
1097 nt_status = driver_unix_convert(conn,
1098 driverpath_in,
1099 &dirfsp,
1100 &smb_fname);
1101 if (!NT_STATUS_IS_OK(nt_status)) {
1102 *perr = ntstatus_to_werror(nt_status);
1103 goto error_exit;
1106 nt_status = vfs_file_exist(conn, smb_fname);
1107 if (!NT_STATUS_IS_OK(nt_status)) {
1108 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
1109 *perr = WERR_FILE_NOT_FOUND;
1110 goto error_exit;
1113 nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
1114 if (!NT_STATUS_IS_OK(nt_status)) {
1115 DBG_NOTICE("Can't open file [%s]: %s\n",
1116 smb_fname_str_dbg(smb_fname),
1117 nt_errstr(nt_status));
1118 *perr = WERR_ACCESS_DENIED;
1119 goto error_exit;
1122 nt_status = SMB_VFS_CREATE_FILE(
1123 conn, /* conn */
1124 NULL, /* req */
1125 dirfsp, /* dirfsp */
1126 smb_fname, /* fname */
1127 FILE_GENERIC_READ, /* access_mask */
1128 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1129 FILE_OPEN, /* create_disposition*/
1130 0, /* create_options */
1131 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1132 INTERNAL_OPEN_ONLY, /* oplock_request */
1133 NULL, /* lease */
1134 0, /* private_flags */
1135 0, /* allocation_size */
1136 NULL, /* sd */
1137 NULL, /* ea_list */
1138 &fsp, /* result */
1139 NULL, /* pinfo */
1140 NULL, NULL); /* create context */
1142 if (!NT_STATUS_IS_OK(nt_status)) {
1143 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
1144 "%d\n", smb_fname_str_dbg(smb_fname), errno));
1145 *perr = WERR_ACCESS_DENIED;
1146 goto error_exit;
1149 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
1150 if (ret == -1) {
1151 *perr = WERR_INVALID_PARAMETER;
1152 goto error_exit;
1153 } else if (!ret) {
1154 DEBUG(6,("get_correct_cversion: Version info not "
1155 "found [%s]\n",
1156 smb_fname_str_dbg(smb_fname)));
1157 *perr = WERR_INVALID_PARAMETER;
1158 goto error_exit;
1162 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1163 * for more details. Version in this case is not just the version of the
1164 * file, but the version in the sense of kernel mode (2) vs. user mode
1165 * (3) drivers. Other bits of the version fields are the version info.
1166 * JRR 010716
1168 cversion = major & 0x0000ffff;
1169 switch (cversion) {
1170 case 2: /* WinNT drivers */
1171 case 3: /* Win2K drivers */
1172 break;
1174 default:
1175 DEBUG(6,("get_correct_cversion: cversion "
1176 "invalid [%s] cversion = %d\n",
1177 smb_fname_str_dbg(smb_fname),
1178 cversion));
1179 goto error_exit;
1182 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
1183 " = 0x%x minor = 0x%x\n",
1184 smb_fname_str_dbg(smb_fname), major, minor));
1186 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1187 smb_fname_str_dbg(smb_fname), cversion));
1188 *perr = WERR_OK;
1190 error_exit:
1191 unbecome_user_without_service();
1192 error_free_conn:
1193 if (fsp != NULL) {
1194 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1196 if (!W_ERROR_IS_OK(*perr)) {
1197 cversion = -1;
1200 TALLOC_FREE(frame);
1201 return cversion;
1204 /****************************************************************************
1205 ****************************************************************************/
1207 #define strip_driver_path(_mem_ctx, _element) do { \
1208 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
1209 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
1210 W_ERROR_HAVE_NO_MEMORY((_element)); \
1212 } while (0);
1214 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
1215 const struct auth_session_info *session_info,
1216 const char *architecture,
1217 const char **driver_path,
1218 const char **data_file,
1219 const char **config_file,
1220 const char **help_file,
1221 struct spoolss_StringArray *dependent_files,
1222 enum spoolss_DriverOSVersion *version,
1223 uint32_t flags,
1224 const char **driver_directory)
1226 const char *short_architecture;
1227 int i;
1228 WERROR err;
1229 char *_p;
1231 if (!*driver_path || !*data_file) {
1232 return WERR_INVALID_PARAMETER;
1235 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
1236 return WERR_INVALID_PARAMETER;
1239 if (flags & APD_COPY_FROM_DIRECTORY) {
1240 char *path;
1241 char *q;
1244 * driver_path is set to:
1246 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
1248 path = talloc_strdup(mem_ctx, *driver_path);
1249 if (path == NULL) {
1250 return WERR_NOT_ENOUGH_MEMORY;
1253 /* Remove pscript5.dll */
1254 q = strrchr_m(path, '\\');
1255 if (q == NULL) {
1256 return WERR_INVALID_PARAMETER;
1258 *q = '\0';
1260 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
1261 q = strrchr_m(path, '\\');
1262 if (q == NULL) {
1263 return WERR_INVALID_PARAMETER;
1267 * Set driver_directory to:
1269 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1271 * This is the directory where all the files have been uploaded
1273 *driver_directory = q + 1;
1276 /* clean up the driver name.
1277 * we can get .\driver.dll
1278 * or worse c:\windows\system\driver.dll !
1280 /* using an intermediate string to not have overlapping memcpy()'s */
1282 strip_driver_path(mem_ctx, *driver_path);
1283 strip_driver_path(mem_ctx, *data_file);
1284 if (*config_file) {
1285 strip_driver_path(mem_ctx, *config_file);
1287 if (help_file) {
1288 strip_driver_path(mem_ctx, *help_file);
1291 if (dependent_files && dependent_files->string) {
1292 for (i=0; dependent_files->string[i]; i++) {
1293 strip_driver_path(mem_ctx, dependent_files->string[i]);
1297 short_architecture = get_short_archi(architecture);
1298 if (!short_architecture) {
1299 return WERR_UNKNOWN_PRINTER_DRIVER;
1302 /* jfm:7/16/2000 the client always sends the cversion=0.
1303 * The server should check which version the driver is by reading
1304 * the PE header of driver->driverpath.
1306 * For Windows 95/98 the version is 0 (so the value sent is correct)
1307 * For Windows NT (the architecture doesn't matter)
1308 * NT 3.1: cversion=0
1309 * NT 3.5/3.51: cversion=1
1310 * NT 4: cversion=2
1311 * NT2K: cversion=3
1314 *version = get_correct_cversion(session_info,
1315 short_architecture,
1316 *driver_path,
1317 *driver_directory,
1318 &err);
1319 if (*version == -1) {
1320 return err;
1323 return WERR_OK;
1326 /****************************************************************************
1327 ****************************************************************************/
1329 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1330 const struct auth_session_info *session_info,
1331 const struct spoolss_AddDriverInfoCtr *r,
1332 uint32_t flags,
1333 const char **driver_directory)
1335 switch (r->level) {
1336 case 3:
1337 return clean_up_driver_struct_level(mem_ctx, session_info,
1338 r->info.info3->architecture,
1339 &r->info.info3->driver_path,
1340 &r->info.info3->data_file,
1341 &r->info.info3->config_file,
1342 &r->info.info3->help_file,
1343 r->info.info3->dependent_files,
1344 &r->info.info3->version,
1345 flags,
1346 driver_directory);
1347 case 6:
1348 return clean_up_driver_struct_level(mem_ctx, session_info,
1349 r->info.info6->architecture,
1350 &r->info.info6->driver_path,
1351 &r->info.info6->data_file,
1352 &r->info.info6->config_file,
1353 &r->info.info6->help_file,
1354 r->info.info6->dependent_files,
1355 &r->info.info6->version,
1356 flags,
1357 driver_directory);
1358 case 8:
1359 return clean_up_driver_struct_level(mem_ctx, session_info,
1360 r->info.info8->architecture,
1361 &r->info.info8->driver_path,
1362 &r->info.info8->data_file,
1363 &r->info.info8->config_file,
1364 &r->info.info8->help_file,
1365 r->info.info8->dependent_files,
1366 &r->info.info8->version,
1367 flags,
1368 driver_directory);
1369 default:
1370 return WERR_NOT_SUPPORTED;
1374 /****************************************************************************
1375 This function sucks and should be replaced. JRA.
1376 ****************************************************************************/
1378 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1379 const struct spoolss_AddDriverInfo6 *src)
1381 dst->version = src->version;
1383 dst->driver_name = src->driver_name;
1384 dst->architecture = src->architecture;
1385 dst->driver_path = src->driver_path;
1386 dst->data_file = src->data_file;
1387 dst->config_file = src->config_file;
1388 dst->help_file = src->help_file;
1389 dst->monitor_name = src->monitor_name;
1390 dst->default_datatype = src->default_datatype;
1391 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1392 dst->dependent_files = src->dependent_files;
1395 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1396 const struct spoolss_AddDriverInfo8 *src)
1398 dst->version = src->version;
1400 dst->driver_name = src->driver_name;
1401 dst->architecture = src->architecture;
1402 dst->driver_path = src->driver_path;
1403 dst->data_file = src->data_file;
1404 dst->config_file = src->config_file;
1405 dst->help_file = src->help_file;
1406 dst->monitor_name = src->monitor_name;
1407 dst->default_datatype = src->default_datatype;
1408 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1409 dst->dependent_files = src->dependent_files;
1412 /****************************************************************************
1413 ****************************************************************************/
1415 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1416 connection_struct *conn,
1417 const char *driver_file,
1418 const char *short_architecture,
1419 uint32_t driver_version,
1420 uint32_t version,
1421 const char *driver_directory)
1423 struct smb_filename *smb_fname_old = NULL;
1424 struct smb_filename *smb_fname_new = NULL;
1425 char *old_name = NULL;
1426 char *new_name = NULL;
1427 NTSTATUS status;
1428 WERROR ret;
1430 if (driver_directory != NULL) {
1431 old_name = talloc_asprintf(mem_ctx,
1432 "%s/%s/%s",
1433 short_architecture,
1434 driver_directory,
1435 driver_file);
1436 } else {
1437 old_name = talloc_asprintf(mem_ctx,
1438 "%s/%s",
1439 short_architecture,
1440 driver_file);
1442 if (old_name == NULL) {
1443 return WERR_NOT_ENOUGH_MEMORY;
1446 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1447 short_architecture, driver_version, driver_file);
1448 if (new_name == NULL) {
1449 TALLOC_FREE(old_name);
1450 return WERR_NOT_ENOUGH_MEMORY;
1453 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1454 struct files_struct *dirfsp = NULL;
1456 status = driver_unix_convert(conn,
1457 old_name,
1458 &dirfsp,
1459 &smb_fname_old);
1460 if (!NT_STATUS_IS_OK(status)) {
1461 ret = WERR_NOT_ENOUGH_MEMORY;
1462 goto out;
1465 /* Setup a synthetic smb_filename struct */
1466 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1467 if (!smb_fname_new) {
1468 ret = WERR_NOT_ENOUGH_MEMORY;
1469 goto out;
1472 smb_fname_new->base_name = new_name;
1474 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1475 "'%s'\n", smb_fname_old->base_name,
1476 smb_fname_new->base_name));
1478 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1479 FILE_OVERWRITE_IF);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 DEBUG(0,("move_driver_file_to_download_area: Unable "
1483 "to rename [%s] to [%s]: %s\n",
1484 smb_fname_old->base_name, new_name,
1485 nt_errstr(status)));
1486 ret = WERR_APP_INIT_FAILURE;
1487 goto out;
1491 ret = WERR_OK;
1492 out:
1493 TALLOC_FREE(smb_fname_old);
1494 TALLOC_FREE(smb_fname_new);
1495 return ret;
1498 WERROR move_driver_to_download_area(const struct auth_session_info *session_info,
1499 const struct spoolss_AddDriverInfoCtr *r,
1500 const char *driver_directory)
1502 TALLOC_CTX *frame = talloc_stackframe();
1503 const struct loadparm_substitution *lp_sub =
1504 loadparm_s3_global_substitution();
1505 struct spoolss_AddDriverInfo3 *driver;
1506 struct spoolss_AddDriverInfo3 converted_driver;
1507 const char *short_architecture;
1508 struct files_struct *dirfsp = NULL;
1509 struct smb_filename *smb_dname = NULL;
1510 char *new_dir = NULL;
1511 struct conn_struct_tos *c = NULL;
1512 connection_struct *conn = NULL;
1513 NTSTATUS nt_status;
1514 int i;
1515 int ver = 0;
1516 char *printdollar = NULL;
1517 int printdollar_snum;
1518 WERROR err = WERR_OK;
1520 switch (r->level) {
1521 case 3:
1522 driver = r->info.info3;
1523 break;
1524 case 6:
1525 convert_level_6_to_level3(&converted_driver, r->info.info6);
1526 driver = &converted_driver;
1527 break;
1528 case 8:
1529 convert_level_8_to_level3(&converted_driver, r->info.info8);
1530 driver = &converted_driver;
1531 break;
1532 default:
1533 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1534 TALLOC_FREE(frame);
1535 return WERR_INVALID_LEVEL;
1538 short_architecture = get_short_archi(driver->architecture);
1539 if (!short_architecture) {
1540 TALLOC_FREE(frame);
1541 return WERR_UNKNOWN_PRINTER_DRIVER;
1544 printdollar_snum = find_service(frame, "print$", &printdollar);
1545 if (!printdollar) {
1546 TALLOC_FREE(frame);
1547 return WERR_NOT_ENOUGH_MEMORY;
1549 if (printdollar_snum == -1) {
1550 TALLOC_FREE(frame);
1551 return WERR_BAD_NET_NAME;
1554 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1555 printdollar_snum,
1556 lp_path(frame, lp_sub, printdollar_snum),
1557 session_info,
1558 &c);
1559 if (!NT_STATUS_IS_OK(nt_status)) {
1560 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1561 "returned %s\n", nt_errstr(nt_status)));
1562 err = ntstatus_to_werror(nt_status);
1563 TALLOC_FREE(frame);
1564 return err;
1566 conn = c->conn;
1568 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1569 if (!NT_STATUS_IS_OK(nt_status)) {
1570 DEBUG(0, ("failed set force user / group\n"));
1571 err = ntstatus_to_werror(nt_status);
1572 goto err_free_conn;
1575 if (!become_user_without_service_by_session(conn, session_info)) {
1576 DEBUG(0, ("failed to become user\n"));
1577 err = WERR_ACCESS_DENIED;
1578 goto err_free_conn;
1581 new_dir = talloc_asprintf(frame,
1582 "%s/%d",
1583 short_architecture,
1584 driver->version);
1585 if (!new_dir) {
1586 err = WERR_NOT_ENOUGH_MEMORY;
1587 goto err_exit;
1589 nt_status = driver_unix_convert(conn, new_dir, &dirfsp, &smb_dname);
1590 if (!NT_STATUS_IS_OK(nt_status)) {
1591 err = WERR_NOT_ENOUGH_MEMORY;
1592 goto err_exit;
1595 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1597 nt_status = create_directory(conn, NULL, dirfsp, smb_dname);
1598 if (!NT_STATUS_IS_OK(nt_status)
1599 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1600 DEBUG(0, ("failed to create driver destination directory: %s\n",
1601 nt_errstr(nt_status)));
1602 err = ntstatus_to_werror(nt_status);
1603 goto err_exit;
1606 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1607 * listed for this driver which has already been moved, skip it (note:
1608 * drivers may list the same file name several times. Then check if the
1609 * file already exists in archi\version\, if so, check that the version
1610 * info (or time stamps if version info is unavailable) is newer (or the
1611 * date is later). If it is, move it to archi\version\filexxx.yyy.
1612 * Otherwise, delete the file.
1614 * If a file is not moved to archi\version\ because of an error, all the
1615 * rest of the 'unmoved' driver files are removed from archi\. If one or
1616 * more of the driver's files was already moved to archi\version\, it
1617 * potentially leaves the driver in a partially updated state. Version
1618 * trauma will most likely occur if an client attempts to use any printer
1619 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1620 * done is appropriate... later JRR
1623 DEBUG(5,("Moving files now !\n"));
1625 if (driver->driver_path && strlen(driver->driver_path)) {
1627 err = move_driver_file_to_download_area(frame,
1628 conn,
1629 driver->driver_path,
1630 short_architecture,
1631 driver->version,
1632 ver,
1633 driver_directory);
1634 if (!W_ERROR_IS_OK(err)) {
1635 goto err_exit;
1639 if (driver->data_file && strlen(driver->data_file)) {
1640 if (!strequal(driver->data_file, driver->driver_path)) {
1642 err = move_driver_file_to_download_area(frame,
1643 conn,
1644 driver->data_file,
1645 short_architecture,
1646 driver->version,
1647 ver,
1648 driver_directory);
1649 if (!W_ERROR_IS_OK(err)) {
1650 goto err_exit;
1655 if (driver->config_file && strlen(driver->config_file)) {
1656 if (!strequal(driver->config_file, driver->driver_path) &&
1657 !strequal(driver->config_file, driver->data_file)) {
1659 err = move_driver_file_to_download_area(frame,
1660 conn,
1661 driver->config_file,
1662 short_architecture,
1663 driver->version,
1664 ver,
1665 driver_directory);
1666 if (!W_ERROR_IS_OK(err)) {
1667 goto err_exit;
1672 if (driver->help_file && strlen(driver->help_file)) {
1673 if (!strequal(driver->help_file, driver->driver_path) &&
1674 !strequal(driver->help_file, driver->data_file) &&
1675 !strequal(driver->help_file, driver->config_file)) {
1677 err = move_driver_file_to_download_area(frame,
1678 conn,
1679 driver->help_file,
1680 short_architecture,
1681 driver->version,
1682 ver,
1683 driver_directory);
1684 if (!W_ERROR_IS_OK(err)) {
1685 goto err_exit;
1690 if (driver->dependent_files && driver->dependent_files->string) {
1691 for (i=0; driver->dependent_files->string[i]; i++) {
1692 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1693 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1694 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1695 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1696 int j;
1697 for (j=0; j < i; j++) {
1698 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1699 goto NextDriver;
1703 err = move_driver_file_to_download_area(frame,
1704 conn,
1705 driver->dependent_files->string[i],
1706 short_architecture,
1707 driver->version,
1708 ver,
1709 driver_directory);
1710 if (!W_ERROR_IS_OK(err)) {
1711 goto err_exit;
1714 NextDriver: ;
1718 err = WERR_OK;
1719 err_exit:
1720 unbecome_user_without_service();
1721 err_free_conn:
1722 TALLOC_FREE(frame);
1723 return err;
1726 /****************************************************************************
1727 Determine whether or not a particular driver is currently assigned
1728 to a printer
1729 ****************************************************************************/
1731 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1732 struct dcerpc_binding_handle *b,
1733 const struct spoolss_DriverInfo8 *r)
1735 const struct loadparm_substitution *lp_sub =
1736 loadparm_s3_global_substitution();
1737 int snum;
1738 int n_services = lp_numservices();
1739 bool in_use = false;
1740 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1741 WERROR result;
1743 if (!r) {
1744 return false;
1747 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1749 /* loop through the printers.tdb and check for the drivername */
1751 for (snum=0; snum<n_services && !in_use; snum++) {
1752 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1753 continue;
1756 result = winreg_get_printer(mem_ctx, b,
1757 lp_servicename(talloc_tos(), lp_sub, snum),
1758 &pinfo2);
1759 if (!W_ERROR_IS_OK(result)) {
1760 continue; /* skip */
1763 if (strequal(r->driver_name, pinfo2->drivername)) {
1764 in_use = true;
1767 TALLOC_FREE(pinfo2);
1770 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1772 if ( in_use ) {
1773 struct spoolss_DriverInfo8 *driver = NULL;
1774 WERROR werr;
1776 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1778 /* we can still remove the driver if there is one of
1779 "Windows NT x86" version 2 or 3 left */
1781 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1782 if (r->version == 2) {
1783 werr = winreg_get_driver(mem_ctx, b,
1784 r->architecture,
1785 r->driver_name,
1786 3, &driver);
1787 } else if (r->version == 3) {
1788 werr = winreg_get_driver(mem_ctx, b,
1789 r->architecture,
1790 r->driver_name,
1791 2, &driver);
1792 } else {
1793 DBG_ERR("Unknown driver version (%d)\n",
1794 r->version);
1795 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1797 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1798 werr = winreg_get_driver(mem_ctx, b,
1799 SPOOLSS_ARCHITECTURE_NT_X86,
1800 r->driver_name,
1801 DRIVER_ANY_VERSION,
1802 &driver);
1803 } else {
1804 DBG_ERR("Unknown driver architecture: %s\n",
1805 r->architecture);
1806 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1809 /* now check the error code */
1811 if ( W_ERROR_IS_OK(werr) ) {
1812 /* it's ok to remove the driver, we have other architectures left */
1813 in_use = false;
1814 talloc_free(driver);
1818 /* report that the driver is not in use by default */
1820 return in_use;
1824 /**********************************************************************
1825 Check to see if a ogiven file is in use by *info
1826 *********************************************************************/
1828 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1830 int i = 0;
1832 if ( !info )
1833 return False;
1835 /* mz: skip files that are in the list but already deleted */
1836 if (!file || !file[0]) {
1837 return false;
1840 if (strequal(file, info->driver_path))
1841 return True;
1843 if (strequal(file, info->data_file))
1844 return True;
1846 if (strequal(file, info->config_file))
1847 return True;
1849 if (strequal(file, info->help_file))
1850 return True;
1852 /* see of there are any dependent files to examine */
1854 if (!info->dependent_files)
1855 return False;
1857 while (info->dependent_files[i] && *info->dependent_files[i]) {
1858 if (strequal(file, info->dependent_files[i]))
1859 return True;
1860 i++;
1863 return False;
1867 /**********************************************************************
1868 Utility function to remove the dependent file pointed to by the
1869 input parameter from the list
1870 *********************************************************************/
1872 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1875 /* bump everything down a slot */
1877 while (files && files[idx+1]) {
1878 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1879 idx++;
1882 files[idx] = NULL;
1884 return;
1887 /**********************************************************************
1888 Check if any of the files used by src are also used by drv
1889 *********************************************************************/
1891 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1892 struct spoolss_DriverInfo8 *src,
1893 const struct spoolss_DriverInfo8 *drv)
1895 bool in_use = False;
1896 int i = 0;
1898 if ( !src || !drv )
1899 return False;
1901 /* check each file. Remove it from the src structure if it overlaps */
1903 if (drv_file_in_use(src->driver_path, drv)) {
1904 in_use = True;
1905 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1906 src->driver_path = talloc_strdup(mem_ctx, "");
1907 if (!src->driver_path) { return false; }
1910 if (drv_file_in_use(src->data_file, drv)) {
1911 in_use = True;
1912 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1913 src->data_file = talloc_strdup(mem_ctx, "");
1914 if (!src->data_file) { return false; }
1917 if (drv_file_in_use(src->config_file, drv)) {
1918 in_use = True;
1919 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1920 src->config_file = talloc_strdup(mem_ctx, "");
1921 if (!src->config_file) { return false; }
1924 if (drv_file_in_use(src->help_file, drv)) {
1925 in_use = True;
1926 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1927 src->help_file = talloc_strdup(mem_ctx, "");
1928 if (!src->help_file) { return false; }
1931 /* are there any dependentfiles to examine? */
1933 if (!src->dependent_files)
1934 return in_use;
1936 while (src->dependent_files[i] && *src->dependent_files[i]) {
1937 if (drv_file_in_use(src->dependent_files[i], drv)) {
1938 in_use = True;
1939 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1940 trim_dependent_file(mem_ctx, src->dependent_files, i);
1941 } else
1942 i++;
1945 return in_use;
1948 /****************************************************************************
1949 Determine whether or not a particular driver files are currently being
1950 used by any other driver.
1952 Return value is True if any files were in use by other drivers
1953 and False otherwise.
1955 Upon return, *info has been modified to only contain the driver files
1956 which are not in use
1958 Fix from mz:
1960 This needs to check all drivers to ensure that all files in use
1961 have been removed from *info, not just the ones in the first
1962 match.
1963 ****************************************************************************/
1965 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1966 struct dcerpc_binding_handle *b,
1967 struct spoolss_DriverInfo8 *info)
1969 uint32_t version;
1970 struct spoolss_DriverInfo8 *driver;
1971 bool in_use = false;
1972 uint32_t i, num_drivers;
1973 const char **drivers;
1974 WERROR result;
1976 if ( !info )
1977 return False;
1979 version = info->version;
1981 /* loop over all driver versions */
1983 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1985 /* get the list of drivers */
1987 result = winreg_get_driver_list(mem_ctx, b,
1988 info->architecture, version,
1989 &num_drivers, &drivers);
1990 if (!W_ERROR_IS_OK(result)) {
1991 return true;
1994 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1995 num_drivers, info->architecture, version));
1997 /* check each driver for overlap in files */
1999 for (i = 0; i < num_drivers; i++) {
2000 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
2002 driver = NULL;
2004 result = winreg_get_driver(mem_ctx, b,
2005 info->architecture, drivers[i],
2006 version, &driver);
2007 if (!W_ERROR_IS_OK(result)) {
2008 talloc_free(drivers);
2009 return True;
2012 /* check if d2 uses any files from d1 */
2013 /* only if this is a different driver than the one being deleted */
2015 if (!strequal(info->driver_name, driver->driver_name)) {
2016 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
2017 /* mz: Do not instantly return -
2018 * we need to ensure this file isn't
2019 * also in use by other drivers. */
2020 in_use = true;
2024 talloc_free(driver);
2027 talloc_free(drivers);
2029 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2031 return in_use;
2034 static NTSTATUS driver_unlink_internals(connection_struct *conn,
2035 const char *short_arch,
2036 int vers,
2037 const char *fname)
2039 TALLOC_CTX *tmp_ctx = talloc_new(conn);
2040 struct smb_filename *smb_fname = NULL;
2041 char *print_dlr_path;
2042 NTSTATUS status = NT_STATUS_NO_MEMORY;
2044 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
2045 short_arch, vers, fname);
2046 if (print_dlr_path == NULL) {
2047 goto err_out;
2050 status = synthetic_pathref(tmp_ctx,
2051 conn->cwd_fsp,
2052 print_dlr_path,
2053 NULL,
2054 NULL,
2057 &smb_fname);
2058 if (!NT_STATUS_IS_OK(status)) {
2059 goto err_out;
2062 status = unlink_internals(conn, NULL, 0, NULL, smb_fname);
2063 err_out:
2064 talloc_free(tmp_ctx);
2065 return status;
2068 /****************************************************************************
2069 Actually delete the driver files. Make sure that
2070 printer_driver_files_in_use() return False before calling
2071 this.
2072 ****************************************************************************/
2074 bool delete_driver_files(const struct auth_session_info *session_info,
2075 const struct spoolss_DriverInfo8 *r)
2077 TALLOC_CTX *frame = talloc_stackframe();
2078 const struct loadparm_substitution *lp_sub =
2079 loadparm_s3_global_substitution();
2080 const char *short_arch;
2081 struct conn_struct_tos *c = NULL;
2082 connection_struct *conn = NULL;
2083 NTSTATUS nt_status;
2084 char *printdollar = NULL;
2085 int printdollar_snum;
2086 bool ret = false;
2088 if (!r) {
2089 TALLOC_FREE(frame);
2090 return false;
2093 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2094 r->driver_name, r->version));
2096 printdollar_snum = find_service(frame, "print$", &printdollar);
2097 if (!printdollar) {
2098 TALLOC_FREE(frame);
2099 return false;
2101 if (printdollar_snum == -1) {
2102 TALLOC_FREE(frame);
2103 return false;
2106 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
2107 printdollar_snum,
2108 lp_path(frame, lp_sub, printdollar_snum),
2109 session_info,
2110 &c);
2111 if (!NT_STATUS_IS_OK(nt_status)) {
2112 DEBUG(0,("delete_driver_files: create_conn_struct "
2113 "returned %s\n", nt_errstr(nt_status)));
2114 TALLOC_FREE(frame);
2115 return false;
2117 conn = c->conn;
2119 nt_status = set_conn_force_user_group(conn, printdollar_snum);
2120 if (!NT_STATUS_IS_OK(nt_status)) {
2121 DEBUG(0, ("failed set force user / group\n"));
2122 ret = false;
2123 goto err_free_conn;
2126 if (!become_user_without_service_by_session(conn, session_info)) {
2127 DEBUG(0, ("failed to become user\n"));
2128 ret = false;
2129 goto err_free_conn;
2132 if ( !CAN_WRITE(conn) ) {
2133 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2134 ret = false;
2135 goto err_out;
2138 short_arch = get_short_archi(r->architecture);
2139 if (short_arch == NULL) {
2140 DEBUG(0, ("bad architecture %s\n", r->architecture));
2141 ret = false;
2142 goto err_out;
2145 /* now delete the files */
2147 if (r->driver_path && r->driver_path[0]) {
2148 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
2149 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
2152 if (r->config_file && r->config_file[0]) {
2153 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
2154 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
2157 if (r->data_file && r->data_file[0]) {
2158 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
2159 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
2162 if (r->help_file && r->help_file[0]) {
2163 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
2164 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
2167 if (r->dependent_files) {
2168 int i = 0;
2169 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2170 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
2171 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
2172 i++;
2176 ret = true;
2177 err_out:
2178 unbecome_user_without_service();
2179 err_free_conn:
2180 TALLOC_FREE(frame);
2181 return ret;
2184 /* error code:
2185 0: everything OK
2186 1: level not implemented
2187 2: file doesn't exist
2188 3: can't allocate memory
2189 4: can't free memory
2190 5: non existent struct
2194 A printer and a printer driver are 2 different things.
2195 NT manages them separately, Samba does the same.
2196 Why ? Simply because it's easier and it makes sense !
2198 Now explanation: You have 3 printers behind your samba server,
2199 2 of them are the same make and model (laser A and B). But laser B
2200 has an 3000 sheet feeder and laser A doesn't such an option.
2201 Your third printer is an old dot-matrix model for the accounting :-).
2203 If the /usr/local/samba/lib directory (default dir), you will have
2204 5 files to describe all of this.
2206 3 files for the printers (1 by printer):
2207 NTprinter_laser A
2208 NTprinter_laser B
2209 NTprinter_accounting
2210 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2211 NTdriver_printer model X
2212 NTdriver_printer model Y
2214 jfm: I should use this comment for the text file to explain
2215 same thing for the forms BTW.
2216 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2220 /* Convert generic access rights to printer object specific access rights.
2221 It turns out that NT4 security descriptors use generic access rights and
2222 NT5 the object specific ones. */
2224 void map_printer_permissions(struct security_descriptor *sd)
2226 uint32_t i;
2228 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2229 se_map_generic(&sd->dacl->aces[i].access_mask,
2230 &printer_generic_mapping);
2234 void map_job_permissions(struct security_descriptor *sd)
2236 uint32_t i;
2238 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2239 se_map_generic(&sd->dacl->aces[i].access_mask,
2240 &job_generic_mapping);
2245 /****************************************************************************
2246 Check a user has permissions to perform the given operation. We use the
2247 permission constants defined in include/rpc_spoolss.h to check the various
2248 actions we perform when checking printer access.
2250 PRINTER_ACCESS_ADMINISTER:
2251 print_queue_pause, print_queue_resume, update_printer_sec,
2252 update_printer, spoolss_addprinterex_level_2,
2253 _spoolss_setprinterdata
2255 PRINTER_ACCESS_USE:
2256 print_job_start
2258 JOB_ACCESS_ADMINISTER:
2259 print_job_delete, print_job_pause, print_job_resume,
2260 print_queue_purge
2262 Try access control in the following order (for performance reasons):
2263 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2264 2) check security descriptor (bit comparisons in memory)
2265 3) "printer admins" (may result in numerous calls to winbind)
2267 ****************************************************************************/
2268 WERROR print_access_check(const struct auth_session_info *session_info,
2269 struct messaging_context *msg_ctx, int snum,
2270 int access_type)
2272 struct spoolss_security_descriptor *secdesc = NULL;
2273 const struct loadparm_substitution *lp_sub =
2274 loadparm_s3_global_substitution();
2275 uint32_t access_granted;
2276 size_t sd_size;
2277 NTSTATUS status;
2278 WERROR result;
2279 const char *pname;
2280 TALLOC_CTX *mem_ctx = NULL;
2282 /* If user is NULL then use the current_user structure */
2284 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2286 if ((session_info->unix_token->uid == sec_initial_uid())
2287 || security_token_has_privilege(session_info->security_token,
2288 SEC_PRIV_PRINT_OPERATOR)) {
2289 return WERR_OK;
2292 /* Get printer name */
2294 pname = lp_printername(talloc_tos(), lp_sub, snum);
2296 if (!pname || !*pname) {
2297 return WERR_ACCESS_DENIED;
2300 /* Get printer security descriptor */
2302 if(!(mem_ctx = talloc_init("print_access_check"))) {
2303 return WERR_NOT_ENOUGH_MEMORY;
2306 result = winreg_get_printer_secdesc_internal(mem_ctx,
2307 get_session_info_system(),
2308 msg_ctx,
2309 pname,
2310 &secdesc);
2311 if (!W_ERROR_IS_OK(result)) {
2312 talloc_destroy(mem_ctx);
2313 return WERR_NOT_ENOUGH_MEMORY;
2316 if (access_type == JOB_ACCESS_ADMINISTER) {
2317 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2319 /* Create a child security descriptor to check permissions
2320 against. This is because print jobs are child objects
2321 objects of a printer. */
2322 status = se_create_child_secdesc(mem_ctx,
2323 &secdesc,
2324 &sd_size,
2325 parent_secdesc,
2326 parent_secdesc->owner_sid,
2327 parent_secdesc->group_sid,
2328 false);
2329 if (!NT_STATUS_IS_OK(status)) {
2330 talloc_destroy(mem_ctx);
2331 return ntstatus_to_werror(status);
2334 map_job_permissions(secdesc);
2335 } else {
2336 map_printer_permissions(secdesc);
2339 /* Check access */
2340 status = se_access_check(secdesc, session_info->security_token, access_type,
2341 &access_granted);
2343 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2345 talloc_destroy(mem_ctx);
2347 return ntstatus_to_werror(status);
2350 /****************************************************************************
2351 Check the time parameters allow a print operation.
2352 *****************************************************************************/
2354 bool print_time_access_check(const struct auth_session_info *session_info,
2355 struct messaging_context *msg_ctx,
2356 const char *servicename)
2358 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2359 WERROR result;
2360 bool ok = False;
2361 time_t now = time(NULL);
2362 struct tm *t;
2363 uint32_t mins;
2365 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2366 servicename, &pinfo2);
2367 if (!W_ERROR_IS_OK(result)) {
2368 return False;
2371 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2372 ok = True;
2375 t = gmtime(&now);
2376 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2378 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2379 ok = True;
2382 TALLOC_FREE(pinfo2);
2384 if (!ok) {
2385 errno = EACCES;
2388 return ok;
2391 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2392 const struct auth_session_info *session_info,
2393 struct messaging_context *msg_ctx,
2394 const char *printer)
2396 WERROR result;
2398 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2399 printer, "");
2400 if (!W_ERROR_IS_OK(result)) {
2401 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2402 "%s\n", printer, win_errstr(result)));
2406 void nt_printer_add(TALLOC_CTX *mem_ctx,
2407 const struct auth_session_info *session_info,
2408 struct messaging_context *msg_ctx,
2409 const char *printer)
2411 WERROR result;
2413 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2414 printer);
2415 if (!W_ERROR_IS_OK(result)) {
2416 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2417 printer, win_errstr(result)));