s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / source3 / printing / nt_printing.c
blob14a1e496c04a8aded23cd637d8e91bb55b1e3fbc
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 = SMB_VFS_CREATE_FILE(
833 conn, /* conn */
834 NULL, /* req */
835 dirfsp, /* dirfsp */
836 smb_fname, /* fname */
837 FILE_GENERIC_READ, /* access_mask */
838 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
839 FILE_OPEN, /* create_disposition*/
840 0, /* create_options */
841 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
842 INTERNAL_OPEN_ONLY, /* oplock_request */
843 NULL, /* lease */
844 0, /* allocation_size */
845 0, /* private_flags */
846 NULL, /* sd */
847 NULL, /* ea_list */
848 &fsp, /* result */
849 NULL, /* pinfo */
850 NULL, NULL); /* create context */
852 if (!NT_STATUS_IS_OK(status)) {
853 /* Old file not found, so by definition new file is in fact newer */
854 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
855 "errno = %d\n", smb_fname_str_dbg(smb_fname),
856 errno));
857 ret = 1;
858 goto done;
862 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
863 if (ret == -1) {
864 goto error_exit;
867 if (!ret) {
868 DEBUG(6,("file_version_is_newer: Version info not found [%s], "
869 "use mod time\n",
870 old_file));
871 use_version = false;
872 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
873 goto error_exit;
875 old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
876 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
877 (long)old_create_time));
880 close_file_free(NULL, &fsp, NORMAL_CLOSE);
882 /* Get file version info (if available) for new file */
883 status = driver_unix_convert(conn, new_file, &dirfsp, &smb_fname);
884 if (!NT_STATUS_IS_OK(status)) {
885 goto error_exit;
888 status = SMB_VFS_CREATE_FILE(
889 conn, /* conn */
890 NULL, /* req */
891 dirfsp, /* dirfsp */
892 smb_fname, /* fname */
893 FILE_GENERIC_READ, /* access_mask */
894 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
895 FILE_OPEN, /* create_disposition*/
896 0, /* create_options */
897 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
898 INTERNAL_OPEN_ONLY, /* oplock_request */
899 NULL, /* lease */
900 0, /* allocation_size */
901 0, /* private_flags */
902 NULL, /* sd */
903 NULL, /* ea_list */
904 &fsp, /* result */
905 NULL, /* pinfo */
906 NULL, NULL); /* create context */
908 if (!NT_STATUS_IS_OK(status)) {
909 /* New file not found, this shouldn't occur if the caller did its job */
910 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
911 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
912 goto error_exit;
916 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
917 if (ret == -1) {
918 goto error_exit;
921 if (!ret) {
922 DEBUG(6,("file_version_is_newer: Version info not found [%s], "
923 "use mod time\n",
924 new_file));
925 use_version = false;
926 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
927 goto error_exit;
929 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
930 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
931 (long)new_create_time));
934 close_file_free(NULL, &fsp, NORMAL_CLOSE);
936 if (use_version && (new_major != old_major || new_minor != old_minor)) {
937 /* Compare versions and choose the larger version number */
938 if (new_major > old_major ||
939 (new_major == old_major && new_minor > old_minor)) {
941 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
942 ret = 1;
943 goto done;
945 else {
946 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
947 ret = 0;
948 goto done;
951 } else {
952 /* Compare modification time/dates and choose the newest time/date */
953 if (new_create_time > old_create_time) {
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;
965 error_exit:
966 if(fsp)
967 close_file_free(NULL, &fsp, NORMAL_CLOSE);
968 ret = -1;
969 done:
970 TALLOC_FREE(smb_fname);
971 return ret;
974 /****************************************************************************
975 Determine the correct cVersion associated with an architecture and driver
976 ****************************************************************************/
977 static uint32_t get_correct_cversion(const struct auth_session_info *session_info,
978 const char *architecture,
979 const char *driverpath_in,
980 const char *driver_directory,
981 WERROR *perr)
983 TALLOC_CTX *frame = talloc_stackframe();
984 const struct loadparm_substitution *lp_sub =
985 loadparm_s3_global_substitution();
986 int cversion = -1;
987 NTSTATUS nt_status;
988 struct smb_filename *smb_fname = NULL;
989 files_struct *fsp = NULL;
990 struct files_struct *dirfsp = NULL;
991 struct conn_struct_tos *c = NULL;
992 connection_struct *conn = NULL;
993 char *printdollar = NULL;
994 char *printdollar_path = NULL;
995 char *working_dir = NULL;
996 int printdollar_snum;
997 uint32_t major, minor;
998 int ret;
1000 *perr = WERR_INVALID_PARAMETER;
1002 /* If architecture is Windows 95/98/ME, the version is always 0. */
1003 if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
1004 DEBUG(10,("get_correct_cversion: Driver is Win9x, cversion = 0\n"));
1005 *perr = WERR_OK;
1006 TALLOC_FREE(frame);
1007 return 0;
1010 /* If architecture is Windows x64, the version is always 3. */
1011 if (strcmp(architecture, SPL_ARCH_X64) == 0 ||
1012 strcmp(architecture, SPL_ARCH_ARM64) == 0) {
1013 DBG_DEBUG("get_correct_cversion: this architecture must be, cversion = 3\n");
1014 *perr = WERR_OK;
1015 TALLOC_FREE(frame);
1016 return 3;
1019 printdollar_snum = find_service(frame, "print$", &printdollar);
1020 if (!printdollar) {
1021 *perr = WERR_NOT_ENOUGH_MEMORY;
1022 TALLOC_FREE(frame);
1023 return -1;
1025 if (printdollar_snum == -1) {
1026 *perr = WERR_BAD_NET_NAME;
1027 TALLOC_FREE(frame);
1028 return -1;
1031 printdollar_path = lp_path(frame, lp_sub, printdollar_snum);
1032 if (printdollar_path == NULL) {
1033 *perr = WERR_NOT_ENOUGH_MEMORY;
1034 TALLOC_FREE(frame);
1035 return -1;
1038 working_dir = talloc_asprintf(frame,
1039 "%s/%s",
1040 printdollar_path,
1041 architecture);
1043 * If the driver has been uploaded into a temorpary driver
1044 * directory, switch to the driver directory.
1046 if (driver_directory != NULL) {
1047 working_dir = talloc_asprintf(frame, "%s/%s/%s",
1048 printdollar_path,
1049 architecture,
1050 driver_directory);
1053 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1054 printdollar_snum,
1055 working_dir,
1056 session_info,
1057 &c);
1058 if (!NT_STATUS_IS_OK(nt_status)) {
1059 DEBUG(0,("get_correct_cversion: create_conn_struct "
1060 "returned %s\n", nt_errstr(nt_status)));
1061 *perr = ntstatus_to_werror(nt_status);
1062 TALLOC_FREE(frame);
1063 return -1;
1065 conn = c->conn;
1067 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1068 if (!NT_STATUS_IS_OK(nt_status)) {
1069 DEBUG(0, ("failed set force user / group\n"));
1070 *perr = ntstatus_to_werror(nt_status);
1071 goto error_free_conn;
1074 if (!become_user_without_service_by_session(conn, session_info)) {
1075 DEBUG(0, ("failed to become user\n"));
1076 *perr = WERR_ACCESS_DENIED;
1077 goto error_free_conn;
1081 * We switch to the directory where the driver files are located,
1082 * so only work on the file names
1084 nt_status = driver_unix_convert(conn,
1085 driverpath_in,
1086 &dirfsp,
1087 &smb_fname);
1088 if (!NT_STATUS_IS_OK(nt_status)) {
1089 *perr = ntstatus_to_werror(nt_status);
1090 goto error_exit;
1093 nt_status = vfs_file_exist(conn, smb_fname);
1094 if (!NT_STATUS_IS_OK(nt_status)) {
1095 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
1096 *perr = WERR_FILE_NOT_FOUND;
1097 goto error_exit;
1100 nt_status = SMB_VFS_CREATE_FILE(
1101 conn, /* conn */
1102 NULL, /* req */
1103 dirfsp, /* dirfsp */
1104 smb_fname, /* fname */
1105 FILE_GENERIC_READ, /* access_mask */
1106 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1107 FILE_OPEN, /* create_disposition*/
1108 0, /* create_options */
1109 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1110 INTERNAL_OPEN_ONLY, /* oplock_request */
1111 NULL, /* lease */
1112 0, /* private_flags */
1113 0, /* allocation_size */
1114 NULL, /* sd */
1115 NULL, /* ea_list */
1116 &fsp, /* result */
1117 NULL, /* pinfo */
1118 NULL, NULL); /* create context */
1120 if (!NT_STATUS_IS_OK(nt_status)) {
1121 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
1122 "%d\n", smb_fname_str_dbg(smb_fname), errno));
1123 *perr = WERR_ACCESS_DENIED;
1124 goto error_exit;
1127 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
1128 if (ret == -1) {
1129 *perr = WERR_INVALID_PARAMETER;
1130 goto error_exit;
1131 } else if (!ret) {
1132 DEBUG(6,("get_correct_cversion: Version info not "
1133 "found [%s]\n",
1134 smb_fname_str_dbg(smb_fname)));
1135 *perr = WERR_INVALID_PARAMETER;
1136 goto error_exit;
1140 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1141 * for more details. Version in this case is not just the version of the
1142 * file, but the version in the sense of kernel mode (2) vs. user mode
1143 * (3) drivers. Other bits of the version fields are the version info.
1144 * JRR 010716
1146 cversion = major & 0x0000ffff;
1147 switch (cversion) {
1148 case 2: /* WinNT drivers */
1149 case 3: /* Win2K drivers */
1150 break;
1152 default:
1153 DEBUG(6,("get_correct_cversion: cversion "
1154 "invalid [%s] cversion = %d\n",
1155 smb_fname_str_dbg(smb_fname),
1156 cversion));
1157 goto error_exit;
1160 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
1161 " = 0x%x minor = 0x%x\n",
1162 smb_fname_str_dbg(smb_fname), major, minor));
1164 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1165 smb_fname_str_dbg(smb_fname), cversion));
1166 *perr = WERR_OK;
1168 error_exit:
1169 unbecome_user_without_service();
1170 error_free_conn:
1171 if (fsp != NULL) {
1172 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1174 if (!W_ERROR_IS_OK(*perr)) {
1175 cversion = -1;
1178 TALLOC_FREE(frame);
1179 return cversion;
1182 /****************************************************************************
1183 ****************************************************************************/
1185 #define strip_driver_path(_mem_ctx, _element) do { \
1186 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
1187 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
1188 W_ERROR_HAVE_NO_MEMORY((_element)); \
1190 } while (0);
1192 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
1193 const struct auth_session_info *session_info,
1194 const char *architecture,
1195 const char **driver_path,
1196 const char **data_file,
1197 const char **config_file,
1198 const char **help_file,
1199 struct spoolss_StringArray *dependent_files,
1200 enum spoolss_DriverOSVersion *version,
1201 uint32_t flags,
1202 const char **driver_directory)
1204 const char *short_architecture;
1205 int i;
1206 WERROR err;
1207 char *_p;
1209 if (!*driver_path || !*data_file) {
1210 return WERR_INVALID_PARAMETER;
1213 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
1214 return WERR_INVALID_PARAMETER;
1217 if (flags & APD_COPY_FROM_DIRECTORY) {
1218 char *path;
1219 char *q;
1222 * driver_path is set to:
1224 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
1226 path = talloc_strdup(mem_ctx, *driver_path);
1227 if (path == NULL) {
1228 return WERR_NOT_ENOUGH_MEMORY;
1231 /* Remove pscript5.dll */
1232 q = strrchr_m(path, '\\');
1233 if (q == NULL) {
1234 return WERR_INVALID_PARAMETER;
1236 *q = '\0';
1238 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
1239 q = strrchr_m(path, '\\');
1240 if (q == NULL) {
1241 return WERR_INVALID_PARAMETER;
1245 * Set driver_directory to:
1247 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1249 * This is the directory where all the files have been uploaded
1251 *driver_directory = q + 1;
1254 /* clean up the driver name.
1255 * we can get .\driver.dll
1256 * or worse c:\windows\system\driver.dll !
1258 /* using an intermediate string to not have overlapping memcpy()'s */
1260 strip_driver_path(mem_ctx, *driver_path);
1261 strip_driver_path(mem_ctx, *data_file);
1262 if (*config_file) {
1263 strip_driver_path(mem_ctx, *config_file);
1265 if (help_file) {
1266 strip_driver_path(mem_ctx, *help_file);
1269 if (dependent_files && dependent_files->string) {
1270 for (i=0; dependent_files->string[i]; i++) {
1271 strip_driver_path(mem_ctx, dependent_files->string[i]);
1275 short_architecture = get_short_archi(architecture);
1276 if (!short_architecture) {
1277 return WERR_UNKNOWN_PRINTER_DRIVER;
1280 /* jfm:7/16/2000 the client always sends the cversion=0.
1281 * The server should check which version the driver is by reading
1282 * the PE header of driver->driverpath.
1284 * For Windows 95/98 the version is 0 (so the value sent is correct)
1285 * For Windows NT (the architecture doesn't matter)
1286 * NT 3.1: cversion=0
1287 * NT 3.5/3.51: cversion=1
1288 * NT 4: cversion=2
1289 * NT2K: cversion=3
1292 *version = get_correct_cversion(session_info,
1293 short_architecture,
1294 *driver_path,
1295 *driver_directory,
1296 &err);
1297 if (*version == -1) {
1298 return err;
1301 return WERR_OK;
1304 /****************************************************************************
1305 ****************************************************************************/
1307 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1308 const struct auth_session_info *session_info,
1309 const struct spoolss_AddDriverInfoCtr *r,
1310 uint32_t flags,
1311 const char **driver_directory)
1313 switch (r->level) {
1314 case 3:
1315 return clean_up_driver_struct_level(mem_ctx, session_info,
1316 r->info.info3->architecture,
1317 &r->info.info3->driver_path,
1318 &r->info.info3->data_file,
1319 &r->info.info3->config_file,
1320 &r->info.info3->help_file,
1321 r->info.info3->dependent_files,
1322 &r->info.info3->version,
1323 flags,
1324 driver_directory);
1325 case 6:
1326 return clean_up_driver_struct_level(mem_ctx, session_info,
1327 r->info.info6->architecture,
1328 &r->info.info6->driver_path,
1329 &r->info.info6->data_file,
1330 &r->info.info6->config_file,
1331 &r->info.info6->help_file,
1332 r->info.info6->dependent_files,
1333 &r->info.info6->version,
1334 flags,
1335 driver_directory);
1336 case 8:
1337 return clean_up_driver_struct_level(mem_ctx, session_info,
1338 r->info.info8->architecture,
1339 &r->info.info8->driver_path,
1340 &r->info.info8->data_file,
1341 &r->info.info8->config_file,
1342 &r->info.info8->help_file,
1343 r->info.info8->dependent_files,
1344 &r->info.info8->version,
1345 flags,
1346 driver_directory);
1347 default:
1348 return WERR_NOT_SUPPORTED;
1352 /****************************************************************************
1353 This function sucks and should be replaced. JRA.
1354 ****************************************************************************/
1356 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1357 const struct spoolss_AddDriverInfo6 *src)
1359 dst->version = src->version;
1361 dst->driver_name = src->driver_name;
1362 dst->architecture = src->architecture;
1363 dst->driver_path = src->driver_path;
1364 dst->data_file = src->data_file;
1365 dst->config_file = src->config_file;
1366 dst->help_file = src->help_file;
1367 dst->monitor_name = src->monitor_name;
1368 dst->default_datatype = src->default_datatype;
1369 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1370 dst->dependent_files = src->dependent_files;
1373 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1374 const struct spoolss_AddDriverInfo8 *src)
1376 dst->version = src->version;
1378 dst->driver_name = src->driver_name;
1379 dst->architecture = src->architecture;
1380 dst->driver_path = src->driver_path;
1381 dst->data_file = src->data_file;
1382 dst->config_file = src->config_file;
1383 dst->help_file = src->help_file;
1384 dst->monitor_name = src->monitor_name;
1385 dst->default_datatype = src->default_datatype;
1386 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1387 dst->dependent_files = src->dependent_files;
1390 /****************************************************************************
1391 ****************************************************************************/
1393 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1394 connection_struct *conn,
1395 const char *driver_file,
1396 const char *short_architecture,
1397 uint32_t driver_version,
1398 uint32_t version,
1399 const char *driver_directory)
1401 struct smb_filename *smb_fname_old = NULL;
1402 struct smb_filename *smb_fname_new = NULL;
1403 char *old_name = NULL;
1404 char *new_name = NULL;
1405 NTSTATUS status;
1406 WERROR ret;
1408 if (driver_directory != NULL) {
1409 old_name = talloc_asprintf(mem_ctx,
1410 "%s/%s/%s",
1411 short_architecture,
1412 driver_directory,
1413 driver_file);
1414 } else {
1415 old_name = talloc_asprintf(mem_ctx,
1416 "%s/%s",
1417 short_architecture,
1418 driver_file);
1420 if (old_name == NULL) {
1421 return WERR_NOT_ENOUGH_MEMORY;
1424 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1425 short_architecture, driver_version, driver_file);
1426 if (new_name == NULL) {
1427 TALLOC_FREE(old_name);
1428 return WERR_NOT_ENOUGH_MEMORY;
1431 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1432 struct files_struct *dirfsp = NULL;
1434 status = driver_unix_convert(conn,
1435 old_name,
1436 &dirfsp,
1437 &smb_fname_old);
1438 if (!NT_STATUS_IS_OK(status)) {
1439 ret = WERR_NOT_ENOUGH_MEMORY;
1440 goto out;
1443 /* Setup a synthetic smb_filename struct */
1444 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1445 if (!smb_fname_new) {
1446 ret = WERR_NOT_ENOUGH_MEMORY;
1447 goto out;
1450 smb_fname_new->base_name = new_name;
1452 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1453 "'%s'\n", smb_fname_old->base_name,
1454 smb_fname_new->base_name));
1456 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1457 FILE_OVERWRITE_IF);
1459 if (!NT_STATUS_IS_OK(status)) {
1460 DEBUG(0,("move_driver_file_to_download_area: Unable "
1461 "to rename [%s] to [%s]: %s\n",
1462 smb_fname_old->base_name, new_name,
1463 nt_errstr(status)));
1464 ret = WERR_APP_INIT_FAILURE;
1465 goto out;
1469 ret = WERR_OK;
1470 out:
1471 TALLOC_FREE(smb_fname_old);
1472 TALLOC_FREE(smb_fname_new);
1473 return ret;
1476 WERROR move_driver_to_download_area(const struct auth_session_info *session_info,
1477 const struct spoolss_AddDriverInfoCtr *r,
1478 const char *driver_directory)
1480 TALLOC_CTX *frame = talloc_stackframe();
1481 const struct loadparm_substitution *lp_sub =
1482 loadparm_s3_global_substitution();
1483 struct spoolss_AddDriverInfo3 *driver;
1484 struct spoolss_AddDriverInfo3 converted_driver;
1485 const char *short_architecture;
1486 struct files_struct *dirfsp = NULL;
1487 struct smb_filename *smb_dname = NULL;
1488 char *new_dir = NULL;
1489 struct conn_struct_tos *c = NULL;
1490 connection_struct *conn = NULL;
1491 NTSTATUS nt_status;
1492 int i;
1493 int ver = 0;
1494 char *printdollar = NULL;
1495 int printdollar_snum;
1496 WERROR err = WERR_OK;
1498 switch (r->level) {
1499 case 3:
1500 driver = r->info.info3;
1501 break;
1502 case 6:
1503 convert_level_6_to_level3(&converted_driver, r->info.info6);
1504 driver = &converted_driver;
1505 break;
1506 case 8:
1507 convert_level_8_to_level3(&converted_driver, r->info.info8);
1508 driver = &converted_driver;
1509 break;
1510 default:
1511 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1512 TALLOC_FREE(frame);
1513 return WERR_INVALID_LEVEL;
1516 short_architecture = get_short_archi(driver->architecture);
1517 if (!short_architecture) {
1518 TALLOC_FREE(frame);
1519 return WERR_UNKNOWN_PRINTER_DRIVER;
1522 printdollar_snum = find_service(frame, "print$", &printdollar);
1523 if (!printdollar) {
1524 TALLOC_FREE(frame);
1525 return WERR_NOT_ENOUGH_MEMORY;
1527 if (printdollar_snum == -1) {
1528 TALLOC_FREE(frame);
1529 return WERR_BAD_NET_NAME;
1532 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
1533 printdollar_snum,
1534 lp_path(frame, lp_sub, printdollar_snum),
1535 session_info,
1536 &c);
1537 if (!NT_STATUS_IS_OK(nt_status)) {
1538 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1539 "returned %s\n", nt_errstr(nt_status)));
1540 err = ntstatus_to_werror(nt_status);
1541 TALLOC_FREE(frame);
1542 return err;
1544 conn = c->conn;
1546 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1547 if (!NT_STATUS_IS_OK(nt_status)) {
1548 DEBUG(0, ("failed set force user / group\n"));
1549 err = ntstatus_to_werror(nt_status);
1550 goto err_free_conn;
1553 if (!become_user_without_service_by_session(conn, session_info)) {
1554 DEBUG(0, ("failed to become user\n"));
1555 err = WERR_ACCESS_DENIED;
1556 goto err_free_conn;
1559 new_dir = talloc_asprintf(frame,
1560 "%s/%d",
1561 short_architecture,
1562 driver->version);
1563 if (!new_dir) {
1564 err = WERR_NOT_ENOUGH_MEMORY;
1565 goto err_exit;
1567 nt_status = driver_unix_convert(conn, new_dir, &dirfsp, &smb_dname);
1568 if (!NT_STATUS_IS_OK(nt_status)) {
1569 err = WERR_NOT_ENOUGH_MEMORY;
1570 goto err_exit;
1573 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1575 nt_status = create_directory(conn, NULL, dirfsp, smb_dname);
1576 if (!NT_STATUS_IS_OK(nt_status)
1577 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1578 DEBUG(0, ("failed to create driver destination directory: %s\n",
1579 nt_errstr(nt_status)));
1580 err = ntstatus_to_werror(nt_status);
1581 goto err_exit;
1584 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1585 * listed for this driver which has already been moved, skip it (note:
1586 * drivers may list the same file name several times. Then check if the
1587 * file already exists in archi\version\, if so, check that the version
1588 * info (or time stamps if version info is unavailable) is newer (or the
1589 * date is later). If it is, move it to archi\version\filexxx.yyy.
1590 * Otherwise, delete the file.
1592 * If a file is not moved to archi\version\ because of an error, all the
1593 * rest of the 'unmoved' driver files are removed from archi\. If one or
1594 * more of the driver's files was already moved to archi\version\, it
1595 * potentially leaves the driver in a partially updated state. Version
1596 * trauma will most likely occur if an client attempts to use any printer
1597 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1598 * done is appropriate... later JRR
1601 DEBUG(5,("Moving files now !\n"));
1603 if (driver->driver_path && strlen(driver->driver_path)) {
1605 err = move_driver_file_to_download_area(frame,
1606 conn,
1607 driver->driver_path,
1608 short_architecture,
1609 driver->version,
1610 ver,
1611 driver_directory);
1612 if (!W_ERROR_IS_OK(err)) {
1613 goto err_exit;
1617 if (driver->data_file && strlen(driver->data_file)) {
1618 if (!strequal(driver->data_file, driver->driver_path)) {
1620 err = move_driver_file_to_download_area(frame,
1621 conn,
1622 driver->data_file,
1623 short_architecture,
1624 driver->version,
1625 ver,
1626 driver_directory);
1627 if (!W_ERROR_IS_OK(err)) {
1628 goto err_exit;
1633 if (driver->config_file && strlen(driver->config_file)) {
1634 if (!strequal(driver->config_file, driver->driver_path) &&
1635 !strequal(driver->config_file, driver->data_file)) {
1637 err = move_driver_file_to_download_area(frame,
1638 conn,
1639 driver->config_file,
1640 short_architecture,
1641 driver->version,
1642 ver,
1643 driver_directory);
1644 if (!W_ERROR_IS_OK(err)) {
1645 goto err_exit;
1650 if (driver->help_file && strlen(driver->help_file)) {
1651 if (!strequal(driver->help_file, driver->driver_path) &&
1652 !strequal(driver->help_file, driver->data_file) &&
1653 !strequal(driver->help_file, driver->config_file)) {
1655 err = move_driver_file_to_download_area(frame,
1656 conn,
1657 driver->help_file,
1658 short_architecture,
1659 driver->version,
1660 ver,
1661 driver_directory);
1662 if (!W_ERROR_IS_OK(err)) {
1663 goto err_exit;
1668 if (driver->dependent_files && driver->dependent_files->string) {
1669 for (i=0; driver->dependent_files->string[i]; i++) {
1670 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1671 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1672 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1673 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1674 int j;
1675 for (j=0; j < i; j++) {
1676 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1677 goto NextDriver;
1681 err = move_driver_file_to_download_area(frame,
1682 conn,
1683 driver->dependent_files->string[i],
1684 short_architecture,
1685 driver->version,
1686 ver,
1687 driver_directory);
1688 if (!W_ERROR_IS_OK(err)) {
1689 goto err_exit;
1692 NextDriver: ;
1696 err = WERR_OK;
1697 err_exit:
1698 unbecome_user_without_service();
1699 err_free_conn:
1700 TALLOC_FREE(frame);
1701 return err;
1704 /****************************************************************************
1705 Determine whether or not a particular driver is currently assigned
1706 to a printer
1707 ****************************************************************************/
1709 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
1710 struct dcerpc_binding_handle *b,
1711 const struct spoolss_DriverInfo8 *r)
1713 const struct loadparm_substitution *lp_sub =
1714 loadparm_s3_global_substitution();
1715 int snum;
1716 int n_services = lp_numservices();
1717 bool in_use = false;
1718 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1719 WERROR result;
1721 if (!r) {
1722 return false;
1725 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1727 /* loop through the printers.tdb and check for the drivername */
1729 for (snum=0; snum<n_services && !in_use; snum++) {
1730 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1731 continue;
1734 result = winreg_get_printer(mem_ctx, b,
1735 lp_servicename(talloc_tos(), lp_sub, snum),
1736 &pinfo2);
1737 if (!W_ERROR_IS_OK(result)) {
1738 continue; /* skip */
1741 if (strequal(r->driver_name, pinfo2->drivername)) {
1742 in_use = true;
1745 TALLOC_FREE(pinfo2);
1748 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1750 if ( in_use ) {
1751 struct spoolss_DriverInfo8 *driver = NULL;
1752 WERROR werr;
1754 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1756 /* we can still remove the driver if there is one of
1757 "Windows NT x86" version 2 or 3 left */
1759 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1760 if (r->version == 2) {
1761 werr = winreg_get_driver(mem_ctx, b,
1762 r->architecture,
1763 r->driver_name,
1764 3, &driver);
1765 } else if (r->version == 3) {
1766 werr = winreg_get_driver(mem_ctx, b,
1767 r->architecture,
1768 r->driver_name,
1769 2, &driver);
1770 } else {
1771 DBG_ERR("Unknown driver version (%d)\n",
1772 r->version);
1773 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1775 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1776 werr = winreg_get_driver(mem_ctx, b,
1777 SPOOLSS_ARCHITECTURE_NT_X86,
1778 r->driver_name,
1779 DRIVER_ANY_VERSION,
1780 &driver);
1781 } else {
1782 DBG_ERR("Unknown driver architecture: %s\n",
1783 r->architecture);
1784 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1787 /* now check the error code */
1789 if ( W_ERROR_IS_OK(werr) ) {
1790 /* it's ok to remove the driver, we have other architectures left */
1791 in_use = false;
1792 talloc_free(driver);
1796 /* report that the driver is not in use by default */
1798 return in_use;
1802 /**********************************************************************
1803 Check to see if a ogiven file is in use by *info
1804 *********************************************************************/
1806 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1808 int i = 0;
1810 if ( !info )
1811 return False;
1813 /* mz: skip files that are in the list but already deleted */
1814 if (!file || !file[0]) {
1815 return false;
1818 if (strequal(file, info->driver_path))
1819 return True;
1821 if (strequal(file, info->data_file))
1822 return True;
1824 if (strequal(file, info->config_file))
1825 return True;
1827 if (strequal(file, info->help_file))
1828 return True;
1830 /* see of there are any dependent files to examine */
1832 if (!info->dependent_files)
1833 return False;
1835 while (info->dependent_files[i] && *info->dependent_files[i]) {
1836 if (strequal(file, info->dependent_files[i]))
1837 return True;
1838 i++;
1841 return False;
1845 /**********************************************************************
1846 Utility function to remove the dependent file pointed to by the
1847 input parameter from the list
1848 *********************************************************************/
1850 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1853 /* bump everything down a slot */
1855 while (files && files[idx+1]) {
1856 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1857 idx++;
1860 files[idx] = NULL;
1862 return;
1865 /**********************************************************************
1866 Check if any of the files used by src are also used by drv
1867 *********************************************************************/
1869 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1870 struct spoolss_DriverInfo8 *src,
1871 const struct spoolss_DriverInfo8 *drv)
1873 bool in_use = False;
1874 int i = 0;
1876 if ( !src || !drv )
1877 return False;
1879 /* check each file. Remove it from the src structure if it overlaps */
1881 if (drv_file_in_use(src->driver_path, drv)) {
1882 in_use = True;
1883 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1884 src->driver_path = talloc_strdup(mem_ctx, "");
1885 if (!src->driver_path) { return false; }
1888 if (drv_file_in_use(src->data_file, drv)) {
1889 in_use = True;
1890 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1891 src->data_file = talloc_strdup(mem_ctx, "");
1892 if (!src->data_file) { return false; }
1895 if (drv_file_in_use(src->config_file, drv)) {
1896 in_use = True;
1897 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1898 src->config_file = talloc_strdup(mem_ctx, "");
1899 if (!src->config_file) { return false; }
1902 if (drv_file_in_use(src->help_file, drv)) {
1903 in_use = True;
1904 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1905 src->help_file = talloc_strdup(mem_ctx, "");
1906 if (!src->help_file) { return false; }
1909 /* are there any dependentfiles to examine? */
1911 if (!src->dependent_files)
1912 return in_use;
1914 while (src->dependent_files[i] && *src->dependent_files[i]) {
1915 if (drv_file_in_use(src->dependent_files[i], drv)) {
1916 in_use = True;
1917 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1918 trim_dependent_file(mem_ctx, src->dependent_files, i);
1919 } else
1920 i++;
1923 return in_use;
1926 /****************************************************************************
1927 Determine whether or not a particular driver files are currently being
1928 used by any other driver.
1930 Return value is True if any files were in use by other drivers
1931 and False otherwise.
1933 Upon return, *info has been modified to only contain the driver files
1934 which are not in use
1936 Fix from mz:
1938 This needs to check all drivers to ensure that all files in use
1939 have been removed from *info, not just the ones in the first
1940 match.
1941 ****************************************************************************/
1943 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1944 struct dcerpc_binding_handle *b,
1945 struct spoolss_DriverInfo8 *info)
1947 uint32_t version;
1948 struct spoolss_DriverInfo8 *driver;
1949 bool in_use = false;
1950 uint32_t i, num_drivers;
1951 const char **drivers;
1952 WERROR result;
1954 if ( !info )
1955 return False;
1957 version = info->version;
1959 /* loop over all driver versions */
1961 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1963 /* get the list of drivers */
1965 result = winreg_get_driver_list(mem_ctx, b,
1966 info->architecture, version,
1967 &num_drivers, &drivers);
1968 if (!W_ERROR_IS_OK(result)) {
1969 return true;
1972 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1973 num_drivers, info->architecture, version));
1975 /* check each driver for overlap in files */
1977 for (i = 0; i < num_drivers; i++) {
1978 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1980 driver = NULL;
1982 result = winreg_get_driver(mem_ctx, b,
1983 info->architecture, drivers[i],
1984 version, &driver);
1985 if (!W_ERROR_IS_OK(result)) {
1986 talloc_free(drivers);
1987 return True;
1990 /* check if d2 uses any files from d1 */
1991 /* only if this is a different driver than the one being deleted */
1993 if (!strequal(info->driver_name, driver->driver_name)) {
1994 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1995 /* mz: Do not instantly return -
1996 * we need to ensure this file isn't
1997 * also in use by other drivers. */
1998 in_use = true;
2002 talloc_free(driver);
2005 talloc_free(drivers);
2007 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2009 return in_use;
2012 static NTSTATUS driver_unlink_internals(connection_struct *conn,
2013 const char *short_arch,
2014 int vers,
2015 const char *fname)
2017 TALLOC_CTX *tmp_ctx = talloc_new(conn);
2018 struct smb_filename *smb_fname = NULL;
2019 char *print_dlr_path;
2020 NTSTATUS status = NT_STATUS_NO_MEMORY;
2022 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
2023 short_arch, vers, fname);
2024 if (print_dlr_path == NULL) {
2025 goto err_out;
2028 status = synthetic_pathref(tmp_ctx,
2029 conn->cwd_fsp,
2030 print_dlr_path,
2031 NULL,
2032 NULL,
2035 &smb_fname);
2036 if (!NT_STATUS_IS_OK(status)) {
2037 goto err_out;
2040 status = unlink_internals(conn, NULL, 0, NULL, smb_fname);
2041 err_out:
2042 talloc_free(tmp_ctx);
2043 return status;
2046 /****************************************************************************
2047 Actually delete the driver files. Make sure that
2048 printer_driver_files_in_use() return False before calling
2049 this.
2050 ****************************************************************************/
2052 bool delete_driver_files(const struct auth_session_info *session_info,
2053 const struct spoolss_DriverInfo8 *r)
2055 TALLOC_CTX *frame = talloc_stackframe();
2056 const struct loadparm_substitution *lp_sub =
2057 loadparm_s3_global_substitution();
2058 const char *short_arch;
2059 struct conn_struct_tos *c = NULL;
2060 connection_struct *conn = NULL;
2061 NTSTATUS nt_status;
2062 char *printdollar = NULL;
2063 int printdollar_snum;
2064 bool ret = false;
2066 if (!r) {
2067 TALLOC_FREE(frame);
2068 return false;
2071 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2072 r->driver_name, r->version));
2074 printdollar_snum = find_service(frame, "print$", &printdollar);
2075 if (!printdollar) {
2076 TALLOC_FREE(frame);
2077 return false;
2079 if (printdollar_snum == -1) {
2080 TALLOC_FREE(frame);
2081 return false;
2084 nt_status = create_conn_struct_tos_cwd(global_messaging_context(),
2085 printdollar_snum,
2086 lp_path(frame, lp_sub, printdollar_snum),
2087 session_info,
2088 &c);
2089 if (!NT_STATUS_IS_OK(nt_status)) {
2090 DEBUG(0,("delete_driver_files: create_conn_struct "
2091 "returned %s\n", nt_errstr(nt_status)));
2092 TALLOC_FREE(frame);
2093 return false;
2095 conn = c->conn;
2097 nt_status = set_conn_force_user_group(conn, printdollar_snum);
2098 if (!NT_STATUS_IS_OK(nt_status)) {
2099 DEBUG(0, ("failed set force user / group\n"));
2100 ret = false;
2101 goto err_free_conn;
2104 if (!become_user_without_service_by_session(conn, session_info)) {
2105 DEBUG(0, ("failed to become user\n"));
2106 ret = false;
2107 goto err_free_conn;
2110 if ( !CAN_WRITE(conn) ) {
2111 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2112 ret = false;
2113 goto err_out;
2116 short_arch = get_short_archi(r->architecture);
2117 if (short_arch == NULL) {
2118 DEBUG(0, ("bad architecture %s\n", r->architecture));
2119 ret = false;
2120 goto err_out;
2123 /* now delete the files */
2125 if (r->driver_path && r->driver_path[0]) {
2126 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
2127 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
2130 if (r->config_file && r->config_file[0]) {
2131 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
2132 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
2135 if (r->data_file && r->data_file[0]) {
2136 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
2137 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
2140 if (r->help_file && r->help_file[0]) {
2141 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
2142 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
2145 if (r->dependent_files) {
2146 int i = 0;
2147 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2148 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
2149 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
2150 i++;
2154 ret = true;
2155 err_out:
2156 unbecome_user_without_service();
2157 err_free_conn:
2158 TALLOC_FREE(frame);
2159 return ret;
2162 /* error code:
2163 0: everything OK
2164 1: level not implemented
2165 2: file doesn't exist
2166 3: can't allocate memory
2167 4: can't free memory
2168 5: non existent struct
2172 A printer and a printer driver are 2 different things.
2173 NT manages them separately, Samba does the same.
2174 Why ? Simply because it's easier and it makes sense !
2176 Now explanation: You have 3 printers behind your samba server,
2177 2 of them are the same make and model (laser A and B). But laser B
2178 has an 3000 sheet feeder and laser A doesn't such an option.
2179 Your third printer is an old dot-matrix model for the accounting :-).
2181 If the /usr/local/samba/lib directory (default dir), you will have
2182 5 files to describe all of this.
2184 3 files for the printers (1 by printer):
2185 NTprinter_laser A
2186 NTprinter_laser B
2187 NTprinter_accounting
2188 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2189 NTdriver_printer model X
2190 NTdriver_printer model Y
2192 jfm: I should use this comment for the text file to explain
2193 same thing for the forms BTW.
2194 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2198 /* Convert generic access rights to printer object specific access rights.
2199 It turns out that NT4 security descriptors use generic access rights and
2200 NT5 the object specific ones. */
2202 void map_printer_permissions(struct security_descriptor *sd)
2204 uint32_t i;
2206 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2207 se_map_generic(&sd->dacl->aces[i].access_mask,
2208 &printer_generic_mapping);
2212 void map_job_permissions(struct security_descriptor *sd)
2214 uint32_t i;
2216 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2217 se_map_generic(&sd->dacl->aces[i].access_mask,
2218 &job_generic_mapping);
2223 /****************************************************************************
2224 Check a user has permissions to perform the given operation. We use the
2225 permission constants defined in include/rpc_spoolss.h to check the various
2226 actions we perform when checking printer access.
2228 PRINTER_ACCESS_ADMINISTER:
2229 print_queue_pause, print_queue_resume, update_printer_sec,
2230 update_printer, spoolss_addprinterex_level_2,
2231 _spoolss_setprinterdata
2233 PRINTER_ACCESS_USE:
2234 print_job_start
2236 JOB_ACCESS_ADMINISTER:
2237 print_job_delete, print_job_pause, print_job_resume,
2238 print_queue_purge
2240 Try access control in the following order (for performance reasons):
2241 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2242 2) check security descriptor (bit comparisons in memory)
2243 3) "printer admins" (may result in numerous calls to winbind)
2245 ****************************************************************************/
2246 WERROR print_access_check(const struct auth_session_info *session_info,
2247 struct messaging_context *msg_ctx, int snum,
2248 int access_type)
2250 struct spoolss_security_descriptor *secdesc = NULL;
2251 const struct loadparm_substitution *lp_sub =
2252 loadparm_s3_global_substitution();
2253 uint32_t access_granted;
2254 size_t sd_size;
2255 NTSTATUS status;
2256 WERROR result;
2257 const char *pname;
2258 TALLOC_CTX *mem_ctx = NULL;
2260 /* If user is NULL then use the current_user structure */
2262 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2264 if ((session_info->unix_token->uid == sec_initial_uid())
2265 || security_token_has_privilege(session_info->security_token,
2266 SEC_PRIV_PRINT_OPERATOR)) {
2267 return WERR_OK;
2270 /* Get printer name */
2272 pname = lp_printername(talloc_tos(), lp_sub, snum);
2274 if (!pname || !*pname) {
2275 return WERR_ACCESS_DENIED;
2278 /* Get printer security descriptor */
2280 if(!(mem_ctx = talloc_init("print_access_check"))) {
2281 return WERR_NOT_ENOUGH_MEMORY;
2284 result = winreg_get_printer_secdesc_internal(mem_ctx,
2285 get_session_info_system(),
2286 msg_ctx,
2287 pname,
2288 &secdesc);
2289 if (!W_ERROR_IS_OK(result)) {
2290 talloc_destroy(mem_ctx);
2291 return WERR_NOT_ENOUGH_MEMORY;
2294 if (access_type == JOB_ACCESS_ADMINISTER) {
2295 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2297 /* Create a child security descriptor to check permissions
2298 against. This is because print jobs are child objects
2299 objects of a printer. */
2300 status = se_create_child_secdesc(mem_ctx,
2301 &secdesc,
2302 &sd_size,
2303 parent_secdesc,
2304 parent_secdesc->owner_sid,
2305 parent_secdesc->group_sid,
2306 false);
2307 if (!NT_STATUS_IS_OK(status)) {
2308 talloc_destroy(mem_ctx);
2309 return ntstatus_to_werror(status);
2312 map_job_permissions(secdesc);
2313 } else {
2314 map_printer_permissions(secdesc);
2317 /* Check access */
2318 status = se_access_check(secdesc, session_info->security_token, access_type,
2319 &access_granted);
2321 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2323 talloc_destroy(mem_ctx);
2325 return ntstatus_to_werror(status);
2328 /****************************************************************************
2329 Check the time parameters allow a print operation.
2330 *****************************************************************************/
2332 bool print_time_access_check(const struct auth_session_info *session_info,
2333 struct messaging_context *msg_ctx,
2334 const char *servicename)
2336 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2337 WERROR result;
2338 bool ok = False;
2339 time_t now = time(NULL);
2340 struct tm *t;
2341 uint32_t mins;
2343 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2344 servicename, &pinfo2);
2345 if (!W_ERROR_IS_OK(result)) {
2346 return False;
2349 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2350 ok = True;
2353 t = gmtime(&now);
2354 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2356 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2357 ok = True;
2360 TALLOC_FREE(pinfo2);
2362 if (!ok) {
2363 errno = EACCES;
2366 return ok;
2369 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2370 const struct auth_session_info *session_info,
2371 struct messaging_context *msg_ctx,
2372 const char *printer)
2374 WERROR result;
2376 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2377 printer, "");
2378 if (!W_ERROR_IS_OK(result)) {
2379 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2380 "%s\n", printer, win_errstr(result)));
2384 void nt_printer_add(TALLOC_CTX *mem_ctx,
2385 const struct auth_session_info *session_info,
2386 struct messaging_context *msg_ctx,
2387 const char *printer)
2389 WERROR result;
2391 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2392 printer);
2393 if (!W_ERROR_IS_OK(result)) {
2394 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2395 printer, win_errstr(result)));