s3:registry: move reg_objects.h to registry/ and use it only where needed
[amitay/samba.git] / source3 / printing / nt_printing.c
index 8e6fe1f364fda426aecbbe4b16986f33b8f8b882..42ea5fb7c4e71be0813d6913a05a4c64dec64e00 100644 (file)
  */
 
 #include "includes.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "printing/pcap.h"
+#include "registry.h"
+#include "registry/reg_objects.h"
 
 static TDB_CONTEXT *tdb_forms; /* used for forms files */
 static TDB_CONTEXT *tdb_drivers; /* used for driver files */
@@ -27,7 +31,6 @@ static TDB_CONTEXT *tdb_printers; /* used for printers files */
 
 #define FORMS_PREFIX "FORMS/"
 #define DRIVERS_PREFIX "DRIVERS/"
-#define DRIVER_INIT_PREFIX "DRIVER_INIT/"
 #define PRINTERS_PREFIX "PRINTERS/"
 #define SECDESC_PREFIX "SECDESC/"
 #define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
@@ -91,6 +94,8 @@ static const nt_forms_struct default_forms[] = {
        {"Legal",0x1,0x34b5c,0x56d10,0x0,0x0,0x34b5c,0x56d10},
        {"Statement",0x1,0x221b4,0x34b5c,0x0,0x0,0x221b4,0x34b5c},
        {"Executive",0x1,0x2cf56,0x411cc,0x0,0x0,0x2cf56,0x411cc},
+       {"A0",0x1,0xcd528,0x122488,0x0,0x0,0xcd528,0x122488},
+       {"A1",0x1,0x91050,0xcd528,0x0,0x0,0x91050,0xcd528},
        {"A3",0x1,0x48828,0x668a0,0x0,0x0,0x48828,0x668a0},
        {"A4",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
        {"A4 Small",0x1,0x33450,0x48828,0x0,0x0,0x33450,0x48828},
@@ -204,21 +209,7 @@ static const nt_forms_struct default_forms[] = {
        {"PRC Envelope #10 Rotated",0x1,0x6fd10,0x4f1a0,0x0,0x0,0x6fd10,0x4f1a0}
 };
 
-struct table_node {
-       const char      *long_archi;
-       const char      *short_archi;
-       int     version;
-};
-
-#define SPL_ARCH_WIN40         "WIN40"
-#define SPL_ARCH_W32X86                "W32X86"
-#define SPL_ARCH_W32MIPS       "W32MIPS"
-#define SPL_ARCH_W32ALPHA      "W32ALPHA"
-#define SPL_ARCH_W32PPC                "W32PPC"
-#define SPL_ARCH_IA64          "IA64"
-#define SPL_ARCH_X64           "x64"
-
-static const struct table_node archi_table[]= {
+static const struct print_architecture_table_node archi_table[]= {
 
        {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
        {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
@@ -344,9 +335,9 @@ static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
                             TDB_DATA data, void *state )
 {
        NTSTATUS status;
-       SEC_DESC_BUF *sd_orig = NULL;
-       SEC_DESC_BUF *sd_new, *sd_store;
-       SEC_DESC *sec, *new_sec;
+       struct sec_desc_buf *sd_orig = NULL;
+       struct sec_desc_buf *sd_new, *sd_store;
+       struct security_descriptor *sec, *new_sec;
        TALLOC_CTX *ctx = state;
        int result, i;
        uint32 sd_size;
@@ -402,9 +393,9 @@ static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
                }
        }
 
-       /* create a new SEC_DESC with the appropriate owner and group SIDs */
+       /* create a new struct security_descriptor with the appropriate owner and group SIDs */
 
-       new_sec = make_sec_desc( ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+       new_sec = make_sec_desc( ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
                                 &global_sid_Builtin_Administrators,
                                 &global_sid_Builtin_Administrators,
                                 NULL, NULL, &size_new_sec );
@@ -416,15 +407,15 @@ static int sec_desc_upg_fn( TDB_CONTEXT *the_tdb, TDB_DATA key,
                return 0;
        }
 
-       if ( !(sd_store = sec_desc_merge( ctx, sd_new, sd_orig )) ) {
+       if ( !(sd_store = sec_desc_merge_buf( ctx, sd_new, sd_orig )) ) {
                DEBUG(0,("sec_desc_upg_fn: Failed to update sec_desc for %s\n", key.dptr ));
                return 0;
        }
 
        /* store it back */
 
-       sd_size = ndr_size_security_descriptor(sd_store->sd, NULL, 0)
-               + sizeof(SEC_DESC_BUF);
+       sd_size = ndr_size_security_descriptor(sd_store->sd, 0)
+               + sizeof(struct sec_desc_buf);
 
        status = marshall_sec_desc_buf(ctx, sd_store, &data.dptr, &data.dsize);
        if (!NT_STATUS_IS_OK(status)) {
@@ -622,17 +613,9 @@ bool nt_printing_init(struct messaging_context *msg_ctx)
        messaging_register(msg_ctx, NULL, MSG_PRINTER_DRVUPGRADE,
                           do_drv_upgrade_printer);
 
-       /*
-        * register callback to handle updating printer data
-        * when a driver is initialized
-        */
-
-       messaging_register(msg_ctx, NULL, MSG_PRINTERDATA_INIT_RESET,
-                          reset_all_printerdata);
-
        /* of course, none of the message callbacks matter if you don't
           tell messages.c that you interested in receiving PRINT_GENERAL
-          msgs.  This is done in claim_connection() */
+          msgs.  This is done in serverid_register() */
 
 
        if ( lp_security() == SEC_ADS ) {
@@ -648,25 +631,30 @@ bool nt_printing_init(struct messaging_context *msg_ctx)
  Function to allow filename parsing "the old way".
 ********************************************************************/
 
-static char *driver_unix_convert(connection_struct *conn,
-               const char *old_name,
-               SMB_STRUCT_STAT *pst)
+static NTSTATUS driver_unix_convert(connection_struct *conn,
+                                   const char *old_name,
+                                   struct smb_filename **smb_fname)
 {
+       NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
        char *name = talloc_strdup(ctx, old_name);
-       char *new_name = NULL;
 
        if (!name) {
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
        unix_format(name);
        name = unix_clean_name(ctx, name);
        if (!name) {
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
        trim_string(name,"/","/");
-       unix_convert(ctx,conn, name, false, &new_name, NULL, pst);
-       return new_name;
+
+       status = unix_convert(ctx, conn, name, smb_fname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       return NT_STATUS_OK;
 }
 
 /*******************************************************************
@@ -745,7 +733,7 @@ int get_builtin_ntforms(nt_forms_struct **list)
        if (!*list) {
                return 0;
        }
-       return sizeof(default_forms) / sizeof(default_forms[0]);
+       return ARRAY_SIZE(default_forms);
 }
 
 /****************************************************************************
@@ -754,18 +742,17 @@ int get_builtin_ntforms(nt_forms_struct **list)
 
 bool get_a_builtin_ntform_by_string(const char *form_name, nt_forms_struct *form)
 {
-       int i,count;
+       int i;
        DEBUGADD(6,("Looking for builtin form %s \n", form_name));
-       count = sizeof(default_forms) / sizeof(default_forms[0]);
-       for (i=0;i<count;i++) {
+       for (i=0; i<ARRAY_SIZE(default_forms); i++) {
                if (strequal(form_name,default_forms[i].name)) {
                        DEBUGADD(6,("Found builtin form %s \n", form_name));
                        memcpy(form,&default_forms[i],sizeof(*form));
-                       break;
+                       return true;
                }
        }
 
-       return (i !=count);
+       return false;
 }
 
 /****************************************************************************
@@ -928,7 +915,7 @@ bool delete_a_form(nt_forms_struct **list, const char *del_name, int *count, WER
 
        if (n == *count) {
                DEBUG(10,("delete_a_form, [%s] not found\n", del_name));
-               *ret = WERR_INVALID_PARAM;
+               *ret = WERR_INVALID_FORM_NAME;
                return False;
        }
 
@@ -1287,7 +1274,6 @@ the modification date). Otherwise chose the numerically larger version number.
 static int file_version_is_newer(connection_struct *conn, fstring new_file, fstring old_file)
 {
        bool use_version = true;
-       char *filepath = NULL;
 
        uint32 new_major;
        uint32 new_minor;
@@ -1297,20 +1283,20 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
        uint32 old_minor;
        time_t old_create_time;
 
+       struct smb_filename *smb_fname = NULL;
        files_struct    *fsp = NULL;
        SMB_STRUCT_STAT st;
-       SMB_STRUCT_STAT stat_buf;
 
        NTSTATUS status;
+       int ret;
 
        SET_STAT_INVALID(st);
-       SET_STAT_INVALID(stat_buf);
        new_create_time = (time_t)0;
        old_create_time = (time_t)0;
 
        /* Get file version info (if available) for previous file (if it exists) */
-       filepath = driver_unix_convert(conn,old_file,&stat_buf);
-       if (!filepath) {
+       status = driver_unix_convert(conn, old_file, &smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
                goto error_exit;
        }
 
@@ -1318,8 +1304,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                conn,                                   /* conn */
                NULL,                                   /* req */
                0,                                      /* root_dir_fid */
-               filepath,                               /* fname */
-               0,                                      /* create_file_flags */
+               smb_fname,                              /* fname */
                FILE_GENERIC_READ,                      /* access_mask */
                FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
                FILE_OPEN,                              /* create_disposition*/
@@ -1327,20 +1312,22 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
                0,                                      /* allocation_size */
+               0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL,                                   /* pinfo */
-               &stat_buf);                             /* psbuf */
+               NULL);                                  /* pinfo */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* Old file not found, so by definition new file is in fact newer */
-               DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n",
-                               filepath, errno));
-               return 1;
+               DEBUG(10,("file_version_is_newer: Can't open old file [%s], "
+                         "errno = %d\n", smb_fname_str_dbg(smb_fname),
+                         errno));
+               ret = 1;
+               goto done;
 
        } else {
-               int ret = get_file_version(fsp, old_file, &old_major, &old_minor);
+               ret = get_file_version(fsp, old_file, &old_major, &old_minor);
                if (ret == -1) {
                        goto error_exit;
                }
@@ -1352,7 +1339,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                        if (SMB_VFS_FSTAT(fsp, &st) == -1) {
                                 goto error_exit;
                        }
-                       old_create_time = st.st_mtime;
+                       old_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
                                (long)old_create_time));
                }
@@ -1361,8 +1348,8 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
        fsp = NULL;
 
        /* Get file version info (if available) for new file */
-       filepath = driver_unix_convert(conn,new_file,&stat_buf);
-       if (!filepath) {
+       status = driver_unix_convert(conn, new_file, &smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
                goto error_exit;
        }
 
@@ -1370,8 +1357,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                conn,                                   /* conn */
                NULL,                                   /* req */
                0,                                      /* root_dir_fid */
-               filepath,                               /* fname */
-               0,                                      /* create_file_flags */
+               smb_fname,                              /* fname */
                FILE_GENERIC_READ,                      /* access_mask */
                FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
                FILE_OPEN,                              /* create_disposition*/
@@ -1379,20 +1365,20 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
                0,                                      /* allocation_size */
+               0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL,                                   /* pinfo */
-               &stat_buf);                             /* psbuf */
+               NULL);                                  /* pinfo */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* New file not found, this shouldn't occur if the caller did its job */
-               DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n",
-                               filepath, errno));
+               DEBUG(3,("file_version_is_newer: Can't open new file [%s], "
+                        "errno = %d\n", smb_fname_str_dbg(smb_fname), errno));
                goto error_exit;
 
        } else {
-               int ret = get_file_version(fsp, new_file, &new_major, &new_minor);
+               ret = get_file_version(fsp, new_file, &new_major, &new_minor);
                if (ret == -1) {
                        goto error_exit;
                }
@@ -1404,7 +1390,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                        if (SMB_VFS_FSTAT(fsp, &st) == -1) {
                                goto error_exit;
                        }
-                       new_create_time = st.st_mtime;
+                       new_create_time = convert_timespec_to_time_t(st.st_ex_mtime);
                        DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n",
                                (long)new_create_time));
                }
@@ -1418,29 +1404,36 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
                        (new_major == old_major && new_minor > old_minor)) {
 
                        DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
-                       return 1;
+                       ret = 1;
+                       goto done;
                }
                else {
                        DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
-                       return 0;
+                       ret = 0;
+                       goto done;
                }
 
        } else {
                /* Compare modification time/dates and choose the newest time/date */
                if (new_create_time > old_create_time) {
                        DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file));
-                       return 1;
+                       ret = 1;
+                       goto done;
                }
                else {
                        DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file));
-                       return 0;
+                       ret = 0;
+                       goto done;
                }
        }
 
-       error_exit:
-               if(fsp)
-                       close_file(NULL, fsp, NORMAL_CLOSE);
-               return -1;
+ error_exit:
+       if(fsp)
+               close_file(NULL, fsp, NORMAL_CLOSE);
+       ret = -1;
+ done:
+       TALLOC_FREE(smb_fname);
+       return ret;
 }
 
 /****************************************************************************
@@ -1448,22 +1441,20 @@ Determine the correct cVersion associated with an architecture and driver
 ****************************************************************************/
 static uint32 get_correct_cversion(struct pipes_struct *p,
                                   const char *architecture,
-                                  fstring driverpath_in,
+                                  const char *driverpath_in,
                                   WERROR *perr)
 {
        int               cversion;
        NTSTATUS          nt_status;
-       char *driverpath = NULL;
+       struct smb_filename *smb_fname = NULL;
+       char *driverpath = NULL;
        files_struct      *fsp = NULL;
-       SMB_STRUCT_STAT   st;
        connection_struct *conn = NULL;
        NTSTATUS status;
        char *oldcwd;
        fstring printdollar;
        int printdollar_snum;
 
-       SET_STAT_INVALID(st);
-
        *perr = WERR_INVALID_PARAM;
 
        /* If architecture is Windows 95/98/ME, the version is always 0. */
@@ -1509,13 +1500,14 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                goto error_exit;
        }
 
-       driverpath = driver_unix_convert(conn,driverpath,&st);
-       if (!driverpath) {
-               *perr = WERR_NOMEM;
+       nt_status = driver_unix_convert(conn, driverpath, &smb_fname);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               *perr = ntstatus_to_werror(nt_status);
                goto error_exit;
        }
 
-       if (!vfs_file_exist(conn, driverpath, &st)) {
+       nt_status = vfs_file_exist(conn, smb_fname);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                *perr = WERR_BADFILE;
                goto error_exit;
        }
@@ -1524,34 +1516,37 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                conn,                                   /* conn */
                NULL,                                   /* req */
                0,                                      /* root_dir_fid */
-               driverpath,                             /* fname */
-               0,                                      /* create_file_flags */
+               smb_fname,                              /* fname */
                FILE_GENERIC_READ,                      /* access_mask */
                FILE_SHARE_READ | FILE_SHARE_WRITE,     /* share_access */
                FILE_OPEN,                              /* create_disposition*/
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                INTERNAL_OPEN_ONLY,                     /* oplock_request */
+               0,                                      /* private_flags */
                0,                                      /* allocation_size */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL,                                   /* pinfo */
-               &st);                                   /* psbuf */
+               NULL);                                  /* pinfo */
 
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n",
-                               driverpath, errno));
+               DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = "
+                        "%d\n", smb_fname_str_dbg(smb_fname), errno));
                *perr = WERR_ACCESS_DENIED;
                goto error_exit;
        } else {
                uint32 major;
                uint32 minor;
-               int    ret = get_file_version(fsp, driverpath, &major, &minor);
+               int    ret;
+
+               ret = get_file_version(fsp, smb_fname->base_name, &major, &minor);
                if (ret == -1) goto error_exit;
 
                if (!ret) {
-                       DEBUG(6,("get_correct_cversion: Version info not found [%s]\n", driverpath));
+                       DEBUG(6,("get_correct_cversion: Version info not "
+                                "found [%s]\n",
+                                smb_fname_str_dbg(smb_fname)));
                        goto error_exit;
                }
 
@@ -1569,29 +1564,33 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
                                break;
 
                        default:
-                               DEBUG(6,("get_correct_cversion: cversion invalid [%s]  cversion = %d\n",
-                                       driverpath, cversion));
+                               DEBUG(6,("get_correct_cversion: cversion "
+                                        "invalid [%s]  cversion = %d\n",
+                                        smb_fname_str_dbg(smb_fname),
+                                        cversion));
                                goto error_exit;
                }
 
-               DEBUG(10,("get_correct_cversion: Version info found [%s]  major = 0x%x  minor = 0x%x\n",
-                                 driverpath, major, minor));
+               DEBUG(10,("get_correct_cversion: Version info found [%s] major"
+                         " = 0x%x  minor = 0x%x\n",
+                         smb_fname_str_dbg(smb_fname), major, minor));
        }
 
        DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
-               driverpath, cversion));
+                 smb_fname_str_dbg(smb_fname), cversion));
 
        goto done;
 
  error_exit:
        cversion = -1;
  done:
+       TALLOC_FREE(smb_fname);
        if (fsp != NULL) {
                close_file(NULL, fsp, NORMAL_CLOSE);
        }
        if (conn != NULL) {
                vfs_ChDir(conn, oldcwd);
-               conn_free_internal(conn);
+               conn_free(conn);
        }
        if (cversion != -1) {
                *perr = WERR_OK;
@@ -1601,51 +1600,54 @@ static uint32 get_correct_cversion(struct pipes_struct *p,
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR clean_up_driver_struct_level_3(struct pipes_struct *rpc_pipe,
-                                            NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+
+#define strip_driver_path(_mem_ctx, _element) do { \
+       if (_element && ((_p = strrchr((_element), '\\')) != NULL)) { \
+               (_element) = talloc_asprintf((_mem_ctx), "%s", _p+1); \
+               W_ERROR_HAVE_NO_MEMORY((_element)); \
+       } \
+} while (0);
+
+static WERROR clean_up_driver_struct_level(TALLOC_CTX *mem_ctx,
+                                          struct pipes_struct *rpc_pipe,
+                                          const char *architecture,
+                                          const char **driver_path,
+                                          const char **data_file,
+                                          const char **config_file,
+                                          const char **help_file,
+                                          struct spoolss_StringArray *dependent_files,
+                                          uint32_t *version)
 {
-       const char *architecture;
-       fstring new_name;
-       char *p;
+       const char *short_architecture;
        int i;
        WERROR err;
+       char *_p;
+
+       if (!*driver_path || !*data_file || !*config_file) {
+               return WERR_INVALID_PARAM;
+       }
 
        /* clean up the driver name.
         * we can get .\driver.dll
         * or worse c:\windows\system\driver.dll !
         */
        /* using an intermediate string to not have overlaping memcpy()'s */
-       if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->driverpath, new_name);
-       }
-
-       if ((p = strrchr(driver->datafile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->datafile, new_name);
-       }
-
-       if ((p = strrchr(driver->configfile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->configfile, new_name);
-       }
 
-       if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->helpfile, new_name);
+       strip_driver_path(mem_ctx, *driver_path);
+       strip_driver_path(mem_ctx, *data_file);
+       strip_driver_path(mem_ctx, *config_file);
+       if (help_file) {
+               strip_driver_path(mem_ctx, *help_file);
        }
 
-       if (driver->dependentfiles) {
-               for (i=0; *driver->dependentfiles[i]; i++) {
-                       if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
-                               fstrcpy(new_name, p+1);
-                               fstrcpy(driver->dependentfiles[i], new_name);
-                       }
+       if (dependent_files && dependent_files->string) {
+               for (i=0; dependent_files->string[i]; i++) {
+                       strip_driver_path(mem_ctx, dependent_files->string[i]);
                }
        }
 
-       architecture = get_short_archi(driver->environment);
-       if (!architecture) {
+       short_architecture = get_short_archi(architecture);
+       if (!short_architecture) {
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
@@ -1660,162 +1662,175 @@ static WERROR clean_up_driver_struct_level_3(struct pipes_struct *rpc_pipe,
         *      NT 4: cversion=2
         *      NT2K: cversion=3
         */
-       if ((driver->cversion = get_correct_cversion(rpc_pipe, architecture,
-                                                    driver->driverpath,
-                                                    &err)) == -1)
+
+       *version = get_correct_cversion(rpc_pipe, short_architecture,
+                                       *driver_path, &err);
+       if (*version == -1) {
                return err;
+       }
 
        return WERR_OK;
 }
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR clean_up_driver_struct_level_6(struct pipes_struct *rpc_pipe,
-                                            NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
-{
-       const char *architecture;
-       fstring new_name;
-       char *p;
-       int i;
-       WERROR err;
-
-       /* clean up the driver name.
-        * we can get .\driver.dll
-        * or worse c:\windows\system\driver.dll !
-        */
-       /* using an intermediate string to not have overlaping memcpy()'s */
-       if ((p = strrchr(driver->driverpath,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->driverpath, new_name);
-       }
-
-       if ((p = strrchr(driver->datafile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->datafile, new_name);
-       }
-
-       if ((p = strrchr(driver->configfile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->configfile, new_name);
-       }
-
-       if ((p = strrchr(driver->helpfile,'\\')) != NULL) {
-               fstrcpy(new_name, p+1);
-               fstrcpy(driver->helpfile, new_name);
-       }
-
-       if (driver->dependentfiles) {
-               for (i=0; *driver->dependentfiles[i]; i++) {
-                       if ((p = strrchr(driver->dependentfiles[i],'\\')) != NULL) {
-                               fstrcpy(new_name, p+1);
-                               fstrcpy(driver->dependentfiles[i], new_name);
-                       }
-               }
-       }
 
-       architecture = get_short_archi(driver->environment);
-       if (!architecture) {
-               return WERR_UNKNOWN_PRINTER_DRIVER;
+WERROR clean_up_driver_struct(struct pipes_struct *rpc_pipe,
+                             struct spoolss_AddDriverInfoCtr *r)
+{
+       switch (r->level) {
+       case 3:
+               return clean_up_driver_struct_level(r, rpc_pipe,
+                                                   r->info.info3->architecture,
+                                                   &r->info.info3->driver_path,
+                                                   &r->info.info3->data_file,
+                                                   &r->info.info3->config_file,
+                                                   &r->info.info3->help_file,
+                                                   r->info.info3->dependent_files,
+                                                   &r->info.info3->version);
+       case 6:
+               return clean_up_driver_struct_level(r, rpc_pipe,
+                                                   r->info.info6->architecture,
+                                                   &r->info.info6->driver_path,
+                                                   &r->info.info6->data_file,
+                                                   &r->info.info6->config_file,
+                                                   &r->info.info6->help_file,
+                                                   r->info.info6->dependent_files,
+                                                   &r->info.info6->version);
+       default:
+               return WERR_NOT_SUPPORTED;
        }
+}
 
-       /* jfm:7/16/2000 the client always sends the cversion=0.
-        * The server should check which version the driver is by reading
-        * the PE header of driver->driverpath.
-        *
-        * For Windows 95/98 the version is 0 (so the value sent is correct)
-        * For Windows NT (the architecture doesn't matter)
-        *      NT 3.1: cversion=0
-        *      NT 3.5/3.51: cversion=1
-        *      NT 4: cversion=2
-        *      NT2K: cversion=3
-        */
-
-       if ((driver->version = get_correct_cversion(rpc_pipe, architecture,
-                                                   driver->driverpath,
-                                                   &err)) == -1)
-                       return err;
+/****************************************************************************
+ This function sucks and should be replaced. JRA.
+****************************************************************************/
 
-       return WERR_OK;
+static void convert_level_6_to_level3(struct spoolss_AddDriverInfo3 *dst,
+                                     const struct spoolss_AddDriverInfo6 *src)
+{
+       dst->version            = src->version;
+
+       dst->driver_name        = src->driver_name;
+       dst->architecture       = src->architecture;
+       dst->driver_path        = src->driver_path;
+       dst->data_file          = src->data_file;
+       dst->config_file        = src->config_file;
+       dst->help_file          = src->help_file;
+       dst->monitor_name       = src->monitor_name;
+       dst->default_datatype   = src->default_datatype;
+       dst->_ndr_size_dependent_files = src->_ndr_size_dependent_files;
+       dst->dependent_files    = src->dependent_files;
 }
 
 /****************************************************************************
+ This function sucks and should be replaced. JRA.
 ****************************************************************************/
-WERROR clean_up_driver_struct(struct pipes_struct *rpc_pipe,
-                             NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
-                             uint32 level)
+
+static void convert_level_8_to_level3(TALLOC_CTX *mem_ctx,
+                                     struct spoolss_AddDriverInfo3 *dst,
+                                     const struct spoolss_DriverInfo8 *src)
 {
-       switch (level) {
-               case 3:
-               {
-                       NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
-                       driver=driver_abstract.info_3;
-                       return clean_up_driver_struct_level_3(rpc_pipe,
-                                                             driver);
-               }
-               case 6:
-               {
-                       NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver;
-                       driver=driver_abstract.info_6;
-                       return clean_up_driver_struct_level_6(rpc_pipe,
-                                                             driver);
-               }
-               default:
-                       return WERR_INVALID_PARAM;
+       dst->version            = src->version;
+       dst->driver_name        = src->driver_name;
+       dst->architecture       = src->architecture;
+       dst->driver_path        = src->driver_path;
+       dst->data_file          = src->data_file;
+       dst->config_file        = src->config_file;
+       dst->help_file          = src->help_file;
+       dst->monitor_name       = src->monitor_name;
+       dst->default_datatype   = src->default_datatype;
+       if (src->dependent_files) {
+               dst->dependent_files = talloc_zero(mem_ctx, struct spoolss_StringArray);
+               if (!dst->dependent_files) return;
+               dst->dependent_files->string = src->dependent_files;
+       } else {
+               dst->dependent_files = NULL;
        }
 }
 
 /****************************************************************************
- This function sucks and should be replaced. JRA.
 ****************************************************************************/
 
-static void convert_level_6_to_level3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dst, NT_PRINTER_DRIVER_INFO_LEVEL_6 *src)
+static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx,
+                                               connection_struct *conn,
+                                               const char *driver_file,
+                                               const char *short_architecture,
+                                               uint32_t driver_version,
+                                               uint32_t version)
 {
-    dst->cversion  = src->version;
-
-    fstrcpy( dst->name, src->name);
-    fstrcpy( dst->environment, src->environment);
-    fstrcpy( dst->driverpath, src->driverpath);
-    fstrcpy( dst->datafile, src->datafile);
-    fstrcpy( dst->configfile, src->configfile);
-    fstrcpy( dst->helpfile, src->helpfile);
-    fstrcpy( dst->monitorname, src->monitorname);
-    fstrcpy( dst->defaultdatatype, src->defaultdatatype);
-    dst->dependentfiles = src->dependentfiles;
-}
+       struct smb_filename *smb_fname_old = NULL;
+       struct smb_filename *smb_fname_new = NULL;
+       char *old_name = NULL;
+       char *new_name = NULL;
+       NTSTATUS status;
+       WERROR ret;
 
-#if 0 /* Debugging function */
+       old_name = talloc_asprintf(mem_ctx, "%s/%s",
+                                  short_architecture, driver_file);
+       W_ERROR_HAVE_NO_MEMORY(old_name);
 
-static char* ffmt(unsigned char *c){
-       int i;
-       static char ffmt_str[17];
+       new_name = talloc_asprintf(mem_ctx, "%s/%d/%s",
+                                  short_architecture, driver_version, driver_file);
+       if (new_name == NULL) {
+               TALLOC_FREE(old_name);
+               return WERR_NOMEM;
+       }
+
+       if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) {
+
+               status = driver_unix_convert(conn, old_name, &smb_fname_old);
+               if (!NT_STATUS_IS_OK(status)) {
+                       ret = WERR_NOMEM;
+                       goto out;
+               }
 
-       for (i=0; i<16; i++) {
-               if ((c[i] < ' ') || (c[i] > '~'))
-                       ffmt_str[i]='.';
-               else
-                       ffmt_str[i]=c[i];
+               /* Setup a synthetic smb_filename struct */
+               smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename);
+               if (!smb_fname_new) {
+                       ret = WERR_NOMEM;
+                       goto out;
+               }
+
+               smb_fname_new->base_name = new_name;
+
+               DEBUG(10,("move_driver_file_to_download_area: copying '%s' to "
+                         "'%s'\n", smb_fname_old->base_name,
+                         smb_fname_new->base_name));
+
+               status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new,
+                                  OPENX_FILE_EXISTS_TRUNCATE |
+                                  OPENX_FILE_CREATE_IF_NOT_EXIST,
+                                  0, false);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("move_driver_file_to_download_area: Unable "
+                                "to rename [%s] to [%s]: %s\n",
+                                smb_fname_old->base_name, new_name,
+                                nt_errstr(status)));
+                       ret = WERR_ACCESS_DENIED;
+                       goto out;
+               }
        }
-    ffmt_str[16]='\0';
-       return ffmt_str;
-}
 
-#endif
+       ret = WERR_OK;
+ out:
+       TALLOC_FREE(smb_fname_old);
+       TALLOC_FREE(smb_fname_new);
+       return ret;
+}
 
-/****************************************************************************
-****************************************************************************/
 WERROR move_driver_to_download_area(struct pipes_struct *p,
-                                   NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
-                                   uint32 level, WERROR *perr)
+                                   struct spoolss_AddDriverInfoCtr *r,
+                                   WERROR *perr)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver;
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver;
-       const char *architecture;
+       struct spoolss_AddDriverInfo3 *driver;
+       struct spoolss_AddDriverInfo3 converted_driver;
+       const char *short_architecture;
+       struct smb_filename *smb_dname = NULL;
        char *new_dir = NULL;
-       char *old_name = NULL;
-       char *new_name = NULL;
        connection_struct *conn = NULL;
        NTSTATUS nt_status;
-       SMB_STRUCT_STAT st;
        int i;
        TALLOC_CTX *ctx = talloc_tos();
        int ver = 0;
@@ -1825,18 +1840,21 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
 
        *perr = WERR_OK;
 
-       if (level==3)
-               driver=driver_abstract.info_3;
-       else if (level==6) {
-               convert_level_6_to_level3(&converted_driver, driver_abstract.info_6);
+       switch (r->level) {
+       case 3:
+               driver = r->info.info3;
+               break;
+       case 6:
+               convert_level_6_to_level3(&converted_driver, r->info.info6);
                driver = &converted_driver;
-       } else {
-               DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)level ));
+               break;
+       default:
+               DEBUG(0,("move_driver_to_download_area: Unknown info level (%u)\n", (unsigned int)r->level));
                return WERR_UNKNOWN_LEVEL;
        }
 
-       architecture = get_short_archi(driver->environment);
-       if (!architecture) {
+       short_architecture = get_short_archi(driver->architecture);
+       if (!short_architecture) {
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
@@ -1858,34 +1876,35 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
                return *perr;
        }
 
-       DEBUG(5,("Creating first directory\n"));
        new_dir = talloc_asprintf(ctx,
                                "%s/%d",
-                               architecture,
-                               driver->cversion);
+                               short_architecture,
+                               driver->version);
        if (!new_dir) {
                *perr = WERR_NOMEM;
                goto err_exit;
        }
-       new_dir = driver_unix_convert(conn,new_dir,&st);
-       if (!new_dir) {
+       nt_status = driver_unix_convert(conn, new_dir, &smb_dname);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                *perr = WERR_NOMEM;
                goto err_exit;
        }
 
-       create_directory(conn, NULL, new_dir);
+       DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name));
+
+       create_directory(conn, NULL, smb_dname);
 
        /* For each driver file, archi\filexxx.yyy, if there is a duplicate file
         * listed for this driver which has already been moved, skip it (note:
         * drivers may list the same file name several times. Then check if the
-        * file already exists in archi\cversion\, if so, check that the version
+        * file already exists in archi\version\, if so, check that the version
         * info (or time stamps if version info is unavailable) is newer (or the
-        * date is later). If it is, move it to archi\cversion\filexxx.yyy.
+        * date is later). If it is, move it to archi\version\filexxx.yyy.
         * Otherwise, delete the file.
         *
-        * If a file is not moved to archi\cversion\ because of an error, all the
+        * If a file is not moved to archi\version\ because of an error, all the
         * rest of the 'unmoved' driver files are removed from archi\. If one or
-        * more of the driver's files was already moved to archi\cversion\, it
+        * more of the driver's files was already moved to archi\version\, it
         * potentially leaves the driver in a partially updated state. Version
         * trauma will most likely occur if an client attempts to use any printer
         * bound to the driver. Perhaps a rewrite to make sure the moves can be
@@ -1894,191 +1913,103 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
 
        DEBUG(5,("Moving files now !\n"));
 
-       if (driver->driverpath && strlen(driver->driverpath)) {
-               new_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       architecture,
-                                       driver->driverpath);
-               if (!new_name) {
-                       *perr = WERR_NOMEM;
-                       goto err_exit;
-               }
-               old_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       new_dir,
-                                       driver->driverpath);
-               if (!old_name) {
-                       *perr = WERR_NOMEM;
-                       goto err_exit;
-               }
+       if (driver->driver_path && strlen(driver->driver_path)) {
 
-               if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                       new_name = driver_unix_convert(conn,new_name,&st);
-                       if (!new_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
-                                               OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
-                               DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
-                                               new_name, old_name));
-                               *perr = WERR_ACCESS_DENIED;
+               *perr = move_driver_file_to_download_area(ctx,
+                                                         conn,
+                                                         driver->driver_path,
+                                                         short_architecture,
+                                                         driver->version,
+                                                         ver);
+               if (!W_ERROR_IS_OK(*perr)) {
+                       if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
                                ver = -1;
                        }
+                       goto err_exit;
                }
        }
 
-       if (driver->datafile && strlen(driver->datafile)) {
-               if (!strequal(driver->datafile, driver->driverpath)) {
-                       new_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       architecture,
-                                       driver->datafile);
-                       if (!new_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       old_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       new_dir,
-                                       driver->datafile);
-                       if (!old_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               new_name = driver_unix_convert(conn,new_name,&st);
-                               if (!new_name) {
-                                       *perr = WERR_NOMEM;
-                                       goto err_exit;
-                               }
-                               if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
-                                               OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
-                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
-                                                       new_name, old_name));
-                                       *perr = WERR_ACCESS_DENIED;
+       if (driver->data_file && strlen(driver->data_file)) {
+               if (!strequal(driver->data_file, driver->driver_path)) {
+
+                       *perr = move_driver_file_to_download_area(ctx,
+                                                                 conn,
+                                                                 driver->data_file,
+                                                                 short_architecture,
+                                                                 driver->version,
+                                                                 ver);
+                       if (!W_ERROR_IS_OK(*perr)) {
+                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
                                        ver = -1;
                                }
+                               goto err_exit;
                        }
                }
        }
 
-       if (driver->configfile && strlen(driver->configfile)) {
-               if (!strequal(driver->configfile, driver->driverpath) &&
-                       !strequal(driver->configfile, driver->datafile)) {
-                       new_name = talloc_asprintf(ctx,
-                                               "%s/%s",
-                                               architecture,
-                                               driver->configfile);
-                       if (!new_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       old_name = talloc_asprintf(ctx,
-                                               "%s/%s",
-                                               new_dir,
-                                               driver->configfile);
-                       if (!old_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               new_name = driver_unix_convert(conn,new_name,&st);
-                               if (!new_name) {
-                                       *perr = WERR_NOMEM;
-                                       goto err_exit;
-                               }
-                               if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
-                                               OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
-                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
-                                                       new_name, old_name));
-                                       *perr = WERR_ACCESS_DENIED;
+       if (driver->config_file && strlen(driver->config_file)) {
+               if (!strequal(driver->config_file, driver->driver_path) &&
+                   !strequal(driver->config_file, driver->data_file)) {
+
+                       *perr = move_driver_file_to_download_area(ctx,
+                                                                 conn,
+                                                                 driver->config_file,
+                                                                 short_architecture,
+                                                                 driver->version,
+                                                                 ver);
+                       if (!W_ERROR_IS_OK(*perr)) {
+                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
                                        ver = -1;
                                }
+                               goto err_exit;
                        }
                }
        }
 
-       if (driver->helpfile && strlen(driver->helpfile)) {
-               if (!strequal(driver->helpfile, driver->driverpath) &&
-                       !strequal(driver->helpfile, driver->datafile) &&
-                       !strequal(driver->helpfile, driver->configfile)) {
-                       new_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       architecture,
-                                       driver->helpfile);
-                       if (!new_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       old_name = talloc_asprintf(ctx,
-                                       "%s/%s",
-                                       new_dir,
-                                       driver->helpfile);
-                       if (!old_name) {
-                               *perr = WERR_NOMEM;
-                               goto err_exit;
-                       }
-                       if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                               new_name = driver_unix_convert(conn,new_name,&st);
-                               if (!new_name) {
-                                       *perr = WERR_NOMEM;
-                                       goto err_exit;
-                               }
-                               if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name, OPENX_FILE_EXISTS_TRUNCATE|
-                                               OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
-                                       DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
-                                                       new_name, old_name));
-                                       *perr = WERR_ACCESS_DENIED;
+       if (driver->help_file && strlen(driver->help_file)) {
+               if (!strequal(driver->help_file, driver->driver_path) &&
+                   !strequal(driver->help_file, driver->data_file) &&
+                   !strequal(driver->help_file, driver->config_file)) {
+
+                       *perr = move_driver_file_to_download_area(ctx,
+                                                                 conn,
+                                                                 driver->help_file,
+                                                                 short_architecture,
+                                                                 driver->version,
+                                                                 ver);
+                       if (!W_ERROR_IS_OK(*perr)) {
+                               if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
                                        ver = -1;
                                }
+                               goto err_exit;
                        }
                }
        }
 
-       if (driver->dependentfiles) {
-               for (i=0; *driver->dependentfiles[i]; i++) {
-                       if (!strequal(driver->dependentfiles[i], driver->driverpath) &&
-                               !strequal(driver->dependentfiles[i], driver->datafile) &&
-                               !strequal(driver->dependentfiles[i], driver->configfile) &&
-                               !strequal(driver->dependentfiles[i], driver->helpfile)) {
+       if (driver->dependent_files && driver->dependent_files->string) {
+               for (i=0; driver->dependent_files->string[i]; i++) {
+                       if (!strequal(driver->dependent_files->string[i], driver->driver_path) &&
+                           !strequal(driver->dependent_files->string[i], driver->data_file) &&
+                           !strequal(driver->dependent_files->string[i], driver->config_file) &&
+                           !strequal(driver->dependent_files->string[i], driver->help_file)) {
                                int j;
                                for (j=0; j < i; j++) {
-                                       if (strequal(driver->dependentfiles[i], driver->dependentfiles[j])) {
+                                       if (strequal(driver->dependent_files->string[i], driver->dependent_files->string[j])) {
                                                goto NextDriver;
                                        }
                                }
 
-                               new_name = talloc_asprintf(ctx,
-                                               "%s/%s",
-                                               architecture,
-                                               driver->dependentfiles[i]);
-                               if (!new_name) {
-                                       *perr = WERR_NOMEM;
-                                       goto err_exit;
-                               }
-                               old_name = talloc_asprintf(ctx,
-                                               "%s/%s",
-                                               new_dir,
-                                               driver->dependentfiles[i]);
-                               if (!old_name) {
-                                       *perr = WERR_NOMEM;
-                                       goto err_exit;
-                               }
-                               if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) {
-                                       new_name = driver_unix_convert(conn,new_name,&st);
-                                       if (!new_name) {
-                                               *perr = WERR_NOMEM;
-                                               goto err_exit;
-                                       }
-                                       if ( !NT_STATUS_IS_OK(copy_file(ctx,conn, new_name, old_name,
-                                                       OPENX_FILE_EXISTS_TRUNCATE|
-                                                       OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False))) {
-                                               DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n",
-                                                               new_name, old_name));
-                                               *perr = WERR_ACCESS_DENIED;
+                               *perr = move_driver_file_to_download_area(ctx,
+                                                                         conn,
+                                                                         driver->dependent_files->string[i],
+                                                                         short_architecture,
+                                                                         driver->version,
+                                                                         ver);
+                               if (!W_ERROR_IS_OK(*perr)) {
+                                       if (W_ERROR_EQUAL(*perr, WERR_ACCESS_DENIED)) {
                                                ver = -1;
                                        }
+                                       goto err_exit;
                                }
                        }
                NextDriver: ;
@@ -2086,10 +2017,11 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
        }
 
   err_exit:
+       TALLOC_FREE(smb_dname);
 
        if (conn != NULL) {
                vfs_ChDir(conn, oldcwd);
-               conn_free_internal(conn);
+               conn_free(conn);
        }
 
        if (W_ERROR_EQUAL(*perr, WERR_OK)) {
@@ -2104,19 +2036,18 @@ WERROR move_driver_to_download_area(struct pipes_struct *p,
 /****************************************************************************
 ****************************************************************************/
 
-static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
+static uint32 add_a_printer_driver_3(struct spoolss_AddDriverInfo3 *driver)
 {
        TALLOC_CTX *ctx = talloc_tos();
        int len, buflen;
        const char *architecture;
        char *directory = NULL;
-       fstring temp_name;
        char *key = NULL;
        uint8 *buf;
        int i, ret;
        TDB_DATA dbuf;
 
-       architecture = get_short_archi(driver->environment);
+       architecture = get_short_archi(driver->architecture);
        if (!architecture) {
                return (uint32)-1;
        }
@@ -2127,46 +2058,44 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
         */
 
        directory = talloc_asprintf(ctx, "\\print$\\%s\\%d\\",
-                       architecture, driver->cversion);
+                       architecture, driver->version);
        if (!directory) {
                return (uint32)-1;
        }
 
+#define gen_full_driver_unc_path(ctx, directory, file) \
+       do { \
+               if (file && strlen(file)) { \
+                       file = talloc_asprintf(ctx, "%s%s", directory, file); \
+               } else { \
+                       file = talloc_strdup(ctx, ""); \
+               } \
+               if (!file) { \
+                       return (uint32_t)-1; \
+               } \
+       } while (0);
+
        /* .inf files do not always list a file for each of the four standard files.
         * Don't prepend a path to a null filename, or client claims:
         *   "The server on which the printer resides does not have a suitable
         *   <printer driver name> printer driver installed. Click OK if you
         *   wish to install the driver on your local machine."
         */
-       if (strlen(driver->driverpath)) {
-               fstrcpy(temp_name, driver->driverpath);
-               slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
-       }
-
-       if (strlen(driver->datafile)) {
-               fstrcpy(temp_name, driver->datafile);
-               slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
-       }
-
-       if (strlen(driver->configfile)) {
-               fstrcpy(temp_name, driver->configfile);
-               slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
-       }
 
-       if (strlen(driver->helpfile)) {
-               fstrcpy(temp_name, driver->helpfile);
-               slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
-       }
+       gen_full_driver_unc_path(ctx, directory, driver->driver_path);
+       gen_full_driver_unc_path(ctx, directory, driver->data_file);
+       gen_full_driver_unc_path(ctx, directory, driver->config_file);
+       gen_full_driver_unc_path(ctx, directory, driver->help_file);
 
-       if (driver->dependentfiles) {
-               for (i=0; *driver->dependentfiles[i]; i++) {
-                       fstrcpy(temp_name, driver->dependentfiles[i]);
-                       slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
+       if (driver->dependent_files && driver->dependent_files->string) {
+               for (i=0; driver->dependent_files->string[i]; i++) {
+                       gen_full_driver_unc_path(ctx, directory,
+                               driver->dependent_files->string[i]);
                }
        }
 
        key = talloc_asprintf(ctx, "%s%s/%d/%s", DRIVERS_PREFIX,
-                       architecture, driver->cversion, driver->name);
+                       architecture, driver->version, driver->driver_name);
        if (!key) {
                return (uint32)-1;
        }
@@ -2179,20 +2108,20 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
  again:
        len = 0;
        len += tdb_pack(buf+len, buflen-len, "dffffffff",
-                       driver->cversion,
-                       driver->name,
-                       driver->environment,
-                       driver->driverpath,
-                       driver->datafile,
-                       driver->configfile,
-                       driver->helpfile,
-                       driver->monitorname,
-                       driver->defaultdatatype);
-
-       if (driver->dependentfiles) {
-               for (i=0; *driver->dependentfiles[i]; i++) {
+                       driver->version,
+                       driver->driver_name,
+                       driver->architecture,
+                       driver->driver_path,
+                       driver->data_file,
+                       driver->config_file,
+                       driver->help_file,
+                       driver->monitor_name ? driver->monitor_name : "",
+                       driver->default_datatype ? driver->default_datatype : "");
+
+       if (driver->dependent_files && driver->dependent_files->string) {
+               for (i=0; driver->dependent_files->string[i]; i++) {
                        len += tdb_pack(buf+len, buflen-len, "f",
-                                       driver->dependentfiles[i]);
+                                       driver->dependent_files->string[i]);
                }
        }
 
@@ -2222,51 +2151,43 @@ done:
 
 /****************************************************************************
 ****************************************************************************/
-static uint32 add_a_printer_driver_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver)
+
+static uint32_t add_a_printer_driver_8(struct spoolss_DriverInfo8 *driver)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 info3;
+       TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
+       struct spoolss_AddDriverInfo3 info3;
+       uint32_t ret;
 
-       ZERO_STRUCT(info3);
-       info3.cversion = driver->version;
-       fstrcpy(info3.name,driver->name);
-       fstrcpy(info3.environment,driver->environment);
-       fstrcpy(info3.driverpath,driver->driverpath);
-       fstrcpy(info3.datafile,driver->datafile);
-       fstrcpy(info3.configfile,driver->configfile);
-       fstrcpy(info3.helpfile,driver->helpfile);
-       fstrcpy(info3.monitorname,driver->monitorname);
-       fstrcpy(info3.defaultdatatype,driver->defaultdatatype);
-       info3.dependentfiles = driver->dependentfiles;
-
-       return add_a_printer_driver_3(&info3);
-}
+       convert_level_8_to_level3(mem_ctx, &info3, driver);
+
+       ret = add_a_printer_driver_3(&info3);
+       talloc_free(mem_ctx);
 
+       return ret;
+}
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, const char *driver, const char *arch)
-{
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 info;
-
-       ZERO_STRUCT(info);
 
-       fstrcpy(info.name, driver);
-       fstrcpy(info.defaultdatatype, "RAW");
-
-       fstrcpy(info.driverpath, "");
-       fstrcpy(info.datafile, "");
-       fstrcpy(info.configfile, "");
-       fstrcpy(info.helpfile, "");
-
-       if ((info.dependentfiles= SMB_MALLOC_ARRAY(fstring, 2)) == NULL)
+static WERROR get_a_printer_driver_3_default(TALLOC_CTX *mem_ctx,
+                                            struct spoolss_DriverInfo3 *info,
+                                            const char *driver, const char *arch)
+{
+       info->driver_name = talloc_strdup(mem_ctx, driver);
+       if (!info->driver_name) {
                return WERR_NOMEM;
+       }
 
-       memset(info.dependentfiles, '\0', 2*sizeof(fstring));
-       fstrcpy(info.dependentfiles[0], "");
+       info->default_datatype = talloc_strdup(mem_ctx, "RAW");
+       if (!info->default_datatype) {
+               return WERR_NOMEM;
+       }
 
-       *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&info, sizeof(info));
-       if (!*info_ptr) {
-               SAFE_FREE(info.dependentfiles);
+       info->driver_path = talloc_strdup(mem_ctx, "");
+       info->data_file = talloc_strdup(mem_ctx, "");
+       info->config_file = talloc_strdup(mem_ctx, "");
+       info->help_file = talloc_strdup(mem_ctx, "");
+       if (!info->driver_path || !info->data_file || !info->config_file || !info->help_file) {
                return WERR_NOMEM;
        }
 
@@ -2275,16 +2196,18 @@ static WERROR get_a_printer_driver_3_default(NT_PRINTER_DRIVER_INFO_LEVEL_3 **in
 
 /****************************************************************************
 ****************************************************************************/
-static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr, fstring drivername, const char *arch, uint32 version)
+
+static WERROR get_a_printer_driver_3(TALLOC_CTX *mem_ctx,
+                                    struct spoolss_DriverInfo3 *driver,
+                                    const char *drivername, const char *arch,
+                                    uint32_t version)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 driver;
        TDB_DATA dbuf;
        const char *architecture;
        int len = 0;
        int i;
        char *key = NULL;
-
-       ZERO_STRUCT(driver);
+       fstring name, driverpath, environment, datafile, configfile, helpfile, monitorname, defaultdatatype;
 
        architecture = get_short_archi(arch);
        if ( !architecture ) {
@@ -2310,106 +2233,65 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        }
 
        len += tdb_unpack(dbuf.dptr, dbuf.dsize, "dffffffff",
-                         &driver.cversion,
-                         driver.name,
-                         driver.environment,
-                         driver.driverpath,
-                         driver.datafile,
-                         driver.configfile,
-                         driver.helpfile,
-                         driver.monitorname,
-                         driver.defaultdatatype);
+                         &driver->version,
+                         name,
+                         environment,
+                         driverpath,
+                         datafile,
+                         configfile,
+                         helpfile,
+                         monitorname,
+                         defaultdatatype);
+
+       driver->driver_name     = talloc_strdup(mem_ctx, name);
+       driver->architecture    = talloc_strdup(mem_ctx, environment);
+       driver->driver_path     = talloc_strdup(mem_ctx, driverpath);
+       driver->data_file       = talloc_strdup(mem_ctx, datafile);
+       driver->config_file     = talloc_strdup(mem_ctx, configfile);
+       driver->help_file       = talloc_strdup(mem_ctx, helpfile);
+       driver->monitor_name    = talloc_strdup(mem_ctx, monitorname);
+       driver->default_datatype        = talloc_strdup(mem_ctx, defaultdatatype);
 
        i=0;
+
        while (len < dbuf.dsize) {
-               driver.dependentfiles = SMB_REALLOC_ARRAY(driver.dependentfiles, fstring, i+2);
-               if ( !driver.dependentfiles ) {
+
+               fstring file;
+
+               driver->dependent_files = talloc_realloc(mem_ctx, driver->dependent_files, const char *, i+2);
+               if (!driver->dependent_files ) {
                        DEBUG(0,("get_a_printer_driver_3: failed to enlarge buffer!\n"));
                        break;
                }
 
                len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f",
-                                 &driver.dependentfiles[i]);
+                                 &file);
+
+               driver->dependent_files[i] = talloc_strdup(mem_ctx, file);
+
                i++;
        }
 
-       if ( driver.dependentfiles )
-               fstrcpy( driver.dependentfiles[i], "" );
+       if (driver->dependent_files)
+               driver->dependent_files[i] = NULL;
 
        SAFE_FREE(dbuf.dptr);
        SAFE_FREE(key);
 
        if (len != dbuf.dsize) {
-               SAFE_FREE(driver.dependentfiles);
-
-               return get_a_printer_driver_3_default(info_ptr, drivername, arch);
-       }
-
-       *info_ptr = (NT_PRINTER_DRIVER_INFO_LEVEL_3 *)memdup(&driver, sizeof(driver));
-       if (!*info_ptr) {
-               SAFE_FREE(driver.dependentfiles);
-               return WERR_NOMEM;
+               return get_a_printer_driver_3_default(mem_ctx, driver, drivername, arch);
        }
 
        return WERR_OK;
 }
 
 /****************************************************************************
- Debugging function, dump at level 6 the struct in the logs.
 ****************************************************************************/
-
-static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+int pack_devicemode(NT_DEVICEMODE *nt_devmode, uint8 *buf, int buflen)
 {
-       uint32 result;
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
-       int i;
+       int len = 0;
 
-       DEBUG(20,("Dumping printer driver at level [%d]\n", level));
-
-       switch (level)
-       {
-               case 3:
-               {
-                       if (driver.info_3 == NULL)
-                               result=5;
-                       else {
-                               info3=driver.info_3;
-
-                               DEBUGADD(20,("version:[%d]\n",         info3->cversion));
-                               DEBUGADD(20,("name:[%s]\n",            info3->name));
-                               DEBUGADD(20,("environment:[%s]\n",     info3->environment));
-                               DEBUGADD(20,("driverpath:[%s]\n",      info3->driverpath));
-                               DEBUGADD(20,("datafile:[%s]\n",        info3->datafile));
-                               DEBUGADD(20,("configfile:[%s]\n",      info3->configfile));
-                               DEBUGADD(20,("helpfile:[%s]\n",        info3->helpfile));
-                               DEBUGADD(20,("monitorname:[%s]\n",     info3->monitorname));
-                               DEBUGADD(20,("defaultdatatype:[%s]\n", info3->defaultdatatype));
-
-                               for (i=0; info3->dependentfiles &&
-                                         *info3->dependentfiles[i]; i++) {
-                                       DEBUGADD(20,("dependentfile:[%s]\n",
-                                                     info3->dependentfiles[i]));
-                               }
-                               result=0;
-                       }
-                       break;
-               }
-               default:
-                       DEBUGADD(20,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
-                       result=1;
-                       break;
-       }
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-int pack_devicemode(NT_DEVICEMODE *nt_devmode, uint8 *buf, int buflen)
-{
-       int len = 0;
-
-       len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
+       len += tdb_pack(buf+len, buflen-len, "p", nt_devmode);
 
        if (!nt_devmode)
                return len;
@@ -2472,8 +2354,8 @@ static int pack_values(NT_PRINTER_DATA *data, uint8 *buf, int buflen)
 {
        int             len = 0;
        int             i, j;
-       REGISTRY_VALUE  *val;
-       REGVAL_CTR      *val_ctr;
+       struct regval_blob      *val;
+       struct regval_ctr       *val_ctr;
        char *path = NULL;
        int             num_values;
 
@@ -2547,7 +2429,7 @@ uint32 del_a_printer(const char *sharename)
 
        close_all_print_db();
 
-       if (geteuid() == 0) {
+       if (geteuid() == sec_initial_uid()) {
                if (asprintf(&printdb_path, "%s%s.tdb",
                                cache_path("printing/"),
                                sharename) < 0) {
@@ -2665,6 +2547,167 @@ done:
        return ret;
 }
 
+/****************************************************************************
+ Create and allocate a default devicemode.
+****************************************************************************/
+
+WERROR spoolss_create_default_devmode(TALLOC_CTX *mem_ctx,
+                                     const char *devicename,
+                                     struct spoolss_DeviceMode **devmode)
+{
+       struct spoolss_DeviceMode *dm;
+       char *dname;
+
+       dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
+       if (dm == NULL) {
+               return WERR_NOMEM;
+       }
+
+       dname = talloc_asprintf(dm, "%s", devicename);
+       if (dname == NULL) {
+               return WERR_NOMEM;
+       }
+       if (strlen(dname) > MAXDEVICENAME) {
+               dname[MAXDEVICENAME] = '\0';
+       }
+       dm->devicename = dname;
+
+       dm->formname = talloc_strdup(dm, "Letter");
+       if (dm->formname == NULL) {
+               return WERR_NOMEM;
+       }
+
+       dm->specversion          = DMSPEC_NT4_AND_ABOVE;
+       dm->driverversion        = 0x0400;
+       dm->size                 = 0x00DC;
+       dm->__driverextra_length = 0;
+       dm->fields               = DEVMODE_FORMNAME |
+                                  DEVMODE_TTOPTION |
+                                  DEVMODE_PRINTQUALITY |
+                                  DEVMODE_DEFAULTSOURCE |
+                                  DEVMODE_COPIES |
+                                  DEVMODE_SCALE |
+                                  DEVMODE_PAPERSIZE |
+                                  DEVMODE_ORIENTATION;
+       dm->orientation          = DMORIENT_PORTRAIT;
+       dm->papersize            = DMPAPER_LETTER;
+       dm->paperlength          = 0;
+       dm->paperwidth           = 0;
+       dm->scale                = 0x64;
+       dm->copies               = 1;
+       dm->defaultsource        = DMBIN_FORMSOURCE;
+       dm->printquality         = DMRES_HIGH;           /* 0x0258 */
+       dm->color                = DMRES_MONOCHROME;
+       dm->duplex               = DMDUP_SIMPLEX;
+       dm->yresolution          = 0;
+       dm->ttoption             = DMTT_SUBDEV;
+       dm->collate              = DMCOLLATE_FALSE;
+       dm->icmmethod            = 0;
+       dm->icmintent            = 0;
+       dm->mediatype            = 0;
+       dm->dithertype           = 0;
+
+       dm->logpixels            = 0;
+       dm->bitsperpel           = 0;
+       dm->pelswidth            = 0;
+       dm->pelsheight           = 0;
+       dm->displayflags         = 0;
+       dm->displayfrequency     = 0;
+       dm->reserved1            = 0;
+       dm->reserved2            = 0;
+       dm->panningwidth         = 0;
+       dm->panningheight        = 0;
+
+       dm->driverextra_data.data = NULL;
+       dm->driverextra_data.length = 0;
+
+        *devmode = dm;
+       return WERR_OK;
+}
+
+WERROR spoolss_create_default_secdesc(TALLOC_CTX *mem_ctx,
+                                     struct spoolss_security_descriptor **secdesc)
+{
+       struct security_ace ace[5];     /* max number of ace entries */
+       int i = 0;
+       uint32_t sa;
+       struct security_acl *psa = NULL;
+       struct security_descriptor *psd = NULL;
+       struct dom_sid adm_sid;
+       size_t sd_size;
+
+       /* Create an ACE where Everyone is allowed to print */
+
+       sa = PRINTER_ACE_PRINT;
+       init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                    sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+       /* Add the domain admins group if we are a DC */
+
+       if ( IS_DC ) {
+               struct dom_sid domadmins_sid;
+
+               sid_compose(&domadmins_sid, get_global_sam_sid(),
+                           DOMAIN_RID_ADMINS);
+
+               sa = PRINTER_ACE_FULL_CONTROL;
+               init_sec_ace(&ace[i++], &domadmins_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+               init_sec_ace(&ace[i++], &domadmins_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+       }
+       else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
+               sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
+
+               sa = PRINTER_ACE_FULL_CONTROL;
+               init_sec_ace(&ace[i++], &adm_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+                       SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+               init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+       }
+
+       /* add BUILTIN\Administrators as FULL CONTROL */
+
+       sa = PRINTER_ACE_FULL_CONTROL;
+       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
+               SEC_ACE_TYPE_ACCESS_ALLOWED, sa,
+               SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_INHERIT_ONLY);
+       init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators,
+               SEC_ACE_TYPE_ACCESS_ALLOWED,
+               sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
+
+       /* Make the security descriptor owned by the BUILTIN\Administrators */
+
+       /* The ACL revision number in rpc_secdesc.h differs from the one
+          created by NT when setting ACE entries in printer
+          descriptors.  NT4 complains about the property being edited by a
+          NT5 machine. */
+
+       if ((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
+               psd = make_sec_desc(mem_ctx,
+                                   SD_REVISION,
+                                   SEC_DESC_SELF_RELATIVE,
+                                   &global_sid_Builtin_Administrators,
+                                   &global_sid_Builtin_Administrators,
+                                   NULL,
+                                   psa,
+                                   &sd_size);
+       }
+
+       if (psd == NULL) {
+               DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
+               return WERR_NOMEM;
+       }
+
+       DEBUG(4,("construct_default_printer_sdb: size = %u.\n",
+                (unsigned int)sd_size));
+
+       *secdesc = psd;
+
+       return WERR_OK;
+}
 
 /****************************************************************************
  Malloc and return an NT devicemode.
@@ -2688,26 +2731,31 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
 
        fstrcpy(nt_devmode->formname, "Letter");
 
-       nt_devmode->specversion      = 0x0401;
+       nt_devmode->specversion      = DMSPEC_NT4_AND_ABOVE;
        nt_devmode->driverversion    = 0x0400;
        nt_devmode->size             = 0x00DC;
        nt_devmode->driverextra      = 0x0000;
-       nt_devmode->fields           = FORMNAME | TTOPTION | PRINTQUALITY |
-                                      DEFAULTSOURCE | COPIES | SCALE |
-                                      PAPERSIZE | ORIENTATION;
-       nt_devmode->orientation      = 1;
-       nt_devmode->papersize        = PAPER_LETTER;
+       nt_devmode->fields           = DEVMODE_FORMNAME |
+                                      DEVMODE_TTOPTION |
+                                      DEVMODE_PRINTQUALITY |
+                                      DEVMODE_DEFAULTSOURCE |
+                                      DEVMODE_COPIES |
+                                      DEVMODE_SCALE |
+                                      DEVMODE_PAPERSIZE |
+                                      DEVMODE_ORIENTATION;
+       nt_devmode->orientation      = DMORIENT_PORTRAIT;
+       nt_devmode->papersize        = DMPAPER_LETTER;
        nt_devmode->paperlength      = 0;
        nt_devmode->paperwidth       = 0;
        nt_devmode->scale            = 0x64;
        nt_devmode->copies           = 1;
-       nt_devmode->defaultsource    = BIN_FORMSOURCE;
-       nt_devmode->printquality     = RES_HIGH;           /* 0x0258 */
-       nt_devmode->color            = COLOR_MONOCHROME;
-       nt_devmode->duplex           = DUP_SIMPLEX;
+       nt_devmode->defaultsource    = DMBIN_FORMSOURCE;
+       nt_devmode->printquality     = DMRES_HIGH;           /* 0x0258 */
+       nt_devmode->color            = DMRES_MONOCHROME;
+       nt_devmode->duplex           = DMDUP_SIMPLEX;
        nt_devmode->yresolution      = 0;
-       nt_devmode->ttoption         = TT_SUBDEV;
-       nt_devmode->collate          = COLLATE_FALSE;
+       nt_devmode->ttoption         = DMTT_SUBDEV;
+       nt_devmode->collate          = DMCOLLATE_FALSE;
        nt_devmode->icmmethod        = 0;
        nt_devmode->icmintent        = 0;
        nt_devmode->mediatype        = 0;
@@ -2729,34 +2777,6 @@ NT_DEVICEMODE *construct_nt_devicemode(const fstring default_devicename)
        return nt_devmode;
 }
 
-/****************************************************************************
- Deepcopy an NT devicemode.
-****************************************************************************/
-
-NT_DEVICEMODE *dup_nt_devicemode(NT_DEVICEMODE *nt_devicemode)
-{
-       NT_DEVICEMODE *new_nt_devicemode = NULL;
-
-       if ( !nt_devicemode )
-               return NULL;
-
-       if ((new_nt_devicemode = (NT_DEVICEMODE *)memdup(nt_devicemode, sizeof(NT_DEVICEMODE))) == NULL) {
-               DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
-               return NULL;
-       }
-
-       new_nt_devicemode->nt_dev_private = NULL;
-       if (nt_devicemode->nt_dev_private != NULL) {
-               if ((new_nt_devicemode->nt_dev_private = (uint8 *)memdup(nt_devicemode->nt_dev_private, nt_devicemode->driverextra)) == NULL) {
-                       SAFE_FREE(new_nt_devicemode);
-                       DEBUG(0,("dup_nt_devicemode: malloc fail.\n"));
-                       return NULL;
-        }
-       }
-
-       return new_nt_devicemode;
-}
-
 /****************************************************************************
  Clean up and deallocate a (maybe partially) allocated NT_DEVICEMODE.
 ****************************************************************************/
@@ -2878,6 +2898,7 @@ int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
 {
        NT_PRINTER_KEY  *d;
        int             key_index;
+       WERROR werr;
 
        if ( !name || !data )
                return -1;
@@ -2897,8 +2918,10 @@ int add_new_printer_key( NT_PRINTER_DATA *data, const char *name )
 
        data->keys[key_index].name = talloc_strdup( data, name );
 
-       if ( !(data->keys[key_index].values = TALLOC_ZERO_P( data, REGVAL_CTR )) )
+       werr = regval_ctr_init(data, &(data->keys[key_index].values));
+       if (!W_ERROR_IS_OK(werr)) {
                return -1;
+       }
 
        data->num_keys++;
 
@@ -3068,59 +3091,40 @@ done:
 }
 
 #ifdef HAVE_ADS
-static void map_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+static void map_sz_into_ctr(struct regval_ctr *ctr, const char *val_name,
                            const char *sz)
 {
-       smb_ucs2_t conv_str[1024];
-       size_t str_size;
-
        regval_ctr_delvalue(ctr, val_name);
-       str_size = push_ucs2(NULL, conv_str, sz, sizeof(conv_str),
-                            STR_TERMINATE | STR_NOALIGN);
-       regval_ctr_addvalue(ctr, val_name, REG_SZ,
-                           (char *) conv_str, str_size);
+       regval_ctr_addvalue_sz(ctr, val_name, sz);
 }
 
-static void map_dword_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+static void map_dword_into_ctr(struct regval_ctr *ctr, const char *val_name,
                               uint32 dword)
 {
        regval_ctr_delvalue(ctr, val_name);
        regval_ctr_addvalue(ctr, val_name, REG_DWORD,
-                           (char *) &dword, sizeof(dword));
+                           (uint8 *) &dword, sizeof(dword));
 }
 
-static void map_bool_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+static void map_bool_into_ctr(struct regval_ctr *ctr, const char *val_name,
                              bool b)
 {
        uint8 bin_bool = (b ? 1 : 0);
        regval_ctr_delvalue(ctr, val_name);
        regval_ctr_addvalue(ctr, val_name, REG_BINARY,
-                           (char *) &bin_bool, sizeof(bin_bool));
+                           (uint8 *) &bin_bool, sizeof(bin_bool));
 }
 
-static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
+static void map_single_multi_sz_into_ctr(struct regval_ctr *ctr, const char *val_name,
                                         const char *multi_sz)
 {
-       smb_ucs2_t *conv_strs = NULL;
-       size_t str_size;
-
-       /* a multi-sz has to have a null string terminator, i.e., the last
-          string must be followed by two nulls */
-       str_size = strlen(multi_sz) + 2;
-       conv_strs = SMB_CALLOC_ARRAY(smb_ucs2_t, str_size);
-       if (!conv_strs) {
-               return;
-       }
+       const char *a[2];
 
-       /* Change to byte units. */
-       str_size *= sizeof(smb_ucs2_t);
-       push_ucs2(NULL, conv_strs, multi_sz, str_size,
-                 STR_TERMINATE | STR_NOALIGN);
+       a[0] = multi_sz;
+       a[1] = NULL;
 
        regval_ctr_delvalue(ctr, val_name);
-       regval_ctr_addvalue(ctr, val_name, REG_MULTI_SZ,
-                           (char *) conv_strs, str_size);
-       SAFE_FREE(conv_strs);
+       regval_ctr_addvalue_multi_sz(ctr, val_name, a);
 }
 
 /****************************************************************************
@@ -3132,7 +3136,7 @@ static void map_single_multi_sz_into_ctr(REGVAL_CTR *ctr, const char *val_name,
 
 static bool map_nt_printer_info2_to_dsspooler(NT_PRINTER_INFO_LEVEL_2 *info2)
 {
-       REGVAL_CTR *ctr = NULL;
+       struct regval_ctr *ctr = NULL;
        fstring longname;
        const char *dnssuffix;
        char *allocated_string = NULL;
@@ -3204,8 +3208,7 @@ static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
                               struct GUID guid)
 {
        int i;
-       REGVAL_CTR *ctr=NULL;
-       UNISTR2 unistr_guid;
+       struct regval_ctr *ctr=NULL;
 
        /* find the DsSpooler key */
        if ((i = lookup_printerkey(info2->data, SPOOL_DSSPOOLER_KEY)) < 0)
@@ -3217,15 +3220,8 @@ static void store_printer_guid(NT_PRINTER_INFO_LEVEL_2 *info2,
        /* We used to store this as a REG_BINARY but that causes
           Vista to whine */
 
-       ZERO_STRUCT( unistr_guid );
-
-       init_unistr2( &unistr_guid, GUID_string(talloc_tos(), &guid),
-                     UNI_STR_TERMINATE );
-
-       regval_ctr_addvalue(ctr, "objectGUID", REG_SZ,
-                           (char *)unistr_guid.buffer,
-                           unistr_guid.uni_max_len*2);
-
+       regval_ctr_addvalue_sz(ctr, "objectGUID",
+                              GUID_string(talloc_tos(), &guid));
 }
 
 static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
@@ -3241,7 +3237,12 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
        struct GUID guid;
        WERROR win_rc = WERR_OK;
        size_t converted_size;
-       int ret;
+
+       /* build the ads mods */
+       ctx = talloc_init("nt_printer_publish_ads");
+       if (ctx == NULL) {
+               return WERR_NOMEM;
+       }
 
        DEBUG(5, ("publishing printer %s\n", printer->info_2->printername));
 
@@ -3253,24 +3254,28 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
 
        srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
        if (!srv_dn_utf8) {
+               TALLOC_FREE(ctx);
                return WERR_SERVER_UNAVAILABLE;
        }
        ads_msgfree(ads, res);
        srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1);
        if (!srv_cn_utf8) {
+               TALLOC_FREE(ctx);
                ldap_memfree(srv_dn_utf8);
                return WERR_SERVER_UNAVAILABLE;
        }
        /* Now convert to CH_UNIX. */
-       if (!pull_utf8_allocate(&srv_dn, srv_dn_utf8, &converted_size)) {
+       if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) {
+               TALLOC_FREE(ctx);
                ldap_memfree(srv_dn_utf8);
                ldap_memfree(srv_cn_utf8);
                return WERR_SERVER_UNAVAILABLE;
        }
-       if (!pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0], &converted_size)) {
+       if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) {
+               TALLOC_FREE(ctx);
                ldap_memfree(srv_dn_utf8);
                ldap_memfree(srv_cn_utf8);
-               SAFE_FREE(srv_dn);
+               TALLOC_FREE(srv_dn);
                return WERR_SERVER_UNAVAILABLE;
        }
 
@@ -3279,41 +3284,26 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
 
        srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0);
        if (!srv_cn_escaped) {
-               SAFE_FREE(srv_cn_0);
-               SAFE_FREE(srv_dn);
+               TALLOC_FREE(ctx);
                return WERR_SERVER_UNAVAILABLE;
        }
        sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename);
        if (!sharename_escaped) {
                SAFE_FREE(srv_cn_escaped);
-               SAFE_FREE(srv_cn_0);
-               SAFE_FREE(srv_dn);
+               TALLOC_FREE(ctx);
                return WERR_SERVER_UNAVAILABLE;
        }
 
-       ret = asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
+       prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn);
 
-       SAFE_FREE(srv_dn);
-       SAFE_FREE(srv_cn_0);
        SAFE_FREE(srv_cn_escaped);
        SAFE_FREE(sharename_escaped);
 
-       if (ret == -1) {
-               return WERR_NOMEM;
-       }
-
-       /* build the ads mods */
-       ctx = talloc_init("nt_printer_publish_ads");
-       if (ctx == NULL) {
-               SAFE_FREE(prt_dn);
-               return WERR_NOMEM;
-       }
-
        mods = ads_init_mods(ctx);
 
        if (mods == NULL) {
                SAFE_FREE(prt_dn);
-               talloc_destroy(ctx);
+               TALLOC_FREE(ctx);
                return WERR_NOMEM;
        }
 
@@ -3334,8 +3324,6 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
        if (!ADS_ERR_OK(ads_rc))
                DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc)));
 
-       talloc_destroy(ctx);
-
        /* retreive the guid and store it locally */
        if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) {
                ZERO_STRUCT(guid);
@@ -3344,8 +3332,8 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads,
                store_printer_guid(printer->info_2, guid);
                win_rc = mod_a_printer(printer, 2);
        }
+       TALLOC_FREE(ctx);
 
-       SAFE_FREE(prt_dn);
        return win_rc;
 }
 
@@ -3363,13 +3351,13 @@ static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads,
                            printer->info_2->sharename, global_myname());
 
        if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) {
-               prt_dn = ads_get_dn(ads, res);
+               prt_dn = ads_get_dn(ads, talloc_tos(), res);
                if (!prt_dn) {
                        ads_msgfree(ads, res);
                        return WERR_NOMEM;
                }
                ads_rc = ads_del_dn(ads, prt_dn);
-               ads_memfree(ads, prt_dn);
+               TALLOC_FREE(prt_dn);
        }
 
        if (res) {
@@ -3504,11 +3492,12 @@ bool is_printer_published(Printer_entry *print_hnd, int snum,
                          struct GUID *guid)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       REGVAL_CTR *ctr;
-       REGISTRY_VALUE *guid_val;
+       struct regval_ctr *ctr;
+       struct regval_blob *guid_val;
        WERROR win_rc;
        int i;
        bool ret = False;
+       DATA_BLOB blob;
 
        win_rc = get_a_printer(print_hnd, &printer, 2, lp_servicename(snum));
 
@@ -3525,16 +3514,18 @@ bool is_printer_published(Printer_entry *print_hnd, int snum,
        /* fetching printer guids really ought to be a separate function. */
 
        if ( guid ) {
-               fstring guid_str;
+               char *guid_str;
 
                /* We used to store the guid as REG_BINARY, then swapped
                   to REG_SZ for Vista compatibility so check for both */
 
                switch ( regval_type(guid_val) ){
                case REG_SZ:
-                       rpcstr_pull( guid_str, regval_data_p(guid_val),
-                                    sizeof(guid_str)-1, -1, STR_TERMINATE );
+                       blob = data_blob_const(regval_data_p(guid_val),
+                                              regval_size(guid_val));
+                       pull_reg_sz(talloc_tos(), &blob, (const char **)&guid_str);
                        ret = NT_STATUS_IS_OK(GUID_from_string( guid_str, guid ));
+                       talloc_free(guid_str);
                        break;
                case REG_BINARY:
                        if ( regval_size(guid_val) != sizeof(struct GUID) ) {
@@ -3714,7 +3705,7 @@ WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const cha
                return WERR_NOMEM;
 
        regval_ctr_addvalue( p2->data->keys[key_index].values, value,
-               type, (const char *)data, real_len );
+               type, data, real_len );
 
        DEBUG(8,("add_printer_data: Added key => [%s], value => [%s], type=> [%d], size => [%d]\n",
                key, value, type, real_len  ));
@@ -3725,7 +3716,7 @@ WERROR add_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const cha
 /****************************************************************************
  ***************************************************************************/
 
-REGISTRY_VALUE* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
+struct regval_blob* get_printer_data( NT_PRINTER_INFO_LEVEL_2 *p2, const char *key, const char *value )
 {
        int             key_index;
 
@@ -3752,7 +3743,7 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, const uint8 *buf, int bu
        char            *str;
        int             size;
        uint8           *data_p;
-       REGISTRY_VALUE  *regval_p;
+       struct regval_blob      *regval_p;
        int             key_index;
 
        /* add the "PrinterDriverData" key first for performance reasons */
@@ -3830,28 +3821,20 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, const uint8 *buf, int bu
                     strequal( valuename, "objectGUID" ) )
                {
                        struct GUID guid;
-                       UNISTR2 unistr_guid;
-
-                       ZERO_STRUCT( unistr_guid );
 
                        /* convert the GUID to a UNICODE string */
 
                        memcpy( &guid, data_p, sizeof(struct GUID) );
 
-                       init_unistr2( &unistr_guid,
-                                     GUID_string(talloc_tos(), &guid),
-                                     UNI_STR_TERMINATE );
-
-                       regval_ctr_addvalue( printer_data->keys[key_index].values,
-                                            valuename, REG_SZ,
-                                            (const char *)unistr_guid.buffer,
-                                            unistr_guid.uni_str_len*2 );
+                       regval_ctr_addvalue_sz(printer_data->keys[key_index].values,
+                                              valuename,
+                                              GUID_string(talloc_tos(), &guid));
 
                } else {
                        /* add the value */
 
                        regval_ctr_addvalue( printer_data->keys[key_index].values,
-                                            valuename, type, (const char *)data_p,
+                                            valuename, type, data_p,
                                             size );
                }
 
@@ -3865,39 +3848,36 @@ static int unpack_values(NT_PRINTER_DATA *printer_data, const uint8 *buf, int bu
 /****************************************************************************
  ***************************************************************************/
 
-static char *last_from;
-static char *last_to;
+static char *win_driver;
+static char *os2_driver;
 
-static const char *get_last_from(void)
+static const char *get_win_driver(void)
 {
-       if (!last_from) {
+       if (win_driver == NULL) {
                return "";
        }
-       return last_from;
+       return win_driver;
 }
 
-static const char *get_last_to(void)
+static const char *get_os2_driver(void)
 {
-       if (!last_to) {
+       if (os2_driver == NULL) {
                return "";
        }
-       return last_to;
+       return os2_driver;
 }
 
-static bool set_last_from_to(const char *from, const char *to)
+static bool set_driver_mapping(const char *from, const char *to)
 {
-       char *orig_from = last_from;
-       char *orig_to = last_to;
-
-       last_from = SMB_STRDUP(from);
-       last_to = SMB_STRDUP(to);
+       SAFE_FREE(win_driver);
+       SAFE_FREE(os2_driver);
 
-       SAFE_FREE(orig_from);
-       SAFE_FREE(orig_to);
+       win_driver = SMB_STRDUP(from);
+       os2_driver = SMB_STRDUP(to);
 
-       if (!last_from || !last_to) {
-               SAFE_FREE(last_from);
-               SAFE_FREE(last_to);
+       if (win_driver == NULL || os2_driver == NULL) {
+               SAFE_FREE(win_driver);
+               SAFE_FREE(os2_driver);
                return false;
        }
        return true;
@@ -3916,10 +3896,10 @@ static void map_to_os2_driver(fstring drivername)
        if (!*mapfile)
                return;
 
-       if (strequal(drivername,get_last_from())) {
+       if (strequal(drivername, get_win_driver())) {
                DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
-                       drivername,get_last_to()));
-               fstrcpy(drivername,get_last_to());
+                       drivername, get_os2_driver()));
+               fstrcpy(drivername, get_os2_driver());
                return;
        }
 
@@ -3968,7 +3948,7 @@ static void map_to_os2_driver(fstring drivername)
 
                if (strequal(nt_name,drivername)) {
                        DEBUG(3,("Mapped windows driver %s to os2 driver%s\n",drivername,os2_name));
-                       set_last_from_to(drivername,os2_name);
+                       set_driver_mapping(drivername,os2_name);
                        fstrcpy(drivername,os2_name);
                        TALLOC_FREE(lines);
                        return;
@@ -3978,6 +3958,110 @@ static void map_to_os2_driver(fstring drivername)
        TALLOC_FREE(lines);
 }
 
+/**
+ * @internal
+ *
+ * @brief Map a Windows driver to a OS/2 driver.
+ *
+ * @param[in]  mem_ctx  The memory context to use.
+ *
+ * @param[in,out] pdrivername The drivername of Windows to remap.
+ *
+ * @return              WERR_OK on success, a corresponding WERROR on failure.
+ */
+WERROR spoolss_map_to_os2_driver(TALLOC_CTX *mem_ctx, const char **pdrivername)
+{
+       const char *mapfile = lp_os2_driver_map();
+       char **lines = NULL;
+       const char *drivername;
+       int numlines = 0;
+       int i;
+
+       if (pdrivername == NULL || *pdrivername == NULL || *pdrivername[0] == '\0') {
+               return WERR_INVALID_PARAMETER;
+       }
+
+       drivername = *pdrivername;
+
+       if (mapfile[0] == '\0') {
+               return WERR_BADFILE;
+       }
+
+       if (strequal(drivername, get_win_driver())) {
+               DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",
+                       drivername, get_os2_driver()));
+               drivername = talloc_strdup(mem_ctx, get_os2_driver());
+               if (drivername == NULL) {
+                       return WERR_NOMEM;
+               }
+               *pdrivername = drivername;
+               return WERR_OK;
+       }
+
+       lines = file_lines_load(mapfile, &numlines, 0, NULL);
+       if (numlines == 0 || lines == NULL) {
+               DEBUG(0,("No entries in OS/2 driver map %s\n", mapfile));
+               TALLOC_FREE(lines);
+               return WERR_EMPTY;
+       }
+
+       DEBUG(4,("Scanning OS/2 driver map %s\n",mapfile));
+
+       for( i = 0; i < numlines; i++) {
+               char *nt_name = lines[i];
+               char *os2_name = strchr(nt_name, '=');
+
+               if (os2_name == NULL) {
+                       continue;
+               }
+
+               *os2_name++ = '\0';
+
+               while (isspace(*nt_name)) {
+                       nt_name++;
+               }
+
+               if (*nt_name == '\0' || strchr("#;", *nt_name)) {
+                       continue;
+               }
+
+               {
+                       int l = strlen(nt_name);
+                       while (l && isspace(nt_name[l - 1])) {
+                               nt_name[l - 1] = 0;
+                               l--;
+                       }
+               }
+
+               while (isspace(*os2_name)) {
+                       os2_name++;
+               }
+
+               {
+                       int l = strlen(os2_name);
+                       while (l && isspace(os2_name[l-1])) {
+                               os2_name[l-1] = 0;
+                               l--;
+                       }
+               }
+
+               if (strequal(nt_name, drivername)) {
+                       DEBUG(3,("Mapped Windows driver %s to OS/2 driver %s\n",drivername,os2_name));
+                       set_driver_mapping(drivername, os2_name);
+                       drivername = talloc_strdup(mem_ctx, os2_name);
+                       TALLOC_FREE(lines);
+                       if (drivername == NULL) {
+                               return WERR_NOMEM;
+                       }
+                       *pdrivername = drivername;
+                       return WERR_OK;
+               }
+       }
+
+       TALLOC_FREE(lines);
+       return WERR_OK;
+}
+
 /****************************************************************************
  Get a default printer info 2 struct.
 ****************************************************************************/
@@ -4015,8 +4099,17 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info,
        if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {
                /* Pull the location and comment strings from cups if we don't
                   already have one */
-               if ( !strlen(info->location) || !strlen(info->comment) )
-                       cups_pull_comment_location( info );
+               if ( !strlen(info->location) || !strlen(info->comment) ) {
+                       char *comment = NULL;
+                       char *location = NULL;
+                       if (cups_pull_comment_location(info, info->sharename,
+                                                      &comment, &location)) {
+                               strlcpy(info->comment, comment, sizeof(info->comment));
+                               fstrcpy(info->location, location);
+                               TALLOC_FREE(comment);
+                               TALLOC_FREE(location);
+                       }
+               }
        }
 #endif
 
@@ -4050,6 +4143,13 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 *info,
                goto fail;
        }
 
+       info->data = TALLOC_ZERO_P(info, NT_PRINTER_DATA);
+       if (!info->data) {
+               goto fail;
+       }
+
+       add_new_printer_key(info->data, SPOOL_PRINTERDATA_KEY);
+
        return WERR_OK;
 
 fail:
@@ -4130,8 +4230,17 @@ static WERROR get_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info,
        if (get_loc_com && (enum printing_types)lp_printing(snum) == PRINT_CUPS ) {
                /* Pull the location and comment strings from cups if we don't
                   already have one */
-               if ( !strlen(info->location) || !strlen(info->comment) )
-                       cups_pull_comment_location( info );
+               if ( !strlen(info->location) || !strlen(info->comment) ) {
+                       char *location = NULL;
+                       comment = NULL;
+                       if (cups_pull_comment_location(info, info->sharename,
+                                                      &comment, &location)) {
+                               strlcpy(info->comment, comment, sizeof(info->comment));
+                               fstrcpy(info->location, location);
+                               TALLOC_FREE(comment);
+                               TALLOC_FREE(location);
+                       }
+               }
        }
 #endif
 
@@ -4330,419 +4439,50 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
 }
 
 /****************************************************************************
- Initialize printer devmode & data with previously saved driver init values.
+ Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
+
+ Previously the code had a memory allocation problem because it always
+ used the TALLOC_CTX from the Printer_entry*.   This context lasts
+ as a long as the original handle is open.  So if the client made a lot
+ of getprinter[data]() calls, the memory usage would climb.  Now we use
+ a short lived TALLOC_CTX for printer_info_2 objects returned.  We
+ still use the Printer_entry->ctx for maintaining the cache copy though
+ since that object must live as long as the handle by definition.
+                                                    --jerry
+
 ****************************************************************************/
 
-static bool set_driver_init_2( NT_PRINTER_INFO_LEVEL_2 *info_ptr )
+static WERROR get_a_printer_internal( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
+                       const char *sharename, bool get_loc_com)
 {
-       int                     len = 0;
-       char *key = NULL;
-       TDB_DATA                dbuf;
-       NT_PRINTER_INFO_LEVEL_2 info;
+       WERROR result;
+       fstring servername;
 
+       DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
 
-       ZERO_STRUCT(info);
+       if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
+               DEBUG(0,("get_a_printer: talloc() fail.\n"));
+               return WERR_NOMEM;
+       }
 
-       /*
-        * Delete any printer data 'values' already set. When called for driver
-        * replace, there will generally be some, but during an add printer, there
-        * should not be any (if there are delete them).
-        */
+       switch (level) {
+               case 2:
+                       if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
+                               DEBUG(0,("get_a_printer: talloc() fail.\n"));
+                               TALLOC_FREE( *pp_printer );
+                               return WERR_NOMEM;
+                       }
 
-       if ( info_ptr->data )
-               delete_all_printer_data( info_ptr, "" );
+                       if ( print_hnd )
+                               fstrcpy( servername, print_hnd->servername );
+                       else {
+                               fstrcpy( servername, "%L" );
+                               standard_sub_basic( "", "", servername,
+                                                   sizeof(servername)-1 );
+                       }
 
-       if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX,
-                               info_ptr->drivername) < 0) {
-               return false;
-       }
-
-       dbuf = tdb_fetch_bystring(tdb_drivers, key);
-       if (!dbuf.dptr) {
-               /*
-                * When changing to a driver that has no init info in the tdb, remove
-                * the previous drivers init info and leave the new on blank.
-                */
-               free_nt_devicemode(&info_ptr->devmode);
-               SAFE_FREE(key);
-               return false;
-       }
-
-       SAFE_FREE(key);
-       /*
-        * Get the saved DEVMODE..
-        */
-
-       len += unpack_devicemode(&info.devmode,dbuf.dptr+len, dbuf.dsize-len);
-
-       /*
-        * The saved DEVMODE contains the devicename from the printer used during
-        * the initialization save. Change it to reflect the new printer.
-        */
-
-       if ( info.devmode ) {
-               ZERO_STRUCT(info.devmode->devicename);
-               fstrcpy(info.devmode->devicename, info_ptr->printername);
-       }
-
-       /*
-        * NT/2k does not change out the entire DeviceMode of a printer
-        * when changing the driver.  Only the driverextra, private, &
-        * driverversion fields.   --jerry  (Thu Mar 14 08:58:43 CST 2002)
-        *
-        * Later examination revealed that Windows NT/2k does reset the
-        * the printer's device mode, bit **only** when you change a
-        * property of the device mode such as the page orientation.
-        * --jerry
-        */
-
-
-       /* Bind the saved DEVMODE to the new the printer */
-
-       free_nt_devicemode(&info_ptr->devmode);
-       info_ptr->devmode = info.devmode;
-
-       DEBUG(10,("set_driver_init_2: Set printer [%s] init %s DEVMODE for driver [%s]\n",
-               info_ptr->printername, info_ptr->devmode?"VALID":"NULL", info_ptr->drivername));
-
-       /* Add the printer data 'values' to the new printer */
-
-       if ( !(info_ptr->data = TALLOC_ZERO_P( info_ptr, NT_PRINTER_DATA )) ) {
-               DEBUG(0,("set_driver_init_2: talloc() failed!\n"));
-               return False;
-       }
-
-       len += unpack_values( info_ptr->data, dbuf.dptr+len, dbuf.dsize-len );
-
-       SAFE_FREE(dbuf.dptr);
-
-       return true;
-}
-
-/****************************************************************************
- Initialize printer devmode & data with previously saved driver init values.
- When a printer is created using AddPrinter, the drivername bound to the
- printer is used to lookup previously saved driver initialization info, which
- is bound to the new printer.
-****************************************************************************/
-
-bool set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
-{
-       bool result = False;
-
-       switch (level) {
-               case 2:
-                       result = set_driver_init_2(printer->info_2);
-                       break;
-
-               default:
-                       DEBUG(0,("set_driver_init: Programmer's error!  Unknown driver_init level [%d]\n",
-                               level));
-                       break;
-       }
-
-       return result;
-}
-
-/****************************************************************************
- Delete driver init data stored for a specified driver
-****************************************************************************/
-
-bool del_driver_init(char *drivername)
-{
-       char *key;
-       bool ret;
-
-       if (!drivername || !*drivername) {
-               DEBUG(3,("del_driver_init: No drivername specified!\n"));
-               return false;
-       }
-
-       if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, drivername) < 0) {
-               return false;
-       }
-
-       DEBUG(6,("del_driver_init: Removing driver init data for [%s]\n",
-                               drivername));
-
-       ret = (tdb_delete_bystring(tdb_drivers, key) == 0);
-       SAFE_FREE(key);
-       return ret;
-}
-
-/****************************************************************************
- Pack up the DEVMODE and values for a printer into a 'driver init' entry
- in the tdb. Note: this is different from the driver entry and the printer
- entry. There should be a single driver init entry for each driver regardless
- of whether it was installed from NT or 2K. Technically, they should be
- different, but they work out to the same struct.
-****************************************************************************/
-
-static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
-{
-       char *key = NULL;
-       uint8 *buf;
-       int buflen, len, ret;
-       int retlen;
-       TDB_DATA dbuf;
-
-       buf = NULL;
-       buflen = 0;
-
- again:
-       len = 0;
-       len += pack_devicemode(info->devmode, buf+len, buflen-len);
-
-       retlen = pack_values( info->data, buf+len, buflen-len );
-       if (retlen == -1) {
-               ret = -1;
-               goto done;
-       }
-       len += retlen;
-
-       if (buflen < len) {
-               buf = (uint8 *)SMB_REALLOC(buf, len);
-               if (!buf) {
-                       DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
-                       ret = -1;
-                       goto done;
-               }
-               buflen = len;
-               goto again;
-       }
-
-       SAFE_FREE(key);
-       if (asprintf(&key, "%s%s", DRIVER_INIT_PREFIX, info->drivername) < 0) {
-               ret = (uint32)-1;
-               goto done;
-       }
-
-       dbuf.dptr = buf;
-       dbuf.dsize = len;
-
-       ret = tdb_store_bystring(tdb_drivers, key, dbuf, TDB_REPLACE);
-
-done:
-       if (ret == -1)
-               DEBUG(8, ("update_driver_init_2: error updating printer init to tdb on disk\n"));
-
-       SAFE_FREE(buf);
-
-       DEBUG(10,("update_driver_init_2: Saved printer [%s] init DEVMODE & values for driver [%s]\n",
-                info->sharename, info->drivername));
-
-       return ret;
-}
-
-/****************************************************************************
- Update (i.e. save) the driver init info (DEVMODE and values) for a printer
-****************************************************************************/
-
-static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
-{
-       uint32 result;
-
-       dump_a_printer(printer, level);
-
-       switch (level) {
-               case 2:
-                       result = update_driver_init_2(printer->info_2);
-                       break;
-               default:
-                       result = 1;
-                       break;
-       }
-
-       return result;
-}
-
-/****************************************************************************
- Convert the printer data value, a REG_BINARY array, into an initialization
- DEVMODE. Note: the array must be parsed as if it was a DEVMODE in an rpc...
- got to keep the endians happy :).
-****************************************************************************/
-
-static bool convert_driver_init(TALLOC_CTX *mem_ctx, NT_DEVICEMODE *nt_devmode,
-                               const uint8_t *data, uint32_t data_len)
-{
-       struct spoolss_DeviceMode devmode;
-       enum ndr_err_code ndr_err;
-       DATA_BLOB blob;
-
-       ZERO_STRUCT(devmode);
-
-       blob = data_blob_const(data, data_len);
-
-       ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, &devmode,
-                       (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               DEBUG(10,("convert_driver_init: error parsing spoolss_DeviceMode\n"));
-               return false;
-       }
-
-       return convert_devicemode("", &devmode, &nt_devmode);
-}
-
-/****************************************************************************
- Set the DRIVER_INIT info in the tdb. Requires Win32 client code that:
-
- 1. Use the driver's config DLL to this UNC printername and:
-    a. Call DrvPrintEvent with PRINTER_EVENT_INITIALIZE
-    b. Call DrvConvertDevMode with CDM_DRIVER_DEFAULT to get default DEVMODE
- 2. Call SetPrinterData with the 'magic' key and the DEVMODE as data.
-
- The last step triggers saving the "driver initialization" information for
- this printer into the tdb. Later, new printers that use this driver will
- have this initialization information bound to them. This simulates the
- driver initialization, as if it had run on the Samba server (as it would
- have done on NT).
-
- The Win32 client side code requirement sucks! But until we can run arbitrary
- Win32 printer driver code on any Unix that Samba runs on, we are stuck with it.
-
- It would have been easier to use SetPrinter because all the UNMARSHALLING of
- the DEVMODE is done there, but 2K/XP clients do not set the DEVMODE... think
- about it and you will realize why.  JRR 010720
-****************************************************************************/
-
-static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, uint8 *data, uint32 data_len )
-{
-       WERROR        status       = WERR_OK;
-       TALLOC_CTX    *ctx         = NULL;
-       NT_DEVICEMODE *nt_devmode  = NULL;
-       NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
-
-       /*
-        * When the DEVMODE is already set on the printer, don't try to unpack it.
-        */
-       DEBUG(8,("save_driver_init_2: Enter...\n"));
-
-       if ( !printer->info_2->devmode && data_len ) {
-               /*
-                * Set devmode on printer info, so entire printer initialization can be
-                * saved to tdb.
-                */
-
-               if ((ctx = talloc_init("save_driver_init_2")) == NULL)
-                       return WERR_NOMEM;
-
-               if ((nt_devmode = SMB_MALLOC_P(NT_DEVICEMODE)) == NULL) {
-                       status = WERR_NOMEM;
-                       goto done;
-               }
-
-               ZERO_STRUCTP(nt_devmode);
-
-               /*
-                * The DEVMODE is held in the 'data' component of the param in raw binary.
-                * Convert it to to a devmode structure
-                */
-               if ( !convert_driver_init( ctx, nt_devmode, data, data_len )) {
-                       DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
-                       status = WERR_INVALID_PARAM;
-                       goto done;
-               }
-
-               printer->info_2->devmode = nt_devmode;
-       }
-
-       /*
-        * Pack up and add (or update) the DEVMODE and any current printer data to
-        * a 'driver init' element in the tdb
-        *
-        */
-
-       if ( update_driver_init(printer, 2) != 0 ) {
-               DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
-               status = WERR_NOMEM;
-               goto done;
-       }
-
-       /*
-        * If driver initialization info was successfully saved, set the current
-        * printer to match it. This allows initialization of the current printer
-        * as well as the driver.
-        */
-       status = mod_a_printer(printer, 2);
-       if (!W_ERROR_IS_OK(status)) {
-               DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
-                                 printer->info_2->printername));
-       }
-
-  done:
-       talloc_destroy(ctx);
-       free_nt_devicemode( &nt_devmode );
-
-       printer->info_2->devmode = tmp_devmode;
-
-       return status;
-}
-
-/****************************************************************************
- Update the driver init info (DEVMODE and specifics) for a printer
-****************************************************************************/
-
-WERROR save_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level, uint8 *data, uint32 data_len)
-{
-       WERROR status = WERR_OK;
-
-       switch (level) {
-               case 2:
-                       status = save_driver_init_2( printer, data, data_len );
-                       break;
-               default:
-                       status = WERR_UNKNOWN_LEVEL;
-                       break;
-       }
-
-       return status;
-}
-
-/****************************************************************************
- Get a NT_PRINTER_INFO_LEVEL struct. It returns malloced memory.
-
- Previously the code had a memory allocation problem because it always
- used the TALLOC_CTX from the Printer_entry*.   This context lasts
- as a long as the original handle is open.  So if the client made a lot
- of getprinter[data]() calls, the memory usage would climb.  Now we use
- a short lived TALLOC_CTX for printer_info_2 objects returned.  We
- still use the Printer_entry->ctx for maintaining the cache copy though
- since that object must live as long as the handle by definition.
-                                                    --jerry
-
-****************************************************************************/
-
-static WERROR get_a_printer_internal( Printer_entry *print_hnd, NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level,
-                       const char *sharename, bool get_loc_com)
-{
-       WERROR result;
-       fstring servername;
-
-       DEBUG(10,("get_a_printer: [%s] level %u\n", sharename, (unsigned int)level));
-
-       if ( !(*pp_printer = TALLOC_ZERO_P(NULL, NT_PRINTER_INFO_LEVEL)) ) {
-               DEBUG(0,("get_a_printer: talloc() fail.\n"));
-               return WERR_NOMEM;
-       }
-
-       switch (level) {
-               case 2:
-                       if ( !((*pp_printer)->info_2 = TALLOC_ZERO_P(*pp_printer, NT_PRINTER_INFO_LEVEL_2)) ) {
-                               DEBUG(0,("get_a_printer: talloc() fail.\n"));
-                               TALLOC_FREE( *pp_printer );
-                               return WERR_NOMEM;
-                       }
-
-                       if ( print_hnd )
-                               fstrcpy( servername, print_hnd->servername );
-                       else {
-                               fstrcpy( servername, "%L" );
-                               standard_sub_basic( "", "", servername,
-                                                   sizeof(servername)-1 );
-                       }
-
-                       result = get_a_printer_2( (*pp_printer)->info_2,
-                                       servername, sharename, get_loc_com);
+                       result = get_a_printer_2( (*pp_printer)->info_2,
+                                       servername, sharename, get_loc_com);
 
                        /* we have a new printer now.  Save it with this handle */
 
@@ -4812,108 +4552,186 @@ uint32 free_a_printer(NT_PRINTER_INFO_LEVEL **pp_printer, uint32 level)
 
 /****************************************************************************
 ****************************************************************************/
-uint32 add_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
+
+bool driver_info_ctr_to_info8(struct spoolss_AddDriverInfoCtr *r,
+                             struct spoolss_DriverInfo8 *_info8)
 {
-       uint32 result;
-       DEBUG(104,("adding a printer at level [%d]\n", level));
-       dump_a_printer_driver(driver, level);
+       struct spoolss_DriverInfo8 info8;
+
+       ZERO_STRUCT(info8);
+
+       switch (r->level) {
+       case 3:
+               info8.version           = r->info.info3->version;
+               info8.driver_name       = r->info.info3->driver_name;
+               info8.architecture      = r->info.info3->architecture;
+               info8.driver_path       = r->info.info3->driver_path;
+               info8.data_file         = r->info.info3->data_file;
+               info8.config_file       = r->info.info3->config_file;
+               info8.help_file         = r->info.info3->help_file;
+               info8.monitor_name      = r->info.info3->monitor_name;
+               info8.default_datatype  = r->info.info3->default_datatype;
+               if (r->info.info3->dependent_files && r->info.info3->dependent_files->string) {
+                       info8.dependent_files   = r->info.info3->dependent_files->string;
+               }
+               break;
+       case 6:
+               info8.version           = r->info.info6->version;
+               info8.driver_name       = r->info.info6->driver_name;
+               info8.architecture      = r->info.info6->architecture;
+               info8.driver_path       = r->info.info6->driver_path;
+               info8.data_file         = r->info.info6->data_file;
+               info8.config_file       = r->info.info6->config_file;
+               info8.help_file         = r->info.info6->help_file;
+               info8.monitor_name      = r->info.info6->monitor_name;
+               info8.default_datatype  = r->info.info6->default_datatype;
+               if (r->info.info6->dependent_files && r->info.info6->dependent_files->string) {
+                       info8.dependent_files   = r->info.info6->dependent_files->string;
+               }
+               info8.driver_date       = r->info.info6->driver_date;
+               info8.driver_version    = r->info.info6->driver_version;
+               info8.manufacturer_name = r->info.info6->manufacturer_name;
+               info8.manufacturer_url  = r->info.info6->manufacturer_url;
+               info8.hardware_id       = r->info.info6->hardware_id;
+               info8.provider          = r->info.info6->provider;
+               break;
+       case 8:
+               info8.version           = r->info.info8->version;
+               info8.driver_name       = r->info.info8->driver_name;
+               info8.architecture      = r->info.info8->architecture;
+               info8.driver_path       = r->info.info8->driver_path;
+               info8.data_file         = r->info.info8->data_file;
+               info8.config_file       = r->info.info8->config_file;
+               info8.help_file         = r->info.info8->help_file;
+               info8.monitor_name      = r->info.info8->monitor_name;
+               info8.default_datatype  = r->info.info8->default_datatype;
+               if (r->info.info8->dependent_files && r->info.info8->dependent_files->string) {
+                       info8.dependent_files   = r->info.info8->dependent_files->string;
+               }
+               if (r->info.info8->previous_names && r->info.info8->previous_names->string) {
+                       info8.previous_names    = r->info.info8->previous_names->string;
+               }
+               info8.driver_date       = r->info.info8->driver_date;
+               info8.driver_version    = r->info.info8->driver_version;
+               info8.manufacturer_name = r->info.info8->manufacturer_name;
+               info8.manufacturer_url  = r->info.info8->manufacturer_url;
+               info8.hardware_id       = r->info.info8->hardware_id;
+               info8.provider          = r->info.info8->provider;
+               info8.print_processor   = r->info.info8->print_processor;
+               info8.vendor_setup      = r->info.info8->vendor_setup;
+               if (r->info.info8->color_profiles && r->info.info8->color_profiles->string) {
+                       info8.color_profiles = r->info.info8->color_profiles->string;
+               }
+               info8.inf_path          = r->info.info8->inf_path;
+               info8.printer_driver_attributes = r->info.info8->printer_driver_attributes;
+               if (r->info.info8->core_driver_dependencies && r->info.info8->core_driver_dependencies->string) {
+                       info8.core_driver_dependencies = r->info.info8->core_driver_dependencies->string;
+               }
+               info8.min_inbox_driver_ver_date = r->info.info8->min_inbox_driver_ver_date;
+               info8.min_inbox_driver_ver_version = r->info.info8->min_inbox_driver_ver_version;
+               break;
+       default:
+               return false;
+       }
 
-       switch (level) {
-               case 3:
-                       result=add_a_printer_driver_3(driver.info_3);
-                       break;
+       *_info8 = info8;
 
-               case 6:
-                       result=add_a_printer_driver_6(driver.info_6);
-                       break;
+       return true;
+}
 
-               default:
-                       result=1;
-                       break;
+
+uint32_t add_a_printer_driver(TALLOC_CTX *mem_ctx,
+                             struct spoolss_AddDriverInfoCtr *r,
+                             char **driver_name,
+                             uint32_t *version)
+{
+       struct spoolss_DriverInfo8 info8;
+
+       ZERO_STRUCT(info8);
+
+       DEBUG(10,("adding a printer at level [%d]\n", r->level));
+
+       if (!driver_info_ctr_to_info8(r, &info8)) {
+               return -1;
        }
 
-       return result;
+       *driver_name = talloc_strdup(mem_ctx, info8.driver_name);
+       if (!*driver_name) {
+               return -1;
+       }
+       *version = info8.version;
+
+       return add_a_printer_driver_8(&info8);
 }
+
 /****************************************************************************
 ****************************************************************************/
 
-WERROR get_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL *driver, uint32 level,
-                            fstring drivername, const char *architecture, uint32 version)
+WERROR get_a_printer_driver(TALLOC_CTX *mem_ctx,
+                           struct spoolss_DriverInfo8 **driver,
+                           const char *drivername, const char *architecture,
+                           uint32_t version)
 {
        WERROR result;
+       struct spoolss_DriverInfo3 info3;
+       struct spoolss_DriverInfo8 *info8;
 
-       switch (level) {
-               case 3:
-                       /* Sometime we just want any version of the driver */
+       ZERO_STRUCT(info3);
+
+       /* Sometime we just want any version of the driver */
 
-                       if ( version == DRIVER_ANY_VERSION ) {
-                               /* look for Win2k first and then for NT4 */
-                               result = get_a_printer_driver_3(&driver->info_3, drivername,
+       if (version == DRIVER_ANY_VERSION) {
+               /* look for Win2k first and then for NT4 */
+               result = get_a_printer_driver_3(mem_ctx,
+                                               &info3,
+                                               drivername,
                                                architecture, 3);
+               if (!W_ERROR_IS_OK(result)) {
+                       result = get_a_printer_driver_3(mem_ctx,
+                                                       &info3,
+                                                       drivername,
+                                                       architecture, 2);
+               }
+       } else {
+               result = get_a_printer_driver_3(mem_ctx,
+                                               &info3,
+                                               drivername,
+                                               architecture,
+                                               version);
+       }
 
-                               if ( !W_ERROR_IS_OK(result) ) {
-                                       result = get_a_printer_driver_3( &driver->info_3,
-                                                       drivername, architecture, 2 );
-                               }
-                       } else {
-                               result = get_a_printer_driver_3(&driver->info_3, drivername,
-                                       architecture, version);
-                       }
-                       break;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-               default:
-                       result=W_ERROR(1);
-                       break;
+       info8 = talloc_zero(mem_ctx, struct spoolss_DriverInfo8);
+       if (!info8) {
+               return WERR_NOMEM;
        }
 
-       if (W_ERROR_IS_OK(result))
-               dump_a_printer_driver(*driver, level);
+       info8->version          = info3.version;
+       info8->driver_name      = info3.driver_name;
+       info8->architecture     = info3.architecture;
+       info8->driver_path      = info3.driver_path;
+       info8->data_file        = info3.data_file;
+       info8->config_file      = info3.config_file;
+       info8->help_file        = info3.help_file;
+       info8->dependent_files  = info3.dependent_files;
+       info8->monitor_name     = info3.monitor_name;
+       info8->default_datatype = info3.default_datatype;
 
-       return result;
+       *driver = info8;
+
+       return WERR_OK;
 }
 
 /****************************************************************************
 ****************************************************************************/
-uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
-{
-       uint32 result;
 
-       switch (level) {
-               case 3:
-               {
-                       NT_PRINTER_DRIVER_INFO_LEVEL_3 *info3;
-                       if (driver.info_3 != NULL)
-                       {
-                               info3=driver.info_3;
-                               SAFE_FREE(info3->dependentfiles);
-                               ZERO_STRUCTP(info3);
-                               SAFE_FREE(info3);
-                               result=0;
-                       } else {
-                               result=4;
-                       }
-                       break;
-               }
-               case 6:
-               {
-                       NT_PRINTER_DRIVER_INFO_LEVEL_6 *info6;
-                       if (driver.info_6 != NULL) {
-                               info6=driver.info_6;
-                               SAFE_FREE(info6->dependentfiles);
-                               SAFE_FREE(info6->previousnames);
-                               ZERO_STRUCTP(info6);
-                               SAFE_FREE(info6);
-                               result=0;
-                       } else {
-                               result=4;
-                       }
-                       break;
-               }
-               default:
-                       result=1;
-                       break;
-       }
-       return result;
+uint32_t free_a_printer_driver(struct spoolss_DriverInfo8 *driver)
+{
+       talloc_free(driver);
+       return 0;
 }
 
 
@@ -4922,15 +4740,16 @@ uint32 free_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
   to a printer
 ****************************************************************************/
 
-bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
+bool printer_driver_in_use(const struct spoolss_DriverInfo8 *r)
 {
        int snum;
        int n_services = lp_numservices();
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        bool in_use = False;
 
-       if ( !info_3 )
-               return False;
+       if (!r) {
+               return false;
+       }
 
        DEBUG(10,("printer_driver_in_use: Beginning search through ntprinters.tdb...\n"));
 
@@ -4943,7 +4762,7 @@ bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
                if ( !W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_servicename(snum))) )
                        continue;
 
-               if ( strequal(info_3->name, printer->info_2->drivername) )
+               if (strequal(r->driver_name, printer->info_2->drivername))
                        in_use = True;
 
                free_a_printer( &printer, 2 );
@@ -4952,28 +4771,28 @@ bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
        DEBUG(10,("printer_driver_in_use: Completed search through ntprinters.tdb...\n"));
 
        if ( in_use ) {
-               NT_PRINTER_DRIVER_INFO_LEVEL d;
+               struct spoolss_DriverInfo8 *d;
                WERROR werr;
 
-               DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", info_3->name));
+               DEBUG(5,("printer_driver_in_use: driver \"%s\" is currently in use\n", r->driver_name));
 
                /* we can still remove the driver if there is one of
                   "Windows NT x86" version 2 or 3 left */
 
-               if ( !strequal( "Windows NT x86", info_3->environment ) ) {
-                       werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", DRIVER_ANY_VERSION );
+               if (!strequal("Windows NT x86", r->architecture)) {
+                       werr = get_a_printer_driver(talloc_tos(), &d, r->driver_name, "Windows NT x86", DRIVER_ANY_VERSION);
                }
                else {
-                       switch ( info_3->cversion ) {
+                       switch (r->version) {
                        case 2:
-                               werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 3 );
+                               werr = get_a_printer_driver(talloc_tos(), &d, r->driver_name, "Windows NT x86", 3);
                                break;
                        case 3:
-                               werr = get_a_printer_driver( &d, 3, info_3->name, "Windows NT x86", 2 );
+                               werr = get_a_printer_driver(talloc_tos(), &d, r->driver_name, "Windows NT x86", 2);
                                break;
                        default:
                                DEBUG(0,("printer_driver_in_use: ERROR! unknown driver version (%d)\n",
-                                       info_3->cversion));
+                                       r->version));
                                werr = WERR_UNKNOWN_PRINTER_DRIVER;
                                break;
                        }
@@ -4984,7 +4803,7 @@ bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
                if ( W_ERROR_IS_OK(werr) ) {
                        /* it's ok to remove the driver, we have other architctures left */
                        in_use = False;
-                       free_a_printer_driver( d, 3 );
+                       free_a_printer_driver(d);
                }
        }
 
@@ -4998,7 +4817,7 @@ bool printer_driver_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3 )
  Check to see if a ogiven file is in use by *info
  *********************************************************************/
 
-static bool drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
+static bool drv_file_in_use(const char *file, const struct spoolss_DriverInfo8 *info)
 {
        int i = 0;
 
@@ -5010,25 +4829,25 @@ static bool drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
                return false;
        }
 
-       if ( strequal(file, info->driverpath) )
+       if (strequal(file, info->driver_path))
                return True;
 
-       if ( strequal(file, info->datafile) )
+       if (strequal(file, info->data_file))
                return True;
 
-       if ( strequal(file, info->configfile) )
+       if (strequal(file, info->config_file))
                return True;
 
-       if ( strequal(file, info->helpfile) )
+       if (strequal(file, info->help_file))
                return True;
 
        /* see of there are any dependent files to examine */
 
-       if ( !info->dependentfiles )
+       if (!info->dependent_files)
                return False;
 
-       while ( *info->dependentfiles[i] ) {
-               if ( strequal(file, info->dependentfiles[i]) )
+       while (info->dependent_files[i] && *info->dependent_files[i]) {
+               if (strequal(file, info->dependent_files[i]))
                        return True;
                i++;
        }
@@ -5042,17 +4861,17 @@ static bool drv_file_in_use( char* file, NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
  input parameter from the list
  *********************************************************************/
 
-static void trim_dependent_file( fstring files[], int idx )
+static void trim_dependent_file(TALLOC_CTX *mem_ctx, const char **files, int idx)
 {
 
        /* bump everything down a slot */
 
-       while( *files[idx+1] ) {
-               fstrcpy( files[idx], files[idx+1] );
+       while (files && files[idx+1]) {
+               files[idx] = talloc_strdup(mem_ctx, files[idx+1]);
                idx++;
        }
 
-       *files[idx] = '\0';
+       files[idx] = NULL;
 
        return;
 }
@@ -5061,8 +4880,9 @@ static void trim_dependent_file( fstring files[], int idx )
  Check if any of the files used by src are also used by drv
  *********************************************************************/
 
-static bool trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
-                                      NT_PRINTER_DRIVER_INFO_LEVEL_3 *drv )
+static bool trim_overlap_drv_files(TALLOC_CTX *mem_ctx,
+                                  struct spoolss_DriverInfo8 *src,
+                                  const struct spoolss_DriverInfo8 *drv)
 {
        bool    in_use = False;
        int     i = 0;
@@ -5072,40 +4892,44 @@ static bool trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
 
        /* check each file.  Remove it from the src structure if it overlaps */
 
-       if ( drv_file_in_use(src->driverpath, drv) ) {
+       if (drv_file_in_use(src->driver_path, drv)) {
                in_use = True;
-               DEBUG(10,("Removing driverfile [%s] from list\n", src->driverpath));
-               fstrcpy( src->driverpath, "" );
+               DEBUG(10,("Removing driverfile [%s] from list\n", src->driver_path));
+               src->driver_path = talloc_strdup(mem_ctx, "");
+               if (!src->driver_path) { return false; }
        }
 
-       if ( drv_file_in_use(src->datafile, drv) ) {
+       if (drv_file_in_use(src->data_file, drv)) {
                in_use = True;
-               DEBUG(10,("Removing datafile [%s] from list\n", src->datafile));
-               fstrcpy( src->datafile, "" );
+               DEBUG(10,("Removing datafile [%s] from list\n", src->data_file));
+               src->data_file = talloc_strdup(mem_ctx, "");
+               if (!src->data_file) { return false; }
        }
 
-       if ( drv_file_in_use(src->configfile, drv) ) {
+       if (drv_file_in_use(src->config_file, drv)) {
                in_use = True;
-               DEBUG(10,("Removing configfile [%s] from list\n", src->configfile));
-               fstrcpy( src->configfile, "" );
+               DEBUG(10,("Removing configfile [%s] from list\n", src->config_file));
+               src->config_file = talloc_strdup(mem_ctx, "");
+               if (!src->config_file) { return false; }
        }
 
-       if ( drv_file_in_use(src->helpfile, drv) ) {
+       if (drv_file_in_use(src->help_file, drv)) {
                in_use = True;
-               DEBUG(10,("Removing helpfile [%s] from list\n", src->helpfile));
-               fstrcpy( src->helpfile, "" );
+               DEBUG(10,("Removing helpfile [%s] from list\n", src->help_file));
+               src->help_file = talloc_strdup(mem_ctx, "");
+               if (!src->help_file) { return false; }
        }
 
        /* are there any dependentfiles to examine? */
 
-       if ( !src->dependentfiles )
+       if (!src->dependent_files)
                return in_use;
 
-       while ( *src->dependentfiles[i] ) {
-               if ( drv_file_in_use(src->dependentfiles[i], drv) ) {
+       while (src->dependent_files[i] && *src->dependent_files[i]) {
+               if (drv_file_in_use(src->dependent_files[i], drv)) {
                        in_use = True;
-                       DEBUG(10,("Removing [%s] from dependent file list\n", src->dependentfiles[i]));
-                       trim_dependent_file( src->dependentfiles, i );
+                       DEBUG(10,("Removing [%s] from dependent file list\n", src->dependent_files[i]));
+                       trim_dependent_file(mem_ctx, src->dependent_files, i);
                } else
                        i++;
        }
@@ -5130,19 +4954,20 @@ static bool trim_overlap_drv_files( NT_PRINTER_DRIVER_INFO_LEVEL_3 *src,
   match.
 ****************************************************************************/
 
-bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
+bool printer_driver_files_in_use(TALLOC_CTX *mem_ctx,
+                                struct spoolss_DriverInfo8 *info)
 {
        int                             i;
        int                             ndrivers;
        uint32                          version;
        fstring                         *list = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       struct spoolss_DriverInfo8      *driver;
        bool in_use = false;
 
        if ( !info )
                return False;
 
-       version = info->cversion;
+       version = info->version;
 
        /* loop over all driver versions */
 
@@ -5151,19 +4976,19 @@ bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
        /* get the list of drivers */
 
        list = NULL;
-       ndrivers = get_ntdrivers(&list, info->environment, version);
+       ndrivers = get_ntdrivers(&list, info->architecture, version);
 
        DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
-               ndrivers, info->environment, version));
+               ndrivers, info->architecture, version));
 
        /* check each driver for overlap in files */
 
        for (i=0; i<ndrivers; i++) {
                DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
 
-               ZERO_STRUCT(driver);
+               driver = NULL;
 
-               if ( !W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, list[i], info->environment, version)) ) {
+               if (!W_ERROR_IS_OK(get_a_printer_driver(talloc_tos(), &driver, list[i], info->architecture, version))) {
                        SAFE_FREE(list);
                        return True;
                }
@@ -5171,8 +4996,8 @@ bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
                /* check if d2 uses any files from d1 */
                /* only if this is a different driver than the one being deleted */
 
-               if ( !strequal(info->name, driver.info_3->name) ) {
-                       if ( trim_overlap_drv_files(info, driver.info_3) ) {
+               if (!strequal(info->driver_name, driver->driver_name)) {
+                       if (trim_overlap_drv_files(mem_ctx, info, driver)) {
                                /* mz: Do not instantly return -
                                 * we need to ensure this file isn't
                                 * also in use by other drivers. */
@@ -5180,19 +5005,32 @@ bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
                        }
                }
 
-               free_a_printer_driver(driver, 3);
+               free_a_printer_driver(driver);
        }
 
        SAFE_FREE(list);
 
        DEBUG(5,("printer_driver_files_in_use: Completed search through ntdrivers.tdb...\n"));
 
-       driver.info_3 = info;
+       return in_use;
+}
 
-       if ( DEBUGLEVEL >= 20 )
-               dump_a_printer_driver( driver, 3 );
+static NTSTATUS driver_unlink_internals(connection_struct *conn,
+                                       const char *name)
+{
+       struct smb_filename *smb_fname = NULL;
+       NTSTATUS status;
 
-       return in_use;
+       status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
+           &smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = unlink_internals(conn, NULL, 0, smb_fname, false);
+
+       TALLOC_FREE(smb_fname);
+       return status;
 }
 
 /****************************************************************************
@@ -5202,23 +5040,24 @@ bool printer_driver_files_in_use ( NT_PRINTER_DRIVER_INFO_LEVEL_3 *info )
 ****************************************************************************/
 
 static bool delete_driver_files(struct pipes_struct *rpc_pipe,
-                               NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3)
+                               const struct spoolss_DriverInfo8 *r)
 {
        int i = 0;
        char *s;
        const char *file;
        connection_struct *conn;
        NTSTATUS nt_status;
-       SMB_STRUCT_STAT  st;
        char *oldcwd;
        fstring printdollar;
        int printdollar_snum;
        bool ret = false;
 
-       if ( !info_3 )
-               return False;
+       if (!r) {
+               return false;
+       }
 
-       DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n", info_3->name, info_3->cversion));
+       DEBUG(6,("delete_driver_files: deleting driver [%s] - version [%d]\n",
+               r->driver_name, r->version));
 
        fstrcpy(printdollar, "print$");
 
@@ -5244,55 +5083,50 @@ static bool delete_driver_files(struct pipes_struct *rpc_pipe,
        /* now delete the files; must strip the '\print$' string from
           fron of path                                                */
 
-       if ( *info_3->driverpath ) {
-               if ( (s = strchr( &info_3->driverpath[1], '\\' )) != NULL ) {
+       if (r->driver_path && r->driver_path[0]) {
+               if ((s = strchr(&r->driver_path[1], '\\')) != NULL) {
                        file = s;
-                       driver_unix_convert(conn,file,&st);
                        DEBUG(10,("deleting driverfile [%s]\n", s));
-                       unlink_internals(conn, NULL, 0, file, False);
+                       driver_unlink_internals(conn, file);
                }
        }
 
-       if ( *info_3->configfile ) {
-               if ( (s = strchr( &info_3->configfile[1], '\\' )) != NULL ) {
+       if (r->config_file && r->config_file[0]) {
+               if ((s = strchr(&r->config_file[1], '\\')) != NULL) {
                        file = s;
-                       driver_unix_convert(conn,file,&st);
                        DEBUG(10,("deleting configfile [%s]\n", s));
-                       unlink_internals(conn, NULL, 0, file, False);
+                       driver_unlink_internals(conn, file);
                }
        }
 
-       if ( *info_3->datafile ) {
-               if ( (s = strchr( &info_3->datafile[1], '\\' )) != NULL ) {
+       if (r->data_file && r->data_file[0]) {
+               if ((s = strchr(&r->data_file[1], '\\')) != NULL) {
                        file = s;
-                       driver_unix_convert(conn,file,&st);
                        DEBUG(10,("deleting datafile [%s]\n", s));
-                       unlink_internals(conn, NULL, 0, file, False);
+                       driver_unlink_internals(conn, file);
                }
        }
 
-       if ( *info_3->helpfile ) {
-               if ( (s = strchr( &info_3->helpfile[1], '\\' )) != NULL ) {
+       if (r->help_file && r->help_file[0]) {
+               if ((s = strchr(&r->help_file[1], '\\')) != NULL) {
                        file = s;
-                       driver_unix_convert(conn,file,&st);
                        DEBUG(10,("deleting helpfile [%s]\n", s));
-                       unlink_internals(conn, NULL, 0, file, False);
+                       driver_unlink_internals(conn, file);
                }
        }
 
        /* check if we are done removing files */
 
-       if ( info_3->dependentfiles ) {
-               while ( info_3->dependentfiles[i][0] ) {
+       if (r->dependent_files) {
+               while (r->dependent_files[i] && r->dependent_files[i][0]) {
                        char *p;
 
                        /* bypass the "\print$" portion of the path */
 
-                       if ( (p = strchr( info_3->dependentfiles[i]+1, '\\' )) != NULL ) {
+                       if ((p = strchr(r->dependent_files[i]+1, '\\')) != NULL) {
                                file = p;
-                               driver_unix_convert(conn,file,&st);
                                DEBUG(10,("deleting dependent file [%s]\n", file));
-                               unlink_internals(conn, NULL, 0, file, False);
+                               driver_unlink_internals(conn, file);
                        }
 
                        i++;
@@ -5305,7 +5139,7 @@ static bool delete_driver_files(struct pipes_struct *rpc_pipe,
  done:
        if (conn != NULL) {
                vfs_ChDir(conn, oldcwd);
-               conn_free_internal(conn);
+               conn_free(conn);
        }
        return ret;
 }
@@ -5316,31 +5150,27 @@ static bool delete_driver_files(struct pipes_struct *rpc_pipe,
  ***************************************************************************/
 
 WERROR delete_printer_driver(struct pipes_struct *rpc_pipe,
-                            NT_PRINTER_DRIVER_INFO_LEVEL_3 *info_3,
+                            const struct spoolss_DriverInfo8 *r,
                             uint32 version, bool delete_files )
 {
        char *key = NULL;
        const char     *arch;
        TDB_DATA        dbuf;
-       NT_PRINTER_DRIVER_INFO_LEVEL    ctr;
 
        /* delete the tdb data first */
 
-       arch = get_short_archi(info_3->environment);
+       arch = get_short_archi(r->architecture);
        if (!arch) {
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
        if (asprintf(&key, "%s%s/%d/%s", DRIVERS_PREFIX,
-                       arch, version, info_3->name) < 0) {
+                       arch, version, r->driver_name) < 0) {
                return WERR_NOMEM;
        }
 
        DEBUG(5,("delete_printer_driver: key = [%s] delete_files = %s\n",
                key, delete_files ? "TRUE" : "FALSE" ));
 
-       ctr.info_3 = info_3;
-       dump_a_printer_driver( ctr, 3 );
-
        /* check if the driver actually exists for this environment */
 
        dbuf = tdb_fetch_bystring( tdb_drivers, key );
@@ -5367,7 +5197,7 @@ WERROR delete_printer_driver(struct pipes_struct *rpc_pipe,
         */
 
        if ( delete_files )
-               delete_driver_files(rpc_pipe, info_3);
+               delete_driver_files(rpc_pipe, r);
 
        DEBUG(5,("delete_printer_driver: driver delete successful [%s]\n", key));
        SAFE_FREE(key);
@@ -5379,10 +5209,10 @@ WERROR delete_printer_driver(struct pipes_struct *rpc_pipe,
  Store a security desc for a printer.
 ****************************************************************************/
 
-WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
+WERROR nt_printing_setsec(const char *sharename, struct sec_desc_buf *secdesc_ctr)
 {
-       SEC_DESC_BUF *new_secdesc_ctr = NULL;
-       SEC_DESC_BUF *old_secdesc_ctr = NULL;
+       struct sec_desc_buf *new_secdesc_ctr = NULL;
+       struct sec_desc_buf *old_secdesc_ctr = NULL;
        TALLOC_CTX *mem_ctx = NULL;
        TDB_DATA kbuf;
        TDB_DATA dbuf;
@@ -5400,9 +5230,9 @@ WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
           descriptor then copy them over from the old one. */
 
        if (!secdesc_ctr->sd->owner_sid || !secdesc_ctr->sd->group_sid) {
-               DOM_SID *owner_sid, *group_sid;
-               SEC_ACL *dacl, *sacl;
-               SEC_DESC *psd = NULL;
+               struct dom_sid *owner_sid, *group_sid;
+               struct security_acl *dacl, *sacl;
+               struct security_descriptor *psd = NULL;
                size_t size;
 
                if (!nt_printing_getsec(mem_ctx, sharename, &old_secdesc_ctr)) {
@@ -5483,15 +5313,15 @@ WERROR nt_printing_setsec(const char *sharename, SEC_DESC_BUF *secdesc_ctr)
  Construct a default security descriptor buffer for a printer.
 ****************************************************************************/
 
-static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
+static struct sec_desc_buf *construct_default_printer_sdb(TALLOC_CTX *ctx)
 {
-       SEC_ACE ace[5]; /* max number of ace entries */
+       struct security_ace ace[5];     /* max number of ace entries */
        int i = 0;
        uint32_t sa;
-       SEC_ACL *psa = NULL;
-       SEC_DESC_BUF *sdb = NULL;
-       SEC_DESC *psd = NULL;
-       DOM_SID adm_sid;
+       struct security_acl *psa = NULL;
+       struct sec_desc_buf *sdb = NULL;
+       struct security_descriptor *psd = NULL;
+       struct dom_sid adm_sid;
        size_t sd_size;
 
        /* Create an ACE where Everyone is allowed to print */
@@ -5503,10 +5333,10 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
        /* Add the domain admins group if we are a DC */
 
        if ( IS_DC ) {
-               DOM_SID domadmins_sid;
+               struct dom_sid domadmins_sid;
 
-               sid_copy(&domadmins_sid, get_global_sam_sid());
-               sid_append_rid(&domadmins_sid, DOMAIN_GROUP_RID_ADMINS);
+               sid_compose(&domadmins_sid, get_global_sam_sid(),
+                           DOMAIN_RID_ADMINS);
 
                sa = PRINTER_ACE_FULL_CONTROL;
                init_sec_ace(&ace[i++], &domadmins_sid,
@@ -5516,7 +5346,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
                        sa, SEC_ACE_FLAG_CONTAINER_INHERIT);
        }
        else if (secrets_fetch_domain_sid(lp_workgroup(), &adm_sid)) {
-               sid_append_rid(&adm_sid, DOMAIN_USER_RID_ADMIN);
+               sid_append_rid(&adm_sid, DOMAIN_RID_ADMINISTRATOR);
 
                sa = PRINTER_ACE_FULL_CONTROL;
                init_sec_ace(&ace[i++], &adm_sid,
@@ -5544,7 +5374,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
           NT5 machine. */
 
        if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) != NULL) {
-               psd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
+               psd = make_sec_desc(ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
                        &global_sid_Builtin_Administrators,
                        &global_sid_Builtin_Administrators,
                        NULL, psa, &sd_size);
@@ -5567,7 +5397,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
  Get a security desc for a printer.
 ****************************************************************************/
 
-bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **secdesc_ctr)
+bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, struct sec_desc_buf **secdesc_ctr)
 {
        TDB_DATA kbuf;
        TDB_DATA dbuf;
@@ -5614,18 +5444,18 @@ bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **s
           down.  Take ownership of security descriptor. */
 
        if (sid_equal((*secdesc_ctr)->sd->owner_sid, &global_sid_World)) {
-               DOM_SID owner_sid;
+               struct dom_sid owner_sid;
 
                /* Change sd owner to workgroup administrator */
 
                if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
-                       SEC_DESC_BUF *new_secdesc_ctr = NULL;
-                       SEC_DESC *psd = NULL;
+                       struct sec_desc_buf *new_secdesc_ctr = NULL;
+                       struct security_descriptor *psd = NULL;
                        size_t size;
 
                        /* Create new sd */
 
-                       sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
+                       sid_append_rid(&owner_sid, DOMAIN_RID_ADMINISTRATOR);
 
                        psd = make_sec_desc(ctx, (*secdesc_ctr)->sd->revision, (*secdesc_ctr)->sd->type,
                                            &owner_sid,
@@ -5654,7 +5484,7 @@ bool nt_printing_getsec(TALLOC_CTX *ctx, const char *sharename, SEC_DESC_BUF **s
        }
 
        if (DEBUGLEVEL >= 10) {
-               SEC_ACL *the_acl = (*secdesc_ctr)->sd->dacl;
+               struct security_acl *the_acl = (*secdesc_ctr)->sd->dacl;
                int i;
 
                DEBUG(10, ("secdesc_ctr for %s has %d aces:\n",
@@ -5711,7 +5541,7 @@ jfm: I should use this comment for the text file to explain
    It turns out that NT4 security descriptors use generic access rights and
    NT5 the object specific ones. */
 
-void map_printer_permissions(SEC_DESC *sd)
+void map_printer_permissions(struct security_descriptor *sd)
 {
        int i;
 
@@ -5721,7 +5551,7 @@ void map_printer_permissions(SEC_DESC *sd)
        }
 }
 
-void map_job_permissions(SEC_DESC *sd)
+void map_job_permissions(struct security_descriptor *sd)
 {
        int i;
 
@@ -5750,7 +5580,7 @@ void map_job_permissions(SEC_DESC *sd)
        print_queue_purge
 
   Try access control in the following order (for performance reasons):
-    1)  root ans SE_PRINT_OPERATOR can do anything (easy check)
+    1)  root and SE_PRINT_OPERATOR can do anything (easy check)
     2)  check security descriptor (bit comparisons in memory)
     3)  "printer admins" (may result in numerous calls to winbind)
 
@@ -5758,7 +5588,7 @@ void map_job_permissions(SEC_DESC *sd)
 bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
                        int access_type)
 {
-       SEC_DESC_BUF *secdesc = NULL;
+       struct sec_desc_buf *secdesc = NULL;
        uint32 access_granted;
        NTSTATUS status;
        const char *pname;
@@ -5769,7 +5599,7 @@ bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
 
        /* Always allow root or SE_PRINT_OPERATROR to do anything */
 
-       if (server_info->utok.uid == 0
+       if (server_info->utok.uid == sec_initial_uid()
            || user_has_privileges(server_info->ptok, &se_printop ) ) {
                return True;
        }
@@ -5797,7 +5627,7 @@ bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
        }
 
        if (access_type == JOB_ACCESS_ADMINISTER) {
-               SEC_DESC_BUF *parent_secdesc = secdesc;
+               struct sec_desc_buf *parent_secdesc = secdesc;
 
                /* Create a child security descriptor to check permissions
                   against.  This is because print jobs are child objects
@@ -5824,7 +5654,7 @@ bool print_access_check(struct auth_serversupplied_info *server_info, int snum,
 
         /* see if we need to try the printer admin list */
 
-        if ((access_granted == 0) &&
+        if (!NT_STATUS_IS_OK(status) &&
            (token_contains_name_in_list(uidtoname(server_info->utok.uid),
                                         NULL, NULL, server_info->ptok,
                                         lp_printer_admin(snum)))) {