s3: printing: Move handle_ne_file code into a separate function.
[samba.git] / source3 / printing / nt_printing.c
index 4afddd31c232bf3ad22a2e99cfeb24cc2c7d9ad1..65172a750844b459b9a4947246bad133451ffa47 100644 (file)
  */
 
 #include "includes.h"
-#include "librpc/gen_ndr/messaging.h"
-#include "printing/pcap.h"
 #include "printing/nt_printing_tdb.h"
-#include "printing/nt_printing_migrate.h"
-#include "registry.h"
-#include "registry/reg_objects.h"
-#include "../librpc/gen_ndr/ndr_security.h"
 #include "../librpc/gen_ndr/ndr_spoolss.h"
-#include "rpc_server/srv_spoolss_util.h"
+#include "rpc_server/spoolss/srv_spoolss_util.h"
 #include "nt_printing.h"
 #include "secrets.h"
 #include "../librpc/gen_ndr/netlogon.h"
+#include "../libcli/security/security.h"
+#include "passdb/machine_sid.h"
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "auth.h"
+#include "messages.h"
+#include "rpc_server/spoolss/srv_spoolss_nt.h"
+#include "rpc_client/cli_winreg_spoolss.h"
 
 /* Map generic permissions to printer object specific permissions */
 
@@ -72,6 +74,152 @@ static const struct print_architecture_table_node archi_table[]= {
        {NULL,                   "",            -1 }
 };
 
+static bool print_driver_directories_init(void)
+{
+       int service, i;
+       char *driver_path;
+       bool ok;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+       const char *dir_list[] = {
+               "W32X86/PCC",
+               "x64/PCC",
+               "color"
+       };
+
+       service = lp_servicenumber("print$");
+       if (service < 0) {
+               /* We don't have a print$ share */
+               DEBUG(5, ("No print$ share has been configured.\n"));
+               talloc_free(mem_ctx);
+               return true;
+       }
+
+       driver_path = lp_path(mem_ctx, service);
+       if (driver_path == NULL) {
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       ok = directory_create_or_exist(driver_path, 0755);
+       if (!ok) {
+               DEBUG(1, ("Failed to create printer driver directory %s\n",
+                         driver_path));
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       for (i = 0; archi_table[i].long_archi != NULL; i++) {
+               const char *arch_path;
+
+               arch_path = talloc_asprintf(mem_ctx,
+                                           "%s/%s",
+                                           driver_path,
+                                           archi_table[i].short_archi);
+               if (arch_path == NULL) {
+                       talloc_free(mem_ctx);
+                       return false;
+               }
+
+               ok = directory_create_or_exist(arch_path, 0755);
+               if (!ok) {
+                       DEBUG(1, ("Failed to create printer driver "
+                                 "architecture directory %s\n",
+                                 arch_path));
+                       talloc_free(mem_ctx);
+                       return false;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dir_list); i++) {
+               const char *path;
+
+               path = talloc_asprintf(mem_ctx,
+                                      "%s/%s",
+                                      driver_path,
+                                      dir_list[i]);
+               if (path == NULL) {
+                       talloc_free(mem_ctx);
+                       return false;
+               }
+
+               ok = directory_create_or_exist(path, 0755);
+               if (!ok) {
+                       DEBUG(1, ("Failed to create printer driver "
+                                 "architecture directory %s\n",
+                                 path));
+                       talloc_free(mem_ctx);
+                       return false;
+               }
+       }
+
+       driver_path = state_path("DriverStore");
+       if (driver_path == NULL) {
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       ok = directory_create_or_exist(driver_path, 0755);
+       if (!ok) {
+               DEBUG(1,("failed to create path %s\n", driver_path));
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       driver_path = state_path("DriverStore/FileRepository");
+       if (driver_path == NULL) {
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       ok = directory_create_or_exist(driver_path, 0755);
+       if (!ok) {
+               DEBUG(1,("failed to create path %s\n", driver_path));
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       driver_path = state_path("DriverStore/Temp");
+       if (driver_path == NULL) {
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       ok = directory_create_or_exist(driver_path, 0755);
+       if (!ok) {
+               DEBUG(1,("failed to create path %s\n", driver_path));
+               talloc_free(mem_ctx);
+               return false;
+       }
+
+       talloc_free(mem_ctx);
+       return true;
+}
+
+/****************************************************************************
+ Forward a MSG_PRINTER_DRVUPGRADE message from another smbd to the
+ background lpq updater.
+****************************************************************************/
+
+static void forward_drv_upgrade_printer_msg(struct messaging_context *msg,
+                               void *private_data,
+                               uint32_t msg_type,
+                               struct server_id server_id,
+                               DATA_BLOB *data)
+{
+       extern pid_t background_lpq_updater_pid;
+
+       if (background_lpq_updater_pid == -1) {
+               DEBUG(3,("no background lpq queue updater\n"));
+               return;
+       }
+
+       messaging_send_buf(msg,
+                       pid_to_procid(background_lpq_updater_pid),
+                       MSG_PRINTER_DRVUPGRADE,
+                       data->data,
+                       data->length);
+}
+
 /****************************************************************************
  Open the NT printing tdbs. Done once before fork().
 ****************************************************************************/
@@ -80,23 +228,23 @@ bool nt_printing_init(struct messaging_context *msg_ctx)
 {
        WERROR win_rc;
 
+       if (!print_driver_directories_init()) {
+               return false;
+       }
+
        if (!nt_printing_tdb_upgrade()) {
                return false;
        }
 
        /*
         * register callback to handle updating printers as new
-        * drivers are installed
+        * drivers are installed. Forwards to background lpq updater.
         */
        messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
-                          do_drv_upgrade_printer);
-
-       /* of course, none of the message callbacks matter if you don't
-          tell messages.c that you interested in receiving PRINT_GENERAL
-          msgs.  This is done in serverid_register() */
+                       forward_drv_upgrade_printer_msg);
 
        if ( lp_security() == SEC_ADS ) {
-               win_rc = check_published_printers();
+               win_rc = check_published_printers(msg_ctx);
                if (!W_ERROR_IS_OK(win_rc))
                        DEBUG(0, ("nt_printing_init: error checking published printers: %s\n", win_errstr(win_rc)));
        }
@@ -143,11 +291,11 @@ const char *get_short_archi(const char *long_archi)
 {
         int i=-1;
 
-        DEBUG(107,("Getting architecture dependant directory\n"));
+        DEBUG(107,("Getting architecture dependent directory\n"));
         do {
                 i++;
         } while ( (archi_table[i].long_archi!=NULL ) &&
-                  StrCaseCmp(long_archi, archi_table[i].long_archi) );
+                  strcasecmp_m(long_archi, archi_table[i].long_archi) );
 
         if (archi_table[i].long_archi==NULL) {
                 DEBUGADD(10,("Unknown architecture [%s] !\n", long_archi));
@@ -164,227 +312,485 @@ const char *get_short_archi(const char *long_archi)
 }
 
 /****************************************************************************
- Version information in Microsoft files is held in a VS_VERSION_INFO structure.
- There are two case to be covered here: PE (Portable Executable) and NE (New
- Executable) files. Both files support the same INFO structure, but PE files
- store the signature in unicode, and NE files store it as !unicode.
- returns -1 on error, 1 on version info found, and 0 on no version info found.
+ Read data from fsp on the vfs.
+ (note: EINTR re-read differs from vfs_write_data)
 ****************************************************************************/
 
-static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 *minor)
+static ssize_t vfs_read_data(files_struct *fsp,
+                               char *buf,
+                               size_t byte_count)
 {
-       int     i;
-       char    *buf = NULL;
-       ssize_t byte_count;
+       size_t total=0;
 
-       if ((buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE)) == NULL) {
-               DEBUG(0,("get_file_version: PE file [%s] DOS Header malloc failed bytes = %d\n",
-                               fname, DOS_HEADER_SIZE));
-               goto error_exit;
-       }
+       while (total < byte_count) {
+               ssize_t ret = SMB_VFS_READ(fsp, buf + total,
+                                       byte_count - total);
 
-       if ((byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE)) < DOS_HEADER_SIZE) {
-               DEBUG(3,("get_file_version: File [%s] DOS header too short, bytes read = %lu\n",
-                        fname, (unsigned long)byte_count));
-               goto no_version_info;
+               if (ret == 0) {
+                       return total;
+               }
+               if (ret == -1) {
+                       if (errno == EINTR) {
+                               continue;
+                       } else {
+                               return -1;
+                       }
+               }
+               total += ret;
        }
+       return (ssize_t)total;
+}
 
-       /* Is this really a DOS header? */
-       if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
-               DEBUG(6,("get_file_version: File [%s] bad DOS magic = 0x%x\n",
-                               fname, SVAL(buf,DOS_HEADER_MAGIC_OFFSET)));
-               goto no_version_info;
-       }
+/****************************************************************************
+ Detect the major and minor version of a PE file.
+ Returns:
 
-       /* Skip OEM header (if any) and the DOS stub to start of Windows header */
-       if (SMB_VFS_LSEEK(fsp, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) {
-               DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n",
-                               fname, errno));
-               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
-               goto no_version_info;
-       }
+ 1 if file is a PE file and we got version numbers,
+ 0 if this file is a PE file and we couldn't get the version numbers,
+ -1 on error.
 
-       /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
-       if ((byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE)) < NE_HEADER_SIZE) {
-               DEBUG(3,("get_file_version: File [%s] Windows header too short, bytes read = %lu\n",
-                        fname, (unsigned long)byte_count));
-               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
-               goto no_version_info;
+ NB. buf is passed into and freed inside this function. This is a
+ bad API design, but fixing this is a task for another day.
+****************************************************************************/
+
+static int handle_pe_file(files_struct *fsp,
+                               char *fname,
+                               char *buf,
+                               uint32_t *major,
+                               uint32_t *minor)
+{
+       unsigned int i;
+       unsigned int num_sections;
+       unsigned int section_table_bytes;
+       ssize_t byte_count;
+       off_t oret;
+       off_t pos;
+       int ret = -1;
+
+       /* Just skip over optional header to get to section table */
+       pos = SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-
+               (NE_HEADER_SIZE-PE_HEADER_SIZE);
+
+       oret = SMB_VFS_LSEEK(fsp, pos, SEEK_CUR);
+       if (oret == (off_t)-1) {
+               DBG_NOTICE("File [%s] Windows optional header "
+                       "too short, errno = %d\n",
+                       fname,
+                       errno);
+               goto out;
        }
 
-       /* The header may be a PE (Portable Executable) or an NE (New Executable) */
-       if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
-               unsigned int num_sections;
-               unsigned int section_table_bytes;
-
-               /* Just skip over optional header to get to section table */
-               if (SMB_VFS_LSEEK(fsp,
-                               SVAL(buf,PE_HEADER_OPTIONAL_HEADER_SIZE)-(NE_HEADER_SIZE-PE_HEADER_SIZE),
-                               SEEK_CUR) == (SMB_OFF_T)-1) {
-                       DEBUG(3,("get_file_version: File [%s] Windows optional header too short, errno = %d\n",
-                               fname, errno));
-                       goto error_exit;
-               }
+       /* get the section table */
+       num_sections        = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
+       section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
+       if (section_table_bytes == 0) {
+               goto out;
+       }
 
-               /* get the section table */
-               num_sections        = SVAL(buf,PE_HEADER_NUMBER_OF_SECTIONS);
-               section_table_bytes = num_sections * PE_HEADER_SECT_HEADER_SIZE;
-               if (section_table_bytes == 0)
-                       goto error_exit;
+       SAFE_FREE(buf);
+       buf = (char *)SMB_MALLOC(section_table_bytes);
+       if (buf == NULL) {
+               DBG_ERR("PE file [%s] section table malloc "
+                       "failed bytes = %d\n",
+                       fname,
+                       section_table_bytes);
+               goto out;
+       }
 
-               SAFE_FREE(buf);
-               if ((buf=(char *)SMB_MALLOC(section_table_bytes)) == NULL) {
-                       DEBUG(0,("get_file_version: PE file [%s] section table malloc failed bytes = %d\n",
-                                       fname, section_table_bytes));
-                       goto error_exit;
-               }
+       byte_count = vfs_read_data(fsp, buf, section_table_bytes);
+       if (byte_count < section_table_bytes) {
+               DBG_NOTICE("PE file [%s] Section header too short, "
+                       "bytes read = %lu\n",
+                       fname,
+                       (unsigned long)byte_count);
+               goto out;
+       }
 
-               if ((byte_count = vfs_read_data(fsp, buf, section_table_bytes)) < section_table_bytes) {
-                       DEBUG(3,("get_file_version: PE file [%s] Section header too short, bytes read = %lu\n",
-                                fname, (unsigned long)byte_count));
-                       goto error_exit;
-               }
+       /*
+        * Iterate the section table looking for
+        * the resource section ".rsrc"
+        */
+       for (i = 0; i < num_sections; i++) {
+               int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
+
+               if (strcmp(".rsrc",
+                       &buf[sec_offset+ PE_HEADER_SECT_NAME_OFFSET]) == 0) {
+                       unsigned int section_pos = IVAL(buf,
+                                       sec_offset+
+                                       PE_HEADER_SECT_PTR_DATA_OFFSET);
+                       unsigned int section_bytes = IVAL(buf,
+                                       sec_offset+
+                                       PE_HEADER_SECT_SIZE_DATA_OFFSET);
+
+                       if (section_bytes == 0) {
+                               goto out;
+                       }
 
-               /* Iterate the section table looking for the resource section ".rsrc" */
-               for (i = 0; i < num_sections; i++) {
-                       int sec_offset = i * PE_HEADER_SECT_HEADER_SIZE;
+                       SAFE_FREE(buf);
+                       buf=(char *)SMB_MALLOC(section_bytes);
+                       if (buf == NULL) {
+                               DBG_ERR("PE file [%s] version malloc "
+                                       "failed bytes = %d\n",
+                                       fname,
+                                       section_bytes);
+                               goto out;
+                       }
 
-                       if (strcmp(".rsrc", &buf[sec_offset+PE_HEADER_SECT_NAME_OFFSET]) == 0) {
-                               unsigned int section_pos   = IVAL(buf,sec_offset+PE_HEADER_SECT_PTR_DATA_OFFSET);
-                               unsigned int section_bytes = IVAL(buf,sec_offset+PE_HEADER_SECT_SIZE_DATA_OFFSET);
+                       /*
+                        * Seek to the start of the .rsrc
+                        * section info
+                        */
+                       oret = SMB_VFS_LSEEK(fsp,
+                                       section_pos,
+                                       SEEK_SET);
+                       if (oret == (off_t)-1) {
+                               DBG_NOTICE("PE file [%s] too short for "
+                                       "section info, errno = %d\n",
+                                       fname,
+                                       errno);
+                               goto out;
+                       }
 
-                               if (section_bytes == 0)
-                                       goto error_exit;
+                       byte_count = vfs_read_data(fsp,
+                                               buf,
+                                               section_bytes);
+                       if (byte_count < section_bytes) {
+                               DBG_NOTICE("PE file "
+                                       "[%s] .rsrc section too short, "
+                                       "bytes read = %lu\n",
+                                        fname,
+                                       (unsigned long)byte_count);
+                               goto out;
+                       }
 
-                               SAFE_FREE(buf);
-                               if ((buf=(char *)SMB_MALLOC(section_bytes)) == NULL) {
-                                       DEBUG(0,("get_file_version: PE file [%s] version malloc failed bytes = %d\n",
-                                                       fname, section_bytes));
-                                       goto error_exit;
-                               }
+                       if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE) {
+                               goto out;
+                       }
 
-                               /* Seek to the start of the .rsrc section info */
-                               if (SMB_VFS_LSEEK(fsp, section_pos, SEEK_SET) == (SMB_OFF_T)-1) {
-                                       DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n",
-                                                       fname, errno));
-                                       goto error_exit;
+                       for (i=0;
+                               i< section_bytes - VS_VERSION_INFO_UNICODE_SIZE;
+                                       i++) {
+                               /*
+                                * Scan for 1st 3 unicoded bytes
+                                * followed by word aligned magic
+                                * value.
+                                */
+                               int mpos;
+                               bool magic_match = false;
+
+                               if (buf[i] == 'V' &&
+                                               buf[i+1] == '\0' &&
+                                               buf[i+2] == 'S') {
+                                       magic_match = true;
                                }
 
-                               if ((byte_count = vfs_read_data(fsp, buf, section_bytes)) < section_bytes) {
-                                       DEBUG(3,("get_file_version: PE file [%s] .rsrc section too short, bytes read = %lu\n",
-                                                fname, (unsigned long)byte_count));
-                                       goto error_exit;
+                               if (magic_match == false) {
+                                       continue;
                                }
 
-                               if (section_bytes < VS_VERSION_INFO_UNICODE_SIZE)
-                                       goto error_exit;
-
-                               for (i=0; i<section_bytes-VS_VERSION_INFO_UNICODE_SIZE; i++) {
-                                       /* Scan for 1st 3 unicoded bytes followed by word aligned magic value */
-                                       if (buf[i] == 'V' && buf[i+1] == '\0' && buf[i+2] == 'S') {
-                                               /* Align to next long address */
-                                               int pos = (i + sizeof(VS_SIGNATURE)*2 + 3) & 0xfffffffc;
-
-                                               if (IVAL(buf,pos) == VS_MAGIC_VALUE) {
-                                                       *major = IVAL(buf,pos+VS_MAJOR_OFFSET);
-                                                       *minor = IVAL(buf,pos+VS_MINOR_OFFSET);
-
-                                                       DEBUG(6,("get_file_version: PE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
-                                                                         fname, *major, *minor,
-                                                                         (*major>>16)&0xffff, *major&0xffff,
-                                                                         (*minor>>16)&0xffff, *minor&0xffff));
-                                                       SAFE_FREE(buf);
-                                                       return 1;
-                                               }
-                                       }
+                               /* Align to next long address */
+                               mpos = (i + sizeof(VS_SIGNATURE)*2 +
+                                       3) & 0xfffffffc;
+
+                               if (IVAL(buf,mpos) == VS_MAGIC_VALUE) {
+                                       *major = IVAL(buf,
+                                                       mpos+ VS_MAJOR_OFFSET);
+                                       *minor = IVAL(buf,
+                                                       mpos+ VS_MINOR_OFFSET);
+
+                                       DBG_INFO("PE file [%s] Version = "
+                                               "%08x:%08x (%d.%d.%d.%d)\n",
+                                               fname,
+                                               *major,
+                                               *minor,
+                                               (*major>>16)&0xffff,
+                                               *major&0xffff,
+                                               (*minor>>16)&0xffff,
+                                               *minor&0xffff);
+                                       ret = 1;
+                                       goto out;
                                }
                        }
                }
+       }
 
-               /* Version info not found, fall back to origin date/time */
-               DEBUG(10,("get_file_version: PE file [%s] has no version info\n", fname));
-               SAFE_FREE(buf);
-               return 0;
+       /* Version info not found, fall back to origin date/time */
+       DBG_DEBUG("PE file [%s] has no version info\n", fname);
+       ret = 0;
 
-       } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) == NE_HEADER_SIGNATURE) {
-               if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
-                       DEBUG(3,("get_file_version: NE file [%s] wrong target OS = 0x%x\n",
-                                       fname, CVAL(buf,NE_HEADER_TARGET_OS_OFFSET)));
-                       /* At this point, we assume the file is in error. It still could be somthing
-                        * else besides a NE file, but it unlikely at this point. */
-                       goto error_exit;
-               }
+  out:
 
-               /* Allocate a bit more space to speed up things */
-               SAFE_FREE(buf);
-               if ((buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE)) == NULL) {
-                       DEBUG(0,("get_file_version: NE file [%s] malloc failed bytes  = %d\n",
-                                       fname, PE_HEADER_SIZE));
-                       goto error_exit;
+       SAFE_FREE(buf);
+       return ret;
+}
+
+/****************************************************************************
+ Detect the major and minor version of an NE file.
+ Returns:
+
+ 1 if file is an NE file and we got version numbers,
+ 0 if this file is an NE file and we couldn't get the version numbers,
+ -1 on error.
+
+ NB. buf is passed into and freed inside this function. This is a
+ bad API design, but fixing this is a task for another day.
+****************************************************************************/
+
+static int handle_ne_file(files_struct *fsp,
+                               char *fname,
+                               char *buf,
+                               uint32_t *major,
+                               uint32_t *minor)
+{
+       unsigned int i;
+       ssize_t byte_count;
+       int ret = -1;
+
+       if (CVAL(buf,NE_HEADER_TARGET_OS_OFFSET) != NE_HEADER_TARGOS_WIN ) {
+               DBG_NOTICE("NE file [%s] wrong target OS = 0x%x\n",
+                       fname,
+                       CVAL(buf,NE_HEADER_TARGET_OS_OFFSET));
+               /*
+                * At this point, we assume the file is in error.
+                * It still could be something else besides a NE file,
+                * but it unlikely at this point.
+                */
+               goto out;
+       }
+
+       /* Allocate a bit more space to speed up things */
+       SAFE_FREE(buf);
+       buf=(char *)SMB_MALLOC(VS_NE_BUF_SIZE);
+       if (buf == NULL) {
+               DBG_ERR("NE file [%s] malloc failed bytes  = %d\n",
+                       fname,
+                       PE_HEADER_SIZE);
+               goto out;
+       }
+
+       /*
+        * This is a HACK! I got tired of trying to sort through the
+        * messy 'NE' file format. If anyone wants to clean this up
+        * please have at it, but this works. 'NE' files will
+        * eventually fade away. JRR
+        */
+       byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE);
+       while (byte_count > 0) {
+               /*
+                * Cover case that should not occur in a well
+                * formed 'NE' .dll file
+                */
+               if (byte_count-VS_VERSION_INFO_SIZE <= 0) {
+                       break;
                }
 
-               /* This is a HACK! I got tired of trying to sort through the messy
-                * 'NE' file format. If anyone wants to clean this up please have at
-                * it, but this works. 'NE' files will eventually fade away. JRR */
-               while((byte_count = vfs_read_data(fsp, buf, VS_NE_BUF_SIZE)) > 0) {
-                       /* Cover case that should not occur in a well formed 'NE' .dll file */
-                       if (byte_count-VS_VERSION_INFO_SIZE <= 0) break;
-
-                       for(i=0; i<byte_count; i++) {
-                               /* Fast skip past data that can't possibly match */
-                               if (buf[i] != 'V') continue;
-
-                               /* Potential match data crosses buf boundry, move it to beginning
-                                * of buf, and fill the buf with as much as it will hold. */
-                               if (i>byte_count-VS_VERSION_INFO_SIZE) {
-                                       int bc;
-
-                                       memcpy(buf, &buf[i], byte_count-i);
-                                       if ((bc = vfs_read_data(fsp, &buf[byte_count-i], VS_NE_BUF_SIZE-
-                                                                  (byte_count-i))) < 0) {
-
-                                               DEBUG(0,("get_file_version: NE file [%s] Read error, errno=%d\n",
-                                                                fname, errno));
-                                               goto error_exit;
-                                       }
+               for(i=0; i<byte_count; i++) {
+                       /*
+                        * Fast skip past data that can't
+                        * possibly match
+                        */
+                       if (buf[i] != 'V') {
+                               byte_count = vfs_read_data(fsp,
+                                               buf,
+                                               VS_NE_BUF_SIZE);
+                               continue;
+                       }
 
-                                       byte_count = bc + (byte_count - i);
-                                       if (byte_count<VS_VERSION_INFO_SIZE) break;
+                       /*
+                        * Potential match data crosses buf boundry,
+                        * move it to beginning of buf, and fill the
+                        * buf with as much as it will hold.
+                        */
+                       if (i>byte_count-VS_VERSION_INFO_SIZE) {
+                               ssize_t amount_read;
+                               ssize_t amount_unused = byte_count-i;
+
+                               memmove(buf, &buf[i], amount_unused);
+                               amount_read = vfs_read_data(fsp,
+                                               &buf[amount_unused],
+                                               VS_NE_BUF_SIZE- amount_unused);
+                               if (amount_read < 0) {
+                                       DBG_ERR("NE file [%s] Read "
+                                               "error, errno=%d\n",
+                                               fname,
+                                               errno);
+                                       goto out;
+                               }
 
-                                       i = 0;
+                               if (amount_read + amount_unused <
+                                               amount_read) {
+                                       /* Check for integer wrap. */
+                                       break;
                                }
 
-                               /* Check that the full signature string and the magic number that
-                                * follows exist (not a perfect solution, but the chances that this
-                                * occurs in code is, well, remote. Yes I know I'm comparing the 'V'
-                                * twice, as it is simpler to read the code. */
-                               if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
-                                       /* Compute skip alignment to next long address */
-                                       int skip = -(SMB_VFS_LSEEK(fsp, 0, SEEK_CUR) - (byte_count - i) +
-                                                                sizeof(VS_SIGNATURE)) & 3;
-                                       if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue;
-
-                                       *major = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MAJOR_OFFSET);
-                                       *minor = IVAL(buf,i+sizeof(VS_SIGNATURE)+skip+VS_MINOR_OFFSET);
-                                       DEBUG(6,("get_file_version: NE file [%s] Version = %08x:%08x (%d.%d.%d.%d)\n",
-                                                         fname, *major, *minor,
-                                                         (*major>>16)&0xffff, *major&0xffff,
-                                                         (*minor>>16)&0xffff, *minor&0xffff));
-                                       SAFE_FREE(buf);
-                                       return 1;
+                               byte_count = amount_read +
+                                            amount_unused;
+                               if (byte_count < VS_VERSION_INFO_SIZE) {
+                                       break;
                                }
+
+                               i = 0;
+                       }
+
+                       /*
+                        * Check that the full signature string and
+                        * the magic number that follows exist (not
+                        * a perfect solution, but the chances that this
+                        * occurs in code is, well, remote. Yes I know
+                        * I'm comparing the 'V' twice, as it is
+                        * simpler to read the code.
+                        */
+                       if (strcmp(&buf[i], VS_SIGNATURE) == 0) {
+                               /*
+                                * Compute skip alignment to next
+                                * long address.
+                                */
+                               off_t cpos = SMB_VFS_LSEEK(fsp,
+                                               0,
+                                               SEEK_CUR);
+
+                               int skip = -(cpos - (byte_count - i) +
+                                        sizeof(VS_SIGNATURE)) & 3;
+                               if (IVAL(buf,
+                                       i+sizeof(VS_SIGNATURE)+skip)
+                                               != 0xfeef04bd) {
+                                       byte_count = vfs_read_data(fsp,
+                                                       buf,
+                                                       VS_NE_BUF_SIZE);
+                                       continue;
+                               }
+
+                               *major = IVAL(buf,
+                                       i+sizeof(VS_SIGNATURE)+
+                                       skip+VS_MAJOR_OFFSET);
+                               *minor = IVAL(buf,
+                                       i+sizeof(VS_SIGNATURE)+
+                                       skip+VS_MINOR_OFFSET);
+                               DBG_INFO("NE file [%s] Version "
+                                       "= %08x:%08x (%d.%d.%d.%d)\n",
+                                       fname,
+                                       *major,
+                                       *minor,
+                                       (*major>>16)&0xffff,
+                                       *major&0xffff,
+                                       (*minor>>16)&0xffff,
+                                       *minor&0xffff);
+                               ret = 1;
+                               goto out;
                        }
                }
+       }
 
-               /* Version info not found, fall back to origin date/time */
-               DEBUG(0,("get_file_version: NE file [%s] Version info not found\n", fname));
-               SAFE_FREE(buf);
-               return 0;
+       /* Version info not found, fall back to origin date/time */
+       DBG_ERR("NE file [%s] Version info not found\n", fname);
+       ret = 0;
+
+  out:
 
-       } else
-               /* Assume this isn't an error... the file just looks sort of like a PE/NE file */
-               DEBUG(3,("get_file_version: File [%s] unknown file format, signature = 0x%x\n",
-                               fname, IVAL(buf,PE_HEADER_SIGNATURE_OFFSET)));
+       SAFE_FREE(buf);
+       return ret;
+}
+
+/****************************************************************************
+ Version information in Microsoft files is held in a VS_VERSION_INFO structure.
+ There are two case to be covered here: PE (Portable Executable) and NE (New
+ Executable) files. Both files support the same INFO structure, but PE files
+ store the signature in unicode, and NE files store it as !unicode.
+ returns -1 on error, 1 on version info found, and 0 on no version info found.
+****************************************************************************/
+
+static int get_file_version(files_struct *fsp,
+                               char *fname,
+                               uint32_t *major,
+                               uint32_t *minor)
+{
+       char    *buf = NULL;
+       ssize_t byte_count;
+       off_t pos;
+       off_t oret;
+
+       buf=(char *)SMB_MALLOC(DOS_HEADER_SIZE);
+       if (buf == NULL) {
+               DBG_ERR("PE file [%s] DOS Header malloc failed bytes = %d\n",
+                       fname,
+                       DOS_HEADER_SIZE);
+               goto error_exit;
+       }
+
+       byte_count = vfs_read_data(fsp, buf, DOS_HEADER_SIZE);
+       if (byte_count < DOS_HEADER_SIZE) {
+               DBG_NOTICE("File [%s] DOS header too short, bytes read = %lu\n",
+                        fname,
+                       (unsigned long)byte_count);
+               goto no_version_info;
+       }
+
+       /* Is this really a DOS header? */
+       if (SVAL(buf,DOS_HEADER_MAGIC_OFFSET) != DOS_HEADER_MAGIC) {
+               DBG_INFO("File [%s] bad DOS magic = 0x%x\n",
+                       fname,
+                       SVAL(buf,DOS_HEADER_MAGIC_OFFSET));
+               goto no_version_info;
+       }
+
+       /*
+        * Skip OEM header (if any) and the
+        * DOS stub to start of Windows header.
+        */
+       pos = SVAL(buf,DOS_HEADER_LFANEW_OFFSET);
+       oret = SMB_VFS_LSEEK(fsp, pos, SEEK_SET);
+       if (oret == (off_t)-1) {
+               DBG_NOTICE("File [%s] too short, errno = %d\n",
+                       fname,
+                       errno);
+               /*
+                * Assume this isn't an error...
+                * the file just looks sort of like a PE/NE file.
+                */
+               goto no_version_info;
+       }
+
+       /* Note: DOS_HEADER_SIZE and NE_HEADER_SIZE are incidentally same */
+       byte_count = vfs_read_data(fsp, buf, NE_HEADER_SIZE);
+       if (byte_count < NE_HEADER_SIZE) {
+               DBG_NOTICE("File [%s] Windows header too short, "
+                       "bytes read = %lu\n",
+                       fname,
+                       (unsigned long)byte_count);
+               /*
+                * Assume this isn't an error...
+                * the file just looks sort of like a PE/NE file
+                */
+               goto no_version_info;
+       }
+
+       /*
+        * The header may be a PE (Portable Executable)
+        * or an NE (New Executable).
+        */
+       if (IVAL(buf,PE_HEADER_SIGNATURE_OFFSET) == PE_HEADER_SIGNATURE) {
+               return handle_pe_file(fsp,
+                                       fname,
+                                       buf,
+                                       major,
+                                       minor);
+       } else if (SVAL(buf,NE_HEADER_SIGNATURE_OFFSET) ==
+                       NE_HEADER_SIGNATURE) {
+               return handle_ne_file(fsp,
+                                       fname,
+                                       buf,
+                                       major,
+                                       minor);
+       } else {
+               /*
+                * Assume this isn't an error... the file just
+                * looks sort of like a PE/NE file.
+                */
+               DBG_NOTICE("File [%s] unknown file format, signature = 0x%x\n",
+                       fname,
+                       IVAL(buf,PE_HEADER_SIGNATURE_OFFSET));
+               /* Fallthrough into no_version_info: */
+       }
 
        no_version_info:
                SAFE_FREE(buf);
@@ -409,12 +815,12 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 {
        bool use_version = true;
 
-       uint32 new_major;
-       uint32 new_minor;
+       uint32_t new_major;
+       uint32_t new_minor;
        time_t new_create_time;
 
-       uint32 old_major;
-       uint32 old_minor;
+       uint32_t old_major;
+       uint32_t old_minor;
        time_t old_create_time;
 
        struct smb_filename *smb_fname = NULL;
@@ -445,12 +851,14 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* Old file not found, so by definition new file is in fact newer */
@@ -498,12 +906,14 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* New file not found, this shouldn't occur if the caller did its job */
@@ -573,23 +983,24 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
 /****************************************************************************
 Determine the correct cVersion associated with an architecture and driver
 ****************************************************************************/
-static uint32 get_correct_cversion(struct pipes_struct *p,
+static uint32_t get_correct_cversion(struct auth_session_info *session_info,
                                   const char *architecture,
                                   const char *driverpath_in,
+                                  const char *driver_directory,
                                   WERROR *perr)
 {
-       int               cversion;
+       int cversion = -1;
        NTSTATUS          nt_status;
        struct smb_filename *smb_fname = NULL;
-       char *driverpath = NULL;
        files_struct      *fsp = NULL;
        connection_struct *conn = NULL;
-       NTSTATUS status;
-       char *oldcwd;
-       fstring printdollar;
+       struct smb_filename *oldcwd_fname = NULL;
+       char *printdollar = NULL;
+       char *printdollar_path = NULL;
+       char *working_dir = NULL;
        int printdollar_snum;
 
-       *perr = WERR_INVALID_PARAM;
+       *perr = WERR_INVALID_PARAMETER;
 
        /* If architecture is Windows 95/98/ME, the version is always 0. */
        if (strcmp(architecture, SPL_ARCH_WIN40) == 0) {
@@ -605,17 +1016,44 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                return 3;
        }
 
-       fstrcpy(printdollar, "print$");
-
-       printdollar_snum = find_service(printdollar);
+       printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
+       if (!printdollar) {
+               *perr = WERR_NOT_ENOUGH_MEMORY;
+               return -1;
+       }
        if (printdollar_snum == -1) {
-               *perr = WERR_NO_SUCH_SHARE;
+               *perr = WERR_BAD_NET_NAME;
+               return -1;
+       }
+
+       printdollar_path = lp_path(talloc_tos(), printdollar_snum);
+       if (printdollar_path == NULL) {
+               *perr = WERR_NOT_ENOUGH_MEMORY;
                return -1;
        }
 
-       nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
-                                      lp_pathname(printdollar_snum),
-                                      p->server_info, &oldcwd);
+       working_dir = talloc_asprintf(talloc_tos(),
+                                     "%s/%s",
+                                     printdollar_path,
+                                     architecture);
+       /*
+        * If the driver has been uploaded into a temorpary driver
+        * directory, switch to the driver directory.
+        */
+       if (driver_directory != NULL) {
+               working_dir = talloc_asprintf(talloc_tos(), "%s/%s/%s",
+                                             printdollar_path,
+                                             architecture,
+                                             driver_directory);
+       }
+
+       nt_status = create_conn_struct_cwd(talloc_tos(),
+                                          server_event_context(),
+                                          server_messaging_context(),
+                                          &conn,
+                                          printdollar_snum,
+                                          working_dir,
+                                          session_info, &oldcwd_fname);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(0,("get_correct_cversion: create_conn_struct "
                         "returned %s\n", nt_errstr(nt_status)));
@@ -623,18 +1061,24 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                return -1;
        }
 
-       /* Open the driver file (Portable Executable format) and determine the
-        * deriver the cversion. */
-       driverpath = talloc_asprintf(talloc_tos(),
-                                       "%s/%s",
-                                       architecture,
-                                       driverpath_in);
-       if (!driverpath) {
-               *perr = WERR_NOMEM;
-               goto error_exit;
+       nt_status = set_conn_force_user_group(conn, printdollar_snum);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("failed set force user / group\n"));
+               *perr = ntstatus_to_werror(nt_status);
+               goto error_free_conn;
        }
 
-       nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
+       if (!become_user_by_session(conn, session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               *perr = WERR_ACCESS_DENIED;
+               goto error_free_conn;
+       }
+
+       /*
+        * We switch to the directory where the driver files are located,
+        * so only work on the file names
+        */
+       nt_status = driver_unix_convert(conn, driverpath_in, &smb_fname);
        if (!NT_STATUS_IS_OK(nt_status)) {
                *perr = ntstatus_to_werror(nt_status);
                goto error_exit;
@@ -642,11 +1086,12 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
 
        nt_status = vfs_file_exist(conn, smb_fname);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               *perr = WERR_BADFILE;
+               DEBUG(3,("get_correct_cversion: vfs_file_exist failed\n"));
+               *perr = WERR_FILE_NOT_FOUND;
                goto error_exit;
        }
 
-       status = SMB_VFS_CREATE_FILE(
+       nt_status = SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                NULL,                                   /* req */
                0,                                      /* root_dir_fid */
@@ -657,30 +1102,34 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* private_flags */
                0,                                      /* allocation_size */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
-       if (!NT_STATUS_IS_OK(status)) {
+       if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
                         "%d\n", smb_fname_str_dbg(smb_fname), errno));
                *perr = WERR_ACCESS_DENIED;
                goto error_exit;
        } else {
-               uint32 major;
-               uint32 minor;
+               uint32_t major;
+               uint32_t minor;
                int    ret;
 
                ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
-               if (ret == -1) goto error_exit;
-
-               if (!ret) {
+               if (ret == -1) {
+                       *perr = WERR_INVALID_PARAMETER;
+                       goto error_exit;
+               } else if (!ret) {
                        DEBUG(6,("get_correct_cversion: Version info not "
                                 "found [%s]\n",
                                 smb_fname_str_dbg(smb_fname)));
+                       *perr = WERR_INVALID_PARAMETER;
                        goto error_exit;
                }
 
@@ -712,23 +1161,25 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
 
        DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
                  smb_fname_str_dbg(smb_fname), cversion));
-
-       goto done;
+       *perr = WERR_OK;
 
  error_exit:
-       cversion = -1;
done:
+       unbecome_user();
error_free_conn:
        TALLOC_FREE(smb_fname);
        if (fsp != NULL) {
                close_file(NULL, fsp, NORMAL_CLOSE);
        }
        if (conn != NULL) {
-               vfs_ChDir(conn, oldcwd);
+               vfs_ChDir(conn, oldcwd_fname);
+               TALLOC_FREE(oldcwd_fname);
+               SMB_VFS_DISCONNECT(conn);
                conn_free(conn);
        }
-       if (cversion != -1) {
-               *perr = WERR_OK;
+       if (!W_ERROR_IS_OK(*perr)) {
+               cversion = -1;
        }
+
        return cversion;
 }
 
@@ -743,22 +1194,65 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
 } while (0);
 
 static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
-                                          struct pipes_struct *rpc_pipe,
+                                          struct auth_session_info *session_info,
                                           const char *architecture,
                                           const char **driver_path,
                                           const char **data_file,
                                           const char **config_file,
                                           const char **help_file,
                                           struct spoolss_StringArray *dependent_files,
-                                          uint32_t *version)
+                                          enum spoolss_DriverOSVersion *version,
+                                          uint32_t flags,
+                                          const char **driver_directory)
 {
        const char *short_architecture;
        int i;
        WERROR err;
        char *_p;
 
-       if (!*driver_path || !*data_file || !*config_file) {
-               return WERR_INVALID_PARAM;
+       if (!*driver_path || !*data_file) {
+               return WERR_INVALID_PARAMETER;
+       }
+
+       if (!strequal(architecture, SPOOLSS_ARCHITECTURE_4_0) && !*config_file) {
+               return WERR_INVALID_PARAMETER;
+       }
+
+       if (flags & APD_COPY_FROM_DIRECTORY) {
+               char *path;
+               char *q;
+
+               /*
+                * driver_path is set to:
+                *
+                * \\PRINTSRV\print$\x64\{279245b0-a8bd-4431-bf6f-baee92ac15c0}\pscript5.dll
+                */
+               path = talloc_strdup(mem_ctx, *driver_path);
+               if (path == NULL) {
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
+
+               /* Remove pscript5.dll */
+               q = strrchr_m(path, '\\');
+               if (q == NULL) {
+                       return WERR_INVALID_PARAMETER;
+               }
+               *q = '\0';
+
+               /* Get \{279245b0-a8bd-4431-bf6f-baee92ac15c0} */
+               q = strrchr_m(path, '\\');
+               if (q == NULL) {
+                       return WERR_INVALID_PARAMETER;
+               }
+
+               /*
+                * Set driver_directory to:
+                *
+                * {279245b0-a8bd-4431-bf6f-baee92ac15c0}
+                *
+                * This is the directory where all the files have been uploaded
+                */
+               *driver_directory = q + 1;
        }
 
        /* clean up the driver name.
@@ -769,7 +1263,9 @@ static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
 
        strip_driver_path(mem_ctx, *driver_path);
        strip_driver_path(mem_ctx, *data_file);
-       strip_driver_path(mem_ctx, *config_file);
+       if (*config_file) {
+               strip_driver_path(mem_ctx, *config_file);
+       }
        if (help_file) {
                strip_driver_path(mem_ctx, *help_file);
        }
@@ -797,8 +1293,11 @@ static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
         *      NT2K: cversion=3
         */
 
-       *version = get_correct_cversion(rpc_pipe, short_architecture,
-                                       *driver_path, &err);
+       *version = get_correct_cversion(session_info,
+                                       short_architecture,
+                                       *driver_path,
+                                       *driver_directory,
+                                       &err);
        if (*version == -1) {
                return err;
        }
@@ -810,28 +1309,45 @@ static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
 ****************************************************************************/
 
 WERROR clean_up_driver_struct(TALLOC_CTX *mem_ctx,
-                             struct pipes_struct *rpc_pipe,
-                             struct spoolss_AddDriverInfoCtr *r)
+                             struct auth_session_info *session_info,
+                             struct spoolss_AddDriverInfoCtr *r,
+                             uint32_t flags,
+                             const char **driver_directory)
 {
        switch (r->level) {
        case 3:
-               return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
+               return clean_up_driver_struct_level(mem_ctx, session_info,
                                                    r->info.info3->architecture,
                                                    &r->info.info3->driver_path,
                                                    &r->info.info3->data_file,
                                                    &r->info.info3->config_file,
                                                    &r->info.info3->help_file,
                                                    r->info.info3->dependent_files,
-                                                   &r->info.info3->version);
+                                                   &r->info.info3->version,
+                                                   flags,
+                                                   driver_directory);
        case 6:
-               return clean_up_driver_struct_level(mem_ctx, rpc_pipe,
+               return clean_up_driver_struct_level(mem_ctx, session_info,
                                                    r->info.info6->architecture,
                                                    &r->info.info6->driver_path,
                                                    &r->info.info6->data_file,
                                                    &r->info.info6->config_file,
                                                    &r->info.info6->help_file,
                                                    r->info.info6->dependent_files,
-                                                   &r->info.info6->version);
+                                                   &r->info.info6->version,
+                                                   flags,
+                                                   driver_directory);
+       case 8:
+               return clean_up_driver_struct_level(mem_ctx, session_info,
+                                                   r->info.info8->architecture,
+                                                   &r->info.info8->driver_path,
+                                                   &r->info.info8->data_file,
+                                                   &r->info.info8->config_file,
+                                                   &r->info.info8->help_file,
+                                                   r->info.info8->dependent_files,
+                                                   &r->info.info8->version,
+                                                   flags,
+                                                   driver_directory);
        default:
                return WERR_NOT_SUPPORTED;
        }
@@ -858,6 +1374,23 @@ static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
        dst->dependent_files    = src->dependent_files;
 }
 
+static void convert_level_8_to_level3(struct spoolss_AddDriverInfo3 *dst,
+                                     const struct spoolss_AddDriverInfo8 *src)
+{
+       dst->version            = src->version;
+
+       dst->driver_name        = src->driver_name;
+       dst->architecture       = src->architecture;
+       dst->driver_path        = src->driver_path;
+       dst->data_file          = src->data_file;
+       dst->config_file        = src->config_file;
+       dst->help_file          = src->help_file;
+       dst->monitor_name       = src->monitor_name;
+       dst->default_datatype   = src->default_datatype;
+       dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
+       dst->dependent_files    = src->dependent_files;
+}
+
 /****************************************************************************
 ****************************************************************************/
 
@@ -866,7 +1399,8 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
                                                const char *driver_file,
                                                const char *short_architecture,
                                                uint32_t driver_version,
-                                               uint32_t version)
+                                               uint32_t version,
+                                               const char *driver_directory)
 {
        struct smb_filename *smb_fname_old = NULL;
        struct smb_filename *smb_fname_new = NULL;
@@ -875,29 +1409,41 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        WERROR ret;
 
-       old_name = talloc_asprintf(mem_ctx, "%s/%s",
-                                  short_architecture, driver_file);
-       W_ERROR_HAVE_NO_MEMORY(old_name);
+       if (driver_directory != NULL) {
+               old_name = talloc_asprintf(mem_ctx,
+                                          "%s/%s/%s",
+                                          short_architecture,
+                                          driver_directory,
+                                          driver_file);
+       } else {
+               old_name = talloc_asprintf(mem_ctx,
+                                          "%s/%s",
+                                          short_architecture,
+                                          driver_file);
+       }
+       if (old_name == NULL) {
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
 
        new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
                                   short_architecture, driver_version, driver_file);
        if (new_name == NULL) {
                TALLOC_FREE(old_name);
-               return WERR_NOMEM;
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
        if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
 
                status = driver_unix_convert(conn, old_name, &smb_fname_old);
                if (!NT_STATUS_IS_OK(status)) {
-                       ret = WERR_NOMEM;
+                       ret = WERR_NOT_ENOUGH_MEMORY;
                        goto out;
                }
 
                /* Setup a synthetic smb_filename struct */
-               smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
+               smb_fname_new = talloc_zero(mem_ctx, struct smb_filename);
                if (!smb_fname_new) {
-                       ret = WERR_NOMEM;
+                       ret = WERR_NOT_ENOUGH_MEMORY;
                        goto out;
                }
 
@@ -917,7 +1463,7 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
                                 "to rename [%s] to [%s]: %s\n",
                                 smb_fname_old->base_name, new_name,
                                 nt_errstr(status)));
-                       ret = WERR_ACCESS_DENIED;
+                       ret = WERR_APP_INIT_FAILURE;
                        goto out;
                }
        }
@@ -929,9 +1475,9 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
        return ret;
 }
 
-WERROR move_driver_to_download_area(struct pipes_struct *p,
+WERROR move_driver_to_download_area(struct auth_session_info *session_info,
                                    struct spoolss_AddDriverInfoCtr *r,
-                                   WERROR *perr)
+                                   const char *driver_directory)
 {
        struct spoolss_AddDriverInfo3 *driver;
        struct spoolss_AddDriverInfo3 converted_driver;
@@ -943,11 +1489,10 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
        int i;
        TALLOC_CTX *ctx = talloc_tos();
        int ver = 0;
-       char *oldcwd;
-       fstring printdollar;
+       struct smb_filename *oldcwd_fname = NULL;
+       char *printdollar = NULL;
        int printdollar_snum;
-
-       *perr = WERR_OK;
+       WERROR err = WERR_OK;
 
        switch (r->level) {
        case 3:
@@ -957,9 +1502,13 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                convert_level_6_to_level3(&converted_driver, r->info.info6);
                driver = &converted_driver;
                break;
+       case 8:
+               convert_level_8_to_level3(&converted_driver, r->info.info8);
+               driver = &converted_driver;
+               break;
        default:
                DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
-               return WERR_UNKNOWN_LEVEL;
+               return WERR_INVALID_LEVEL;
        }
 
        short_architecture = get_short_archi(driver->architecture);
@@ -967,22 +1516,39 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       fstrcpy(printdollar, "print$");
-
-       printdollar_snum = find_service(printdollar);
+       printdollar_snum = find_service(ctx, "print$", &printdollar);
+       if (!printdollar) {
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
        if (printdollar_snum == -1) {
-               *perr = WERR_NO_SUCH_SHARE;
-               return WERR_NO_SUCH_SHARE;
+               return WERR_BAD_NET_NAME;
        }
 
-       nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
-                                      lp_pathname(printdollar_snum),
-                                      p->server_info, &oldcwd);
+       nt_status = create_conn_struct_cwd(talloc_tos(),
+                                          server_event_context(),
+                                          server_messaging_context(),
+                                          &conn,
+                                          printdollar_snum,
+                                          lp_path(talloc_tos(), printdollar_snum),
+                                          session_info, &oldcwd_fname);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(0,("move_driver_to_download_area: create_conn_struct "
                         "returned %s\n", nt_errstr(nt_status)));
-               *perr = ntstatus_to_werror(nt_status);
-               return *perr;
+               err = ntstatus_to_werror(nt_status);
+               return err;
+       }
+
+       nt_status = set_conn_force_user_group(conn, printdollar_snum);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("failed set force user / group\n"));
+               err = ntstatus_to_werror(nt_status);
+               goto err_free_conn;
+       }
+
+       if (!become_user_by_session(conn, session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               err = WERR_ACCESS_DENIED;
+               goto err_free_conn;
        }
 
        new_dir = talloc_asprintf(ctx,
@@ -990,18 +1556,25 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                                short_architecture,
                                driver->version);
        if (!new_dir) {
-               *perr = WERR_NOMEM;
+               err = WERR_NOT_ENOUGH_MEMORY;
                goto err_exit;
        }
        nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               *perr = WERR_NOMEM;
+               err = WERR_NOT_ENOUGH_MEMORY;
                goto err_exit;
        }
 
        DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
 
-       create_directory(conn, NULL, smb_dname);
+       nt_status = create_directory(conn, NULL, smb_dname);
+       if (!NT_STATUS_IS_OK(nt_status)
+        && !NT_STATUS_EQUAL(nt_status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+               DEBUG(0, ("failed to create driver destination directory: %s\n",
+                         nt_errstr(nt_status)));
+               err = ntstatus_to_werror(nt_status);
+               goto err_exit;
+       }
 
        /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
         * listed for this driver which has already been moved, skip it (note:
@@ -1024,16 +1597,14 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
 
        if (driver->driver_path && strlen(driver->driver_path)) {
 
-               *perr = move_driver_file_to_download_area(ctx,
-                                                         conn,
-                                                         driver->driver_path,
-                                                         short_architecture,
-                                                         driver->version,
-                                                         ver);
-               if (!W_ERROR_IS_OK(*perr)) {
-                       if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
-                               ver = -1;
-                       }
+               err = move_driver_file_to_download_area(ctx,
+                                                       conn,
+                                                       driver->driver_path,
+                                                       short_architecture,
+                                                       driver->version,
+                                                       ver,
+                                                       driver_directory);
+               if (!W_ERROR_IS_OK(err)) {
                        goto err_exit;
                }
        }
@@ -1041,16 +1612,14 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
        if (driver->data_file && strlen(driver->data_file)) {
                if (!strequal(driver->data_file, driver->driver_path)) {
 
-                       *perr = move_driver_file_to_download_area(ctx,
-                                                                 conn,
-                                                                 driver->data_file,
-                                                                 short_architecture,
-                                                                 driver->version,
-                                                                 ver);
-                       if (!W_ERROR_IS_OK(*perr)) {
-                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
-                                       ver = -1;
-                               }
+                       err = move_driver_file_to_download_area(ctx,
+                                                               conn,
+                                                               driver->data_file,
+                                                               short_architecture,
+                                                               driver->version,
+                                                               ver,
+                                                               driver_directory);
+                       if (!W_ERROR_IS_OK(err)) {
                                goto err_exit;
                        }
                }
@@ -1060,16 +1629,14 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                if (!strequal(driver->config_file, driver->driver_path) &&
                    !strequal(driver->config_file, driver->data_file)) {
 
-                       *perr = move_driver_file_to_download_area(ctx,
-                                                                 conn,
-                                                                 driver->config_file,
-                                                                 short_architecture,
-                                                                 driver->version,
-                                                                 ver);
-                       if (!W_ERROR_IS_OK(*perr)) {
-                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
-                                       ver = -1;
-                               }
+                       err = move_driver_file_to_download_area(ctx,
+                                                               conn,
+                                                               driver->config_file,
+                                                               short_architecture,
+                                                               driver->version,
+                                                               ver,
+                                                               driver_directory);
+                       if (!W_ERROR_IS_OK(err)) {
                                goto err_exit;
                        }
                }
@@ -1080,16 +1647,14 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                    !strequal(driver->help_file, driver->data_file) &&
                    !strequal(driver->help_file, driver->config_file)) {
 
-                       *perr = move_driver_file_to_download_area(ctx,
-                                                                 conn,
-                                                                 driver->help_file,
-                                                                 short_architecture,
-                                                                 driver->version,
-                                                                 ver);
-                       if (!W_ERROR_IS_OK(*perr)) {
-                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
-                                       ver = -1;
-                               }
+                       err = move_driver_file_to_download_area(ctx,
+                                                               conn,
+                                                               driver->help_file,
+                                                               short_architecture,
+                                                               driver->version,
+                                                               ver,
+                                                               driver_directory);
+                       if (!W_ERROR_IS_OK(err)) {
                                goto err_exit;
                        }
                }
@@ -1108,16 +1673,14 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                                        }
                                }
 
-                               *perr = move_driver_file_to_download_area(ctx,
-                                                                         conn,
-                                                                         driver->dependent_files->string[i],
-                                                                         short_architecture,
-                                                                         driver->version,
-                                                                         ver);
-                               if (!W_ERROR_IS_OK(*perr)) {
-                                       if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
-                                               ver = -1;
-                                       }
+                               err = move_driver_file_to_download_area(ctx,
+                                                                       conn,
+                                                                       driver->dependent_files->string[i],
+                                                                       short_architecture,
+                                                                       driver->version,
+                                                                       ver,
+                                                                       driver_directory);
+                               if (!W_ERROR_IS_OK(err)) {
                                        goto err_exit;
                                }
                        }
@@ -1125,440 +1688,34 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                }
        }
 
-  err_exit:
+       err = WERR_OK;
+ err_exit:
+       unbecome_user();
+ err_free_conn:
        TALLOC_FREE(smb_dname);
 
        if (conn != NULL) {
-               vfs_ChDir(conn, oldcwd);
+               vfs_ChDir(conn, oldcwd_fname);
+               TALLOC_FREE(oldcwd_fname);
+               SMB_VFS_DISCONNECT(conn);
                conn_free(conn);
        }
 
-       if (W_ERROR_EQUAL(*perr, WERR_OK)) {
-               return WERR_OK;
-       }
-       if (ver == -1) {
-               return WERR_UNKNOWN_PRINTER_DRIVER;
-       }
-       return (*perr);
-}
-
-/****************************************************************************
- Create and allocate a default devicemode.
-****************************************************************************/
-
-WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
-                                     const char *devicename,
-                                     struct spoolss_DeviceMode **devmode)
-{
-       struct spoolss_DeviceMode *dm;
-       char *dname;
-
-       dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
-       if (dm == NULL) {
-               return WERR_NOMEM;
-       }
-
-       dname = talloc_asprintf(dm, "%s", devicename);
-       if (dname == NULL) {
-               return WERR_NOMEM;
-       }
-       if (strlen(dname) > MAXDEVICENAME) {
-               dname[MAXDEVICENAME] = '\0';
-       }
-       dm->devicename = dname;
-
-       dm->formname = talloc_strdup(dm, "Letter");
-       if (dm->formname == NULL) {
-               return WERR_NOMEM;
-       }
-
-       dm->specversion          = DMSPEC_NT4_AND_ABOVE;
-       dm->driverversion        = 0x0400;
-       dm->size                 = 0x00DC;
-       dm->__driverextra_length = 0;
-       dm->fields               = DEVMODE_FORMNAME |
-                                  DEVMODE_TTOPTION |
-                                  DEVMODE_PRINTQUALITY |
-                                  DEVMODE_DEFAULTSOURCE |
-                                  DEVMODE_COPIES |
-                                  DEVMODE_SCALE |
-                                  DEVMODE_PAPERSIZE |
-                                  DEVMODE_ORIENTATION;
-       dm->orientation          = DMORIENT_PORTRAIT;
-       dm->papersize            = DMPAPER_LETTER;
-       dm->paperlength          = 0;
-       dm->paperwidth           = 0;
-       dm->scale                = 0x64;
-       dm->copies               = 1;
-       dm->defaultsource        = DMBIN_FORMSOURCE;
-       dm->printquality         = DMRES_HIGH;           /* 0x0258 */
-       dm->color                = DMRES_MONOCHROME;
-       dm->duplex               = DMDUP_SIMPLEX;
-       dm->yresolution          = 0;
-       dm->ttoption             = DMTT_SUBDEV;
-       dm->collate              = DMCOLLATE_FALSE;
-       dm->icmmethod            = 0;
-       dm->icmintent            = 0;
-       dm->mediatype            = 0;
-       dm->dithertype           = 0;
-
-       dm->logpixels            = 0;
-       dm->bitsperpel           = 0;
-       dm->pelswidth            = 0;
-       dm->pelsheight           = 0;
-       dm->displayflags         = 0;
-       dm->displayfrequency     = 0;
-       dm->reserved1            = 0;
-       dm->reserved2            = 0;
-       dm->panningwidth         = 0;
-       dm->panningheight        = 0;
-
-       dm->driverextra_data.data = NULL;
-       dm->driverextra_data.length = 0;
-
-        *devmode = dm;
-       return WERR_OK;
-}
-
-WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
-                                     struct spoolss_security_descriptor **secdesc)
-{
-       struct security_ace ace[7];     /* max number of ace entries */
-       int i = 0;
-       uint32_t sa;
-       struct security_acl *psa = NULL;
-       struct security_descriptor *psd = NULL;
-       struct dom_sid adm_sid;
-       size_t sd_size;
-
-       /* Create an ACE where Everyone is allowed to print */
-
-       sa = PRINTER_ACE_PRINT;
-       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                    sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
-
-       /* Add the domain admins group if we are a DC */
-
-       if ( IS_DC ) {
-               struct dom_sid domadmins_sid;
-
-               sid_compose(&domadmins_sid, get_global_sam_sid(),
-                           DOMAIN_RID_ADMINS);
-
-               sa = PRINTER_ACE_FULL_CONTROL;
-               init_sec_ace(&ace[i++], &domadmins_sid,
-                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
-                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
-               init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
-       }
-       else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
-               sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
-
-               sa = PRINTER_ACE_FULL_CONTROL;
-               init_sec_ace(&ace[i++], &adm_sid,
-                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
-                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
-               init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
-                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
-       }
-
-       /* add BUILTIN\Administrators as FULL CONTROL */
-
-       sa = PRINTER_ACE_FULL_CONTROL;
-       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
-               SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
-               SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
-       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
-               SEC_ACE_TYPE_ACCESS_ALLOWED,
-               sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
-
-       /* add BUILTIN\Print Operators as FULL CONTROL */
-
-       sa = PRINTER_ACE_FULL_CONTROL;
-       init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
-               SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
-               SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
-       init_sec_ace(&ace[i++], &global_sid_Builtin_Print_Operators,
-               SEC_ACE_TYPE_ACCESS_ALLOWED,
-               sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
-
-       /* Make the security descriptor owned by the BUILTIN\Administrators */
-
-       /* The ACL revision number in rpc_secdesc.h differs from the one
-          created by NT when setting ACE entries in printer
-          descriptors.  NT4 complains about the property being edited by a
-          NT5 machine. */
-
-       if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
-               psd = make_sec_desc(mem_ctx,
-                                   SD_REVISION,
-                                   SEC_DESC_SELF_RELATIVE,
-                                   &global_sid_Builtin_Administrators,
-                                   &global_sid_Builtin_Administrators,
-                                   NULL,
-                                   psa,
-                                   &sd_size);
-       }
-
-       if (psd == NULL) {
-               DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
-               return WERR_NOMEM;
-       }
-
-       DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
-                (unsigned int)sd_size));
-
-       *secdesc = psd;
-
-       return WERR_OK;
-}
-
-/****************************************************************************
- ***************************************************************************/
-
-static char *win_driver;
-static char *os2_driver;
-
-static const char *get_win_driver(void)
-{
-       if (win_driver == NULL) {
-               return "";
-       }
-       return win_driver;
-}
-
-static const char *get_os2_driver(void)
-{
-       if (os2_driver == NULL) {
-               return "";
-       }
-       return os2_driver;
-}
-
-static bool set_driver_mapping(const char *from, const char *to)
-{
-       SAFE_FREE(win_driver);
-       SAFE_FREE(os2_driver);
-
-       win_driver = SMB_STRDUP(from);
-       os2_driver = SMB_STRDUP(to);
-
-       if (win_driver == NULL || os2_driver == NULL) {
-               SAFE_FREE(win_driver);
-               SAFE_FREE(os2_driver);
-               return false;
-       }
-       return true;
-}
-
-/**
- * @internal
- *
- * @brief Map a Windows driver to a OS/2 driver.
- *
- * @param[in]  mem_ctx  The memory context to use.
- *
- * @param[in,out] pdrivername The drivername of Windows to remap.
- *
- * @return              WERR_OK on success, a corresponding WERROR on failure.
- */
-WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
-{
-       const char *mapfile = lp_os2_driver_map();
-       char **lines = NULL;
-       const char *drivername;
-       int numlines = 0;
-       int i;
-
-       if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
-               return WERR_INVALID_PARAMETER;
-       }
-
-       drivername = *pdrivername;
-
-       if (mapfile[0] == '\0') {
-               return WERR_BADFILE;
-       }
-
-       if (strequal(drivername, get_win_driver())) {
-               DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
-                       drivername, get_os2_driver()));
-               drivername = talloc_strdup(mem_ctx, get_os2_driver());
-               if (drivername == NULL) {
-                       return WERR_NOMEM;
-               }
-               *pdrivername = drivername;
-               return WERR_OK;
-       }
-
-       lines = file_lines_load(mapfile, &numlines, 0, NULL);
-       if (numlines == 0 || lines == NULL) {
-               DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
-               TALLOC_FREE(lines);
-               return WERR_EMPTY;
-       }
-
-       DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
-
-       for( i = 0; i < numlines; i++) {
-               char *nt_name = lines[i];
-               char *os2_name = strchr(nt_name, '=');
-
-               if (os2_name == NULL) {
-                       continue;
-               }
-
-               *os2_name++ = '\0';
-
-               while (isspace(*nt_name)) {
-                       nt_name++;
-               }
-
-               if (*nt_name == '\0' || strchr("#;", *nt_name)) {
-                       continue;
-               }
-
-               {
-                       int l = strlen(nt_name);
-                       while (l && isspace(nt_name[l - 1])) {
-                               nt_name[l - 1] = 0;
-                               l--;
-                       }
-               }
-
-               while (isspace(*os2_name)) {
-                       os2_name++;
-               }
-
-               {
-                       int l = strlen(os2_name);
-                       while (l && isspace(os2_name[l-1])) {
-                               os2_name[l-1] = 0;
-                               l--;
-                       }
-               }
-
-               if (strequal(nt_name, drivername)) {
-                       DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
-                       set_driver_mapping(drivername, os2_name);
-                       drivername = talloc_strdup(mem_ctx, os2_name);
-                       TALLOC_FREE(lines);
-                       if (drivername == NULL) {
-                               return WERR_NOMEM;
-                       }
-                       *pdrivername = drivername;
-                       return WERR_OK;
-               }
-       }
-
-       TALLOC_FREE(lines);
-       return WERR_OK;
+       return err;
 }
 
-/****************************************************************************
-****************************************************************************/
-
-bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
-                             struct spoolss_DriverInfo8 *_info8)
-{
-       struct spoolss_DriverInfo8 info8;
-
-       ZERO_STRUCT(info8);
-
-       switch (r->level) {
-       case 3:
-               info8.version           = r->info.info3->version;
-               info8.driver_name       = r->info.info3->driver_name;
-               info8.architecture      = r->info.info3->architecture;
-               info8.driver_path       = r->info.info3->driver_path;
-               info8.data_file         = r->info.info3->data_file;
-               info8.config_file       = r->info.info3->config_file;
-               info8.help_file         = r->info.info3->help_file;
-               info8.monitor_name      = r->info.info3->monitor_name;
-               info8.default_datatype  = r->info.info3->default_datatype;
-               if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
-                       info8.dependent_files   = r->info.info3->dependent_files->string;
-               }
-               break;
-       case 6:
-               info8.version           = r->info.info6->version;
-               info8.driver_name       = r->info.info6->driver_name;
-               info8.architecture      = r->info.info6->architecture;
-               info8.driver_path       = r->info.info6->driver_path;
-               info8.data_file         = r->info.info6->data_file;
-               info8.config_file       = r->info.info6->config_file;
-               info8.help_file         = r->info.info6->help_file;
-               info8.monitor_name      = r->info.info6->monitor_name;
-               info8.default_datatype  = r->info.info6->default_datatype;
-               if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
-                       info8.dependent_files   = r->info.info6->dependent_files->string;
-               }
-               info8.driver_date       = r->info.info6->driver_date;
-               info8.driver_version    = r->info.info6->driver_version;
-               info8.manufacturer_name = r->info.info6->manufacturer_name;
-               info8.manufacturer_url  = r->info.info6->manufacturer_url;
-               info8.hardware_id       = r->info.info6->hardware_id;
-               info8.provider          = r->info.info6->provider;
-               break;
-       case 8:
-               info8.version           = r->info.info8->version;
-               info8.driver_name       = r->info.info8->driver_name;
-               info8.architecture      = r->info.info8->architecture;
-               info8.driver_path       = r->info.info8->driver_path;
-               info8.data_file         = r->info.info8->data_file;
-               info8.config_file       = r->info.info8->config_file;
-               info8.help_file         = r->info.info8->help_file;
-               info8.monitor_name      = r->info.info8->monitor_name;
-               info8.default_datatype  = r->info.info8->default_datatype;
-               if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
-                       info8.dependent_files   = r->info.info8->dependent_files->string;
-               }
-               if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
-                       info8.previous_names    = r->info.info8->previous_names->string;
-               }
-               info8.driver_date       = r->info.info8->driver_date;
-               info8.driver_version    = r->info.info8->driver_version;
-               info8.manufacturer_name = r->info.info8->manufacturer_name;
-               info8.manufacturer_url  = r->info.info8->manufacturer_url;
-               info8.hardware_id       = r->info.info8->hardware_id;
-               info8.provider          = r->info.info8->provider;
-               info8.print_processor   = r->info.info8->print_processor;
-               info8.vendor_setup      = r->info.info8->vendor_setup;
-               if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
-                       info8.color_profiles = r->info.info8->color_profiles->string;
-               }
-               info8.inf_path          = r->info.info8->inf_path;
-               info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
-               if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
-                       info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
-               }
-               info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
-               info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
-               break;
-       default:
-               return false;
-       }
-
-       *_info8 = info8;
-
-       return true;
-}
-
-
 /****************************************************************************
   Determine whether or not a particular driver is currently assigned
   to a printer
 ****************************************************************************/
 
 bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
-                          struct auth_serversupplied_info *server_info,
-                          struct messaging_context *msg_ctx,
-                           const struct spoolss_DriverInfo8 *r)
+                          struct dcerpc_binding_handle *b,
+                          const struct spoolss_DriverInfo8 *r)
 {
        int snum;
        int n_services = lp_numservices();
-       bool in_use = False;
+       bool in_use = false;
        struct spoolss_PrinterInfo2 *pinfo2 = NULL;
        WERROR result;
 
@@ -1571,19 +1728,19 @@ bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
        /* loop through the printers.tdb and check for the drivername */
 
        for (snum=0; snum<n_services && !in_use; snum++) {
-               if (!lp_snum_ok(snum) || !lp_print_ok(snum)) {
+               if (!lp_snum_ok(snum) || !lp_printable(snum)) {
                        continue;
                }
 
-               result = winreg_get_printer(mem_ctx, server_info, msg_ctx,
-                                           NULL, lp_servicename(snum),
+               result = winreg_get_printer(mem_ctx, b,
+                                           lp_servicename(talloc_tos(), snum),
                                            &pinfo2);
                if (!W_ERROR_IS_OK(result)) {
                        continue; /* skip */
                }
 
                if (strequal(r->driver_name, pinfo2->drivername)) {
-                       in_use = True;
+                       in_use = true;
                }
 
                TALLOC_FREE(pinfo2);
@@ -1592,7 +1749,7 @@ bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
        DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
 
        if ( in_use ) {
-               struct spoolss_DriverInfo8 *driver;
+               struct spoolss_DriverInfo8 *driver = NULL;
                WERROR werr;
 
                DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
@@ -1600,26 +1757,31 @@ bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
                /* we can still remove the driver if there is one of
                   "Windows NT x86" version 2 or 3 left */
 
-               if (!strequal("Windows NT x86", r->architecture)) {
-                       werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
-                                                "Windows NT x86",
+               if (strequal(SPOOLSS_ARCHITECTURE_NT_X86, r->architecture)) {
+                       if (r->version == 2) {
+                               werr = winreg_get_driver(mem_ctx, b,
+                                                        r->architecture,
+                                                        r->driver_name,
+                                                        3, &driver);
+                       } else if (r->version == 3) {
+                               werr = winreg_get_driver(mem_ctx, b,
+                                                        r->architecture,
+                                                        r->driver_name,
+                                                        2, &driver);
+                       } else {
+                               DBG_ERR("Unknown driver version (%d)\n",
+                                       r->version);
+                               werr = WERR_UNKNOWN_PRINTER_DRIVER;
+                       }
+               } else if (strequal(SPOOLSS_ARCHITECTURE_x64, r->architecture)) {
+                       werr = winreg_get_driver(mem_ctx, b,
+                                                SPOOLSS_ARCHITECTURE_NT_X86,
                                                 r->driver_name,
                                                 DRIVER_ANY_VERSION,
                                                 &driver);
-               } else if (r->version == 2) {
-                       werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
-                                                "Windows NT x86",
-                                                r->driver_name,
-                                                3, &driver);
-               } else if (r->version == 3) {
-                       werr = winreg_get_driver(mem_ctx, server_info, msg_ctx,
-                                                "Windows NT x86",
-                                                r->driver_name,
-                                                2, &driver);
                } else {
-                       DEBUG(0, ("printer_driver_in_use: ERROR!"
-                                 " unknown driver version (%d)\n",
-                                 r->version));
+                       DBG_ERR("Unknown driver architecture: %s\n",
+                               r->architecture);
                        werr = WERR_UNKNOWN_PRINTER_DRIVER;
                }
 
@@ -1627,7 +1789,7 @@ bool printer_driver_in_use(TALLOC_CTX *mem_ctx,
 
                if ( W_ERROR_IS_OK(werr) ) {
                        /* it's ok to remove the driver, we have other architctures left */
-                       in_use = False;
+                       in_use = false;
                        talloc_free(driver);
                }
        }
@@ -1780,12 +1942,11 @@ static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
 ****************************************************************************/
 
 bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
-                                struct auth_serversupplied_info *server_info,
-                                struct messaging_context *msg_ctx,
+                                struct dcerpc_binding_handle *b,
                                 struct spoolss_DriverInfo8 *info)
 {
        int                             i;
-       uint32                          version;
+       uint32_t                                version;
        struct spoolss_DriverInfo8      *driver;
        bool in_use = false;
        uint32_t num_drivers;
@@ -1803,7 +1964,7 @@ bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
 
        /* get the list of drivers */
 
-       result = winreg_get_driver_list(mem_ctx, server_info, msg_ctx,
+       result = winreg_get_driver_list(mem_ctx, b,
                                        info->architecture, version,
                                        &num_drivers, &drivers);
        if (!W_ERROR_IS_OK(result)) {
@@ -1820,7 +1981,7 @@ bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
 
                driver = NULL;
 
-               result = winreg_get_driver(mem_ctx, server_info, msg_ctx,
+               result = winreg_get_driver(mem_ctx, b,
                                           info->architecture, drivers[i],
                                           version, &driver);
                if (!W_ERROR_IS_OK(result)) {
@@ -1851,20 +2012,29 @@ bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS driver_unlink_internals(connection_struct *conn,
-                                       const char *name)
+                                       const char *short_arch,
+                                       int vers,
+                                       const char *fname)
 {
+       TALLOC_CTX *tmp_ctx = talloc_new(conn);
        struct smb_filename *smb_fname = NULL;
-       NTSTATUS status;
+       char *print_dlr_path;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
-           &smb_fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       print_dlr_path = talloc_asprintf(tmp_ctx, "%s/%d/%s",
+                                        short_arch, vers, fname);
+       if (print_dlr_path == NULL) {
+               goto err_out;
        }
 
-       status = unlink_internals(conn, NULL, 0, smb_fname, false);
+       smb_fname = synthetic_smb_fname(tmp_ctx, print_dlr_path, NULL, NULL, 0);
+       if (smb_fname == NULL) {
+               goto err_out;
+       }
 
-       TALLOC_FREE(smb_fname);
+       status = unlink_internals(conn, NULL, 0, smb_fname, false);
+err_out:
+       talloc_free(tmp_ctx);
        return status;
 }
 
@@ -1874,16 +2044,14 @@ static NTSTATUS driver_unlink_internals(connection_struct *conn,
   this.
 ****************************************************************************/
 
-bool delete_driver_files(struct auth_serversupplied_info *server_info,
+bool delete_driver_files(const struct auth_session_info *session_info,
                         const struct spoolss_DriverInfo8 *r)
 {
-       int i = 0;
-       char *s;
-       const char *file;
+       const char *short_arch;
        connection_struct *conn;
        NTSTATUS nt_status;
-       char *oldcwd;
-       fstring printdollar;
+       struct smb_filename *oldcwd_fname = NULL;
+       char *printdollar = NULL;
        int printdollar_snum;
        bool ret = false;
 
@@ -1894,86 +2062,92 @@ bool delete_driver_files(struct auth_serversupplied_info *server_info,
        DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
                r->driver_name, r->version));
 
-       fstrcpy(printdollar, "print$");
-
-       printdollar_snum = find_service(printdollar);
+       printdollar_snum = find_service(talloc_tos(), "print$", &printdollar);
+       if (!printdollar) {
+               return false;
+       }
        if (printdollar_snum == -1) {
                return false;
        }
 
-       nt_status = create_conn_struct(talloc_tos(), &conn, printdollar_snum,
-                                      lp_pathname(printdollar_snum),
-                                      server_info, &oldcwd);
+       nt_status = create_conn_struct_cwd(talloc_tos(),
+                                          server_event_context(),
+                                          server_messaging_context(),
+                                          &conn,
+                                          printdollar_snum,
+                                          lp_path(talloc_tos(), printdollar_snum),
+                                          session_info, &oldcwd_fname);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(0,("delete_driver_files: create_conn_struct "
                         "returned %s\n", nt_errstr(nt_status)));
                return false;
        }
 
+       nt_status = set_conn_force_user_group(conn, printdollar_snum);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("failed set force user / group\n"));
+               ret = false;
+               goto err_free_conn;
+       }
+
+       if (!become_user_by_session(conn, session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               ret = false;
+               goto err_free_conn;
+       }
+
        if ( !CAN_WRITE(conn) ) {
                DEBUG(3,("delete_driver_files: Cannot delete print driver when [print$] is read-only\n"));
-               goto fail;
+               ret = false;
+               goto err_out;
+       }
+
+       short_arch = get_short_archi(r->architecture);
+       if (short_arch == NULL) {
+               DEBUG(0, ("bad architecture %s\n", r->architecture));
+               ret = false;
+               goto err_out;
        }
 
-       /* now delete the files; must strip the '\print$' string from
-          fron of path                                                */
+       /* now delete the files */
 
        if (r->driver_path && r->driver_path[0]) {
-               if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
-                       file = s;
-                       DEBUG(10,("deleting driverfile [%s]\n", s));
-                       driver_unlink_internals(conn, file);
-               }
+               DEBUG(10,("deleting driverfile [%s]\n", r->driver_path));
+               driver_unlink_internals(conn, short_arch, r->version, r->driver_path);
        }
 
        if (r->config_file && r->config_file[0]) {
-               if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
-                       file = s;
-                       DEBUG(10,("deleting configfile [%s]\n", s));
-                       driver_unlink_internals(conn, file);
-               }
+               DEBUG(10,("deleting configfile [%s]\n", r->config_file));
+               driver_unlink_internals(conn, short_arch, r->version, r->config_file);
        }
 
        if (r->data_file && r->data_file[0]) {
-               if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
-                       file = s;
-                       DEBUG(10,("deleting datafile [%s]\n", s));
-                       driver_unlink_internals(conn, file);
-               }
+               DEBUG(10,("deleting datafile [%s]\n", r->data_file));
+               driver_unlink_internals(conn, short_arch, r->version, r->data_file);
        }
 
        if (r->help_file && r->help_file[0]) {
-               if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
-                       file = s;
-                       DEBUG(10,("deleting helpfile [%s]\n", s));
-                       driver_unlink_internals(conn, file);
-               }
+               DEBUG(10,("deleting helpfile [%s]\n", r->help_file));
+               driver_unlink_internals(conn, short_arch, r->version, r->help_file);
        }
 
-       /* check if we are done removing files */
-
        if (r->dependent_files) {
+               int i = 0;
                while (r->dependent_files[i] && r->dependent_files[i][0]) {
-                       char *p;
-
-                       /* bypass the "\print$" portion of the path */
-
-                       if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
-                               file = p;
-                               DEBUG(10,("deleting dependent file [%s]\n", file));
-                               driver_unlink_internals(conn, file);
-                       }
-
+                       DEBUG(10,("deleting dependent file [%s]\n", r->dependent_files[i]));
+                       driver_unlink_internals(conn, short_arch, r->version, r->dependent_files[i]);
                        i++;
                }
        }
 
-       goto done;
fail:
-       ret = false;
done:
+       ret = true;
err_out:
+       unbecome_user();
err_free_conn:
        if (conn != NULL) {
-               vfs_ChDir(conn, oldcwd);
+               vfs_ChDir(conn, oldcwd_fname);
+               TALLOC_FREE(oldcwd_fname);
+               SMB_VFS_DISCONNECT(conn);
                conn_free(conn);
        }
        return ret;
@@ -1985,7 +2159,7 @@ bool delete_driver_files(struct auth_serversupplied_info *server_info,
        2: file doesn't exist
        3: can't allocate memory
        4: can't free memory
-       5: non existant struct
+       5: non existent struct
 */
 
 /*
@@ -2063,53 +2237,50 @@ void map_job_permissions(struct security_descriptor *sd)
     3)  "printer admins" (may result in numerous calls to winbind)
 
  ****************************************************************************/
-bool print_access_check(struct auth_serversupplied_info *server_info,
-                       struct messaging_context *msg_ctx, int snum,
-                       int access_type)
+WERROR print_access_check(const struct auth_session_info *session_info,
+                         struct messaging_context *msg_ctx, int snum,
+                         int access_type)
 {
        struct spoolss_security_descriptor *secdesc = NULL;
-       uint32 access_granted;
+       uint32_t access_granted;
        size_t sd_size;
        NTSTATUS status;
        WERROR result;
        const char *pname;
        TALLOC_CTX *mem_ctx = NULL;
-       SE_PRIV se_printop = SE_PRINT_OPERATOR;
 
        /* If user is NULL then use the current_user structure */
 
        /* Always allow root or SE_PRINT_OPERATROR to do anything */
 
-       if (server_info->utok.uid == sec_initial_uid()
-           || user_has_privileges(server_info->ptok, &se_printop ) ) {
-               return True;
+       if ((session_info->unix_token->uid == sec_initial_uid())
+           || security_token_has_privilege(session_info->security_token,
+                                           SEC_PRIV_PRINT_OPERATOR)) {
+               return WERR_OK;
        }
 
        /* Get printer name */
 
-       pname = lp_printername(snum);
+       pname = lp_printername(talloc_tos(), snum);
 
        if (!pname || !*pname) {
-               errno = EACCES;
-               return False;
+               return WERR_ACCESS_DENIED;
        }
 
        /* Get printer security descriptor */
 
        if(!(mem_ctx = talloc_init("print_access_check"))) {
-               errno = ENOMEM;
-               return False;
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
-       result = winreg_get_printer_secdesc(mem_ctx,
-                                           server_info,
+       result = winreg_get_printer_secdesc_internal(mem_ctx,
+                                           get_session_info_system(),
                                            msg_ctx,
                                            pname,
                                            &secdesc);
        if (!W_ERROR_IS_OK(result)) {
                talloc_destroy(mem_ctx);
-               errno = ENOMEM;
-               return False;
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
        if (access_type == JOB_ACCESS_ADMINISTER) {
@@ -2127,8 +2298,7 @@ bool print_access_check(struct auth_serversupplied_info *server_info,
                                                 false);
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_destroy(mem_ctx);
-                       errno = map_errno_from_nt_status(status);
-                       return False;
+                       return ntstatus_to_werror(status);
                }
 
                map_job_permissions(secdesc);
@@ -2137,36 +2307,21 @@ bool print_access_check(struct auth_serversupplied_info *server_info,
        }
 
        /* Check access */
-       status = se_access_check(secdesc, server_info->ptok, access_type,
+       status = se_access_check(secdesc, session_info->security_token, access_type,
                                 &access_granted);
 
        DEBUG(4, ("access check was %s\n", NT_STATUS_IS_OK(status) ? "SUCCESS" : "FAILURE"));
 
-        /* see if we need to try the printer admin list */
-
-        if (!NT_STATUS_IS_OK(status) &&
-           (token_contains_name_in_list(uidtoname(server_info->utok.uid),
-                                        server_info->info3->base.domain.string,
-                                        NULL, server_info->ptok,
-                                        lp_printer_admin(snum)))) {
-               talloc_destroy(mem_ctx);
-               return True;
-        }
-
        talloc_destroy(mem_ctx);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = EACCES;
-       }
-
-       return NT_STATUS_IS_OK(status);
+       return ntstatus_to_werror(status);
 }
 
 /****************************************************************************
  Check the time parameters allow a print operation.
 *****************************************************************************/
 
-bool print_time_access_check(struct auth_serversupplied_info *server_info,
+bool print_time_access_check(const struct auth_session_info *session_info,
                             struct messaging_context *msg_ctx,
                             const char *servicename)
 {
@@ -2175,10 +2330,10 @@ bool print_time_access_check(struct auth_serversupplied_info *server_info,
        bool ok = False;
        time_t now = time(NULL);
        struct tm *t;
-       uint32 mins;
+       uint32_t mins;
 
-       result = winreg_get_printer(NULL, server_info, msg_ctx,
-                                   NULL, servicename, &pinfo2);
+       result = winreg_get_printer_internal(NULL, session_info, msg_ctx,
+                                   servicename, &pinfo2);
        if (!W_ERROR_IS_OK(result)) {
                return False;
        }
@@ -2188,7 +2343,7 @@ bool print_time_access_check(struct auth_serversupplied_info *server_info,
        }
 
        t = gmtime(&now);
-       mins = (uint32)t->tm_hour*60 + (uint32)t->tm_min;
+       mins = (uint32_t)t->tm_hour*60 + (uint32_t)t->tm_min;
 
        if (mins >= pinfo2->starttime && mins <= pinfo2->untiltime) {
                ok = True;
@@ -2204,16 +2359,31 @@ bool print_time_access_check(struct auth_serversupplied_info *server_info,
 }
 
 void nt_printer_remove(TALLOC_CTX *mem_ctx,
-                       struct auth_serversupplied_info *server_info,
+                       const struct auth_session_info *session_info,
+                       struct messaging_context *msg_ctx,
                        const char *printer)
 {
        WERROR result;
 
-       result = winreg_delete_printer_key(mem_ctx, server_info,
-                                          smbd_messaging_context(),
+       result = winreg_delete_printer_key_internal(mem_ctx, session_info, msg_ctx,
                                           printer, "");
        if (!W_ERROR_IS_OK(result)) {
-               DEBUG(0, ("nt_printer_remove: failed to remove rpinter %s",
-                         printer));
+               DEBUG(0, ("nt_printer_remove: failed to remove printer %s: "
+               "%s\n", printer, win_errstr(result)));
+       }
+}
+
+void nt_printer_add(TALLOC_CTX *mem_ctx,
+                   const struct auth_session_info *session_info,
+                   struct messaging_context *msg_ctx,
+                   const char *printer)
+{
+       WERROR result;
+
+       result = winreg_create_printer_internal(mem_ctx, session_info, msg_ctx,
+                                               printer);
+       if (!W_ERROR_IS_OK(result)) {
+               DEBUG(0, ("nt_printer_add: failed to add printer %s: %s\n",
+                         printer, win_errstr(result)));
        }
 }