s4:torture: test setting EOF of a stream to 0 with enabled AAPL extensions
[Samba.git] / source3 / printing / nt_printing.c
blob1639bfd440661e91a8d93d2519d6724e68d0104c
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2000,
5 * Copyright (C) Jean François Micouleau 1998-2000.
6 * Copyright (C) Gerald Carter 2002-2005.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "printing/nt_printing_tdb.h"
24 #include "../librpc/gen_ndr/ndr_spoolss.h"
25 #include "rpc_server/spoolss/srv_spoolss_util.h"
26 #include "nt_printing.h"
27 #include "secrets.h"
28 #include "../librpc/gen_ndr/netlogon.h"
29 #include "../libcli/security/security.h"
30 #include "passdb/machine_sid.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "auth.h"
34 #include "messages.h"
35 #include "rpc_server/spoolss/srv_spoolss_nt.h"
36 #include "rpc_client/cli_winreg_spoolss.h"
38 /* Map generic permissions to printer object specific permissions */
40 const struct generic_mapping printer_generic_mapping = {
41 PRINTER_READ,
42 PRINTER_WRITE,
43 PRINTER_EXECUTE,
44 PRINTER_ALL_ACCESS
47 /* Map generic permissions to print server object specific permissions */
49 const struct generic_mapping printserver_generic_mapping = {
50 SERVER_READ,
51 SERVER_WRITE,
52 SERVER_EXECUTE,
53 SERVER_ALL_ACCESS
56 /* Map generic permissions to job object specific permissions */
58 const struct generic_mapping job_generic_mapping = {
59 JOB_READ,
60 JOB_WRITE,
61 JOB_EXECUTE,
62 JOB_ALL_ACCESS
65 static const struct print_architecture_table_node archi_table[]= {
67 {"Windows 4.0", SPL_ARCH_WIN40, 0 },
68 {"Windows NT x86", SPL_ARCH_W32X86, 2 },
69 {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 },
70 {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 },
71 {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 },
72 {"Windows IA64", SPL_ARCH_IA64, 3 },
73 {"Windows x64", SPL_ARCH_X64, 3 },
74 {NULL, "", -1 }
77 static bool print_driver_directories_init(void)
79 int service, i;
80 char *driver_path;
81 bool ok;
82 TALLOC_CTX *mem_ctx = talloc_stackframe();
83 const char *dir_list[] = {
84 "W32X86/PCC",
85 "x64/PCC",
86 "color"
89 service = lp_servicenumber("print$");
90 if (service < 0) {
91 /* We don't have a print$ share */
92 DEBUG(5, ("No print$ share has been configured.\n"));
93 talloc_free(mem_ctx);
94 return true;
97 driver_path = lp_path(mem_ctx, service);
98 if (driver_path == NULL) {
99 talloc_free(mem_ctx);
100 return false;
103 ok = directory_create_or_exist(driver_path, 0755);
104 if (!ok) {
105 DEBUG(1, ("Failed to create printer driver directory %s\n",
106 driver_path));
107 talloc_free(mem_ctx);
108 return false;
111 for (i = 0; archi_table[i].long_archi != NULL; i++) {
112 const char *arch_path;
114 arch_path = talloc_asprintf(mem_ctx,
115 "%s/%s",
116 driver_path,
117 archi_table[i].short_archi);
118 if (arch_path == NULL) {
119 talloc_free(mem_ctx);
120 return false;
123 ok = directory_create_or_exist(arch_path, 0755);
124 if (!ok) {
125 DEBUG(1, ("Failed to create printer driver "
126 "architecture directory %s\n",
127 arch_path));
128 talloc_free(mem_ctx);
129 return false;
133 for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
134 const char *path;
136 path = talloc_asprintf(mem_ctx,
137 "%s/%s",
138 driver_path,
139 dir_list[i]);
140 if (path == NULL) {
141 talloc_free(mem_ctx);
142 return false;
145 ok = directory_create_or_exist(path, 0755);
146 if (!ok) {
147 DEBUG(1, ("Failed to create printer driver "
148 "architecture directory %s\n",
149 path));
150 talloc_free(mem_ctx);
151 return false;
155 driver_path = state_path("DriverStore");
156 if (driver_path == NULL) {
157 talloc_free(mem_ctx);
158 return false;
161 ok = directory_create_or_exist(driver_path, 0755);
162 if (!ok) {
163 DEBUG(1,("failed to create path %s\n", driver_path));
164 talloc_free(mem_ctx);
165 return false;
168 driver_path = state_path("DriverStore/FileRepository");
169 if (driver_path == NULL) {
170 talloc_free(mem_ctx);
171 return false;
174 ok = directory_create_or_exist(driver_path, 0755);
175 if (!ok) {
176 DEBUG(1,("failed to create path %s\n", driver_path));
177 talloc_free(mem_ctx);
178 return false;
181 driver_path = state_path("DriverStore/Temp");
182 if (driver_path == NULL) {
183 talloc_free(mem_ctx);
184 return false;
187 ok = directory_create_or_exist(driver_path, 0755);
188 if (!ok) {
189 DEBUG(1,("failed to create path %s\n", driver_path));
190 talloc_free(mem_ctx);
191 return false;
194 talloc_free(mem_ctx);
195 return true;
198 /****************************************************************************
199 Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
200 background lpq updater.
201 ****************************************************************************/
203 static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
204 void *private_data,
205 uint32_t msg_type,
206 struct server_id server_id,
207 DATA_BLOB *data)
209 extern pid_t background_lpq_updater_pid;
211 if (background_lpq_updater_pid == -1) {
212 DEBUG(3,("no background lpq queue updater\n"));
213 return;
216 messaging_send_buf(msg,
217 pid_to_procid(background_lpq_updater_pid),
218 MSG_PRINTER_DRVUPGRADE,
219 data->data,
220 data->length);
223 /****************************************************************************
224 Open the NT printing tdbs. Done once before fork().
225 ****************************************************************************/
227 bool nt_printing_init(struct messaging_context *msg_ctx)
229 WERROR win_rc;
231 if (!print_driver_directories_init()) {
232 return false;
235 if (!nt_printing_tdb_upgrade()) {
236 return false;
240 * register callback to handle updating printers as new
241 * drivers are installed. Forwards to background lpq updater.
243 messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
244 forward_drv_upgrade_printer_msg);
246 if ( lp_security() == SEC_ADS ) {
247 win_rc = check_published_printers(msg_ctx);
248 if (!W_ERROR_IS_OK(win_rc))
249 DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
252 return true;
255 /*******************************************************************
256 Function to allow filename parsing "the old way".
257 ********************************************************************/
259 static NTSTATUS driver_unix_convert(connection_struct *conn,
260 const char *old_name,
261 struct smb_filename **smb_fname)
263 NTSTATUS status;
264 TALLOC_CTX *ctx = talloc_tos();
265 char *name = talloc_strdup(ctx, old_name);
267 if (!name) {
268 return NT_STATUS_NO_MEMORY;
270 unix_format(name);
271 name = unix_clean_name(ctx, name);
272 if (!name) {
273 return NT_STATUS_NO_MEMORY;
275 trim_string(name,"/","/");
277 status = unix_convert(ctx, conn, name, smb_fname, 0);
278 if (!NT_STATUS_IS_OK(status)) {
279 return NT_STATUS_NO_MEMORY;
282 return NT_STATUS_OK;
285 /****************************************************************************
286 Function to do the mapping between the long architecture name and
287 the short one.
288 ****************************************************************************/
290 const char *get_short_archi(const char *long_archi)
292 int i=-1;
294 DEBUG(107,("Getting architecture dependent directory\n"));
295 do {
296 i++;
297 } while ( (archi_table[i].long_archi!=NULL ) &&
298 strcasecmp_m(long_archi, archi_table[i].long_archi) );
300 if (archi_table[i].long_archi==NULL) {
301 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
302 return NULL;
305 /* this might be client code - but shouldn't this be an fstrcpy etc? */
307 DEBUGADD(108,("index: [%d]\n", i));
308 DEBUGADD(108,("long architecture: [%s]\n", archi_table[i].long_archi));
309 DEBUGADD(108,("short architecture: [%s]\n", archi_table[i].short_archi));
311 return archi_table[i].short_archi;
314 /****************************************************************************
315 Read data from fsp on the vfs.
316 ****************************************************************************/
318 static ssize_t printing_pread_data(files_struct *fsp,
319 char *buf,
320 off_t *poff,
321 size_t byte_count)
323 size_t total=0;
324 off_t in_pos = *poff;
326 /* Don't allow integer wrap on read. */
327 if (in_pos + byte_count < in_pos) {
328 return -1;
331 while (total < byte_count) {
332 ssize_t ret = read_file(fsp,
333 buf + total,
334 in_pos,
335 byte_count - total);
337 if (ret == 0) {
338 *poff = in_pos;
339 return total;
341 if (ret == -1) {
342 if (errno == EINTR) {
343 continue;
344 } else {
345 return -1;
348 in_pos += ret;
349 total += ret;
351 *poff = in_pos;
352 return (ssize_t)total;
355 /****************************************************************************
356 Detect the major and minor version of a PE file.
357 Returns:
359 1 if file is a PE file and we got version numbers,
360 0 if this file is a PE file and we couldn't get the version numbers,
361 -1 on error.
363 NB. buf is passed into and freed inside this function. This is a
364 bad API design, but fixing this is a task for another day.
365 ****************************************************************************/
367 static int handle_pe_file(files_struct *fsp,
368 off_t in_pos,
369 char *fname,
370 char *buf,
371 uint32_t *major,
372 uint32_t *minor)
374 unsigned int i;
375 unsigned int num_sections;
376 unsigned int section_table_bytes;
377 ssize_t byte_count;
378 off_t rel_pos;
379 int ret = -1;
381 /* Just skip over optional header to get to section table */
382 rel_pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-
383 (NE_HEADER_SIZE-PE_HEADER_SIZE);
385 if (in_pos + rel_pos < in_pos) {
386 /* Integer wrap. */
387 goto out;
389 in_pos = rel_pos + in_pos;
391 /* get the section table */
392 num_sections = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
394 if (num_sections >= (UINT_MAX / PE_HEADER_SECT_HEADER_SIZE)) {
395 /* Integer wrap. */
396 goto out;
399 section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
400 if (section_table_bytes == 0) {
401 goto out;
404 SAFE_FREE(buf);
405 buf = (char *)SMB_MALLOC(section_table_bytes);
406 if (buf == NULL) {
407 DBG_ERR("PE file [%s] section table malloc "
408 "failed bytes = %d\n",
409 fname,
410 section_table_bytes);
411 goto out;
414 byte_count = printing_pread_data(fsp, buf, &in_pos, section_table_bytes);
415 if (byte_count < section_table_bytes) {
416 DBG_NOTICE("PE file [%s] Section header too short, "
417 "bytes read = %lu\n",
418 fname,
419 (unsigned long)byte_count);
420 goto out;
424 * Iterate the section table looking for
425 * the resource section ".rsrc"
427 for (i = 0; i < num_sections; i++) {
428 int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
430 if (strcmp(".rsrc",
431 &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) {
432 unsigned int section_pos = IVAL(buf,
433 sec_offset+
434 PE_HEADER_SECT_PTR_DATA_OFFSET);
435 unsigned int section_bytes = IVAL(buf,
436 sec_offset+
437 PE_HEADER_SECT_SIZE_DATA_OFFSET);
439 if (section_bytes == 0) {
440 goto out;
443 SAFE_FREE(buf);
444 buf=(char *)SMB_MALLOC(section_bytes);
445 if (buf == NULL) {
446 DBG_ERR("PE file [%s] version malloc "
447 "failed bytes = %d\n",
448 fname,
449 section_bytes);
450 goto out;
454 * Read from the start of the .rsrc
455 * section info
457 in_pos = section_pos;
459 byte_count = printing_pread_data(fsp,
460 buf,
461 &in_pos,
462 section_bytes);
463 if (byte_count < section_bytes) {
464 DBG_NOTICE("PE file "
465 "[%s] .rsrc section too short, "
466 "bytes read = %lu\n",
467 fname,
468 (unsigned long)byte_count);
469 goto out;
472 if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) {
473 goto out;
476 for (i=0;
477 i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE;
478 i++) {
480 * Scan for 1st 3 unicoded bytes
481 * followed by word aligned magic
482 * value.
484 int mpos;
485 bool magic_match = false;
487 if (buf[i] == 'V' &&
488 buf[i+1] == '\0' &&
489 buf[i+2] == 'S') {
490 magic_match = true;
493 if (magic_match == false) {
494 continue;
497 /* Align to next long address */
498 mpos = (i + sizeof(VS_SIGNATURE)*2 +
499 3) & 0xfffffffc;
501 if (IVAL(buf,mpos) == VS_MAGIC_VALUE) {
502 *major = IVAL(buf,
503 mpos+ VS_MAJOR_OFFSET);
504 *minor = IVAL(buf,
505 mpos+ VS_MINOR_OFFSET);
507 DBG_INFO("PE file [%s] Version = "
508 "%08x:%08x (%d.%d.%d.%d)\n",
509 fname,
510 *major,
511 *minor,
512 (*major>>16)&0xffff,
513 *major&0xffff,
514 (*minor>>16)&0xffff,
515 *minor&0xffff);
516 ret = 1;
517 goto out;
523 /* Version info not found, fall back to origin date/time */
524 DBG_DEBUG("PE file [%s] has no version info\n", fname);
525 ret = 0;
527 out:
529 SAFE_FREE(buf);
530 return ret;
533 /****************************************************************************
534 Detect the major and minor version of an NE file.
535 Returns:
537 1 if file is an NE file and we got version numbers,
538 0 if this file is an NE file and we couldn't get the version numbers,
539 -1 on error.
541 NB. buf is passed into and freed inside this function. This is a
542 bad API design, but fixing this is a task for another day.
543 ****************************************************************************/
545 static int handle_ne_file(files_struct *fsp,
546 off_t in_pos,
547 char *fname,
548 char *buf,
549 uint32_t *major,
550 uint32_t *minor)
552 unsigned int i;
553 ssize_t byte_count;
554 int ret = -1;
556 if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
557 DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n",
558 fname,
559 CVAL(buf,NE_HEADER_TARGET_OS_OFFSET));
561 * At this point, we assume the file is in error.
562 * It still could be something else besides a NE file,
563 * but it unlikely at this point.
565 goto out;
568 /* Allocate a bit more space to speed up things */
569 SAFE_FREE(buf);
570 buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE);
571 if (buf == NULL) {
572 DBG_ERR("NE file [%s] malloc failed bytes = %d\n",
573 fname,
574 PE_HEADER_SIZE);
575 goto out;
579 * This is a HACK! I got tired of trying to sort through the
580 * messy 'NE' file format. If anyone wants to clean this up
581 * please have at it, but this works. 'NE' files will
582 * eventually fade away. JRR
584 byte_count = printing_pread_data(fsp, buf, &in_pos, VS_NE_BUF_SIZE);
585 while (byte_count > 0) {
587 * Cover case that should not occur in a well
588 * formed 'NE' .dll file
590 if (byte_count-VS_VERSION_INFO_SIZE <= 0) {
591 break;
594 for(i=0; i<byte_count; i++) {
596 * Fast skip past data that can't
597 * possibly match
599 if (buf[i] != 'V') {
600 byte_count = printing_pread_data(fsp,
601 buf,
602 &in_pos,
603 VS_NE_BUF_SIZE);
604 continue;
608 * Potential match data crosses buf boundry,
609 * move it to beginning of buf, and fill the
610 * buf with as much as it will hold.
612 if (i>byte_count-VS_VERSION_INFO_SIZE) {
613 ssize_t amount_read;
614 ssize_t amount_unused = byte_count-i;
616 memmove(buf, &buf[i], amount_unused);
617 amount_read = printing_pread_data(fsp,
618 &buf[amount_unused],
619 &in_pos,
620 VS_NE_BUF_SIZE- amount_unused);
621 if (amount_read < 0) {
622 DBG_ERR("NE file [%s] Read "
623 "error, errno=%d\n",
624 fname,
625 errno);
626 goto out;
629 if (amount_read + amount_unused <
630 amount_read) {
631 /* Check for integer wrap. */
632 break;
635 byte_count = amount_read +
636 amount_unused;
637 if (byte_count < VS_VERSION_INFO_SIZE) {
638 break;
641 i = 0;
645 * Check that the full signature string and
646 * the magic number that follows exist (not
647 * a perfect solution, but the chances that this
648 * occurs in code is, well, remote. Yes I know
649 * I'm comparing the 'V' twice, as it is
650 * simpler to read the code.
652 if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
654 * Compute skip alignment to next
655 * long address.
657 off_t cpos = in_pos;
658 int skip = -(cpos - (byte_count - i) +
659 sizeof(VS_SIGNATURE)) & 3;
660 if (IVAL(buf,
661 i+sizeof(VS_SIGNATURE)+skip)
662 != 0xfeef04bd) {
663 byte_count = printing_pread_data(fsp,
664 buf,
665 &in_pos,
666 VS_NE_BUF_SIZE);
667 continue;
670 *major = IVAL(buf,
671 i+sizeof(VS_SIGNATURE)+
672 skip+VS_MAJOR_OFFSET);
673 *minor = IVAL(buf,
674 i+sizeof(VS_SIGNATURE)+
675 skip+VS_MINOR_OFFSET);
676 DBG_INFO("NE file [%s] Version "
677 "= %08x:%08x (%d.%d.%d.%d)\n",
678 fname,
679 *major,
680 *minor,
681 (*major>>16)&0xffff,
682 *major&0xffff,
683 (*minor>>16)&0xffff,
684 *minor&0xffff);
685 ret = 1;
686 goto out;
691 /* Version info not found, fall back to origin date/time */
692 DBG_ERR("NE file [%s] Version info not found\n", fname);
693 ret = 0;
695 out:
697 SAFE_FREE(buf);
698 return ret;
701 /****************************************************************************
702 Version information in Microsoft files is held in a VS_VERSION_INFO structure.
703 There are two case to be covered here: PE (Portable Executable) and NE (New
704 Executable) files. Both files support the same INFO structure, but PE files
705 store the signature in unicode, and NE files store it as !unicode.
706 returns -1 on error, 1 on version info found, and 0 on no version info found.
707 ****************************************************************************/
709 static int get_file_version(files_struct *fsp,
710 char *fname,
711 uint32_t *major,
712 uint32_t *minor)
714 char *buf = NULL;
715 ssize_t byte_count;
716 off_t in_pos = fsp->fh->pos;
718 buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE);
719 if (buf == NULL) {
720 DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n",
721 fname,
722 DOS_HEADER_SIZE);
723 goto error_exit;
726 byte_count = printing_pread_data(fsp, buf, &in_pos, DOS_HEADER_SIZE);
727 if (byte_count < DOS_HEADER_SIZE) {
728 DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n",
729 fname,
730 (unsigned long)byte_count);
731 goto no_version_info;
734 /* Is this really a DOS header? */
735 if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
736 DBG_INFO("File [%s] bad DOS magic = 0x%x\n",
737 fname,
738 SVAL(buf,DOS_HEADER_MAGIC_OFFSET));
739 goto no_version_info;
743 * Skip OEM header (if any) and the
744 * DOS stub to start of Windows header.
746 in_pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET);
748 /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
749 byte_count = printing_pread_data(fsp, buf, &in_pos, NE_HEADER_SIZE);
750 if (byte_count < NE_HEADER_SIZE) {
751 DBG_NOTICE("File [%s] Windows header too short, "
752 "bytes read = %lu\n",
753 fname,
754 (unsigned long)byte_count);
756 * Assume this isn't an error...
757 * the file just looks sort of like a PE/NE file
759 goto no_version_info;
763 * The header may be a PE (Portable Executable)
764 * or an NE (New Executable).
766 if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
767 return handle_pe_file(fsp,
768 in_pos,
769 fname,
770 buf,
771 major,
772 minor);
773 } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) ==
774 NE_HEADER_SIGNATURE) {
775 return handle_ne_file(fsp,
776 in_pos,
777 fname,
778 buf,
779 major,
780 minor);
781 } else {
783 * Assume this isn't an error... the file just
784 * looks sort of like a PE/NE file.
786 DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n",
787 fname,
788 IVAL(buf,PE_HEADER_SIGNATURE_OFFSET));
789 /* Fallthrough into no_version_info: */
792 no_version_info:
793 SAFE_FREE(buf);
794 return 0;
796 error_exit:
797 SAFE_FREE(buf);
798 return -1;
801 /****************************************************************************
802 Drivers for Microsoft systems contain multiple files. Often, multiple drivers
803 share one or more files. During the MS installation process files are checked
804 to insure that only a newer version of a shared file is installed over an
805 older version. There are several possibilities for this comparison. If there
806 is no previous version, the new one is newer (obviously). If either file is
807 missing the version info structure, compare the creation date (on Unix use
808 the modification date). Otherwise chose the numerically larger version number.
809 ****************************************************************************/
811 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
813 bool use_version = true;
815 uint32_t new_major;
816 uint32_t new_minor;
817 time_t new_create_time;
819 uint32_t old_major;
820 uint32_t old_minor;
821 time_t old_create_time;
823 struct smb_filename *smb_fname = NULL;
824 files_struct *fsp = NULL;
825 SMB_STRUCT_STAT st;
827 NTSTATUS status;
828 int ret;
830 SET_STAT_INVALID(st);
831 new_create_time = (time_t)0;
832 old_create_time = (time_t)0;
834 /* Get file version info (if available) for previous file (if it exists) */
835 status = driver_unix_convert(conn, old_file, &smb_fname);
836 if (!NT_STATUS_IS_OK(status)) {
837 goto error_exit;
840 status = SMB_VFS_CREATE_FILE(
841 conn, /* conn */
842 NULL, /* req */
843 0, /* root_dir_fid */
844 smb_fname, /* fname */
845 FILE_GENERIC_READ, /* access_mask */
846 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
847 FILE_OPEN, /* create_disposition*/
848 0, /* create_options */
849 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
850 INTERNAL_OPEN_ONLY, /* oplock_request */
851 NULL, /* lease */
852 0, /* allocation_size */
853 0, /* private_flags */
854 NULL, /* sd */
855 NULL, /* ea_list */
856 &fsp, /* result */
857 NULL, /* pinfo */
858 NULL, NULL); /* create context */
860 if (!NT_STATUS_IS_OK(status)) {
861 /* Old file not found, so by definition new file is in fact newer */
862 DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
863 "errno = %d\n", smb_fname_str_dbg(smb_fname),
864 errno));
865 ret = 1;
866 goto done;
868 } else {
869 ret = get_file_version(fsp, old_file, &old_major, &old_minor);
870 if (ret == -1) {
871 goto error_exit;
874 if (!ret) {
875 DEBUG(6,("file_version_is_newer: Version info not found [%s], 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(NULL, fsp, NORMAL_CLOSE);
887 fsp = NULL;
889 /* Get file version info (if available) for new file */
890 status = driver_unix_convert(conn, new_file, &smb_fname);
891 if (!NT_STATUS_IS_OK(status)) {
892 goto error_exit;
895 status = SMB_VFS_CREATE_FILE(
896 conn, /* conn */
897 NULL, /* req */
898 0, /* root_dir_fid */
899 smb_fname, /* fname */
900 FILE_GENERIC_READ, /* access_mask */
901 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
902 FILE_OPEN, /* create_disposition*/
903 0, /* create_options */
904 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
905 INTERNAL_OPEN_ONLY, /* oplock_request */
906 NULL, /* lease */
907 0, /* allocation_size */
908 0, /* private_flags */
909 NULL, /* sd */
910 NULL, /* ea_list */
911 &fsp, /* result */
912 NULL, /* pinfo */
913 NULL, NULL); /* create context */
915 if (!NT_STATUS_IS_OK(status)) {
916 /* New file not found, this shouldn't occur if the caller did its job */
917 DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
918 "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
919 goto error_exit;
921 } else {
922 ret = get_file_version(fsp, new_file, &new_major, &new_minor);
923 if (ret == -1) {
924 goto error_exit;
927 if (!ret) {
928 DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n",
929 new_file));
930 use_version = false;
931 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
932 goto error_exit;
934 new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
935 DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
936 (long)new_create_time));
939 close_file(NULL, fsp, NORMAL_CLOSE);
940 fsp = NULL;
942 if (use_version && (new_major != old_major || new_minor != old_minor)) {
943 /* Compare versions and choose the larger version number */
944 if (new_major > old_major ||
945 (new_major == old_major && new_minor > old_minor)) {
947 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
948 ret = 1;
949 goto done;
951 else {
952 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
953 ret = 0;
954 goto done;
957 } else {
958 /* Compare modification time/dates and choose the newest time/date */
959 if (new_create_time > old_create_time) {
960 DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
961 ret = 1;
962 goto done;
964 else {
965 DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
966 ret = 0;
967 goto done;
971 error_exit:
972 if(fsp)
973 close_file(NULL, fsp, NORMAL_CLOSE);
974 ret = -1;
975 done:
976 TALLOC_FREE(smb_fname);
977 return ret;
980 /****************************************************************************
981 Determine the correct cVersion associated with an architecture and driver
982 ****************************************************************************/
983 static uint32_t get_correct_cversion(struct auth_session_info *session_info,
984 const char *architecture,
985 const char *driverpath_in,
986 const char *driver_directory,
987 WERROR *perr)
989 int cversion = -1;
990 NTSTATUS nt_status;
991 struct smb_filename *smb_fname = NULL;
992 files_struct *fsp = NULL;
993 connection_struct *conn = NULL;
994 struct smb_filename *oldcwd_fname = NULL;
995 char *printdollar = NULL;
996 char *printdollar_path = NULL;
997 char *working_dir = NULL;
998 int printdollar_snum;
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 return 0;
1009 /* If architecture is Windows x64, the version is always 3. */
1010 if (strcmp(architecture, SPL_ARCH_X64) == 0) {
1011 DEBUG(10,("get_correct_cversion: Driver is x64, cversion = 3\n"));
1012 *perr = WERR_OK;
1013 return 3;
1016 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
1017 if (!printdollar) {
1018 *perr = WERR_NOT_ENOUGH_MEMORY;
1019 return -1;
1021 if (printdollar_snum == -1) {
1022 *perr = WERR_BAD_NET_NAME;
1023 return -1;
1026 printdollar_path = lp_path(talloc_tos(), printdollar_snum);
1027 if (printdollar_path == NULL) {
1028 *perr = WERR_NOT_ENOUGH_MEMORY;
1029 return -1;
1032 working_dir = talloc_asprintf(talloc_tos(),
1033 "%s/%s",
1034 printdollar_path,
1035 architecture);
1037 * If the driver has been uploaded into a temorpary driver
1038 * directory, switch to the driver directory.
1040 if (driver_directory != NULL) {
1041 working_dir = talloc_asprintf(talloc_tos(), "%s/%s/%s",
1042 printdollar_path,
1043 architecture,
1044 driver_directory);
1047 nt_status = create_conn_struct_cwd(talloc_tos(),
1048 server_event_context(),
1049 server_messaging_context(),
1050 &conn,
1051 printdollar_snum,
1052 working_dir,
1053 session_info, &oldcwd_fname);
1054 if (!NT_STATUS_IS_OK(nt_status)) {
1055 DEBUG(0,("get_correct_cversion: create_conn_struct "
1056 "returned %s\n", nt_errstr(nt_status)));
1057 *perr = ntstatus_to_werror(nt_status);
1058 return -1;
1061 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1062 if (!NT_STATUS_IS_OK(nt_status)) {
1063 DEBUG(0, ("failed set force user / group\n"));
1064 *perr = ntstatus_to_werror(nt_status);
1065 goto error_free_conn;
1068 if (!become_user_by_session(conn, session_info)) {
1069 DEBUG(0, ("failed to become user\n"));
1070 *perr = WERR_ACCESS_DENIED;
1071 goto error_free_conn;
1075 * We switch to the directory where the driver files are located,
1076 * so only work on the file names
1078 nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
1079 if (!NT_STATUS_IS_OK(nt_status)) {
1080 *perr = ntstatus_to_werror(nt_status);
1081 goto error_exit;
1084 nt_status = vfs_file_exist(conn, smb_fname);
1085 if (!NT_STATUS_IS_OK(nt_status)) {
1086 DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
1087 *perr = WERR_FILE_NOT_FOUND;
1088 goto error_exit;
1091 nt_status = SMB_VFS_CREATE_FILE(
1092 conn, /* conn */
1093 NULL, /* req */
1094 0, /* root_dir_fid */
1095 smb_fname, /* fname */
1096 FILE_GENERIC_READ, /* access_mask */
1097 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1098 FILE_OPEN, /* create_disposition*/
1099 0, /* create_options */
1100 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
1101 INTERNAL_OPEN_ONLY, /* oplock_request */
1102 NULL, /* lease */
1103 0, /* private_flags */
1104 0, /* allocation_size */
1105 NULL, /* sd */
1106 NULL, /* ea_list */
1107 &fsp, /* result */
1108 NULL, /* pinfo */
1109 NULL, NULL); /* create context */
1111 if (!NT_STATUS_IS_OK(nt_status)) {
1112 DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
1113 "%d\n", smb_fname_str_dbg(smb_fname), errno));
1114 *perr = WERR_ACCESS_DENIED;
1115 goto error_exit;
1116 } else {
1117 uint32_t major;
1118 uint32_t minor;
1119 int ret;
1121 ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
1122 if (ret == -1) {
1123 *perr = WERR_INVALID_PARAMETER;
1124 goto error_exit;
1125 } else if (!ret) {
1126 DEBUG(6,("get_correct_cversion: Version info not "
1127 "found [%s]\n",
1128 smb_fname_str_dbg(smb_fname)));
1129 *perr = WERR_INVALID_PARAMETER;
1130 goto error_exit;
1134 * This is a Microsoft'ism. See references in MSDN to VER_FILEVERSION
1135 * for more details. Version in this case is not just the version of the
1136 * file, but the version in the sense of kernal mode (2) vs. user mode
1137 * (3) drivers. Other bits of the version fields are the version info.
1138 * JRR 010716
1140 cversion = major & 0x0000ffff;
1141 switch (cversion) {
1142 case 2: /* WinNT drivers */
1143 case 3: /* Win2K drivers */
1144 break;
1146 default:
1147 DEBUG(6,("get_correct_cversion: cversion "
1148 "invalid [%s] cversion = %d\n",
1149 smb_fname_str_dbg(smb_fname),
1150 cversion));
1151 goto error_exit;
1154 DEBUG(10,("get_correct_cversion: Version info found [%s] major"
1155 " = 0x%x minor = 0x%x\n",
1156 smb_fname_str_dbg(smb_fname), major, minor));
1159 DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
1160 smb_fname_str_dbg(smb_fname), cversion));
1161 *perr = WERR_OK;
1163 error_exit:
1164 unbecome_user();
1165 error_free_conn:
1166 TALLOC_FREE(smb_fname);
1167 if (fsp != NULL) {
1168 close_file(NULL, fsp, NORMAL_CLOSE);
1170 if (conn != NULL) {
1171 vfs_ChDir(conn, oldcwd_fname);
1172 TALLOC_FREE(oldcwd_fname);
1173 SMB_VFS_DISCONNECT(conn);
1174 conn_free(conn);
1176 if (!W_ERROR_IS_OK(*perr)) {
1177 cversion = -1;
1180 return cversion;
1183 /****************************************************************************
1184 ****************************************************************************/
1186 #define strip_driver_path(_mem_ctx, _element) do { \
1187 if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
1188 (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
1189 W_ERROR_HAVE_NO_MEMORY((_element)); \
1191 } while (0);
1193 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
1194 struct auth_session_info *session_info,
1195 const char *architecture,
1196 const char **driver_path,
1197 const char **data_file,
1198 const char **config_file,
1199 const char **help_file,
1200 struct spoolss_StringArray *dependent_files,
1201 enum spoolss_DriverOSVersion *version,
1202 uint32_t flags,
1203 const char **driver_directory)
1205 const char *short_architecture;
1206 int i;
1207 WERROR err;
1208 char *_p;
1210 if (!*driver_path || !*data_file) {
1211 return WERR_INVALID_PARAMETER;
1214 if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
1215 return WERR_INVALID_PARAMETER;
1218 if (flags & APD_COPY_FROM_DIRECTORY) {
1219 char *path;
1220 char *q;
1223 * driver_path is set to:
1225 * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
1227 path = talloc_strdup(mem_ctx, *driver_path);
1228 if (path == NULL) {
1229 return WERR_NOT_ENOUGH_MEMORY;
1232 /* Remove pscript5.dll */
1233 q = strrchr_m(path, '\\');
1234 if (q == NULL) {
1235 return WERR_INVALID_PARAMETER;
1237 *q = '\0';
1239 /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
1240 q = strrchr_m(path, '\\');
1241 if (q == NULL) {
1242 return WERR_INVALID_PARAMETER;
1246 * Set driver_directory to:
1248 * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
1250 * This is the directory where all the files have been uploaded
1252 *driver_directory = q + 1;
1255 /* clean up the driver name.
1256 * we can get .\driver.dll
1257 * or worse c:\windows\system\driver.dll !
1259 /* using an intermediate string to not have overlaping memcpy()'s */
1261 strip_driver_path(mem_ctx, *driver_path);
1262 strip_driver_path(mem_ctx, *data_file);
1263 if (*config_file) {
1264 strip_driver_path(mem_ctx, *config_file);
1266 if (help_file) {
1267 strip_driver_path(mem_ctx, *help_file);
1270 if (dependent_files && dependent_files->string) {
1271 for (i=0; dependent_files->string[i]; i++) {
1272 strip_driver_path(mem_ctx, dependent_files->string[i]);
1276 short_architecture = get_short_archi(architecture);
1277 if (!short_architecture) {
1278 return WERR_UNKNOWN_PRINTER_DRIVER;
1281 /* jfm:7/16/2000 the client always sends the cversion=0.
1282 * The server should check which version the driver is by reading
1283 * the PE header of driver->driverpath.
1285 * For Windows 95/98 the version is 0 (so the value sent is correct)
1286 * For Windows NT (the architecture doesn't matter)
1287 * NT 3.1: cversion=0
1288 * NT 3.5/3.51: cversion=1
1289 * NT 4: cversion=2
1290 * NT2K: cversion=3
1293 *version = get_correct_cversion(session_info,
1294 short_architecture,
1295 *driver_path,
1296 *driver_directory,
1297 &err);
1298 if (*version == -1) {
1299 return err;
1302 return WERR_OK;
1305 /****************************************************************************
1306 ****************************************************************************/
1308 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
1309 struct auth_session_info *session_info,
1310 struct spoolss_AddDriverInfoCtr *r,
1311 uint32_t flags,
1312 const char **driver_directory)
1314 switch (r->level) {
1315 case 3:
1316 return clean_up_driver_struct_level(mem_ctx, session_info,
1317 r->info.info3->architecture,
1318 &r->info.info3->driver_path,
1319 &r->info.info3->data_file,
1320 &r->info.info3->config_file,
1321 &r->info.info3->help_file,
1322 r->info.info3->dependent_files,
1323 &r->info.info3->version,
1324 flags,
1325 driver_directory);
1326 case 6:
1327 return clean_up_driver_struct_level(mem_ctx, session_info,
1328 r->info.info6->architecture,
1329 &r->info.info6->driver_path,
1330 &r->info.info6->data_file,
1331 &r->info.info6->config_file,
1332 &r->info.info6->help_file,
1333 r->info.info6->dependent_files,
1334 &r->info.info6->version,
1335 flags,
1336 driver_directory);
1337 case 8:
1338 return clean_up_driver_struct_level(mem_ctx, session_info,
1339 r->info.info8->architecture,
1340 &r->info.info8->driver_path,
1341 &r->info.info8->data_file,
1342 &r->info.info8->config_file,
1343 &r->info.info8->help_file,
1344 r->info.info8->dependent_files,
1345 &r->info.info8->version,
1346 flags,
1347 driver_directory);
1348 default:
1349 return WERR_NOT_SUPPORTED;
1353 /****************************************************************************
1354 This function sucks and should be replaced. JRA.
1355 ****************************************************************************/
1357 static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
1358 const struct spoolss_AddDriverInfo6 *src)
1360 dst->version = src->version;
1362 dst->driver_name = src->driver_name;
1363 dst->architecture = src->architecture;
1364 dst->driver_path = src->driver_path;
1365 dst->data_file = src->data_file;
1366 dst->config_file = src->config_file;
1367 dst->help_file = src->help_file;
1368 dst->monitor_name = src->monitor_name;
1369 dst->default_datatype = src->default_datatype;
1370 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1371 dst->dependent_files = src->dependent_files;
1374 static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
1375 const struct spoolss_AddDriverInfo8 *src)
1377 dst->version = src->version;
1379 dst->driver_name = src->driver_name;
1380 dst->architecture = src->architecture;
1381 dst->driver_path = src->driver_path;
1382 dst->data_file = src->data_file;
1383 dst->config_file = src->config_file;
1384 dst->help_file = src->help_file;
1385 dst->monitor_name = src->monitor_name;
1386 dst->default_datatype = src->default_datatype;
1387 dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
1388 dst->dependent_files = src->dependent_files;
1391 /****************************************************************************
1392 ****************************************************************************/
1394 static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
1395 connection_struct *conn,
1396 const char *driver_file,
1397 const char *short_architecture,
1398 uint32_t driver_version,
1399 uint32_t version,
1400 const char *driver_directory)
1402 struct smb_filename *smb_fname_old = NULL;
1403 struct smb_filename *smb_fname_new = NULL;
1404 char *old_name = NULL;
1405 char *new_name = NULL;
1406 NTSTATUS status;
1407 WERROR ret;
1409 if (driver_directory != NULL) {
1410 old_name = talloc_asprintf(mem_ctx,
1411 "%s/%s/%s",
1412 short_architecture,
1413 driver_directory,
1414 driver_file);
1415 } else {
1416 old_name = talloc_asprintf(mem_ctx,
1417 "%s/%s",
1418 short_architecture,
1419 driver_file);
1421 if (old_name == NULL) {
1422 return WERR_NOT_ENOUGH_MEMORY;
1425 new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
1426 short_architecture, driver_version, driver_file);
1427 if (new_name == NULL) {
1428 TALLOC_FREE(old_name);
1429 return WERR_NOT_ENOUGH_MEMORY;
1432 if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
1434 status = driver_unix_convert(conn, old_name, &smb_fname_old);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 ret = WERR_NOT_ENOUGH_MEMORY;
1437 goto out;
1440 /* Setup a synthetic smb_filename struct */
1441 smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
1442 if (!smb_fname_new) {
1443 ret = WERR_NOT_ENOUGH_MEMORY;
1444 goto out;
1447 smb_fname_new->base_name = new_name;
1449 DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
1450 "'%s'\n", smb_fname_old->base_name,
1451 smb_fname_new->base_name));
1453 status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
1454 OPENX_FILE_EXISTS_TRUNCATE |
1455 OPENX_FILE_CREATE_IF_NOT_EXIST,
1456 0, false);
1458 if (!NT_STATUS_IS_OK(status)) {
1459 DEBUG(0,("move_driver_file_to_download_area: Unable "
1460 "to rename [%s] to [%s]: %s\n",
1461 smb_fname_old->base_name, new_name,
1462 nt_errstr(status)));
1463 ret = WERR_APP_INIT_FAILURE;
1464 goto out;
1468 ret = WERR_OK;
1469 out:
1470 TALLOC_FREE(smb_fname_old);
1471 TALLOC_FREE(smb_fname_new);
1472 return ret;
1475 WERROR move_driver_to_download_area(struct auth_session_info *session_info,
1476 struct spoolss_AddDriverInfoCtr *r,
1477 const char *driver_directory)
1479 struct spoolss_AddDriverInfo3 *driver;
1480 struct spoolss_AddDriverInfo3 converted_driver;
1481 const char *short_architecture;
1482 struct smb_filename *smb_dname = NULL;
1483 char *new_dir = NULL;
1484 connection_struct *conn = NULL;
1485 NTSTATUS nt_status;
1486 int i;
1487 TALLOC_CTX *ctx = talloc_tos();
1488 int ver = 0;
1489 struct smb_filename *oldcwd_fname = NULL;
1490 char *printdollar = NULL;
1491 int printdollar_snum;
1492 WERROR err = WERR_OK;
1494 switch (r->level) {
1495 case 3:
1496 driver = r->info.info3;
1497 break;
1498 case 6:
1499 convert_level_6_to_level3(&converted_driver, r->info.info6);
1500 driver = &converted_driver;
1501 break;
1502 case 8:
1503 convert_level_8_to_level3(&converted_driver, r->info.info8);
1504 driver = &converted_driver;
1505 break;
1506 default:
1507 DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
1508 return WERR_INVALID_LEVEL;
1511 short_architecture = get_short_archi(driver->architecture);
1512 if (!short_architecture) {
1513 return WERR_UNKNOWN_PRINTER_DRIVER;
1516 printdollar_snum = find_service(ctx, "print$", &printdollar);
1517 if (!printdollar) {
1518 return WERR_NOT_ENOUGH_MEMORY;
1520 if (printdollar_snum == -1) {
1521 return WERR_BAD_NET_NAME;
1524 nt_status = create_conn_struct_cwd(talloc_tos(),
1525 server_event_context(),
1526 server_messaging_context(),
1527 &conn,
1528 printdollar_snum,
1529 lp_path(talloc_tos(), printdollar_snum),
1530 session_info, &oldcwd_fname);
1531 if (!NT_STATUS_IS_OK(nt_status)) {
1532 DEBUG(0,("move_driver_to_download_area: create_conn_struct "
1533 "returned %s\n", nt_errstr(nt_status)));
1534 err = ntstatus_to_werror(nt_status);
1535 return err;
1538 nt_status = set_conn_force_user_group(conn, printdollar_snum);
1539 if (!NT_STATUS_IS_OK(nt_status)) {
1540 DEBUG(0, ("failed set force user / group\n"));
1541 err = ntstatus_to_werror(nt_status);
1542 goto err_free_conn;
1545 if (!become_user_by_session(conn, session_info)) {
1546 DEBUG(0, ("failed to become user\n"));
1547 err = WERR_ACCESS_DENIED;
1548 goto err_free_conn;
1551 new_dir = talloc_asprintf(ctx,
1552 "%s/%d",
1553 short_architecture,
1554 driver->version);
1555 if (!new_dir) {
1556 err = WERR_NOT_ENOUGH_MEMORY;
1557 goto err_exit;
1559 nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
1560 if (!NT_STATUS_IS_OK(nt_status)) {
1561 err = WERR_NOT_ENOUGH_MEMORY;
1562 goto err_exit;
1565 DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
1567 nt_status = create_directory(conn, NULL, smb_dname);
1568 if (!NT_STATUS_IS_OK(nt_status)
1569 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1570 DEBUG(0, ("failed to create driver destination directory: %s\n",
1571 nt_errstr(nt_status)));
1572 err = ntstatus_to_werror(nt_status);
1573 goto err_exit;
1576 /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
1577 * listed for this driver which has already been moved, skip it (note:
1578 * drivers may list the same file name several times. Then check if the
1579 * file already exists in archi\version\, if so, check that the version
1580 * info (or time stamps if version info is unavailable) is newer (or the
1581 * date is later). If it is, move it to archi\version\filexxx.yyy.
1582 * Otherwise, delete the file.
1584 * If a file is not moved to archi\version\ because of an error, all the
1585 * rest of the 'unmoved' driver files are removed from archi\. If one or
1586 * more of the driver's files was already moved to archi\version\, it
1587 * potentially leaves the driver in a partially updated state. Version
1588 * trauma will most likely occur if an client attempts to use any printer
1589 * bound to the driver. Perhaps a rewrite to make sure the moves can be
1590 * done is appropriate... later JRR
1593 DEBUG(5,("Moving files now !\n"));
1595 if (driver->driver_path && strlen(driver->driver_path)) {
1597 err = move_driver_file_to_download_area(ctx,
1598 conn,
1599 driver->driver_path,
1600 short_architecture,
1601 driver->version,
1602 ver,
1603 driver_directory);
1604 if (!W_ERROR_IS_OK(err)) {
1605 goto err_exit;
1609 if (driver->data_file && strlen(driver->data_file)) {
1610 if (!strequal(driver->data_file, driver->driver_path)) {
1612 err = move_driver_file_to_download_area(ctx,
1613 conn,
1614 driver->data_file,
1615 short_architecture,
1616 driver->version,
1617 ver,
1618 driver_directory);
1619 if (!W_ERROR_IS_OK(err)) {
1620 goto err_exit;
1625 if (driver->config_file && strlen(driver->config_file)) {
1626 if (!strequal(driver->config_file, driver->driver_path) &&
1627 !strequal(driver->config_file, driver->data_file)) {
1629 err = move_driver_file_to_download_area(ctx,
1630 conn,
1631 driver->config_file,
1632 short_architecture,
1633 driver->version,
1634 ver,
1635 driver_directory);
1636 if (!W_ERROR_IS_OK(err)) {
1637 goto err_exit;
1642 if (driver->help_file && strlen(driver->help_file)) {
1643 if (!strequal(driver->help_file, driver->driver_path) &&
1644 !strequal(driver->help_file, driver->data_file) &&
1645 !strequal(driver->help_file, driver->config_file)) {
1647 err = move_driver_file_to_download_area(ctx,
1648 conn,
1649 driver->help_file,
1650 short_architecture,
1651 driver->version,
1652 ver,
1653 driver_directory);
1654 if (!W_ERROR_IS_OK(err)) {
1655 goto err_exit;
1660 if (driver->dependent_files && driver->dependent_files->string) {
1661 for (i=0; driver->dependent_files->string[i]; i++) {
1662 if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
1663 !strequal(driver->dependent_files->string[i], driver->data_file) &&
1664 !strequal(driver->dependent_files->string[i], driver->config_file) &&
1665 !strequal(driver->dependent_files->string[i], driver->help_file)) {
1666 int j;
1667 for (j=0; j < i; j++) {
1668 if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
1669 goto NextDriver;
1673 err = move_driver_file_to_download_area(ctx,
1674 conn,
1675 driver->dependent_files->string[i],
1676 short_architecture,
1677 driver->version,
1678 ver,
1679 driver_directory);
1680 if (!W_ERROR_IS_OK(err)) {
1681 goto err_exit;
1684 NextDriver: ;
1688 err = WERR_OK;
1689 err_exit:
1690 unbecome_user();
1691 err_free_conn:
1692 TALLOC_FREE(smb_dname);
1694 if (conn != NULL) {
1695 vfs_ChDir(conn, oldcwd_fname);
1696 TALLOC_FREE(oldcwd_fname);
1697 SMB_VFS_DISCONNECT(conn);
1698 conn_free(conn);
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 int snum;
1714 int n_services = lp_numservices();
1715 bool in_use = false;
1716 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
1717 WERROR result;
1719 if (!r) {
1720 return false;
1723 DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
1725 /* loop through the printers.tdb and check for the drivername */
1727 for (snum=0; snum<n_services && !in_use; snum++) {
1728 if (!lp_snum_ok(snum) || !lp_printable(snum)) {
1729 continue;
1732 result = winreg_get_printer(mem_ctx, b,
1733 lp_servicename(talloc_tos(), snum),
1734 &pinfo2);
1735 if (!W_ERROR_IS_OK(result)) {
1736 continue; /* skip */
1739 if (strequal(r->driver_name, pinfo2->drivername)) {
1740 in_use = true;
1743 TALLOC_FREE(pinfo2);
1746 DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
1748 if ( in_use ) {
1749 struct spoolss_DriverInfo8 *driver = NULL;
1750 WERROR werr;
1752 DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
1754 /* we can still remove the driver if there is one of
1755 "Windows NT x86" version 2 or 3 left */
1757 if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
1758 if (r->version == 2) {
1759 werr = winreg_get_driver(mem_ctx, b,
1760 r->architecture,
1761 r->driver_name,
1762 3, &driver);
1763 } else if (r->version == 3) {
1764 werr = winreg_get_driver(mem_ctx, b,
1765 r->architecture,
1766 r->driver_name,
1767 2, &driver);
1768 } else {
1769 DBG_ERR("Unknown driver version (%d)\n",
1770 r->version);
1771 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1773 } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
1774 werr = winreg_get_driver(mem_ctx, b,
1775 SPOOLSS_ARCHITECTURE_NT_X86,
1776 r->driver_name,
1777 DRIVER_ANY_VERSION,
1778 &driver);
1779 } else {
1780 DBG_ERR("Unknown driver architecture: %s\n",
1781 r->architecture);
1782 werr = WERR_UNKNOWN_PRINTER_DRIVER;
1785 /* now check the error code */
1787 if ( W_ERROR_IS_OK(werr) ) {
1788 /* it's ok to remove the driver, we have other architctures left */
1789 in_use = false;
1790 talloc_free(driver);
1794 /* report that the driver is not in use by default */
1796 return in_use;
1800 /**********************************************************************
1801 Check to see if a ogiven file is in use by *info
1802 *********************************************************************/
1804 static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
1806 int i = 0;
1808 if ( !info )
1809 return False;
1811 /* mz: skip files that are in the list but already deleted */
1812 if (!file || !file[0]) {
1813 return false;
1816 if (strequal(file, info->driver_path))
1817 return True;
1819 if (strequal(file, info->data_file))
1820 return True;
1822 if (strequal(file, info->config_file))
1823 return True;
1825 if (strequal(file, info->help_file))
1826 return True;
1828 /* see of there are any dependent files to examine */
1830 if (!info->dependent_files)
1831 return False;
1833 while (info->dependent_files[i] && *info->dependent_files[i]) {
1834 if (strequal(file, info->dependent_files[i]))
1835 return True;
1836 i++;
1839 return False;
1843 /**********************************************************************
1844 Utility function to remove the dependent file pointed to by the
1845 input parameter from the list
1846 *********************************************************************/
1848 static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
1851 /* bump everything down a slot */
1853 while (files && files[idx+1]) {
1854 files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
1855 idx++;
1858 files[idx] = NULL;
1860 return;
1863 /**********************************************************************
1864 Check if any of the files used by src are also used by drv
1865 *********************************************************************/
1867 static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
1868 struct spoolss_DriverInfo8 *src,
1869 const struct spoolss_DriverInfo8 *drv)
1871 bool in_use = False;
1872 int i = 0;
1874 if ( !src || !drv )
1875 return False;
1877 /* check each file. Remove it from the src structure if it overlaps */
1879 if (drv_file_in_use(src->driver_path, drv)) {
1880 in_use = True;
1881 DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
1882 src->driver_path = talloc_strdup(mem_ctx, "");
1883 if (!src->driver_path) { return false; }
1886 if (drv_file_in_use(src->data_file, drv)) {
1887 in_use = True;
1888 DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
1889 src->data_file = talloc_strdup(mem_ctx, "");
1890 if (!src->data_file) { return false; }
1893 if (drv_file_in_use(src->config_file, drv)) {
1894 in_use = True;
1895 DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
1896 src->config_file = talloc_strdup(mem_ctx, "");
1897 if (!src->config_file) { return false; }
1900 if (drv_file_in_use(src->help_file, drv)) {
1901 in_use = True;
1902 DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
1903 src->help_file = talloc_strdup(mem_ctx, "");
1904 if (!src->help_file) { return false; }
1907 /* are there any dependentfiles to examine? */
1909 if (!src->dependent_files)
1910 return in_use;
1912 while (src->dependent_files[i] && *src->dependent_files[i]) {
1913 if (drv_file_in_use(src->dependent_files[i], drv)) {
1914 in_use = True;
1915 DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
1916 trim_dependent_file(mem_ctx, src->dependent_files, i);
1917 } else
1918 i++;
1921 return in_use;
1924 /****************************************************************************
1925 Determine whether or not a particular driver files are currently being
1926 used by any other driver.
1928 Return value is True if any files were in use by other drivers
1929 and False otherwise.
1931 Upon return, *info has been modified to only contain the driver files
1932 which are not in use
1934 Fix from mz:
1936 This needs to check all drivers to ensure that all files in use
1937 have been removed from *info, not just the ones in the first
1938 match.
1939 ****************************************************************************/
1941 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
1942 struct dcerpc_binding_handle *b,
1943 struct spoolss_DriverInfo8 *info)
1945 int i;
1946 uint32_t version;
1947 struct spoolss_DriverInfo8 *driver;
1948 bool in_use = false;
1949 uint32_t num_drivers;
1950 const char **drivers;
1951 WERROR result;
1953 if ( !info )
1954 return False;
1956 version = info->version;
1958 /* loop over all driver versions */
1960 DEBUG(5,("printer_driver_files_in_use: Beginning search of drivers...\n"));
1962 /* get the list of drivers */
1964 result = winreg_get_driver_list(mem_ctx, b,
1965 info->architecture, version,
1966 &num_drivers, &drivers);
1967 if (!W_ERROR_IS_OK(result)) {
1968 return true;
1971 DEBUGADD(4, ("we have:[%d] drivers in environment [%s] and version [%d]\n",
1972 num_drivers, info->architecture, version));
1974 /* check each driver for overlap in files */
1976 for (i = 0; i < num_drivers; i++) {
1977 DEBUGADD(5,("\tdriver: [%s]\n", drivers[i]));
1979 driver = NULL;
1981 result = winreg_get_driver(mem_ctx, b,
1982 info->architecture, drivers[i],
1983 version, &driver);
1984 if (!W_ERROR_IS_OK(result)) {
1985 talloc_free(drivers);
1986 return True;
1989 /* check if d2 uses any files from d1 */
1990 /* only if this is a different driver than the one being deleted */
1992 if (!strequal(info->driver_name, driver->driver_name)) {
1993 if (trim_overlap_drv_files(mem_ctx, info, driver)) {
1994 /* mz: Do not instantly return -
1995 * we need to ensure this file isn't
1996 * also in use by other drivers. */
1997 in_use = true;
2001 talloc_free(driver);
2004 talloc_free(drivers);
2006 DEBUG(5,("printer_driver_files_in_use: Completed search of drivers...\n"));
2008 return in_use;
2011 static NTSTATUS driver_unlink_internals(connection_struct *conn,
2012 const char *short_arch,
2013 int vers,
2014 const char *fname)
2016 TALLOC_CTX *tmp_ctx = talloc_new(conn);
2017 struct smb_filename *smb_fname = NULL;
2018 char *print_dlr_path;
2019 NTSTATUS status = NT_STATUS_NO_MEMORY;
2021 print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
2022 short_arch, vers, fname);
2023 if (print_dlr_path == NULL) {
2024 goto err_out;
2027 smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
2028 if (smb_fname == NULL) {
2029 goto err_out;
2032 status = unlink_internals(conn, NULL, 0, smb_fname, false);
2033 err_out:
2034 talloc_free(tmp_ctx);
2035 return status;
2038 /****************************************************************************
2039 Actually delete the driver files. Make sure that
2040 printer_driver_files_in_use() return False before calling
2041 this.
2042 ****************************************************************************/
2044 bool delete_driver_files(const struct auth_session_info *session_info,
2045 const struct spoolss_DriverInfo8 *r)
2047 const char *short_arch;
2048 connection_struct *conn;
2049 NTSTATUS nt_status;
2050 struct smb_filename *oldcwd_fname = NULL;
2051 char *printdollar = NULL;
2052 int printdollar_snum;
2053 bool ret = false;
2055 if (!r) {
2056 return false;
2059 DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
2060 r->driver_name, r->version));
2062 printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
2063 if (!printdollar) {
2064 return false;
2066 if (printdollar_snum == -1) {
2067 return false;
2070 nt_status = create_conn_struct_cwd(talloc_tos(),
2071 server_event_context(),
2072 server_messaging_context(),
2073 &conn,
2074 printdollar_snum,
2075 lp_path(talloc_tos(), printdollar_snum),
2076 session_info, &oldcwd_fname);
2077 if (!NT_STATUS_IS_OK(nt_status)) {
2078 DEBUG(0,("delete_driver_files: create_conn_struct "
2079 "returned %s\n", nt_errstr(nt_status)));
2080 return false;
2083 nt_status = set_conn_force_user_group(conn, printdollar_snum);
2084 if (!NT_STATUS_IS_OK(nt_status)) {
2085 DEBUG(0, ("failed set force user / group\n"));
2086 ret = false;
2087 goto err_free_conn;
2090 if (!become_user_by_session(conn, session_info)) {
2091 DEBUG(0, ("failed to become user\n"));
2092 ret = false;
2093 goto err_free_conn;
2096 if ( !CAN_WRITE(conn) ) {
2097 DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
2098 ret = false;
2099 goto err_out;
2102 short_arch = get_short_archi(r->architecture);
2103 if (short_arch == NULL) {
2104 DEBUG(0, ("bad architecture %s\n", r->architecture));
2105 ret = false;
2106 goto err_out;
2109 /* now delete the files */
2111 if (r->driver_path && r->driver_path[0]) {
2112 DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
2113 driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
2116 if (r->config_file && r->config_file[0]) {
2117 DEBUG(10,("deleting configfile [%s]\n", r->config_file));
2118 driver_unlink_internals(conn, short_arch, r->version, r->config_file);
2121 if (r->data_file && r->data_file[0]) {
2122 DEBUG(10,("deleting datafile [%s]\n", r->data_file));
2123 driver_unlink_internals(conn, short_arch, r->version, r->data_file);
2126 if (r->help_file && r->help_file[0]) {
2127 DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
2128 driver_unlink_internals(conn, short_arch, r->version, r->help_file);
2131 if (r->dependent_files) {
2132 int i = 0;
2133 while (r->dependent_files[i] && r->dependent_files[i][0]) {
2134 DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
2135 driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
2136 i++;
2140 ret = true;
2141 err_out:
2142 unbecome_user();
2143 err_free_conn:
2144 if (conn != NULL) {
2145 vfs_ChDir(conn, oldcwd_fname);
2146 TALLOC_FREE(oldcwd_fname);
2147 SMB_VFS_DISCONNECT(conn);
2148 conn_free(conn);
2150 return ret;
2153 /* error code:
2154 0: everything OK
2155 1: level not implemented
2156 2: file doesn't exist
2157 3: can't allocate memory
2158 4: can't free memory
2159 5: non existent struct
2163 A printer and a printer driver are 2 different things.
2164 NT manages them separatelly, Samba does the same.
2165 Why ? Simply because it's easier and it makes sense !
2167 Now explanation: You have 3 printers behind your samba server,
2168 2 of them are the same make and model (laser A and B). But laser B
2169 has an 3000 sheet feeder and laser A doesn't such an option.
2170 Your third printer is an old dot-matrix model for the accounting :-).
2172 If the /usr/local/samba/lib directory (default dir), you will have
2173 5 files to describe all of this.
2175 3 files for the printers (1 by printer):
2176 NTprinter_laser A
2177 NTprinter_laser B
2178 NTprinter_accounting
2179 2 files for the drivers (1 for the laser and 1 for the dot matrix)
2180 NTdriver_printer model X
2181 NTdriver_printer model Y
2183 jfm: I should use this comment for the text file to explain
2184 same thing for the forms BTW.
2185 Je devrais mettre mes commentaires en francais, ca serait mieux :-)
2189 /* Convert generic access rights to printer object specific access rights.
2190 It turns out that NT4 security descriptors use generic access rights and
2191 NT5 the object specific ones. */
2193 void map_printer_permissions(struct security_descriptor *sd)
2195 int i;
2197 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2198 se_map_generic(&sd->dacl->aces[i].access_mask,
2199 &printer_generic_mapping);
2203 void map_job_permissions(struct security_descriptor *sd)
2205 int i;
2207 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
2208 se_map_generic(&sd->dacl->aces[i].access_mask,
2209 &job_generic_mapping);
2214 /****************************************************************************
2215 Check a user has permissions to perform the given operation. We use the
2216 permission constants defined in include/rpc_spoolss.h to check the various
2217 actions we perform when checking printer access.
2219 PRINTER_ACCESS_ADMINISTER:
2220 print_queue_pause, print_queue_resume, update_printer_sec,
2221 update_printer, spoolss_addprinterex_level_2,
2222 _spoolss_setprinterdata
2224 PRINTER_ACCESS_USE:
2225 print_job_start
2227 JOB_ACCESS_ADMINISTER:
2228 print_job_delete, print_job_pause, print_job_resume,
2229 print_queue_purge
2231 Try access control in the following order (for performance reasons):
2232 1) root and SE_PRINT_OPERATOR can do anything (easy check)
2233 2) check security descriptor (bit comparisons in memory)
2234 3) "printer admins" (may result in numerous calls to winbind)
2236 ****************************************************************************/
2237 WERROR print_access_check(const struct auth_session_info *session_info,
2238 struct messaging_context *msg_ctx, int snum,
2239 int access_type)
2241 struct spoolss_security_descriptor *secdesc = NULL;
2242 uint32_t access_granted;
2243 size_t sd_size;
2244 NTSTATUS status;
2245 WERROR result;
2246 const char *pname;
2247 TALLOC_CTX *mem_ctx = NULL;
2249 /* If user is NULL then use the current_user structure */
2251 /* Always allow root or SE_PRINT_OPERATROR to do anything */
2253 if ((session_info->unix_token->uid == sec_initial_uid())
2254 || security_token_has_privilege(session_info->security_token,
2255 SEC_PRIV_PRINT_OPERATOR)) {
2256 return WERR_OK;
2259 /* Get printer name */
2261 pname = lp_printername(talloc_tos(), snum);
2263 if (!pname || !*pname) {
2264 return WERR_ACCESS_DENIED;
2267 /* Get printer security descriptor */
2269 if(!(mem_ctx = talloc_init("print_access_check"))) {
2270 return WERR_NOT_ENOUGH_MEMORY;
2273 result = winreg_get_printer_secdesc_internal(mem_ctx,
2274 get_session_info_system(),
2275 msg_ctx,
2276 pname,
2277 &secdesc);
2278 if (!W_ERROR_IS_OK(result)) {
2279 talloc_destroy(mem_ctx);
2280 return WERR_NOT_ENOUGH_MEMORY;
2283 if (access_type == JOB_ACCESS_ADMINISTER) {
2284 struct spoolss_security_descriptor *parent_secdesc = secdesc;
2286 /* Create a child security descriptor to check permissions
2287 against. This is because print jobs are child objects
2288 objects of a printer. */
2289 status = se_create_child_secdesc(mem_ctx,
2290 &secdesc,
2291 &sd_size,
2292 parent_secdesc,
2293 parent_secdesc->owner_sid,
2294 parent_secdesc->group_sid,
2295 false);
2296 if (!NT_STATUS_IS_OK(status)) {
2297 talloc_destroy(mem_ctx);
2298 return ntstatus_to_werror(status);
2301 map_job_permissions(secdesc);
2302 } else {
2303 map_printer_permissions(secdesc);
2306 /* Check access */
2307 status = se_access_check(secdesc, session_info->security_token, access_type,
2308 &access_granted);
2310 DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
2312 talloc_destroy(mem_ctx);
2314 return ntstatus_to_werror(status);
2317 /****************************************************************************
2318 Check the time parameters allow a print operation.
2319 *****************************************************************************/
2321 bool print_time_access_check(const struct auth_session_info *session_info,
2322 struct messaging_context *msg_ctx,
2323 const char *servicename)
2325 struct spoolss_PrinterInfo2 *pinfo2 = NULL;
2326 WERROR result;
2327 bool ok = False;
2328 time_t now = time(NULL);
2329 struct tm *t;
2330 uint32_t mins;
2332 result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
2333 servicename, &pinfo2);
2334 if (!W_ERROR_IS_OK(result)) {
2335 return False;
2338 if (pinfo2->starttime == 0 && pinfo2->untiltime == 0) {
2339 ok = True;
2342 t = gmtime(&now);
2343 mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
2345 if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
2346 ok = True;
2349 TALLOC_FREE(pinfo2);
2351 if (!ok) {
2352 errno = EACCES;
2355 return ok;
2358 void nt_printer_remove(TALLOC_CTX *mem_ctx,
2359 const struct auth_session_info *session_info,
2360 struct messaging_context *msg_ctx,
2361 const char *printer)
2363 WERROR result;
2365 result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
2366 printer, "");
2367 if (!W_ERROR_IS_OK(result)) {
2368 DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
2369 "%s\n", printer, win_errstr(result)));
2373 void nt_printer_add(TALLOC_CTX *mem_ctx,
2374 const struct auth_session_info *session_info,
2375 struct messaging_context *msg_ctx,
2376 const char *printer)
2378 WERROR result;
2380 result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
2381 printer);
2382 if (!W_ERROR_IS_OK(result)) {
2383 DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
2384 printer, win_errstr(result)));