s3:spoolss: construct the devmode the same way for level 2 and 8
[ira/wip.git] / source3 / rpc_server / srv_spoolss_nt.c
index 9d7216820293b368d4829aba789adebd97edb47b..a5484f8974cf7c9d7f2664c46cffc054344e833a 100644 (file)
@@ -7,7 +7,7 @@
  *  Copyright (C) Jeremy Allison               2001-2002,
  *  Copyright (C) Gerald Carter                       2000-2004,
  *  Copyright (C) Tim Potter                   2001-2002.
- *  Copyright (C) Guenther Deschner                 2009.
+ *  Copyright (C) Guenther Deschner            2009-2010.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,6 +27,8 @@
    up, all the errors returned are DOS errors, not NT status codes. */
 
 #include "includes.h"
+#include "../librpc/gen_ndr/srv_spoolss.h"
+#include "../librpc/gen_ndr/cli_spoolss.h"
 
 /* macros stolen from s4 spoolss server */
 #define SPOOLSS_BUFFER_UNION(fn,ic,info,level) \
@@ -261,7 +263,7 @@ static bool close_printer_handle(pipes_struct *p, struct policy_handle *hnd)
  Delete a printer given a handle.
 ****************************************************************************/
 
-WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename )
+static WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename)
 {
        char *cmd = lp_deleteprinter_cmd();
        char *command = NULL;
@@ -309,9 +311,11 @@ WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sh
                return WERR_BADFID; /* What to return here? */
 
        /* go ahead and re-read the services immediately */
+       become_root();
        reload_services(false);
+       unbecome_root();
 
-       if ( lp_servicenumber( sharename )  < 0 )
+       if ( lp_servicenumber( sharename )  > 0 )
                return WERR_ACCESS_DENIED;
 
        return WERR_OK;
@@ -1480,8 +1484,11 @@ bool convert_devicemode(const char *printername,
                        return false;
        }
 
-       rpcstr_push(nt_devmode->devicename, devmode->devicename, 31, 0);
-       rpcstr_push(nt_devmode->formname, devmode->formname, 31, 0);
+       fstrcpy(nt_devmode->devicename, devmode->devicename);
+       fstrcpy(nt_devmode->formname, devmode->formname);
+
+       nt_devmode->devicename[31] = '\0';
+       nt_devmode->formname[31] = '\0';
 
        nt_devmode->specversion         = devmode->specversion;
        nt_devmode->driverversion       = devmode->driverversion;
@@ -1669,6 +1676,10 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                        return WERR_BADFID;
                }
 
+               if (r->in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
+                       r->in.access_mask = PRINTER_ACCESS_ADMINISTER;
+               }
+
                se_map_standard(&r->in.access_mask, &printer_std_mapping);
 
                /* map an empty access mask to the minimum access mask */
@@ -1824,177 +1835,6 @@ static bool convert_printer_info(struct spoolss_SetPrinterInfoCtr *info_ctr,
        return false;
 }
 
-/*******************************************************************
-********************************************************************/
-
-static bool string_array_to_fstring_array(const char **sarray, fstring **farray)
-{
-       int i;
-
-       if (!sarray) {
-               *farray = NULL;
-               return true;
-       }
-
-       *farray = SMB_MALLOC_ARRAY(fstring, 1);
-       if (!*farray) {
-               return false;
-       }
-
-       for (i=0; sarray[i] != NULL; i++) {
-               *farray = SMB_REALLOC_ARRAY(*farray, fstring, i+2);
-               if (!*farray) {
-                       return false;
-               }
-               fstrcpy((*farray)[i], sarray[i]);
-       }
-
-       fstrcpy((*farray)[i], "");
-
-       return true;
-}
-
-/*******************************************************************
-********************************************************************/
-
-static bool driver_info3_to_nt_driver_info3(struct spoolss_AddDriverInfo3 *r,
-                                           NT_PRINTER_DRIVER_INFO_LEVEL_3 **p)
-{
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 *d;
-
-       DEBUG(7,("driver_info3_to_nt_driver_info3: Converting from UNICODE to ASCII\n"));
-
-       if (*p == NULL) {
-               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_3);
-               if (*p == NULL) {
-                       return false;
-               }
-               ZERO_STRUCTP(*p);
-       }
-
-       d = *p;
-
-       d->cversion =                   r->version;
-
-       fstrcpy(d->name,                r->driver_name);
-       fstrcpy(d->environment,         r->architecture);
-       fstrcpy(d->driverpath,          r->driver_path);
-       fstrcpy(d->datafile,            r->data_file);
-       fstrcpy(d->configfile,          r->config_file);
-       fstrcpy(d->helpfile,            r->help_file);
-       fstrcpy(d->monitorname,         r->monitor_name);
-       fstrcpy(d->defaultdatatype,     r->default_datatype);
-
-       DEBUGADD(8,( "version:         %d\n", d->cversion));
-       DEBUGADD(8,( "name:            %s\n", d->name));
-       DEBUGADD(8,( "environment:     %s\n", d->environment));
-       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
-       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
-       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
-       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
-       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
-       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
-
-       if (r->dependent_files) {
-               if (!string_array_to_fstring_array(r->dependent_files->string,
-                                                  &d->dependentfiles)) {
-                       SAFE_FREE(*p);
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-/*******************************************************************
-********************************************************************/
-
-static bool driver_info6_to_nt_driver_info6(struct spoolss_AddDriverInfo6 *r,
-                                           NT_PRINTER_DRIVER_INFO_LEVEL_6 **p)
-{
-       NT_PRINTER_DRIVER_INFO_LEVEL_6 *d;
-
-       DEBUG(7,("driver_info6_to_nt_driver_info6: Converting from UNICODE to ASCII\n"));
-
-       if (*p == NULL) {
-               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_6);
-               if (*p == NULL) {
-                       return false;
-               }
-               ZERO_STRUCTP(*p);
-       }
-
-       d = *p;
-
-       d->version =                    r->version;
-
-       fstrcpy(d->name,                r->driver_name);
-       fstrcpy(d->environment,         r->architecture);
-       fstrcpy(d->driverpath,          r->driver_path);
-       fstrcpy(d->datafile,            r->data_file);
-       fstrcpy(d->configfile,          r->config_file);
-       fstrcpy(d->helpfile,            r->help_file);
-       fstrcpy(d->monitorname,         r->monitor_name);
-       fstrcpy(d->defaultdatatype,     r->default_datatype);
-
-       DEBUGADD(8,( "version:         %d\n", d->version));
-       DEBUGADD(8,( "name:            %s\n", d->name));
-       DEBUGADD(8,( "environment:     %s\n", d->environment));
-       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
-       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
-       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
-       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
-       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
-       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
-
-       if (r->dependent_files) {
-               if (!string_array_to_fstring_array(r->dependent_files->string,
-                                                  &d->dependentfiles)) {
-                       goto error;
-               }
-       }
-
-       if (r->previous_names) {
-               if (!string_array_to_fstring_array(r->previous_names->string,
-                                                  &d->previousnames)) {
-                       goto error;
-               }
-       }
-
-       return true;
-
- error:
-       SAFE_FREE(*p);
-       return false;
-}
-
-/********************************************************************
- ********************************************************************/
-
-static bool convert_printer_driver_info(const struct spoolss_AddDriverInfoCtr *r,
-                                       NT_PRINTER_DRIVER_INFO_LEVEL *printer,
-                                       uint32_t level)
-{
-       switch (level) {
-       case 3:
-               printer->info_3 = NULL;
-               if (!driver_info3_to_nt_driver_info3(r->info.info3, &printer->info_3)) {
-                       return false;
-               }
-               break;
-       case 6:
-               printer->info_6 = NULL;
-               if (!driver_info6_to_nt_driver_info6(r->info.info6, &printer->info_6)) {
-                       return false;
-               }
-               break;
-       default:
-               return false;
-       }
-
-       return true;
-}
-
 /****************************************************************
  _spoolss_ClosePrinter
 ****************************************************************/
@@ -2055,20 +1895,21 @@ WERROR _spoolss_DeletePrinter(pipes_struct *p,
  * long architecture string
  ******************************************************************/
 
+static const struct print_architecture_table_node archi_table[]= {
+
+       {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
+       {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
+       {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
+       {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
+       {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
+       {"Windows IA64",         SPL_ARCH_IA64,         3 },
+       {"Windows x64",          SPL_ARCH_X64,          3 },
+       {NULL,                   "",            -1 }
+};
+
 static int get_version_id(const char *arch)
 {
        int i;
-       struct print_architecture_table_node archi_table[]= {
-
-               {"Windows 4.0",          "WIN40",       0 },
-               {"Windows NT x86",       "W32X86",      2 },
-               {"Windows NT R4000",     "W32MIPS",     2 },
-               {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
-               {"Windows NT PowerPC",   "W32PPC",      2 },
-               {"Windows IA64",         "IA64",        3 },
-               {"Windows x64",          "x64",         3 },
-               {NULL,                   "",            -1 }
-       };
 
        for (i=0; archi_table[i].long_archi != NULL; i++)
        {
@@ -2086,8 +1927,9 @@ static int get_version_id(const char *arch)
 WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                                    struct spoolss_DeletePrinterDriver *r)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL    info;
-       NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
+
+       struct spoolss_DriverInfo8 *info = NULL;
+       struct spoolss_DriverInfo8 *info_win2k = NULL;
        int                             version;
        WERROR                          status;
        WERROR                          status_win2k = WERR_ACCESS_DENIED;
@@ -2111,10 +1953,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
        if ((version = get_version_id(r->in.architecture)) == -1)
                return WERR_INVALID_ENVIRONMENT;
 
-       ZERO_STRUCT(info);
-       ZERO_STRUCT(info_win2k);
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, r->in.driver,
+       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info, r->in.driver,
                                                r->in.architecture,
                                                version)))
        {
@@ -2122,7 +1961,8 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
 
                if ( version == 2 ) {
                        version = 3;
-                       if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3,
+                       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx,
+                                                               &info,
                                                                r->in.driver,
                                                                r->in.architecture,
                                                                version))) {
@@ -2138,14 +1978,15 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
 
        }
 
-       if (printer_driver_in_use(info.info_3)) {
+       if (printer_driver_in_use(info)) {
                status = WERR_PRINTER_DRIVER_IN_USE;
                goto done;
        }
 
        if ( version == 2 )
        {
-               if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3,
+               if (W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx,
+                                                      &info_win2k,
                                                       r->in.driver,
                                                       r->in.architecture, 3)))
                {
@@ -2153,8 +1994,8 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                        /* remove the Win2k driver first*/
 
                        status_win2k = delete_printer_driver(
-                               p, info_win2k.info_3, 3, false);
-                       free_a_printer_driver( info_win2k, 3 );
+                               p, info_win2k, 3, false);
+                       free_a_printer_driver(info_win2k);
 
                        /* this should not have failed---if it did, report to client */
                        if ( !W_ERROR_IS_OK(status_win2k) )
@@ -2165,7 +2006,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                }
        }
 
-       status = delete_printer_driver(p, info.info_3, version, false);
+       status = delete_printer_driver(p, info, version, false);
 
        /* if at least one of the deletes succeeded return OK */
 
@@ -2173,7 +2014,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                status = WERR_OK;
 
 done:
-       free_a_printer_driver( info, 3 );
+       free_a_printer_driver(info);
 
        return status;
 }
@@ -2185,8 +2026,8 @@ done:
 WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                                      struct spoolss_DeletePrinterDriverEx *r)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL    info;
-       NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
+       struct spoolss_DriverInfo8      *info = NULL;
+       struct spoolss_DriverInfo8      *info_win2k = NULL;
        int                             version;
        bool                            delete_files;
        WERROR                          status;
@@ -2214,10 +2055,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
        if (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION)
                version = r->in.version;
 
-       ZERO_STRUCT(info);
-       ZERO_STRUCT(info_win2k);
-
-       status = get_a_printer_driver(&info, 3, r->in.driver,
+       status = get_a_printer_driver(p->mem_ctx, &info, r->in.driver,
                                      r->in.architecture, version);
 
        if ( !W_ERROR_IS_OK(status) )
@@ -2234,7 +2072,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                /* try for Win2k driver if "Windows NT x86" */
 
                version = 3;
-               if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, r->in.driver,
+               if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info, r->in.driver,
                                                        r->in.architecture,
                                                        version))) {
                        status = WERR_UNKNOWN_PRINTER_DRIVER;
@@ -2242,7 +2080,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                }
        }
 
-       if ( printer_driver_in_use(info.info_3) ) {
+       if (printer_driver_in_use(info)) {
                status = WERR_PRINTER_DRIVER_IN_USE;
                goto done;
        }
@@ -2263,7 +2101,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
 
        /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */
 
-       if ( delete_files && printer_driver_files_in_use(info.info_3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
+       if (delete_files && printer_driver_files_in_use(info, info) & (r->in.delete_flags & DPD_DELETE_ALL_FILES)) {
                /* no idea of the correct error here */
                status = WERR_ACCESS_DENIED;
                goto done;
@@ -2273,14 +2111,14 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
        /* also check for W32X86/3 if necessary; maybe we already have? */
 
        if ( (version == 2) && ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION)  ) {
-               if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3,
+               if (W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info_win2k,
                                                       r->in.driver,
                                                       r->in.architecture, 3)))
                {
 
-                       if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
+                       if (delete_files && printer_driver_files_in_use(info, info_win2k) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
                                /* no idea of the correct error here */
-                               free_a_printer_driver( info_win2k, 3 );
+                               free_a_printer_driver(info_win2k);
                                status = WERR_ACCESS_DENIED;
                                goto done;
                        }
@@ -2289,8 +2127,8 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                        /* remove the Win2k driver first*/
 
                        status_win2k = delete_printer_driver(
-                               p, info_win2k.info_3, 3, delete_files);
-                       free_a_printer_driver( info_win2k, 3 );
+                               p, info_win2k, 3, delete_files);
+                       free_a_printer_driver(info_win2k);
 
                        /* this should not have failed---if it did, report to client */
 
@@ -2299,12 +2137,12 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                }
        }
 
-       status = delete_printer_driver(p, info.info_3, version, delete_files);
+       status = delete_printer_driver(p, info, version, delete_files);
 
        if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
                status = WERR_OK;
 done:
-       free_a_printer_driver( info, 3 );
+       free_a_printer_driver(info);
 
        return status;
 }
@@ -2432,8 +2270,8 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx,
 
        if (!StrCaseCmp(value, "Architecture")) {
                *type = REG_SZ;
-
-               data->string = talloc_strdup(mem_ctx, "Windows NT x86");
+               data->string = talloc_strdup(mem_ctx,
+                       lp_parm_const_string(GLOBAL_SECTION_SNUM, "spoolss", "architecture", SPOOLSS_ARCHITECTURE_NT_X86));
                W_ERROR_HAVE_NO_MEMORY(data->string);
 
                return WERR_OK;
@@ -2467,6 +2305,8 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx,
                return WERR_OK;
        }
 
+       *type = REG_NONE;
+
        return WERR_INVALID_PARAM;
 }
 
@@ -2477,92 +2317,17 @@ static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx,
 WERROR _spoolss_GetPrinterData(pipes_struct *p,
                               struct spoolss_GetPrinterData *r)
 {
-       WERROR result;
-       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       int snum = 0;
-
-       /*
-        * Reminder: when it's a string, the length is in BYTES
-        * even if UNICODE is negociated.
-        *
-        * JFM, 4/19/1999
-        */
-
-       /* in case of problem, return some default values */
-
-       *r->out.needed  = 0;
-       *r->out.type    = 0;
-
-       DEBUG(4,("_spoolss_GetPrinterData\n"));
-
-       if (!Printer) {
-               DEBUG(2,("_spoolss_GetPrinterData: Invalid handle (%s:%u:%u).\n",
-                       OUR_HANDLE(r->in.handle)));
-               result = WERR_BADFID;
-               goto done;
-       }
-
-       if (Printer->printer_type == SPLHND_SERVER) {
-               result = getprinterdata_printer_server(p->mem_ctx,
-                                                      r->in.value_name,
-                                                      r->out.type,
-                                                      r->out.data);
-       } else {
-               if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
-                       result = WERR_BADFID;
-                       goto done;
-               }
-
-               result = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
-               if (!W_ERROR_IS_OK(result)) {
-                       goto done;
-               }
+       struct spoolss_GetPrinterDataEx r2;
 
-               /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
+       r2.in.handle            = r->in.handle;
+       r2.in.key_name          = "PrinterDriverData";
+       r2.in.value_name        = r->in.value_name;
+       r2.in.offered           = r->in.offered;
+       r2.out.type             = r->out.type;
+       r2.out.data             = r->out.data;
+       r2.out.needed           = r->out.needed;
 
-               if (strequal(r->in.value_name, "ChangeId")) {
-                       *r->out.type = REG_DWORD;
-                       r->out.data->value = printer->info_2->changeid;
-                       result = WERR_OK;
-               } else {
-                       struct regval_blob *v;
-                       DATA_BLOB blob;
-
-                       v = get_printer_data(printer->info_2,
-                                            SPOOL_PRINTERDATA_KEY,
-                                            r->in.value_name);
-                       if (!v) {
-                               result = WERR_BADFILE;
-                               goto done;
-                       }
-
-                       *r->out.type = v->type;
-
-                       blob = data_blob_const(v->data_p, v->size);
-
-                       result = pull_spoolss_PrinterData(p->mem_ctx, &blob,
-                                                         r->out.data,
-                                                         *r->out.type);
-               }
-       }
-
- done:
-       /* cleanup & exit */
-
-       if (printer) {
-               free_a_printer(&printer, 2);
-       }
-
-       if (!W_ERROR_IS_OK(result)) {
-               return result;
-       }
-
-       *r->out.needed  = ndr_size_spoolss_PrinterData(r->out.data, *r->out.type, NULL, 0);
-       *r->out.type    = SPOOLSS_BUFFER_OK(*r->out.type, REG_NONE);
-       r->out.data     = SPOOLSS_BUFFER_OK(r->out.data, r->out.data);
-
-       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA);
+       return _spoolss_GetPrinterDataEx(p, &r2);
 }
 
 /*********************************************************
@@ -2575,27 +2340,30 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
        NTSTATUS ret;
        struct cli_state *the_cli;
        struct sockaddr_storage rm_addr;
+       char addr[INET6_ADDRSTRLEN];
 
        if ( is_zero_addr((struct sockaddr *)client_ss) ) {
-               if ( !resolve_name( remote_machine, &rm_addr, 0x20) ) {
+               DEBUG(2,("spoolss_connect_to_client: resolving %s\n",
+                       remote_machine));
+               if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) {
                        DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
                        return false;
                }
-
-               if (ismyaddr((struct sockaddr *)&rm_addr)) {
-                       DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
-                       return false;
-               }
+               print_sockaddr(addr, sizeof(addr), &rm_addr);
        } else {
-               char addr[INET6_ADDRSTRLEN];
                rm_addr = *client_ss;
                print_sockaddr(addr, sizeof(addr), &rm_addr);
                DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n",
                        addr));
        }
 
-       /* setup the connection */
+       if (ismyaddr((struct sockaddr *)&rm_addr)) {
+               DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n",
+                       addr));
+               return false;
+       }
 
+       /* setup the connection */
        ret = cli_full_connection( &the_cli, global_myname(), remote_machine,
                &rm_addr, 0, "IPC$", "IPC",
                "", /* username */
@@ -2784,6 +2552,9 @@ WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
                        !get_printer_snum(p, r->in.handle, &snum, NULL) )
                return WERR_BADFID;
 
+       DEBUG(10,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: "
+               "client_address is %s\n", p->client_address));
+
        if (!interpret_string_addr(&client_ss, p->client_address,
                                   AI_NUMERICHOST)) {
                return WERR_SERVER_UNAVAILABLE;
@@ -3952,255 +3723,241 @@ done:
 }
 
 /********************************************************************
- * construct_printer_info3
- * fill a spoolss_PrinterInfo3 struct
- ********************************************************************/
+ * construct_printer_info1
+ * fill a spoolss_PrinterInfo1 struct
+********************************************************************/
 
-static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx,
+static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
                                      const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_PrinterInfo3 *r,
+                                     uint32_t flags,
+                                     struct spoolss_PrinterInfo1 *r,
                                      int snum)
 {
-       /* These are the components of the SD we are returning. */
+       r->flags                = flags;
 
-       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
-               /* don't use talloc_steal() here unless you do a deep steal of all
-                  the SEC_DESC members */
+       r->description          = talloc_asprintf(mem_ctx, "%s,%s,%s",
+                                                 ntprinter->info_2->printername,
+                                                 ntprinter->info_2->drivername,
+                                                 ntprinter->info_2->location);
+       W_ERROR_HAVE_NO_MEMORY(r->description);
 
-               r->secdesc = dup_sec_desc(mem_ctx,
-                                         ntprinter->info_2->secdesc_buf->sd);
-               W_ERROR_HAVE_NO_MEMORY(r->secdesc);
+       if (*ntprinter->info_2->comment == '\0') {
+               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+       } else {
+               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment); /* saved comment */
        }
+       W_ERROR_HAVE_NO_MEMORY(r->comment);
+
+       r->name                 = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->name);
 
        return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info4
- * fill a spoolss_PrinterInfo4 struct
- ********************************************************************/
+ * construct_printer_info2
+ * fill a spoolss_PrinterInfo2 struct
+********************************************************************/
 
-static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx,
+static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
                                      const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_PrinterInfo4 *r,
+                                     struct spoolss_PrinterInfo2 *r,
                                      int snum)
 {
-       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
-       W_ERROR_HAVE_NO_MEMORY(r->printername);
-       r->servername   = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
-       W_ERROR_HAVE_NO_MEMORY(r->servername);
-
-       r->attributes   = ntprinter->info_2->attributes;
+       int count;
 
-       return WERR_OK;
-}
+       print_status_struct status;
 
-/********************************************************************
- * construct_printer_info5
- * fill a spoolss_PrinterInfo5 struct
- ********************************************************************/
+       count = print_queue_length(snum, &status);
 
-static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx,
-                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_PrinterInfo5 *r,
-                                     int snum)
-{
-       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
+       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
        W_ERROR_HAVE_NO_MEMORY(r->printername);
-       r->portname     = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       r->sharename            = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->sharename);
+       r->portname             = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
        W_ERROR_HAVE_NO_MEMORY(r->portname);
+       r->drivername           = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
+       W_ERROR_HAVE_NO_MEMORY(r->drivername);
 
-       r->attributes   = ntprinter->info_2->attributes;
-
-       /* these two are not used by NT+ according to MSDN */
+       if (*ntprinter->info_2->comment == '\0') {
+               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+       } else {
+               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment);
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->comment);
 
-       r->device_not_selected_timeout          = 0x0;  /* have seen 0x3a98 */
-       r->transmission_retry_timeout           = 0x0;  /* have seen 0xafc8 */
+       r->location             = talloc_strdup(mem_ctx, ntprinter->info_2->location);
+       W_ERROR_HAVE_NO_MEMORY(r->location);
+       r->sepfile              = talloc_strdup(mem_ctx, ntprinter->info_2->sepfile);
+       W_ERROR_HAVE_NO_MEMORY(r->sepfile);
+       r->printprocessor       = talloc_strdup(mem_ctx, ntprinter->info_2->printprocessor);
+       W_ERROR_HAVE_NO_MEMORY(r->printprocessor);
+       r->datatype             = talloc_strdup(mem_ctx, ntprinter->info_2->datatype);
+       W_ERROR_HAVE_NO_MEMORY(r->datatype);
+       r->parameters           = talloc_strdup(mem_ctx, ntprinter->info_2->parameters);
+       W_ERROR_HAVE_NO_MEMORY(r->parameters);
 
-       return WERR_OK;
-}
+       r->attributes           = ntprinter->info_2->attributes;
 
-/********************************************************************
- * construct_printer_info_6
- * fill a spoolss_PrinterInfo6 struct
- ********************************************************************/
+       r->priority             = ntprinter->info_2->priority;
+       r->defaultpriority      = ntprinter->info_2->default_priority;
+       r->starttime            = ntprinter->info_2->starttime;
+       r->untiltime            = ntprinter->info_2->untiltime;
+       r->status               = nt_printq_status(status.status);
+       r->cjobs                = count;
+       r->averageppm           = ntprinter->info_2->averageppm;
 
-static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx,
-                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_PrinterInfo6 *r,
-                                     int snum)
-{
-       int count;
-       print_status_struct status;
+       r->devmode = construct_dev_mode(mem_ctx, lp_const_servicename(snum));
+       if (!r->devmode) {
+               DEBUG(8,("Returning NULL Devicemode!\n"));
+       }
 
-       count = print_queue_length(snum, &status);
+       r->secdesc              = NULL;
 
-       r->status = nt_printq_status(status.status);
+       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
+               /* don't use talloc_steal() here unless you do a deep steal of all
+                  the SEC_DESC members */
+
+               r->secdesc      = dup_sec_desc(mem_ctx, ntprinter->info_2->secdesc_buf->sd);
+       }
 
        return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info7
- * fill a spoolss_PrinterInfo7 struct
+ * construct_printer_info3
+ * fill a spoolss_PrinterInfo3 struct
  ********************************************************************/
 
-static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
-                                     Printer_entry *print_hnd,
-                                     struct spoolss_PrinterInfo7 *r,
+static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo3 *r,
                                      int snum)
 {
-       struct GUID guid;
+       /* These are the components of the SD we are returning. */
 
-       if (is_printer_published(print_hnd, snum, &guid)) {
-               r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
-               r->action = DSPRINT_PUBLISH;
-       } else {
-               r->guid = talloc_strdup(mem_ctx, "");
-               r->action = DSPRINT_UNPUBLISH;
+       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
+               /* don't use talloc_steal() here unless you do a deep steal of all
+                  the SEC_DESC members */
+
+               r->secdesc = dup_sec_desc(mem_ctx,
+                                         ntprinter->info_2->secdesc_buf->sd);
+               W_ERROR_HAVE_NO_MEMORY(r->secdesc);
        }
-       W_ERROR_HAVE_NO_MEMORY(r->guid);
 
        return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info8
- * fill a spoolss_PrinterInfo8 struct
+ * construct_printer_info4
+ * fill a spoolss_PrinterInfo4 struct
  ********************************************************************/
 
-static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx,
+static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx,
                                      const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_DeviceModeInfo *r,
+                                     struct spoolss_PrinterInfo4 *r,
                                      int snum)
 {
-       struct spoolss_DeviceMode *devmode;
-       WERROR result;
-
-       if (!ntprinter->info_2->devmode) {
-               r->devmode = NULL;
-               return WERR_OK;
-       }
-
-       devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
-       W_ERROR_HAVE_NO_MEMORY(devmode);
-
-       result = convert_nt_devicemode(mem_ctx, devmode, ntprinter->info_2->devmode);
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(devmode);
-               return result;
-       }
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->servername   = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
 
-       r->devmode      = devmode;
+       r->attributes   = ntprinter->info_2->attributes;
 
        return WERR_OK;
 }
 
-
 /********************************************************************
- * construct_printer_info1
- * fill a spoolss_PrinterInfo1 struct
-********************************************************************/
+ * construct_printer_info5
+ * fill a spoolss_PrinterInfo5 struct
+ ********************************************************************/
 
-static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
+static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx,
                                      const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     uint32_t flags,
-                                     struct spoolss_PrinterInfo1 *r,
+                                     struct spoolss_PrinterInfo5 *r,
                                      int snum)
 {
-       r->flags                = flags;
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->portname     = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       W_ERROR_HAVE_NO_MEMORY(r->portname);
 
-       r->description          = talloc_asprintf(mem_ctx, "%s,%s,%s",
-                                                 ntprinter->info_2->printername,
-                                                 ntprinter->info_2->drivername,
-                                                 ntprinter->info_2->location);
-       W_ERROR_HAVE_NO_MEMORY(r->description);
+       r->attributes   = ntprinter->info_2->attributes;
 
-       if (*ntprinter->info_2->comment == '\0') {
-               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
-       } else {
-               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment); /* saved comment */
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->comment);
+       /* these two are not used by NT+ according to MSDN */
 
-       r->name                 = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
-       W_ERROR_HAVE_NO_MEMORY(r->name);
+       r->device_not_selected_timeout          = 0x0;  /* have seen 0x3a98 */
+       r->transmission_retry_timeout           = 0x0;  /* have seen 0xafc8 */
 
        return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info2
- * fill a spoolss_PrinterInfo2 struct
-********************************************************************/
+ * construct_printer_info_6
+ * fill a spoolss_PrinterInfo6 struct
+ ********************************************************************/
 
-static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
+static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx,
                                      const NT_PRINTER_INFO_LEVEL *ntprinter,
-                                     struct spoolss_PrinterInfo2 *r,
+                                     struct spoolss_PrinterInfo6 *r,
                                      int snum)
 {
        int count;
-
        print_status_struct status;
 
        count = print_queue_length(snum, &status);
 
-       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
-       W_ERROR_HAVE_NO_MEMORY(r->servername);
-       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
-       W_ERROR_HAVE_NO_MEMORY(r->printername);
-       r->sharename            = talloc_strdup(mem_ctx, lp_servicename(snum));
-       W_ERROR_HAVE_NO_MEMORY(r->sharename);
-       r->portname             = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
-       W_ERROR_HAVE_NO_MEMORY(r->portname);
-       r->drivername           = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
-       W_ERROR_HAVE_NO_MEMORY(r->drivername);
+       r->status = nt_printq_status(status.status);
 
-       if (*ntprinter->info_2->comment == '\0') {
-               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+       return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_info7
+ * fill a spoolss_PrinterInfo7 struct
+ ********************************************************************/
+
+static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
+                                     Printer_entry *print_hnd,
+                                     struct spoolss_PrinterInfo7 *r,
+                                     int snum)
+{
+       struct GUID guid;
+
+       if (is_printer_published(print_hnd, snum, &guid)) {
+               r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
+               r->action = DSPRINT_PUBLISH;
        } else {
-               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment);
+               r->guid = talloc_strdup(mem_ctx, "");
+               r->action = DSPRINT_UNPUBLISH;
        }
-       W_ERROR_HAVE_NO_MEMORY(r->comment);
-
-       r->location             = talloc_strdup(mem_ctx, ntprinter->info_2->location);
-       W_ERROR_HAVE_NO_MEMORY(r->location);
-       r->sepfile              = talloc_strdup(mem_ctx, ntprinter->info_2->sepfile);
-       W_ERROR_HAVE_NO_MEMORY(r->sepfile);
-       r->printprocessor       = talloc_strdup(mem_ctx, ntprinter->info_2->printprocessor);
-       W_ERROR_HAVE_NO_MEMORY(r->printprocessor);
-       r->datatype             = talloc_strdup(mem_ctx, ntprinter->info_2->datatype);
-       W_ERROR_HAVE_NO_MEMORY(r->datatype);
-       r->parameters           = talloc_strdup(mem_ctx, ntprinter->info_2->parameters);
-       W_ERROR_HAVE_NO_MEMORY(r->parameters);
+       W_ERROR_HAVE_NO_MEMORY(r->guid);
 
-       r->attributes           = ntprinter->info_2->attributes;
+       return WERR_OK;
+}
 
-       r->priority             = ntprinter->info_2->priority;
-       r->defaultpriority      = ntprinter->info_2->default_priority;
-       r->starttime            = ntprinter->info_2->starttime;
-       r->untiltime            = ntprinter->info_2->untiltime;
-       r->status               = nt_printq_status(status.status);
-       r->cjobs                = count;
-       r->averageppm           = ntprinter->info_2->averageppm;
+/********************************************************************
+ * construct_printer_info8
+ * fill a spoolss_PrinterInfo8 struct
+ ********************************************************************/
 
+static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_DeviceModeInfo *r,
+                                     int snum)
+{
        r->devmode = construct_dev_mode(mem_ctx, lp_const_servicename(snum));
        if (!r->devmode) {
                DEBUG(8,("Returning NULL Devicemode!\n"));
        }
 
-       r->secdesc              = NULL;
-
-       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
-               /* don't use talloc_steal() here unless you do a deep steal of all
-                  the SEC_DESC members */
-
-               r->secdesc      = dup_sec_desc(mem_ctx, ntprinter->info_2->secdesc_buf->sd);
-       }
-
        return WERR_OK;
 }
 
+
 /********************************************************************
 ********************************************************************/
 
@@ -4510,7 +4267,7 @@ static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx,
 WERROR _spoolss_EnumPrinters(pipes_struct *p,
                             struct spoolss_EnumPrinters *r)
 {
-       const char *name;
+       const char *name = NULL;
        WERROR result;
 
        /* that's an [in out] buffer */
@@ -4538,8 +4295,10 @@ WERROR _spoolss_EnumPrinters(pipes_struct *p,
         * Level 5: same as Level 2
         */
 
-       name = talloc_strdup_upper(p->mem_ctx, r->in.server);
-       W_ERROR_HAVE_NO_MEMORY(name);
+       if (r->in.server) {
+               name = talloc_strdup_upper(p->mem_ctx, r->in.server);
+               W_ERROR_HAVE_NO_MEMORY(name);
+       }
 
        switch (r->in.level) {
        case 0:
@@ -4672,16 +4431,20 @@ WERROR _spoolss_GetPrinter(pipes_struct *p,
  ********************************************************************/
 
 static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
-                                                 fstring *fstring_array,
+                                                 const char **string_array,
                                                  const char *cservername)
 {
        int i, num_strings = 0;
        const char **array = NULL;
 
-       for (i=0; fstring_array && fstring_array[i][0] != '\0'; i++) {
+       if (!string_array) {
+               return NULL;
+       }
+
+       for (i=0; string_array[i] && string_array[i][0] != '\0'; i++) {
 
                const char *str = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                                                 cservername, fstring_array[i]);
+                                                 cservername, string_array[i]);
                if (!str) {
                        TALLOC_FREE(array);
                        return NULL;
@@ -4702,17 +4465,36 @@ static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
        return array;
 }
 
+#define FILL_DRIVER_STRING(mem_ctx, in, out) \
+       do { \
+               if (in && strlen(in)) { \
+                       out = talloc_strdup(mem_ctx, in); \
+                       W_ERROR_HAVE_NO_MEMORY(out); \
+               } else { \
+                       out = NULL; \
+               } \
+       } while (0);
+
+#define FILL_DRIVER_UNC_STRING(mem_ctx, server, in, out) \
+       do { \
+               if (in && strlen(in)) { \
+                       out = talloc_asprintf(mem_ctx, "\\\\%s%s", server, in); \
+               } else { \
+                       out = talloc_strdup(mem_ctx, ""); \
+               } \
+               W_ERROR_HAVE_NO_MEMORY(out); \
+       } while (0);
+
 /********************************************************************
  * fill a spoolss_DriverInfo1 struct
  ********************************************************************/
 
 static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo1 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
-                                       const char *servername,
-                                       const char *architecture)
+                                       const struct spoolss_DriverInfo8 *driver,
+                                       const char *servername)
 {
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
 
        return WERR_OK;
@@ -4724,42 +4506,30 @@ static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo2 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo8 *driver,
                                        const char *servername)
 
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
-               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
-       } else {
-               r->driver_path  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
-               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
-       } else {
-               r->data_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
-               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
-       } else {
-               r->config_file  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
 
        return WERR_OK;
 }
@@ -4770,57 +4540,44 @@ static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo3 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo8 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
-               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
-       } else {
-               r->driver_path  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
-               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
-       } else {
-               r->data_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
-               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
-       } else {
-               r->config_file  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
 
-       if (strlen(driver->info_3->helpfile)) {
-               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->helpfile);
-       } else {
-               r->help_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->help_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->help_file,
+                              r->help_file);
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
-       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
-       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->monitor_name,
+                          r->monitor_name);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->default_datatype,
+                          r->default_datatype);
 
        r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
+                                                          driver->dependent_files,
                                                           cservername);
        return WERR_OK;
 }
@@ -4831,62 +4588,48 @@ static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo4 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo8 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
-               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
-       } else {
-               r->driver_path  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
-               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
-       } else {
-               r->data_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
-               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
-       } else {
-               r->config_file  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
 
-       if (strlen(driver->info_3->helpfile)) {
-               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->helpfile);
-       } else {
-               r->help_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->help_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->help_file,
+                              r->help_file);
 
        r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
+                                                          driver->dependent_files,
                                                           cservername);
 
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->monitor_name,
+                          r->monitor_name);
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
-       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
-       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->default_datatype,
+                          r->default_datatype);
 
        r->previous_names = string_array_from_driver_info(mem_ctx,
-                                                         NULL,
+                                                         driver->previous_names,
                                                          cservername);
 
        return WERR_OK;
@@ -4898,41 +4641,29 @@ static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo5 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo8 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
-               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
-       } else {
-               r->driver_path  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
-               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
-       } else {
-               r->data_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
-               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
-       } else {
-               r->config_file  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
 
        r->driver_attributes    = 0;
        r->config_version       = 0;
@@ -4946,77 +4677,161 @@ static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo6 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo8 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
-               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
-       } else {
-               r->driver_path  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
-               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
-       } else {
-               r->data_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
-               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
-       } else {
-               r->config_file  = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
 
-       if (strlen(driver->info_3->helpfile)) {
-               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->helpfile);
-       } else {
-               r->help_file    = talloc_strdup(mem_ctx, "");
-       }
-       W_ERROR_HAVE_NO_MEMORY(r->help_file);
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->help_file,
+                              r->help_file);
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
-       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
-       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->monitor_name,
+                          r->monitor_name);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->default_datatype,
+                          r->default_datatype);
 
        r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
+                                                          driver->dependent_files,
                                                           cservername);
        r->previous_names = string_array_from_driver_info(mem_ctx,
-                                                         NULL,
+                                                         driver->previous_names,
                                                          cservername);
 
-       r->driver_date          = 0;
-       r->driver_version       = 0;
+       r->driver_date          = driver->driver_date;
+       r->driver_version       = driver->driver_version;
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_name,
+                          r->manufacturer_name);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_url,
+                          r->manufacturer_url);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->hardware_id,
+                          r->hardware_id);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->provider,
+                          r->provider);
+
+       return WERR_OK;
+}
+
+/********************************************************************
+ * fill a spoolss_DriverInfo8 struct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info8(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo8 *r,
+                                       const struct spoolss_DriverInfo8 *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
 
-       r->manufacturer_name    = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name);
-       r->manufacturer_url     = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url);
-       r->hardware_id          = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->hardware_id);
-       r->provider             = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->provider);
+       r->version              = driver->version;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->driver_path,
+                              r->driver_path);
+
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->data_file,
+                              r->data_file);
+
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->config_file,
+                              r->config_file);
+
+       FILL_DRIVER_UNC_STRING(mem_ctx, cservername,
+                              driver->help_file,
+                              r->help_file);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->monitor_name,
+                          r->monitor_name);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->default_datatype,
+                          r->default_datatype);
+
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->dependent_files,
+                                                          cservername);
+       r->previous_names = string_array_from_driver_info(mem_ctx,
+                                                         driver->previous_names,
+                                                         cservername);
+
+       r->driver_date          = driver->driver_date;
+       r->driver_version       = driver->driver_version;
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_name,
+                          r->manufacturer_name);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_url,
+                          r->manufacturer_url);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->hardware_id,
+                          r->hardware_id);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->provider,
+                          r->provider);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->print_processor,
+                          r->print_processor);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->vendor_setup,
+                          r->vendor_setup);
+
+       r->color_profiles = string_array_from_driver_info(mem_ctx,
+                                                         driver->color_profiles,
+                                                         cservername);
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->inf_path,
+                          r->inf_path);
+
+       r->printer_driver_attributes    = driver->printer_driver_attributes;
+
+       r->core_driver_dependencies = string_array_from_driver_info(mem_ctx,
+                                                                   driver->core_driver_dependencies,
+                                                                   cservername);
+
+       r->min_inbox_driver_ver_date    = driver->min_inbox_driver_ver_date;
+       r->min_inbox_driver_ver_version = driver->min_inbox_driver_ver_version;
 
        return WERR_OK;
 }
 
+#if 0 /* disabled until marshalling issues are resolved - gd */
 /********************************************************************
  ********************************************************************/
 
@@ -5040,7 +4855,7 @@ static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx,
  ********************************************************************/
 
 static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
-                                                const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                                const struct spoolss_DriverInfo8 *driver,
                                                 const char *cservername,
                                                 struct spoolss_DriverFileInfo **info_p,
                                                 uint32_t *count_p)
@@ -5053,7 +4868,7 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
        *info_p = NULL;
        *count_p = 0;
 
-       if (strlen(driver->info_3->driverpath)) {
+       if (strlen(driver->driver_path)) {
                info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                            struct spoolss_DriverFileInfo,
                                            count + 1);
@@ -5061,14 +4876,14 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
                result = fill_spoolss_DriverFileInfo(info,
                                                     &info[count],
                                                     cservername,
-                                                    driver->info_3->driverpath,
+                                                    driver->driver_path,
                                                     SPOOLSS_DRIVER_FILE_TYPE_RENDERING,
                                                     0);
                W_ERROR_NOT_OK_RETURN(result);
                count++;
        }
 
-       if (strlen(driver->info_3->configfile)) {
+       if (strlen(driver->config_file)) {
                info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                            struct spoolss_DriverFileInfo,
                                            count + 1);
@@ -5076,14 +4891,14 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
                result = fill_spoolss_DriverFileInfo(info,
                                                     &info[count],
                                                     cservername,
-                                                    driver->info_3->configfile,
+                                                    driver->config_file,
                                                     SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION,
                                                     0);
                W_ERROR_NOT_OK_RETURN(result);
                count++;
        }
 
-       if (strlen(driver->info_3->datafile)) {
+       if (strlen(driver->data_file)) {
                info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                            struct spoolss_DriverFileInfo,
                                            count + 1);
@@ -5091,14 +4906,14 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
                result = fill_spoolss_DriverFileInfo(info,
                                                     &info[count],
                                                     cservername,
-                                                    driver->info_3->datafile,
+                                                    driver->data_file,
                                                     SPOOLSS_DRIVER_FILE_TYPE_DATA,
                                                     0);
                W_ERROR_NOT_OK_RETURN(result);
                count++;
        }
 
-       if (strlen(driver->info_3->helpfile)) {
+       if (strlen(driver->help_file)) {
                info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                            struct spoolss_DriverFileInfo,
                                            count + 1);
@@ -5106,14 +4921,14 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
                result = fill_spoolss_DriverFileInfo(info,
                                                     &info[count],
                                                     cservername,
-                                                    driver->info_3->helpfile,
+                                                    driver->help_file,
                                                     SPOOLSS_DRIVER_FILE_TYPE_HELP,
                                                     0);
                W_ERROR_NOT_OK_RETURN(result);
                count++;
        }
 
-       for (i=0; driver->info_3->dependentfiles[i][0] != '\0'; i++) {
+       for (i=0; driver->dependent_files[i] && driver->dependent_files[i][0] != '\0'; i++) {
                info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                            struct spoolss_DriverFileInfo,
                                            count + 1);
@@ -5121,7 +4936,7 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
                result = fill_spoolss_DriverFileInfo(info,
                                                     &info[count],
                                                     cservername,
-                                                    driver->info_3->dependentfiles[i],
+                                                    driver->dependent_files[i],
                                                     SPOOLSS_DRIVER_FILE_TYPE_OTHER,
                                                     0);
                W_ERROR_NOT_OK_RETURN(result);
@@ -5135,22 +4950,22 @@ static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
 }
 
 /********************************************************************
- * fill a spoolss_DriverInfo101 sttruct
+ * fill a spoolss_DriverInfo101 struct
  ********************************************************************/
 
 static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
                                          struct spoolss_DriverInfo101 *r,
-                                         const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                         const struct spoolss_DriverInfo8 *driver,
                                          const char *servername)
 {
        const char *cservername = canon_servername(servername);
        WERROR result;
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
        result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver,
@@ -5161,249 +4976,64 @@ static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
                return result;
        }
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
-       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->monitor_name,
+                          r->monitor_name);
 
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
-       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->default_datatype,
+                          r->default_datatype);
 
        r->previous_names = string_array_from_driver_info(mem_ctx,
-                                                         NULL,
+                                                         driver->previous_names,
                                                          cservername);
-       r->driver_date          = 0;
-       r->driver_version       = 0;
-
-       r->manufacturer_name    = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name);
-       r->manufacturer_url     = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url);
-       r->hardware_id          = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->hardware_id);
-       r->provider             = talloc_strdup(mem_ctx, "");
-       W_ERROR_HAVE_NO_MEMORY(r->provider);
+       r->driver_date          = driver->driver_date;
+       r->driver_version       = driver->driver_version;
+
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_name,
+                          r->manufacturer_name);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->manufacturer_url,
+                          r->manufacturer_url);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->hardware_id,
+                          r->hardware_id);
+       FILL_DRIVER_STRING(mem_ctx,
+                          driver->provider,
+                          r->provider);
 
        return WERR_OK;
 }
-
-/********************************************************************
- * construct_printer_driver_info_1
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo1 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       WERROR result;
-
-       ZERO_STRUCT(driver);
-
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
-               free_a_printer(&printer, 2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
-       }
-
-       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
-
-       free_a_printer(&printer,2);
-
-       return result;
-}
-
+#endif
 /********************************************************************
- * construct_printer_driver_info_2
- * fill a printer_info_2 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo2 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
+static WERROR construct_printer_driver_info_level(TALLOC_CTX *mem_ctx,
+                                                 uint32_t level,
+                                                 union spoolss_DriverInfo *r,
+                                                 int snum,
+                                                 const char *servername,
+                                                 const char *architecture,
+                                                 uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       struct spoolss_DriverInfo8 *driver;
        WERROR result;
 
-       ZERO_STRUCT(printer);
-       ZERO_STRUCT(driver);
-
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
-               free_a_printer(&printer, 2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
-       }
-
-       result = fill_printer_driver_info2(mem_ctx, r, &driver, servername);
-
-       free_a_printer(&printer,2);
-
-       return result;
-}
-
-/********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo3 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       WERROR status;
-       ZERO_STRUCT(driver);
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-
-#if 0  /* JERRY */
-
-       /*
-        * I put this code in during testing.  Helpful when commenting out the
-        * support for DRIVER_INFO_6 in regards to win2k.  Not needed in general
-        * as win2k always queries the driver using an infor level of 6.
-        * I've left it in (but ifdef'd out) because I'll probably
-        * use it in experimentation again in the future.   --jerry 22/01/2002
-        */
-
-       if (!W_ERROR_IS_OK(status)) {
-               /*
-                * Is this a W2k client ?
-                */
-               if (version == 3) {
-                       /* Yes - try again with a WinNT driver. */
-                       version = 2;
-                       status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-                       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
-               }
-#endif
-
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-#if 0  /* JERRY */
-       }
-#endif
-
-
-       status = fill_printer_driver_info3(mem_ctx, r, &driver, servername);
-
-       free_a_printer(&printer,2);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_6
- * fill a printer_info_6 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo6 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
-       WERROR                          status;
-
-       ZERO_STRUCT(driver);
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       status = fill_printer_driver_info6(mem_ctx, r, &driver, servername);
-
-       free_a_printer(&printer,2);
-       free_a_printer_driver(driver, 3);
-
-       return status;
-}
-
-/********************************************************************
- * construct_printer_info_101
- * fill a printer_info_101 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
-                                               struct spoolss_DriverInfo101 *r,
-                                               int snum,
-                                               const char *servername,
-                                               const char *architecture,
-                                               uint32_t version)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
-       WERROR                          result;
-
-       ZERO_STRUCT(driver);
-
        result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
 
-       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+       DEBUG(8,("construct_printer_driver_info_level: status: %s\n",
                win_errstr(result)));
 
        if (!W_ERROR_IS_OK(result)) {
                return WERR_INVALID_PRINTER_NAME;
        }
 
-       result = get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+       result = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername,
                                      architecture, version);
 
-       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+       DEBUG(8,("construct_printer_driver_info_level: status: %s\n",
                win_errstr(result)));
 
        if (!W_ERROR_IS_OK(result)) {
@@ -5418,9 +5048,9 @@ static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
 
                /* Yes - try again with a WinNT driver. */
                version = 2;
-               result = get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+               result = get_a_printer_driver(mem_ctx, &driver, printer->info_2->drivername,
                                              architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n",
+               DEBUG(8,("construct_printer_driver_level: status: %s\n",
                        win_errstr(result)));
                if (!W_ERROR_IS_OK(result)) {
                        free_a_printer(&printer, 2);
@@ -5428,10 +5058,40 @@ static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
                }
        }
 
-       result = fill_printer_driver_info101(mem_ctx, r, &driver, servername);
+       switch (level) {
+       case 1:
+               result = fill_printer_driver_info1(mem_ctx, &r->info1, driver, servername);
+               break;
+       case 2:
+               result = fill_printer_driver_info2(mem_ctx, &r->info2, driver, servername);
+               break;
+       case 3:
+               result = fill_printer_driver_info3(mem_ctx, &r->info3, driver, servername);
+               break;
+       case 4:
+               result = fill_printer_driver_info4(mem_ctx, &r->info4, driver, servername);
+               break;
+       case 5:
+               result = fill_printer_driver_info5(mem_ctx, &r->info5, driver, servername);
+               break;
+       case 6:
+               result = fill_printer_driver_info6(mem_ctx, &r->info6, driver, servername);
+               break;
+       case 8:
+               result = fill_printer_driver_info8(mem_ctx, &r->info8, driver, servername);
+               break;
+#if 0 /* disabled until marshalling issues are resolved - gd */
+       case 101:
+               result = fill_printer_driver_info101(mem_ctx, &r->info101, driver, servername);
+               break;
+#endif
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
        free_a_printer(&printer, 2);
-       free_a_printer_driver(driver, 3);
+       free_a_printer_driver(driver);
 
        return result;
 }
@@ -5472,52 +5132,11 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
                return WERR_BADFID;
        }
 
-       switch (r->in.level) {
-       case 1:
-               result = construct_printer_driver_info_1(p->mem_ctx,
-                                                        &r->out.info->info1,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 2:
-               result = construct_printer_driver_info_2(p->mem_ctx,
-                                                        &r->out.info->info2,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 3:
-               result = construct_printer_driver_info_3(p->mem_ctx,
-                                                        &r->out.info->info3,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 6:
-               result = construct_printer_driver_info_6(p->mem_ctx,
-                                                        &r->out.info->info6,
-                                                        snum,
-                                                        servername,
-                                                        r->in.architecture,
-                                                        r->in.client_major_version);
-               break;
-       case 101:
-               result = construct_printer_driver_info_101(p->mem_ctx,
-                                                          &r->out.info->info101,
-                                                          snum,
-                                                          servername,
-                                                          r->in.architecture,
-                                                          r->in.client_major_version);
-               break;
-       default:
-               result = WERR_UNKNOWN_LEVEL;
-               break;
-       }
-
+       result = construct_printer_driver_info_level(p->mem_ctx, r->in.level,
+                                                    r->out.info, snum,
+                                                    servername,
+                                                    r->in.architecture,
+                                                    r->in.client_major_version);
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(r->out.info);
                return result;
@@ -5920,7 +5539,7 @@ static bool check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
 /****************************************************************************
 ****************************************************************************/
 
-WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri )
+static WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri)
 {
        char *cmd = lp_addport_cmd();
        char *command = NULL;
@@ -6034,7 +5653,9 @@ bool add_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, NT_PRINTER_INFO_LEV
        }
 
        /* reload our services immediately */
+       become_root();
        reload_services(false);
+       unbecome_root();
 
        numlines = 0;
        /* Get lines and convert them back to dos-codepage */
@@ -6069,7 +5690,7 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
        NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
        WERROR result;
-       UNISTR2 buffer;
+       DATA_BLOB buffer;
        fstring asc_buffer;
 
        DEBUG(8,("update_printer\n"));
@@ -6179,17 +5800,17 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
         */
 
        if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
-               init_unistr2( &buffer, printer->info_2->comment, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->comment);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_comment(snum, printer->info_2->comment);
        }
 
        if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
-               init_unistr2( &buffer, printer->info_2->sharename, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->sharename);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_sharename(snum, printer->info_2->sharename);
        }
@@ -6203,25 +5824,25 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
                        pname = printer->info_2->printername;
 
 
-               init_unistr2( &buffer, pname, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, pname);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_printername( snum, pname );
        }
 
        if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
-               init_unistr2( &buffer, printer->info_2->portname, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->portname);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_port(snum, printer->info_2->portname);
        }
 
        if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
-               init_unistr2( &buffer, printer->info_2->location, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->location);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_location(snum, printer->info_2->location);
        }
@@ -6229,17 +5850,17 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
        /* here we need to update some more DsSpooler keys */
        /* uNCName, serverName, shortServerName */
 
-       init_unistr2( &buffer, global_myname(), UNI_STR_TERMINATE);
+       push_reg_sz(talloc_tos(), &buffer, global_myname());
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
 
        slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
                  global_myname(), printer->info_2->sharename );
-       init_unistr2( &buffer, asc_buffer, UNI_STR_TERMINATE);
+       push_reg_sz(talloc_tos(), &buffer, asc_buffer);
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
 
        /* Update printer info */
        result = mod_a_printer(printer, 2);
@@ -6266,24 +5887,85 @@ static WERROR publish_or_unpublish_printer(pipes_struct *p,
                return WERR_UNKNOWN_LEVEL;
        }
 
-       Printer = find_printer_index_by_hnd(p, handle);
+       Printer = find_printer_index_by_hnd(p, handle);
+
+       DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
+
+       if (!Printer)
+               return WERR_BADFID;
+
+       if (!get_printer_snum(p, handle, &snum, NULL))
+               return WERR_BADFID;
+
+       nt_printer_publish(Printer, snum, info7->action);
+
+       return WERR_OK;
+#else
+       return WERR_UNKNOWN_LEVEL;
+#endif
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static WERROR update_printer_devmode(pipes_struct *p, struct policy_handle *handle,
+                                    struct spoolss_DeviceMode *devmode)
+{
+       int snum;
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+       WERROR result;
+
+       DEBUG(8,("update_printer_devmode\n"));
+
+       result = WERR_OK;
+
+       if (!Printer) {
+               result = WERR_BADFID;
+               goto done;
+       }
+
+       if (!get_printer_snum(p, handle, &snum, NULL)) {
+               result = WERR_BADFID;
+               goto done;
+       }
+
+       if (!W_ERROR_IS_OK(get_a_printer(Printer, &printer, 2, lp_const_servicename(snum)))) {
+               result = WERR_BADFID;
+               goto done;
+       }
+
+       if (devmode) {
+               /* we have a valid devmode
+                  convert it and link it*/
+
+               DEBUGADD(8,("update_printer: Converting the devicemode struct\n"));
+               if (!convert_devicemode(printer->info_2->printername, devmode,
+                                       &printer->info_2->devmode)) {
+                       result =  WERR_NOMEM;
+                       goto done;
+               }
+       }
+
+       /* Check calling user has permission to update printer description */
 
-       DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action));
+       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
+               DEBUG(3, ("update_printer: printer property change denied by handle\n"));
+               result = WERR_ACCESS_DENIED;
+               goto done;
+       }
 
-       if (!Printer)
-               return WERR_BADFID;
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
-               return WERR_BADFID;
+       /* Update printer info */
+       result = mod_a_printer(printer, 2);
 
-       nt_printer_publish(Printer, snum, info7->action);
+done:
+       free_a_printer(&printer, 2);
 
-       return WERR_OK;
-#else
-       return WERR_UNKNOWN_LEVEL;
-#endif
+       return result;
 }
 
+
 /****************************************************************
  _spoolss_SetPrinter
 ****************************************************************/
@@ -6321,6 +6003,9 @@ WERROR _spoolss_SetPrinter(pipes_struct *p,
                case 7:
                        return publish_or_unpublish_printer(p, r->in.handle,
                                                            r->in.info_ctr->info.info7);
+               case 8:
+                       return update_printer_devmode(p, r->in.handle,
+                                                     r->in.devmode_ctr->devmode);
                default:
                        return WERR_UNKNOWN_LEVEL;
        }
@@ -6481,6 +6166,27 @@ static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/****************************************************************************
+fill_job_info3
+****************************************************************************/
+
+static WERROR fill_job_info3(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo3 *r,
+                            const print_queue_struct *queue,
+                            const print_queue_struct *next_queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter)
+{
+       r->job_id               = queue->job;
+       r->next_job_id          = 0;
+       if (next_queue) {
+               r->next_job_id  = next_queue->job;
+       }
+       r->reserved             = 0;
+
+       return WERR_OK;
+}
+
 /****************************************************************************
  Enumjobs at level 1.
 ****************************************************************************/
@@ -6579,6 +6285,57 @@ static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/****************************************************************************
+ Enumjobs at level 3.
+****************************************************************************/
+
+static WERROR enumjobs_level3(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
+                              const NT_PRINTER_INFO_LEVEL *ntprinter,
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
+{
+       union spoolss_JobInfo *info;
+       int i;
+       WERROR result = WERR_OK;
+
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       *count = num_queues;
+
+       for (i=0; i<*count; i++) {
+               const print_queue_struct *next_queue = NULL;
+
+               if (i+1 < *count) {
+                       next_queue = &queue[i+1];
+               }
+
+               result = fill_job_info3(info,
+                                       &info[i].info3,
+                                       &queue[i],
+                                       next_queue,
+                                       i,
+                                       snum,
+                                       ntprinter);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
+
+       *info_p = info;
+
+       return WERR_OK;
+}
+
 /****************************************************************
  _spoolss_EnumJobs
 ****************************************************************/
@@ -6635,6 +6392,10 @@ WERROR _spoolss_EnumJobs(pipes_struct *p,
                result = enumjobs_level2(p->mem_ctx, queue, count, snum,
                                         ntprinter, r->out.info, r->out.count);
                break;
+       case 3:
+               result = enumjobs_level3(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
+               break;
        default:
                result = WERR_UNKNOWN_LEVEL;
                break;
@@ -6710,18 +6471,6 @@ WERROR _spoolss_SetJob(pipes_struct *p,
        return errcode;
 }
 
-static const struct print_architecture_table_node archi_table[]= {
-
-       {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
-       {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
-       {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
-       {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
-       {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
-       {"Windows IA64",         SPL_ARCH_IA64,         3 },
-       {"Windows x64",          SPL_ARCH_X64,          3 },
-       {NULL,                   "",            -1 }
-};
-
 /****************************************************************************
  Enumerates all printer drivers by level and architecture.
 ****************************************************************************/
@@ -6737,7 +6486,7 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
        int ndrivers;
        uint32_t version;
        fstring *list = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       struct spoolss_DriverInfo8 *driver;
        union spoolss_DriverInfo *info = NULL;
        uint32_t count = 0;
        WERROR result = WERR_OK;
@@ -6761,7 +6510,7 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
                                                    union spoolss_DriverInfo,
                                                    count + ndrivers);
                        if (!info) {
-                               DEBUG(0,("enumprinterdrivers_level1: "
+                               DEBUG(0,("enumprinterdrivers_level_by_architecture: "
                                        "failed to enlarge driver info buffer!\n"));
                                result = WERR_NOMEM;
                                goto out;
@@ -6771,7 +6520,7 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
                for (i=0; i<ndrivers; i++) {
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       result = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(mem_ctx, &driver, list[i],
                                                      architecture, version);
                        if (!W_ERROR_IS_OK(result)) {
                                goto out;
@@ -6780,39 +6529,42 @@ static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
                        switch (level) {
                        case 1:
                                result = fill_printer_driver_info1(info, &info[count+i].info1,
-                                                                  &driver, servername,
-                                                                  architecture);
+                                                                  driver, servername);
                                break;
                        case 2:
                                result = fill_printer_driver_info2(info, &info[count+i].info2,
-                                                                  &driver, servername);
+                                                                  driver, servername);
                                break;
                        case 3:
                                result = fill_printer_driver_info3(info, &info[count+i].info3,
-                                                                  &driver, servername);
+                                                                  driver, servername);
                                break;
                        case 4:
                                result = fill_printer_driver_info4(info, &info[count+i].info4,
-                                                                  &driver, servername);
+                                                                  driver, servername);
                                break;
                        case 5:
                                result = fill_printer_driver_info5(info, &info[count+i].info5,
-                                                                  &driver, servername);
+                                                                  driver, servername);
                                break;
                        case 6:
                                result = fill_printer_driver_info6(info, &info[count+i].info6,
-                                                                  &driver, servername);
+                                                                  driver, servername);
+                               break;
+                       case 8:
+                               result = fill_printer_driver_info8(info, &info[count+i].info8,
+                                                                  driver, servername);
                                break;
                        default:
                                result = WERR_UNKNOWN_LEVEL;
                                break;
                        }
 
+                       free_a_printer_driver(driver);
+
                        if (!W_ERROR_IS_OK(result)) {
-                               free_a_printer_driver(driver, 3);
                                goto out;
                        }
-                       free_a_printer_driver(driver, 3);
                }
 
                count += ndrivers;
@@ -6847,7 +6599,7 @@ static WERROR enumprinterdrivers_level(TALLOC_CTX *mem_ctx,
        uint32_t a,i;
        WERROR result = WERR_OK;
 
-       if (strequal(architecture, "all")) {
+       if (strequal(architecture, SPOOLSS_ARCHITECTURE_ALL)) {
 
                for (a=0; archi_table[a].long_archi != NULL; a++) {
 
@@ -6881,91 +6633,6 @@ static WERROR enumprinterdrivers_level(TALLOC_CTX *mem_ctx,
                                                        count_p);
 }
 
-/****************************************************************************
- Enumerates all printer drivers at level 1.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 1,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 2.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 2,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 3.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 3,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 4.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level4(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 4,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 5.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level5(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 5,
-                                       info_p, count);
-}
-
-/****************************************************************************
- Enumerates all printer drivers at level 6.
-****************************************************************************/
-
-static WERROR enumprinterdrivers_level6(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
-{
-       return enumprinterdrivers_level(mem_ctx, servername, architecture, 6,
-                                       info_p, count);
-}
-
-
 /****************************************************************
  _spoolss_EnumPrinterDrivers
 ****************************************************************/
@@ -6994,41 +6661,11 @@ WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       switch (r->in.level) {
-       case 1:
-               result = enumprinterdrivers_level1(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 2:
-               result = enumprinterdrivers_level2(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 3:
-               result = enumprinterdrivers_level3(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 4:
-               result = enumprinterdrivers_level4(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 5:
-               result = enumprinterdrivers_level5(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       case 6:
-               result = enumprinterdrivers_level6(p->mem_ctx, cservername,
-                                                  r->in.environment,
-                                                  r->out.info, r->out.count);
-               break;
-       default:
-               return WERR_UNKNOWN_LEVEL;
-       }
-
+       result = enumprinterdrivers_level(p->mem_ctx, cservername,
+                                         r->in.environment,
+                                         r->in.level,
+                                         r->out.info,
+                                         r->out.count);
        if (!W_ERROR_IS_OK(result)) {
                return result;
        }
@@ -7316,7 +6953,7 @@ static WERROR fill_port_2(TALLOC_CTX *mem_ctx,
  wrapper around the enumer ports command
 ****************************************************************************/
 
-WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines )
+static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines)
 {
        char *cmd = lp_enumports_cmd();
        char **qlines = NULL;
@@ -7551,6 +7188,15 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
                return WERR_NOMEM;
        }
 
+       /* samba does not have a concept of local, non-shared printers yet, so
+        * make sure we always setup sharename - gd */
+       if ((printer->info_2->sharename[0] == '\0') && (printer->info_2->printername != '\0')) {
+               DEBUG(5, ("spoolss_addprinterex_level_2: "
+                       "no sharename has been set, setting printername %s as sharename\n",
+                       printer->info_2->printername));
+               fstrcpy(printer->info_2->sharename, printer->info_2->printername);
+       }
+
        /* check to see if the printer already exists */
 
        if ((snum = print_queue_snum(printer->info_2->sharename)) != -1) {
@@ -7560,6 +7206,37 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
                return WERR_PRINTER_ALREADY_EXISTS;
        }
 
+       if (!lp_force_printername(GLOBAL_SECTION_SNUM)) {
+               if ((snum = print_queue_snum(printer->info_2->printername)) != -1) {
+                       DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n",
+                               printer->info_2->printername));
+                       free_a_printer(&printer, 2);
+                       return WERR_PRINTER_ALREADY_EXISTS;
+               }
+       }
+
+       /* validate printer info struct */
+       if (!info_ctr->info.info2->printername ||
+           strlen(info_ctr->info.info2->printername) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_INVALID_PRINTER_NAME;
+       }
+       if (!info_ctr->info.info2->portname ||
+           strlen(info_ctr->info.info2->portname) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PORT;
+       }
+       if (!info_ctr->info.info2->drivername ||
+           strlen(info_ctr->info.info2->drivername) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
+       if (!info_ctr->info.info2->printprocessor ||
+           strlen(info_ctr->info.info2->printprocessor) == 0) {
+               free_a_printer(&printer,2);
+               return WERR_UNKNOWN_PRINTPROCESSOR;
+       }
+
        /* FIXME!!!  smbd should check to see if the driver is installed before
           trying to add a printer like this  --jerry */
 
@@ -7589,7 +7266,7 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
        }
 
        /* you must be a printer admin to add a new printer */
-       if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+       if (!print_access_check(p->server_info, snum, PRINTER_ACCESS_ADMINISTER)) {
                free_a_printer(&printer,2);
                return WERR_ACCESS_DENIED;
        }
@@ -7701,11 +7378,8 @@ WERROR _spoolss_AddPrinter(pipes_struct *p,
 WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                                 struct spoolss_AddPrinterDriver *r)
 {
-       uint32_t level = r->in.info_ctr->level;
-       struct spoolss_AddDriverInfoCtr *info = r->in.info_ctr;
        WERROR err = WERR_OK;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       const char *driver_name = NULL;
+       char *driver_name = NULL;
        uint32_t version;
        const char *fn;
 
@@ -7722,46 +7396,31 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
 
 
        /* FIXME */
-       if (level != 3 && level != 6) {
+       if (r->in.info_ctr->level != 3 && r->in.info_ctr->level != 6) {
                /* Clever hack from Martin Zielinski <mz@seh.de>
                 * to allow downgrade from level 8 (Vista).
                 */
-               DEBUG(0,("%s: level %d not yet implemented\n", fn, level));
+               DEBUG(0,("%s: level %d not yet implemented\n", fn,
+                       r->in.info_ctr->level));
                return WERR_UNKNOWN_LEVEL;
        }
 
-       ZERO_STRUCT(driver);
-
-       if (!convert_printer_driver_info(info, &driver, level)) {
-               err = WERR_NOMEM;
-               goto done;
-       }
-
        DEBUG(5,("Cleaning driver's information\n"));
-       err = clean_up_driver_struct(p, driver, level);
+       err = clean_up_driver_struct(p, r->in.info_ctr);
        if (!W_ERROR_IS_OK(err))
                goto done;
 
        DEBUG(5,("Moving driver to final destination\n"));
-       if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, driver, level,
+       if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, r->in.info_ctr,
                                                              &err)) ) {
                goto done;
        }
 
-       if (add_a_printer_driver(driver, level)!=0) {
+       if (add_a_printer_driver(p->mem_ctx, r->in.info_ctr, &driver_name, &version)!=0) {
                err = WERR_ACCESS_DENIED;
                goto done;
        }
 
-        switch(level) {
-       case 3:
-               driver_name = driver.info_3->name ? driver.info_3->name : "";
-               break;
-       case 6:
-               driver_name = driver.info_6->name ? driver.info_6->name : "";
-               break;
-        }
-
        /*
         * I think this is where he DrvUpgradePrinter() hook would be
         * be called in a driver's interface DLL on a Windows NT 4.0/2k
@@ -7784,12 +7443,7 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
         * It is necessary to follow the driver install by an initialization step to
         * finish off this process.
        */
-       if (level == 3)
-               version = driver.info_3->cversion;
-       else if (level == 6)
-               version = driver.info_6->version;
-       else
-               version = -1;
+
        switch (version) {
                /*
                 * 9x printer driver - never delete init data
@@ -7805,9 +7459,9 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                */
                case 2:
                {
-                       NT_PRINTER_DRIVER_INFO_LEVEL driver1;
+                       struct spoolss_DriverInfo8 *driver1;
 
-                       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver1, 3, driver_name, "Windows NT x86", 3))) {
+                       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &driver1, driver_name, "Windows NT x86", 3))) {
                                /*
                                 * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
                                */
@@ -7818,7 +7472,7 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                                /*
                                 * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
                                */
-                               free_a_printer_driver(driver1,3);
+                               free_a_printer_driver(driver1);
                                DEBUG(10,("%s: init data not deleted for Nt driver [%s]\n",
                                        fn, driver_name));
                        }
@@ -7835,13 +7489,13 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                        break;
 
                default:
-                       DEBUG(0,("%s: invalid level=%d\n", fn, level));
+                       DEBUG(0,("%s: invalid level=%d\n", fn,
+                               r->in.info_ctr->level));
                        break;
        }
 
 
 done:
-       free_a_printer_driver(driver, level);
        return err;
 }
 
@@ -8143,111 +7797,53 @@ WERROR _spoolss_EnumPrinterData(pipes_struct *p,
                        *r->out.value_needed = strlen_m(regval_name(val));
                } else {
                        r->out.value_name = NULL;
-                       *r->out.value_needed = 0;
-               }
-
-               /* type */
-
-               *r->out.type = regval_type(val);
-
-               /* data - counted in bytes */
-
-               if (r->out.data && regval_size(val)) {
-                       memcpy(r->out.data, regval_data_p(val), regval_size(val));
-               }
-
-               *r->out.data_needed = regval_size(val);
-       }
-
-done:
-       free_a_printer(&printer, 2);
-       return result;
-}
-
-/****************************************************************
- _spoolss_SetPrinterData
-****************************************************************/
-
-WERROR _spoolss_SetPrinterData(pipes_struct *p,
-                              struct spoolss_SetPrinterData *r)
-{
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       int snum=0;
-       WERROR result = WERR_OK;
-       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
-       DATA_BLOB blob;
-
-       DEBUG(5,("_spoolss_SetPrinterData\n"));
-
-       if (!Printer) {
-               DEBUG(2,("_spoolss_SetPrinterData: Invalid handle (%s:%u:%u).\n",
-                       OUR_HANDLE(r->in.handle)));
-               return WERR_BADFID;
-       }
-
-       if (Printer->printer_type == SPLHND_SERVER) {
-               DEBUG(10,("_spoolss_SetPrinterData: "
-                       "Not implemented for server handles yet\n"));
-               return WERR_INVALID_PARAM;
-       }
-
-       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
-               return WERR_BADFID;
-       }
-
-       /*
-        * Access check : NT returns "access denied" if you make a
-        * SetPrinterData call without the necessary privildge.
-        * we were originally returning OK if nothing changed
-        * which made Win2k issue **a lot** of SetPrinterData
-        * when connecting to a printer  --jerry
-        */
-
-       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
-               DEBUG(3,("_spoolss_SetPrinterData: "
-                       "change denied by handle access permissions\n"));
-               result = WERR_ACCESS_DENIED;
-               goto done;
-       }
-
-       result = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
-       if (!W_ERROR_IS_OK(result)) {
-               return result;
-       }
+                       *r->out.value_needed = 0;
+               }
 
-       result = push_spoolss_PrinterData(p->mem_ctx, &blob,
-                                         r->in.type, &r->in.data);
-       if (!W_ERROR_IS_OK(result)) {
-               goto done;
-       }
+               /* type */
 
-       /*
-        * When client side code sets a magic printer data key, detect it and save
-        * the current printer data and the magic key's data (its the DEVMODE) for
-        * future printer/driver initializations.
-        */
-       if ((r->in.type == REG_BINARY) && strequal(r->in.value_name, PHANTOM_DEVMODE_KEY)) {
-               /* Set devmode and printer initialization info */
-               result = save_driver_init(printer, 2, blob.data, blob.length);
+               *r->out.type = regval_type(val);
 
-               srv_spoolss_reset_printerdata(printer->info_2->drivername);
+               /* data - counted in bytes */
 
-               goto done;
-       }
+               /*
+                * See the section "Dynamically Typed Query Parameters"
+                * in MS-RPRN.
+                */
+
+               if (r->out.data && regval_data_p(val) &&
+                               regval_size(val) && r->in.data_offered) {
+                       memcpy(r->out.data, regval_data_p(val),
+                               MIN(regval_size(val),r->in.data_offered));
+               }
 
-       result = set_printer_dataex(printer, SPOOL_PRINTERDATA_KEY,
-                                   r->in.value_name, r->in.type,
-                                   blob.data, blob.length);
-       if (W_ERROR_IS_OK(result)) {
-               result = mod_a_printer(printer, 2);
+               *r->out.data_needed = regval_size(val);
        }
 
 done:
        free_a_printer(&printer, 2);
-
        return result;
 }
 
+/****************************************************************
+ _spoolss_SetPrinterData
+****************************************************************/
+
+WERROR _spoolss_SetPrinterData(pipes_struct *p,
+                              struct spoolss_SetPrinterData *r)
+{
+       struct spoolss_SetPrinterDataEx r2;
+
+       r2.in.handle            = r->in.handle;
+       r2.in.key_name          = "PrinterDriverData";
+       r2.in.value_name        = r->in.value_name;
+       r2.in.type              = r->in.type;
+       r2.in.data              = r->in.data;
+       r2.in._offered          = r->in._offered;
+
+       return _spoolss_SetPrinterDataEx(p, &r2);
+}
+
 /****************************************************************
  _spoolss_ResetPrinter
 ****************************************************************/
@@ -8287,46 +7883,13 @@ WERROR _spoolss_ResetPrinter(pipes_struct *p,
 WERROR _spoolss_DeletePrinterData(pipes_struct *p,
                                  struct spoolss_DeletePrinterData *r)
 {
-       NT_PRINTER_INFO_LEVEL   *printer = NULL;
-       int             snum=0;
-       WERROR          status = WERR_OK;
-       Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
-
-       DEBUG(5,("_spoolss_DeletePrinterData\n"));
-
-       if (!Printer) {
-               DEBUG(2,("_spoolss_DeletePrinterData: Invalid handle (%s:%u:%u).\n",
-                       OUR_HANDLE(r->in.handle)));
-               return WERR_BADFID;
-       }
-
-       if (!get_printer_snum(p, r->in.handle, &snum, NULL))
-               return WERR_BADFID;
-
-       if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) {
-               DEBUG(3, ("_spoolss_DeletePrinterData: "
-                       "printer properties change denied by handle\n"));
-               return WERR_ACCESS_DENIED;
-       }
-
-       status = get_a_printer(Printer, &printer, 2, lp_const_servicename(snum));
-       if (!W_ERROR_IS_OK(status))
-               return status;
-
-       if (!r->in.value_name) {
-               free_a_printer(&printer, 2);
-               return WERR_NOMEM;
-       }
+       struct spoolss_DeletePrinterDataEx r2;
 
-       status = delete_printer_dataex( printer, SPOOL_PRINTERDATA_KEY,
-                                       r->in.value_name );
+       r2.in.handle            = r->in.handle;
+       r2.in.key_name          = "PrinterDriverData";
+       r2.in.value_name        = r->in.value_name;
 
-       if ( W_ERROR_IS_OK(status) )
-               mod_a_printer( printer, 2 );
-
-       free_a_printer(&printer, 2);
-
-       return status;
+       return _spoolss_DeletePrinterDataEx(p, &r2);
 }
 
 /****************************************************************
@@ -9090,9 +8653,6 @@ WERROR _spoolss_GetJob(pipes_struct *p,
 
 /****************************************************************
  _spoolss_GetPrinterDataEx
-
- From MSDN documentation of GetPrinterDataEx: pass request
- to GetPrinterData if key is "PrinterDriverData".
 ****************************************************************/
 
 WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
@@ -9104,6 +8664,7 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        int                     snum = 0;
        WERROR result = WERR_OK;
+       DATA_BLOB blob;
 
        DEBUG(4,("_spoolss_GetPrinterDataEx\n"));
 
@@ -9125,14 +8686,17 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
        /* Is the handle to a printer or to the server? */
 
        if (Printer->printer_type == SPLHND_SERVER) {
-               DEBUG(10,("_spoolss_GetPrinterDataEx: "
-                       "Not implemented for server handles yet\n"));
-               result = WERR_INVALID_PARAM;
+
+               result = getprinterdata_printer_server(p->mem_ctx,
+                                                      r->in.value_name,
+                                                      r->out.type,
+                                                      r->out.data);
                goto done;
        }
 
        if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
-               return WERR_BADFID;
+               result = WERR_BADFID;
+               goto done;
        }
 
        result = get_a_printer(Printer, &printer, 2, lp_servicename(snum));
@@ -9146,6 +8710,17 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
                goto done;
        }
 
+       /* XP sends this and wants to change id value from the PRINTER_INFO_0 */
+
+       if (strequal(r->in.key_name, SPOOL_PRINTERDATA_KEY) &&
+           strequal(r->in.value_name, "ChangeId")) {
+               *r->out.type = REG_DWORD;
+               *r->out.needed = 4;
+               r->out.data->value = printer->info_2->changeid;
+               result = WERR_OK;
+               goto done;
+       }
+
        if (lookup_printerkey(printer->info_2->data, r->in.key_name) == -1) {
                DEBUG(4,("_spoolss_GetPrinterDataEx: "
                        "Invalid keyname [%s]\n", r->in.key_name ));
@@ -9153,8 +8728,6 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
                goto done;
        }
 
-       /* When given a new keyname, we should just create it */
-
        val = get_printer_data(printer->info_2,
                               r->in.key_name, r->in.value_name);
        if (!val) {
@@ -9163,22 +8736,28 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
        }
 
        *r->out.needed = regval_size(val);
-
-       if (*r->out.needed > r->in.offered) {
-               result = WERR_MORE_DATA;
-               goto done;
-       }
-
        *r->out.type = regval_type(val);
 
-       memcpy(r->out.buffer, regval_data_p(val), regval_size(val));
+       blob = data_blob_const(regval_data_p(val), regval_size(val));
+
+       result = pull_spoolss_PrinterData(p->mem_ctx, &blob,
+                                         r->out.data,
+                                         *r->out.type);
 
  done:
        if (printer) {
                free_a_printer(&printer, 2);
        }
 
-       return result;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = ndr_size_spoolss_PrinterData(r->out.data, *r->out.type, NULL, 0);
+       *r->out.type    = SPOOLSS_BUFFER_OK(*r->out.type, REG_NONE);
+       r->out.data     = SPOOLSS_BUFFER_OK(r->out.data, r->out.data);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA);
 }
 
 /****************************************************************
@@ -9193,6 +8772,7 @@ WERROR _spoolss_SetPrinterDataEx(pipes_struct *p,
        WERROR                  result = WERR_OK;
        Printer_entry           *Printer = find_printer_index_by_hnd(p, r->in.handle);
        char                    *oid_string;
+       DATA_BLOB blob;
 
        DEBUG(4,("_spoolss_SetPrinterDataEx\n"));
 
@@ -9242,10 +8822,30 @@ WERROR _spoolss_SetPrinterDataEx(pipes_struct *p,
                oid_string++;
        }
 
+       result = push_spoolss_PrinterData(p->mem_ctx, &blob,
+                                         r->in.type, &r->in.data);
+       if (!W_ERROR_IS_OK(result)) {
+               goto done;
+       }
+
+       /*
+        * When client side code sets a magic printer data key, detect it and save
+        * the current printer data and the magic key's data (its the DEVMODE) for
+        * future printer/driver initializations.
+        */
+       if ((r->in.type == REG_BINARY) && strequal(r->in.value_name, PHANTOM_DEVMODE_KEY)) {
+               /* Set devmode and printer initialization info */
+               result = save_driver_init(printer, 2, blob.data, blob.length);
+
+               srv_spoolss_reset_printerdata(printer->info_2->drivername);
+
+               goto done;
+       }
+
        /* save the registry data */
 
        result = set_printer_dataex(printer, r->in.key_name, r->in.value_name,
-                                   r->in.type, r->in.buffer, r->in.offered);
+                                   r->in.type, blob.data, blob.length);
 
        if (W_ERROR_IS_OK(result)) {
                /* save the OID if one was specified */
@@ -9342,7 +8942,7 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
        WERROR          result = WERR_BADFILE;
        int i;
        const char **array = NULL;
-
+       DATA_BLOB blob;
 
        DEBUG(4,("_spoolss_EnumPrinterKey\n"));
 
@@ -9371,37 +8971,53 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
                goto done;
        }
 
-       *r->out.needed = 4;
-
-       array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 1);
+       array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 2);
        if (!array) {
                result = WERR_NOMEM;
                goto done;
        }
 
+       if (!num_keys) {
+               array[0] = talloc_strdup(array, "");
+               if (!array[0]) {
+                       result = WERR_NOMEM;
+                       goto done;
+               }
+       }
+
        for (i=0; i < num_keys; i++) {
+
+               DEBUG(10,("_spoolss_EnumPrinterKey: adding keyname: %s\n",
+                       keynames[i]));
+
                array[i] = talloc_strdup(array, keynames[i]);
                if (!array[i]) {
                        result = WERR_NOMEM;
                        goto done;
                }
-
-               *r->out.needed += strlen_m_term(keynames[i]) * 2;
        }
 
-       if (r->in.offered < *r->out.needed) {
-               result = WERR_MORE_DATA;
+       if (!push_reg_multi_sz(p->mem_ctx, &blob, array)) {
+               result = WERR_NOMEM;
                goto done;
        }
 
-       result = WERR_OK;
+       *r->out._ndr_size = r->in.offered / 2;
+       *r->out.needed = blob.length;
 
-       *r->out.key_buffer = array;
+       if (r->in.offered < *r->out.needed) {
+               result = WERR_MORE_DATA;
+       } else {
+               result = WERR_OK;
+               r->out.key_buffer->string_array = array;
+       }
 
  done:
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(array);
-               ZERO_STRUCTP(r->out.key_buffer);
+               if (!W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
+                       *r->out.needed = 0;
+               }
        }
 
        free_a_printer(&printer, 2);
@@ -9681,8 +9297,12 @@ WERROR _spoolss_GetPrintProcessorDirectory(pipes_struct *p,
 
        /* r->in.level is ignored */
 
+       /* We always should reply with a local print processor directory so that
+        * users are not forced to have a [prnproc$] share on the Samba spoolss
+        * server - Guenther */
+
        result = getprintprocessordirectory_level_1(p->mem_ctx,
-                                                   r->in.server,
+                                                   NULL, /* r->in.server */
                                                    r->in.environment,
                                                    &r->out.info->info1);
        if (!W_ERROR_IS_OK(result)) {
@@ -10007,7 +9627,10 @@ WERROR _spoolss_XcvData(pipes_struct *p,
 
        *r->out.status_code = 0;
 
-       memcpy(r->out.out_data, out_data.data, out_data.length);
+       if (r->out.out_data && out_data.data && r->in.out_data_size && out_data.length) {
+               memcpy(r->out.out_data, out_data.data,
+                       MIN(r->in.out_data_size, out_data.length));
+       }
 
        return WERR_OK;
 }
@@ -10501,3 +10124,156 @@ WERROR _spoolss_5f(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
+/****************************************************************
+ _spoolss_60
+****************************************************************/
+
+WERROR _spoolss_60(pipes_struct *p,
+                  struct spoolss_60 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_61
+****************************************************************/
+
+WERROR _spoolss_61(pipes_struct *p,
+                  struct spoolss_61 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_62
+****************************************************************/
+
+WERROR _spoolss_62(pipes_struct *p,
+                  struct spoolss_62 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_63
+****************************************************************/
+
+WERROR _spoolss_63(pipes_struct *p,
+                  struct spoolss_63 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_64
+****************************************************************/
+
+WERROR _spoolss_64(pipes_struct *p,
+                  struct spoolss_64 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_65
+****************************************************************/
+
+WERROR _spoolss_65(pipes_struct *p,
+                  struct spoolss_65 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_GetCorePrinterDrivers
+****************************************************************/
+
+WERROR _spoolss_GetCorePrinterDrivers(pipes_struct *p,
+                                     struct spoolss_GetCorePrinterDrivers *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_67
+****************************************************************/
+
+WERROR _spoolss_67(pipes_struct *p,
+                  struct spoolss_67 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_GetPrinterDriverPackagePath
+****************************************************************/
+
+WERROR _spoolss_GetPrinterDriverPackagePath(pipes_struct *p,
+                                           struct spoolss_GetPrinterDriverPackagePath *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_69
+****************************************************************/
+
+WERROR _spoolss_69(pipes_struct *p,
+                  struct spoolss_69 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6a
+****************************************************************/
+
+WERROR _spoolss_6a(pipes_struct *p,
+                  struct spoolss_6a *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6b
+****************************************************************/
+
+WERROR _spoolss_6b(pipes_struct *p,
+                  struct spoolss_6b *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6c
+****************************************************************/
+
+WERROR _spoolss_6c(pipes_struct *p,
+                  struct spoolss_6c *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6d
+****************************************************************/
+
+WERROR _spoolss_6d(pipes_struct *p,
+                  struct spoolss_6d *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}