s3-spoolss: re-arrange driver info level fillup functions.
[ira/wip.git] / source3 / rpc_server / srv_spoolss_nt.c
index 01438fc7d6038594cd721ffee66143c3bb0f7ee4..bcc6f5fa1290eece40fd2ced86f6127d94ea2119 100644 (file)
@@ -53,12 +53,6 @@ extern userdom_struct current_user_info;
 #define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
 #define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
 
-struct table_node {
-       const char    *long_archi;
-       const char    *short_archi;
-       int     version;
-};
-
 static Printer_entry *printers_list;
 
 typedef struct _counter_printer_0 {
@@ -267,7 +261,7 @@ static bool close_printer_handle(pipes_struct *p, struct policy_handle *hnd)
  Delete a printer given a handle.
 ****************************************************************************/
 
-WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename )
+static WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sharename)
 {
        char *cmd = lp_deleteprinter_cmd();
        char *command = NULL;
@@ -315,7 +309,9 @@ WERROR delete_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *sh
                return WERR_BADFID; /* What to return here? */
 
        /* go ahead and re-read the services immediately */
+       become_root();
        reload_services(false);
+       unbecome_root();
 
        if ( lp_servicenumber( sharename )  < 0 )
                return WERR_ACCESS_DENIED;
@@ -445,7 +441,7 @@ static bool set_printer_hnd_name(Printer_entry *Printer, const char *handlename)
                        aprinter++;
                }
        } else {
-               servername = "";
+               servername = global_myname();
        }
 
        /* save the servername to fill in replies on this handle */
@@ -591,7 +587,8 @@ static bool open_printer_hnd(pipes_struct *p, struct policy_handle *hnd,
 
        new_printer->access_granted = access_granted;
 
-       DEBUG(5, ("%d printer handles active\n", (int)p->pipe_handles->count ));
+       DEBUG(5, ("%d printer handles active\n",
+                 (int)num_pipe_handles(p->pipe_handles)));
 
        return true;
 }
@@ -1638,7 +1635,7 @@ WERROR _spoolss_OpenPrinterEx(pipes_struct *p,
                        /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
                           and not a printer admin, then fail */
 
-                       if ((p->server_info->utok.uid != 0) &&
+                       if ((p->server_info->utok.uid != sec_initial_uid()) &&
                            !user_has_privileges(p->server_info->ptok,
                                                 &se_printop ) &&
                            !token_contains_name_in_list(
@@ -1829,202 +1826,6 @@ static bool convert_printer_info(struct spoolss_SetPrinterInfoCtr *info_ctr,
        return false;
 }
 
-/*******************************************************************
-********************************************************************/
-
-static bool string_array_to_fstring_array(const char **sarray, fstring **farray)
-{
-       int i;
-
-       if (!sarray) {
-               *farray = NULL;
-               return true;
-       }
-
-       *farray = SMB_MALLOC_ARRAY(fstring, 1);
-       if (!*farray) {
-               return false;
-       }
-
-       for (i=0; sarray[i] != NULL; i++) {
-               *farray = SMB_REALLOC_ARRAY(*farray, fstring, i+2);
-               if (!*farray) {
-                       return false;
-               }
-               fstrcpy((*farray)[i], sarray[i]);
-       }
-
-       fstrcpy((*farray)[i], "");
-
-       return true;
-}
-
-/*******************************************************************
-********************************************************************/
-
-static bool driver_info3_to_nt_driver_info3(struct spoolss_AddDriverInfo3 *r,
-                                           NT_PRINTER_DRIVER_INFO_LEVEL_3 **p)
-{
-       NT_PRINTER_DRIVER_INFO_LEVEL_3 *d;
-
-       DEBUG(7,("driver_info3_to_nt_driver_info3: Converting from UNICODE to ASCII\n"));
-
-       if (*p == NULL) {
-               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_3);
-               if (*p == NULL) {
-                       return false;
-               }
-               ZERO_STRUCTP(*p);
-       }
-
-       d = *p;
-
-       d->cversion =                   r->version;
-
-       fstrcpy(d->name,                r->driver_name);
-       fstrcpy(d->environment,         r->architecture);
-       fstrcpy(d->driverpath,          r->driver_path);
-       fstrcpy(d->datafile,            r->data_file);
-       fstrcpy(d->configfile,          r->config_file);
-       fstrcpy(d->helpfile,            r->help_file);
-       fstrcpy(d->monitorname,         r->monitor_name);
-       fstrcpy(d->defaultdatatype,     r->default_datatype);
-
-       DEBUGADD(8,( "version:         %d\n", d->cversion));
-       DEBUGADD(8,( "name:            %s\n", d->name));
-       DEBUGADD(8,( "environment:     %s\n", d->environment));
-       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
-       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
-       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
-       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
-       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
-       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
-
-       if (r->dependent_files) {
-               if (!string_array_to_fstring_array(r->dependent_files->string,
-                                                  &d->dependentfiles)) {
-                       SAFE_FREE(*p);
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-/*******************************************************************
-********************************************************************/
-
-static bool driver_info6_to_nt_driver_info6(struct spoolss_AddDriverInfo6 *r,
-                                           NT_PRINTER_DRIVER_INFO_LEVEL_6 **p)
-{
-       NT_PRINTER_DRIVER_INFO_LEVEL_6 *d;
-
-       DEBUG(7,("driver_info6_to_nt_driver_info6: Converting from UNICODE to ASCII\n"));
-
-       if (*p == NULL) {
-               *p = SMB_MALLOC_P(NT_PRINTER_DRIVER_INFO_LEVEL_6);
-               if (*p == NULL) {
-                       return false;
-               }
-               ZERO_STRUCTP(*p);
-       }
-
-       d = *p;
-
-       d->version =                    r->version;
-
-       fstrcpy(d->name,                r->driver_name);
-       fstrcpy(d->environment,         r->architecture);
-       fstrcpy(d->driverpath,          r->driver_path);
-       fstrcpy(d->datafile,            r->data_file);
-       fstrcpy(d->configfile,          r->config_file);
-       fstrcpy(d->helpfile,            r->help_file);
-       fstrcpy(d->monitorname,         r->monitor_name);
-       fstrcpy(d->defaultdatatype,     r->default_datatype);
-
-       DEBUGADD(8,( "version:         %d\n", d->version));
-       DEBUGADD(8,( "name:            %s\n", d->name));
-       DEBUGADD(8,( "environment:     %s\n", d->environment));
-       DEBUGADD(8,( "driverpath:      %s\n", d->driverpath));
-       DEBUGADD(8,( "datafile:        %s\n", d->datafile));
-       DEBUGADD(8,( "configfile:      %s\n", d->configfile));
-       DEBUGADD(8,( "helpfile:        %s\n", d->helpfile));
-       DEBUGADD(8,( "monitorname:     %s\n", d->monitorname));
-       DEBUGADD(8,( "defaultdatatype: %s\n", d->defaultdatatype));
-
-       if (r->dependent_files) {
-               if (!string_array_to_fstring_array(r->dependent_files->string,
-                                                  &d->dependentfiles)) {
-                       goto error;
-               }
-       }
-
-       if (r->previous_names) {
-               if (!string_array_to_fstring_array(r->previous_names->string,
-                                                  &d->previousnames)) {
-                       goto error;
-               }
-       }
-
-       return true;
-
- error:
-       SAFE_FREE(*p);
-       return false;
-}
-
-/********************************************************************
- ********************************************************************/
-
-static bool convert_printer_driver_info(const struct spoolss_AddDriverInfoCtr *r,
-                                       NT_PRINTER_DRIVER_INFO_LEVEL *printer,
-                                       uint32_t level)
-{
-       switch (level) {
-       case 3:
-               printer->info_3 = NULL;
-               if (!driver_info3_to_nt_driver_info3(r->info.info3, &printer->info_3)) {
-                       return false;
-               }
-               break;
-       case 6:
-               printer->info_6 = NULL;
-               if (!driver_info6_to_nt_driver_info6(r->info.info6, &printer->info_6)) {
-                       return false;
-               }
-               break;
-       default:
-               return false;
-       }
-
-       return true;
-}
-
-/********************************************************************
- * _spoolss_enddocprinter_internal.
- ********************************************************************/
-
-static WERROR _spoolss_enddocprinter_internal(pipes_struct *p,
-                                             struct policy_handle *handle)
-{
-       Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
-       int snum;
-
-       if (!Printer) {
-               DEBUG(2,("_spoolss_enddocprinter_internal: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
-               return WERR_BADFID;
-       }
-
-       if (!get_printer_snum(p, handle, &snum, NULL))
-               return WERR_BADFID;
-
-       Printer->document_started = false;
-       print_job_end(snum, Printer->jobid,NORMAL_CLOSE);
-       /* error codes unhandled so far ... */
-
-       return WERR_OK;
-}
-
 /****************************************************************
  _spoolss_ClosePrinter
 ****************************************************************/
@@ -2034,8 +1835,13 @@ WERROR _spoolss_ClosePrinter(pipes_struct *p,
 {
        Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
 
-       if (Printer && Printer->document_started)
-               _spoolss_enddocprinter_internal(p, r->in.handle);          /* print job was not closed */
+       if (Printer && Printer->document_started) {
+               struct spoolss_EndDocPrinter e;
+
+               e.in.handle = r->in.handle;
+
+               _spoolss_EndDocPrinter(p, &e);
+       }
 
        if (!close_printer_handle(p, r->in.handle))
                return WERR_BADFID;
@@ -2060,8 +1866,13 @@ WERROR _spoolss_DeletePrinter(pipes_struct *p,
        Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
        WERROR result;
 
-       if (Printer && Printer->document_started)
-               _spoolss_enddocprinter_internal(p, r->in.handle);  /* print job was not closed */
+       if (Printer && Printer->document_started) {
+               struct spoolss_EndDocPrinter e;
+
+               e.in.handle = r->in.handle;
+
+               _spoolss_EndDocPrinter(p, &e);
+       }
 
        result = delete_printer_handle(p, r->in.handle);
 
@@ -2075,20 +1886,21 @@ WERROR _spoolss_DeletePrinter(pipes_struct *p,
  * long architecture string
  ******************************************************************/
 
+static const struct print_architecture_table_node archi_table[]= {
+
+       {"Windows 4.0",          SPL_ARCH_WIN40,        0 },
+       {"Windows NT x86",       SPL_ARCH_W32X86,       2 },
+       {"Windows NT R4000",     SPL_ARCH_W32MIPS,      2 },
+       {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA,     2 },
+       {"Windows NT PowerPC",   SPL_ARCH_W32PPC,       2 },
+       {"Windows IA64",         SPL_ARCH_IA64,         3 },
+       {"Windows x64",          SPL_ARCH_X64,          3 },
+       {NULL,                   "",            -1 }
+};
+
 static int get_version_id(const char *arch)
 {
        int i;
-       struct table_node archi_table[]= {
-
-               {"Windows 4.0",          "WIN40",       0 },
-               {"Windows NT x86",       "W32X86",      2 },
-               {"Windows NT R4000",     "W32MIPS",     2 },
-               {"Windows NT Alpha_AXP", "W32ALPHA",    2 },
-               {"Windows NT PowerPC",   "W32PPC",      2 },
-               {"Windows IA64",         "IA64",        3 },
-               {"Windows x64",          "x64",         3 },
-               {NULL,                   "",            -1 }
-       };
 
        for (i=0; archi_table[i].long_archi != NULL; i++)
        {
@@ -2106,8 +1918,9 @@ static int get_version_id(const char *arch)
 WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                                    struct spoolss_DeletePrinterDriver *r)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL    info;
-       NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
+
+       union spoolss_DriverInfo *info = NULL;
+       union spoolss_DriverInfo *info_win2k = NULL;
        int                             version;
        WERROR                          status;
        WERROR                          status_win2k = WERR_ACCESS_DENIED;
@@ -2116,7 +1929,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
        /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
           and not a printer admin, then fail */
 
-       if ( (p->server_info->utok.uid != 0)
+       if ( (p->server_info->utok.uid != sec_initial_uid())
                && !user_has_privileges(p->server_info->ptok, &se_printop )
                && !token_contains_name_in_list(
                        uidtoname(p->server_info->utok.uid), NULL,
@@ -2131,10 +1944,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
        if ((version = get_version_id(r->in.architecture)) == -1)
                return WERR_INVALID_ENVIRONMENT;
 
-       ZERO_STRUCT(info);
-       ZERO_STRUCT(info_win2k);
-
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, r->in.driver,
+       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info, 3, r->in.driver,
                                                r->in.architecture,
                                                version)))
        {
@@ -2142,7 +1952,8 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
 
                if ( version == 2 ) {
                        version = 3;
-                       if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3,
+                       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx,
+                                                               &info, 3,
                                                                r->in.driver,
                                                                r->in.architecture,
                                                                version))) {
@@ -2158,14 +1969,15 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
 
        }
 
-       if (printer_driver_in_use(info.info_3)) {
+       if (printer_driver_in_use(&info->info3)) {
                status = WERR_PRINTER_DRIVER_IN_USE;
                goto done;
        }
 
        if ( version == 2 )
        {
-               if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3,
+               if (W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx,
+                                                      &info_win2k, 3,
                                                       r->in.driver,
                                                       r->in.architecture, 3)))
                {
@@ -2173,8 +1985,8 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                        /* remove the Win2k driver first*/
 
                        status_win2k = delete_printer_driver(
-                               p, info_win2k.info_3, 3, false);
-                       free_a_printer_driver( info_win2k, 3 );
+                               p, &info_win2k->info3, 3, false);
+                       free_a_printer_driver(info_win2k);
 
                        /* this should not have failed---if it did, report to client */
                        if ( !W_ERROR_IS_OK(status_win2k) )
@@ -2185,7 +1997,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                }
        }
 
-       status = delete_printer_driver(p, info.info_3, version, false);
+       status = delete_printer_driver(p, &info->info3, version, false);
 
        /* if at least one of the deletes succeeded return OK */
 
@@ -2193,7 +2005,7 @@ WERROR _spoolss_DeletePrinterDriver(pipes_struct *p,
                status = WERR_OK;
 
 done:
-       free_a_printer_driver( info, 3 );
+       free_a_printer_driver(info);
 
        return status;
 }
@@ -2205,8 +2017,8 @@ done:
 WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                                      struct spoolss_DeletePrinterDriverEx *r)
 {
-       NT_PRINTER_DRIVER_INFO_LEVEL    info;
-       NT_PRINTER_DRIVER_INFO_LEVEL    info_win2k;
+       union spoolss_DriverInfo        *info = NULL;
+       union spoolss_DriverInfo        *info_win2k = NULL;
        int                             version;
        bool                            delete_files;
        WERROR                          status;
@@ -2216,7 +2028,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
        /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
           and not a printer admin, then fail */
 
-       if ( (p->server_info->utok.uid != 0)
+       if ( (p->server_info->utok.uid != sec_initial_uid())
                && !user_has_privileges(p->server_info->ptok, &se_printop )
                && !token_contains_name_in_list(
                        uidtoname(p->server_info->utok.uid), NULL, NULL,
@@ -2234,10 +2046,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
        if (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION)
                version = r->in.version;
 
-       ZERO_STRUCT(info);
-       ZERO_STRUCT(info_win2k);
-
-       status = get_a_printer_driver(&info, 3, r->in.driver,
+       status = get_a_printer_driver(p->mem_ctx, &info, 3, r->in.driver,
                                      r->in.architecture, version);
 
        if ( !W_ERROR_IS_OK(status) )
@@ -2254,7 +2063,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                /* try for Win2k driver if "Windows NT x86" */
 
                version = 3;
-               if (!W_ERROR_IS_OK(get_a_printer_driver(&info, 3, r->in.driver,
+               if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info, 3, r->in.driver,
                                                        r->in.architecture,
                                                        version))) {
                        status = WERR_UNKNOWN_PRINTER_DRIVER;
@@ -2262,7 +2071,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                }
        }
 
-       if ( printer_driver_in_use(info.info_3) ) {
+       if ( printer_driver_in_use(&info->info3) ) {
                status = WERR_PRINTER_DRIVER_IN_USE;
                goto done;
        }
@@ -2283,7 +2092,7 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
 
        /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */
 
-       if ( delete_files && printer_driver_files_in_use(info.info_3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
+       if ( delete_files && printer_driver_files_in_use(info, &info->info3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
                /* no idea of the correct error here */
                status = WERR_ACCESS_DENIED;
                goto done;
@@ -2293,14 +2102,14 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
        /* also check for W32X86/3 if necessary; maybe we already have? */
 
        if ( (version == 2) && ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION)  ) {
-               if (W_ERROR_IS_OK(get_a_printer_driver(&info_win2k, 3,
+               if (W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &info_win2k, 3,
                                                       r->in.driver,
                                                       r->in.architecture, 3)))
                {
 
-                       if ( delete_files && printer_driver_files_in_use(info_win2k.info_3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
+                       if ( delete_files && printer_driver_files_in_use(info, &info_win2k->info3) & (r->in.delete_flags & DPD_DELETE_ALL_FILES) ) {
                                /* no idea of the correct error here */
-                               free_a_printer_driver( info_win2k, 3 );
+                               free_a_printer_driver(info_win2k);
                                status = WERR_ACCESS_DENIED;
                                goto done;
                        }
@@ -2309,8 +2118,8 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                        /* remove the Win2k driver first*/
 
                        status_win2k = delete_printer_driver(
-                               p, info_win2k.info_3, 3, delete_files);
-                       free_a_printer_driver( info_win2k, 3 );
+                               p, &info_win2k->info3, 3, delete_files);
+                       free_a_printer_driver(info_win2k);
 
                        /* this should not have failed---if it did, report to client */
 
@@ -2319,12 +2128,12 @@ WERROR _spoolss_DeletePrinterDriverEx(pipes_struct *p,
                }
        }
 
-       status = delete_printer_driver(p, info.info_3, version, delete_files);
+       status = delete_printer_driver(p, &info->info3, version, delete_files);
 
        if ( W_ERROR_IS_OK(status) || W_ERROR_IS_OK(status_win2k) )
                status = WERR_OK;
 done:
-       free_a_printer_driver( info, 3 );
+       free_a_printer_driver(info);
 
        return status;
 }
@@ -2546,7 +2355,7 @@ WERROR _spoolss_GetPrinterData(pipes_struct *p,
                        r->out.data->value = printer->info_2->changeid;
                        result = WERR_OK;
                } else {
-                       REGISTRY_VALUE *v;
+                       struct regval_blob *v;
                        DATA_BLOB blob;
 
                        v = get_printer_data(printer->info_2,
@@ -2597,7 +2406,7 @@ static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe,
        struct sockaddr_storage rm_addr;
 
        if ( is_zero_addr((struct sockaddr *)client_ss) ) {
-               if ( !resolve_name( remote_machine, &rm_addr, 0x20) ) {
+               if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) {
                        DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine));
                        return false;
                }
@@ -4084,6 +3893,39 @@ static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/********************************************************************
+ * construct_printer_info8
+ * fill a spoolss_PrinterInfo8 struct
+ ********************************************************************/
+
+static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_DeviceModeInfo *r,
+                                     int snum)
+{
+       struct spoolss_DeviceMode *devmode;
+       WERROR result;
+
+       if (!ntprinter->info_2->devmode) {
+               r->devmode = NULL;
+               return WERR_OK;
+       }
+
+       devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
+       W_ERROR_HAVE_NO_MEMORY(devmode);
+
+       result = convert_nt_devicemode(mem_ctx, devmode, ntprinter->info_2->devmode);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(devmode);
+               return result;
+       }
+
+       r->devmode      = devmode;
+
+       return WERR_OK;
+}
+
+
 /********************************************************************
  * construct_printer_info1
  * fill a spoolss_PrinterInfo1 struct
@@ -4095,25 +3937,21 @@ static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
                                      struct spoolss_PrinterInfo1 *r,
                                      int snum)
 {
-       char *chaine = NULL;
        r->flags                = flags;
 
+       r->description          = talloc_asprintf(mem_ctx, "%s,%s,%s",
+                                                 ntprinter->info_2->printername,
+                                                 ntprinter->info_2->drivername,
+                                                 ntprinter->info_2->location);
+       W_ERROR_HAVE_NO_MEMORY(r->description);
+
        if (*ntprinter->info_2->comment == '\0') {
                r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
-               chaine = talloc_asprintf(mem_ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, lp_comment(snum));
        } else {
                r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment); /* saved comment */
-               chaine = talloc_asprintf(mem_ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, ntprinter->info_2->comment);
        }
-       W_ERROR_HAVE_NO_MEMORY(chaine);
        W_ERROR_HAVE_NO_MEMORY(r->comment);
 
-       r->description          = talloc_strdup(mem_ctx, chaine);
-       W_ERROR_HAVE_NO_MEMORY(r->description);
        r->name                 = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
        W_ERROR_HAVE_NO_MEMORY(r->name);
 
@@ -4204,61 +4042,88 @@ static bool snum_is_shared_printer(int snum)
  Spoolss_enumprinters.
 ********************************************************************/
 
-static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
-                                      uint32_t flags,
-                                      union spoolss_PrinterInfo **info_p,
-                                      uint32_t *count)
+static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx,
+                                          uint32_t level,
+                                          uint32_t flags,
+                                          union spoolss_PrinterInfo **info_p,
+                                          uint32_t *count_p)
 {
        int snum;
        int n_services = lp_numservices();
        union spoolss_PrinterInfo *info = NULL;
+       uint32_t count = 0;
        WERROR result = WERR_OK;
 
-       DEBUG(4,("enum_all_printers_info_1\n"));
-
-       *count = 0;
+       *count_p = 0;
+       *info_p = NULL;
 
-       for (snum=0; snum<n_services; snum++) {
+       for (snum = 0; snum < n_services; snum++) {
 
                NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-               struct spoolss_PrinterInfo1 info1;
 
                if (!snum_is_shared_printer(snum)) {
                        continue;
                }
 
-               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
+               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n",
+                       lp_servicename(snum), snum));
 
-               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
-               if (!W_ERROR_IS_OK(result)) {
-                       continue;
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           union spoolss_PrinterInfo,
+                                           count + 1);
+               if (!info) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               result = construct_printer_info1(info, ntprinter, flags, &info1, snum);
-               free_a_printer(&ntprinter,2);
+               result = get_a_printer(NULL, &ntprinter, 2,
+                                      lp_const_servicename(snum));
                if (!W_ERROR_IS_OK(result)) {
-                       continue;
+                       goto out;
                }
 
-               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
-                                           union spoolss_PrinterInfo,
-                                           *count + 1);
-               if (!info) {
-                       DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
-                       result = WERR_NOMEM;
+               switch (level) {
+               case 0:
+                       result = construct_printer_info0(info, ntprinter,
+                                                        &info[count].info0, snum);
+                       break;
+               case 1:
+                       result = construct_printer_info1(info, ntprinter, flags,
+                                                        &info[count].info1, snum);
+                       break;
+               case 2:
+                       result = construct_printer_info2(info, ntprinter,
+                                                        &info[count].info2, snum);
+                       break;
+               case 4:
+                       result = construct_printer_info4(info, ntprinter,
+                                                        &info[count].info4, snum);
+                       break;
+               case 5:
+                       result = construct_printer_info5(info, ntprinter,
+                                                        &info[count].info5, snum);
+                       break;
+
+               default:
+                       result = WERR_UNKNOWN_LEVEL;
+                       free_a_printer(&ntprinter, 2);
                        goto out;
                }
 
-               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *count));
+               free_a_printer(&ntprinter, 2);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
 
-               info[*count].info1 = info1;
-               (*count)++;
+               count++;
        }
 
+       *count_p = count;
+       *info_p = info;
+
  out:
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(info);
-               *count = 0;
                return result;
        }
 
@@ -4267,6 +4132,35 @@ static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/********************************************************************
+ * handle enumeration of printers at level 0
+ ********************************************************************/
+
+static WERROR enumprinters_level0(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
+{
+       DEBUG(4,("enum_all_printers_info_0\n"));
+
+       return enum_all_printers_info_level(mem_ctx, 0, flags, info, count);
+}
+
+
+/********************************************************************
+********************************************************************/
+
+static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
+                                      uint32_t flags,
+                                      union spoolss_PrinterInfo **info,
+                                      uint32_t *count)
+{
+       DEBUG(4,("enum_all_printers_info_1\n"));
+
+       return enum_all_printers_info_level(mem_ctx, 1, flags, info, count);
+}
+
 /********************************************************************
  enum_all_printers_info_1_local.
 *********************************************************************/
@@ -4343,64 +4237,12 @@ static WERROR enum_all_printers_info_1_network(TALLOC_CTX *mem_ctx,
  ********************************************************************/
 
 static WERROR enum_all_printers_info_2(TALLOC_CTX *mem_ctx,
-                                      union spoolss_PrinterInfo **info_p,
+                                      union spoolss_PrinterInfo **info,
                                       uint32_t *count)
 {
-       int snum;
-       int n_services = lp_numservices();
-       union spoolss_PrinterInfo *info = NULL;
-       WERROR result = WERR_OK;
-
-       *count = 0;
-
-       for (snum=0; snum<n_services; snum++) {
-
-               struct spoolss_PrinterInfo2 info2;
-               NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-
-               if (!snum_is_shared_printer(snum)) {
-                       continue;
-               }
-
-               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
-
-               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
-               if (!W_ERROR_IS_OK(result)) {
-                       continue;
-               }
-
-               result = construct_printer_info2(info, ntprinter, &info2, snum);
-               free_a_printer(&ntprinter, 2);
-               if (!W_ERROR_IS_OK(result)) {
-                       continue;
-               }
-
-               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
-                                           union spoolss_PrinterInfo,
-                                           *count + 1);
-               if (!info) {
-                       DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
-                       result = WERR_NOMEM;
-                       goto out;
-               }
+       DEBUG(4,("enum_all_printers_info_2\n"));
 
-               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *count + 1));
-
-               info[*count].info2 = info2;
-
-               (*count)++;
-       }
-
- out:
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
-       }
-
-       *info_p = info;
-
-       return WERR_OK;
+       return enum_all_printers_info_level(mem_ctx, 2, 0, info, count);
 }
 
 /********************************************************************
@@ -4459,6 +4301,22 @@ static WERROR enumprinters_level2(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/********************************************************************
+ * handle enumeration of printers at level 4
+ ********************************************************************/
+
+static WERROR enumprinters_level4(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
+{
+       DEBUG(4,("enum_all_printers_info_4\n"));
+
+       return enum_all_printers_info_level(mem_ctx, 4, flags, info, count);
+}
+
+
 /********************************************************************
  * handle enumeration of printers at level 5
  ********************************************************************/
@@ -4469,8 +4327,9 @@ static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx,
                                  union spoolss_PrinterInfo **info,
                                  uint32_t *count)
 {
-/*     return enum_all_printers_info_5(mem_ctx, info, offered, needed, count);*/
-       return WERR_OK;
+       DEBUG(4,("enum_all_printers_info_5\n"));
+
+       return enum_all_printers_info_level(mem_ctx, 5, flags, info, count);
 }
 
 /****************************************************************
@@ -4512,6 +4371,10 @@ WERROR _spoolss_EnumPrinters(pipes_struct *p,
        W_ERROR_HAVE_NO_MEMORY(name);
 
        switch (r->in.level) {
+       case 0:
+               result = enumprinters_level0(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 1:
                result = enumprinters_level1(p->mem_ctx, r->in.flags, name,
                                             r->out.info, r->out.count);
@@ -4520,13 +4383,13 @@ WERROR _spoolss_EnumPrinters(pipes_struct *p,
                result = enumprinters_level2(p->mem_ctx, r->in.flags, name,
                                             r->out.info, r->out.count);
                break;
-       case 5:
-               result = enumprinters_level5(p->mem_ctx, r->in.flags, name,
+       case 4:
+               result = enumprinters_level4(p->mem_ctx, r->in.flags, name,
                                             r->out.info, r->out.count);
                break;
-       case 3:
-       case 4:
-               result = WERR_OK; /* ??? */
+       case 5:
+               result = enumprinters_level5(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
                break;
        default:
                return WERR_UNKNOWN_LEVEL;
@@ -4611,6 +4474,10 @@ WERROR _spoolss_GetPrinter(pipes_struct *p,
                result = construct_printer_info7(p->mem_ctx, Printer,
                                                 &r->out.info->info7, snum);
                break;
+       case 8:
+               result = construct_printer_info8(p->mem_ctx, ntprinter,
+                                                &r->out.info->info8, snum);
+               break;
        default:
                result = WERR_UNKNOWN_LEVEL;
                break;
@@ -4634,16 +4501,20 @@ WERROR _spoolss_GetPrinter(pipes_struct *p,
  ********************************************************************/
 
 static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
-                                                 fstring *fstring_array,
+                                                 const char **string_array,
                                                  const char *cservername)
 {
        int i, num_strings = 0;
        const char **array = NULL;
 
-       for (i=0; fstring_array && fstring_array[i][0] != '\0'; i++) {
+       if (!string_array) {
+               return NULL;
+       }
+
+       for (i=0; string_array[i] && string_array[i][0] != '\0'; i++) {
 
                const char *str = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                                                 cservername, fstring_array[i]);
+                                                 cservername, string_array[i]);
                if (!str) {
                        TALLOC_FREE(array);
                        return NULL;
@@ -4670,11 +4541,11 @@ static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo1 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo3 *driver,
                                        const char *servername,
                                        const char *architecture)
 {
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
 
        return WERR_OK;
@@ -4686,38 +4557,38 @@ static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo2 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo3 *driver,
                                        const char *servername)
 
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
+       if (strlen(driver->driver_path)) {
                r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
+                               cservername, driver->driver_path);
        } else {
                r->driver_path  = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
+       if (strlen(driver->data_file)) {
                r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
+                               cservername, driver->data_file);
        } else {
                r->data_file    = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
+       if (strlen(driver->config_file)) {
                r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
+                               cservername, driver->config_file);
        } else {
                r->config_file  = talloc_strdup(mem_ctx, "");
        }
@@ -4732,118 +4603,233 @@ static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
 
 static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo3 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo3 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
+       if (strlen(driver->driver_path)) {
                r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
+                               cservername, driver->driver_path);
        } else {
                r->driver_path  = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
+       if (strlen(driver->data_file)) {
                r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
+                               cservername, driver->data_file);
        } else {
                r->data_file    = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
+       if (strlen(driver->config_file)) {
                r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
+                               cservername, driver->config_file);
        } else {
                r->config_file  = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       if (strlen(driver->info_3->helpfile)) {
+       if (strlen(driver->help_file)) {
                r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->helpfile);
+                               cservername, driver->help_file);
        } else {
                r->help_file    = talloc_strdup(mem_ctx, "");
        }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       W_ERROR_HAVE_NO_MEMORY(r->help_file);
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->monitor_name);
        W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->default_datatype);
        W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
 
        r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
+                                                          driver->dependent_files,
                                                           cservername);
        return WERR_OK;
 }
 
+/********************************************************************
+ * fill a spoolss_DriverInfo4 struct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo4 *r,
+                                       const struct spoolss_DriverInfo3 *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+
+       r->version              = driver->version;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+       if (strlen(driver->driver_path)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->driver_path);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+
+       if (strlen(driver->data_file)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->data_file);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+
+       if (strlen(driver->config_file)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->config_file);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+
+       if (strlen(driver->help_file)) {
+               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->help_file);
+       } else {
+               r->help_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->help_file);
+
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->dependent_files,
+                                                          cservername);
+
+
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->default_datatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+       r->previous_names = string_array_from_driver_info(mem_ctx,
+                                                         NULL,
+                                                         cservername);
+
+       return WERR_OK;
+}
+
+/********************************************************************
+ * fill a spoolss_DriverInfo5 struct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo5 *r,
+                                       const struct spoolss_DriverInfo3 *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+
+       r->version              = driver->version;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+       if (strlen(driver->driver_path)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->driver_path);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+
+       if (strlen(driver->data_file)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->data_file);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+
+       if (strlen(driver->config_file)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->config_file);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+
+       r->driver_attributes    = 0;
+       r->config_version       = 0;
+       r->driver_version       = 0;
+
+       return WERR_OK;
+}
 /********************************************************************
  * fill a spoolss_DriverInfo6 struct
  ********************************************************************/
 
 static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
                                        struct spoolss_DriverInfo6 *r,
-                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const struct spoolss_DriverInfo3 *driver,
                                        const char *servername)
 {
        const char *cservername = canon_servername(servername);
 
-       r->version              = driver->info_3->cversion;
+       r->version              = driver->version;
 
-       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
        W_ERROR_HAVE_NO_MEMORY(r->driver_name);
-       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
        W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (strlen(driver->info_3->driverpath)) {
+       if (strlen(driver->driver_path)) {
                r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->driverpath);
+                               cservername, driver->driver_path);
        } else {
                r->driver_path  = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       if (strlen(driver->info_3->datafile)) {
+       if (strlen(driver->data_file)) {
                r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->datafile);
+                               cservername, driver->data_file);
        } else {
                r->data_file    = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       if (strlen(driver->info_3->configfile)) {
+       if (strlen(driver->config_file)) {
                r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->configfile);
+                               cservername, driver->config_file);
        } else {
                r->config_file  = talloc_strdup(mem_ctx, "");
        }
        W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       if (strlen(driver->info_3->helpfile)) {
+       if (strlen(driver->help_file)) {
                r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
-                               cservername, driver->info_3->helpfile);
+                               cservername, driver->help_file);
        } else {
                r->help_file    = talloc_strdup(mem_ctx, "");
        }
-       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+       W_ERROR_HAVE_NO_MEMORY(r->help_file);
 
-       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->monitor_name);
        W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
-       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->default_datatype);
        W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
 
        r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
+                                                          driver->dependent_files,
                                                           cservername);
        r->previous_names = string_array_from_driver_info(mem_ctx,
                                                          NULL,
@@ -4864,6 +4850,174 @@ static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/********************************************************************
+ ********************************************************************/
+
+static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx,
+                                         struct spoolss_DriverFileInfo *r,
+                                         const char *cservername,
+                                         const char *file_name,
+                                         enum spoolss_DriverFileType file_type,
+                                         uint32_t file_version)
+{
+       r->file_name    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                                         cservername, file_name);
+       W_ERROR_HAVE_NO_MEMORY(r->file_name);
+       r->file_type    = file_type;
+       r->file_version = file_version;
+
+       return WERR_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
+                                                const struct spoolss_DriverInfo3 *driver,
+                                                const char *cservername,
+                                                struct spoolss_DriverFileInfo **info_p,
+                                                uint32_t *count_p)
+{
+       struct spoolss_DriverFileInfo *info = NULL;
+       uint32_t count = 0;
+       WERROR result;
+       uint32_t i;
+
+       *info_p = NULL;
+       *count_p = 0;
+
+       if (strlen(driver->driver_path)) {
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           struct spoolss_DriverFileInfo,
+                                           count + 1);
+               W_ERROR_HAVE_NO_MEMORY(info);
+               result = fill_spoolss_DriverFileInfo(info,
+                                                    &info[count],
+                                                    cservername,
+                                                    driver->driver_path,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_RENDERING,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->config_file)) {
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           struct spoolss_DriverFileInfo,
+                                           count + 1);
+               W_ERROR_HAVE_NO_MEMORY(info);
+               result = fill_spoolss_DriverFileInfo(info,
+                                                    &info[count],
+                                                    cservername,
+                                                    driver->config_file,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->data_file)) {
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           struct spoolss_DriverFileInfo,
+                                           count + 1);
+               W_ERROR_HAVE_NO_MEMORY(info);
+               result = fill_spoolss_DriverFileInfo(info,
+                                                    &info[count],
+                                                    cservername,
+                                                    driver->data_file,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_DATA,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->help_file)) {
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           struct spoolss_DriverFileInfo,
+                                           count + 1);
+               W_ERROR_HAVE_NO_MEMORY(info);
+               result = fill_spoolss_DriverFileInfo(info,
+                                                    &info[count],
+                                                    cservername,
+                                                    driver->help_file,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_HELP,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       for (i=0; driver->dependent_files[i] && driver->dependent_files[i][0] != '\0'; i++) {
+               info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                           struct spoolss_DriverFileInfo,
+                                           count + 1);
+               W_ERROR_HAVE_NO_MEMORY(info);
+               result = fill_spoolss_DriverFileInfo(info,
+                                                    &info[count],
+                                                    cservername,
+                                                    driver->dependent_files[i],
+                                                    SPOOLSS_DRIVER_FILE_TYPE_OTHER,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       *info_p = info;
+       *count_p = count;
+
+       return WERR_OK;
+}
+
+/********************************************************************
+ * fill a spoolss_DriverInfo101 sttruct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
+                                         struct spoolss_DriverInfo101 *r,
+                                         const struct spoolss_DriverInfo3 *driver,
+                                         const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+       WERROR result;
+
+       r->version              = driver->version;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->driver_name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->architecture);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+       result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver,
+                                                   cservername,
+                                                   &r->file_info,
+                                                   &r->file_count);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->default_datatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+       r->previous_names = string_array_from_driver_info(mem_ctx,
+                                                         NULL,
+                                                         cservername);
+       r->driver_date          = 0;
+       r->driver_version       = 0;
+
+       r->manufacturer_name    = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name);
+       r->manufacturer_url     = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url);
+       r->hardware_id          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->hardware_id);
+       r->provider             = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->provider);
+
+       return WERR_OK;
+}
+
 /********************************************************************
  * construct_printer_driver_info_1
  ********************************************************************/
@@ -4876,21 +5030,20 @@ static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
                                              uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       union spoolss_DriverInfo *driver;
        WERROR result;
 
-       ZERO_STRUCT(driver);
-
        if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
                return WERR_INVALID_PRINTER_NAME;
 
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
+       if (!W_ERROR_IS_OK(get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername, architecture, version))) {
                free_a_printer(&printer, 2);
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
+       result = fill_printer_driver_info1(mem_ctx, r, &driver->info3, servername, architecture);
 
+       free_a_printer_driver(driver);
        free_a_printer(&printer,2);
 
        return result;
@@ -4909,22 +5062,22 @@ static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
                                              uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       union spoolss_DriverInfo *driver;
        WERROR result;
 
        ZERO_STRUCT(printer);
-       ZERO_STRUCT(driver);
 
        if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
                return WERR_INVALID_PRINTER_NAME;
 
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
+       if (!W_ERROR_IS_OK(get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername, architecture, version))) {
                free_a_printer(&printer, 2);
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       result = fill_printer_driver_info2(mem_ctx, r, &driver, servername);
+       result = fill_printer_driver_info2(mem_ctx, r, &driver->info3, servername);
 
+       free_a_printer_driver(driver);
        free_a_printer(&printer,2);
 
        return result;
@@ -4943,7 +5096,7 @@ static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
                                              uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       union spoolss_DriverInfo *driver;
        WERROR status;
        ZERO_STRUCT(driver);
 
@@ -4952,7 +5105,7 @@ static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
        if (!W_ERROR_IS_OK(status))
                return WERR_INVALID_PRINTER_NAME;
 
-       status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+       status = get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername, architecture, version);
        DEBUG(8,("construct_printer_driver_info_3: status: %s\n", win_errstr(status)));
 
 #if 0  /* JERRY */
@@ -4987,8 +5140,9 @@ static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
 #endif
 
 
-       status = fill_printer_driver_info3(mem_ctx, r, &driver, servername);
+       status = fill_printer_driver_info3(mem_ctx, r, &driver->info3, servername);
 
+       free_a_printer_driver(driver);
        free_a_printer(&printer,2);
 
        return status;
@@ -5007,11 +5161,9 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
                                              uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       union spoolss_DriverInfo *driver;
        WERROR                          status;
 
-       ZERO_STRUCT(driver);
-
        status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
 
        DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
@@ -5019,7 +5171,7 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
        if (!W_ERROR_IS_OK(status))
                return WERR_INVALID_PRINTER_NAME;
 
-       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+       status = get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername, architecture, version);
 
        DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
 
@@ -5036,7 +5188,7 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
 
                /* Yes - try again with a WinNT driver. */
                version = 2;
-               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+               status = get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername, architecture, version);
                DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
                if (!W_ERROR_IS_OK(status)) {
                        free_a_printer(&printer,2);
@@ -5044,14 +5196,75 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
                }
        }
 
-       status = fill_printer_driver_info6(mem_ctx, r, &driver, servername);
+       status = fill_printer_driver_info6(mem_ctx, r, &driver->info3, servername);
 
        free_a_printer(&printer,2);
-       free_a_printer_driver(driver, 3);
+       free_a_printer_driver(driver);
 
        return status;
 }
 
+/********************************************************************
+ * construct_printer_info_101
+ * fill a printer_info_101 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
+                                               struct spoolss_DriverInfo101 *r,
+                                               int snum,
+                                               const char *servername,
+                                               const char *architecture,
+                                               uint32_t version)
+{
+       NT_PRINTER_INFO_LEVEL           *printer = NULL;
+       union spoolss_DriverInfo *driver;
+       WERROR                          result;
+
+       result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
+
+       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+               win_errstr(result)));
+
+       if (!W_ERROR_IS_OK(result)) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+       result = get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername,
+                                     architecture, version);
+
+       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+               win_errstr(result)));
+
+       if (!W_ERROR_IS_OK(result)) {
+               /*
+                * Is this a W2k client ?
+                */
+
+               if (version < 3) {
+                       free_a_printer(&printer, 2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
+
+               /* Yes - try again with a WinNT driver. */
+               version = 2;
+               result = get_a_printer_driver(mem_ctx, &driver, 3, printer->info_2->drivername,
+                                             architecture, version);
+               DEBUG(8,("construct_printer_driver_info_6: status: %s\n",
+                       win_errstr(result)));
+               if (!W_ERROR_IS_OK(result)) {
+                       free_a_printer(&printer, 2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
+       }
+
+       result = fill_printer_driver_info101(mem_ctx, r, &driver->info3, servername);
+
+       free_a_printer(&printer, 2);
+       free_a_printer_driver(driver);
+
+       return result;
+}
+
 /****************************************************************
  _spoolss_GetPrinterDriver2
 ****************************************************************/
@@ -5121,13 +5334,15 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
                                                         r->in.architecture,
                                                         r->in.client_major_version);
                break;
-       default:
-#if 0  /* JERRY */
        case 101:
-               /* apparently this call is the equivalent of
-                  EnumPrinterDataEx() for the DsDriver key */
+               result = construct_printer_driver_info_101(p->mem_ctx,
+                                                          &r->out.info->info101,
+                                                          snum,
+                                                          servername,
+                                                          r->in.architecture,
+                                                          r->in.client_major_version);
                break;
-#endif
+       default:
                result = WERR_UNKNOWN_LEVEL;
                break;
        }
@@ -5258,7 +5473,24 @@ WERROR _spoolss_StartDocPrinter(pipes_struct *p,
 WERROR _spoolss_EndDocPrinter(pipes_struct *p,
                              struct spoolss_EndDocPrinter *r)
 {
-       return _spoolss_enddocprinter_internal(p, r->in.handle);
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       int snum;
+
+       if (!Printer) {
+               DEBUG(2,("_spoolss_EndDocPrinter: Invalid handle (%s:%u:%u)\n",
+                       OUR_HANDLE(r->in.handle)));
+               return WERR_BADFID;
+       }
+
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
+               return WERR_BADFID;
+       }
+
+       Printer->document_started = false;
+       print_job_end(snum, Printer->jobid, NORMAL_CLOSE);
+       /* error codes unhandled so far ... */
+
+       return WERR_OK;
 }
 
 /****************************************************************
@@ -5323,20 +5555,14 @@ static WERROR control_printer(struct policy_handle *handle, uint32_t command,
 
        switch (command) {
        case SPOOLSS_PRINTER_CONTROL_PAUSE:
-               if (print_queue_pause(p->server_info, snum, &errcode)) {
-                       errcode = WERR_OK;
-               }
+               errcode = print_queue_pause(p->server_info, snum);
                break;
        case SPOOLSS_PRINTER_CONTROL_RESUME:
        case SPOOLSS_PRINTER_CONTROL_UNPAUSE:
-               if (print_queue_resume(p->server_info, snum, &errcode)) {
-                       errcode = WERR_OK;
-               }
+               errcode = print_queue_resume(p->server_info, snum);
                break;
        case SPOOLSS_PRINTER_CONTROL_PURGE:
-               if (print_queue_purge(p->server_info, snum, &errcode)) {
-                       errcode = WERR_OK;
-               }
+               errcode = print_queue_purge(p->server_info, snum);
                break;
        default:
                return WERR_UNKNOWN_LEVEL;
@@ -5457,7 +5683,7 @@ static WERROR update_printer_sec(struct policy_handle *handle,
                goto done;
        }
 
-       if (sec_desc_equal(new_secdesc_ctr->sd, old_secdesc_ctr->sd)) {
+       if (security_descriptor_equal(new_secdesc_ctr->sd, old_secdesc_ctr->sd)) {
                result = WERR_OK;
                goto done;
        }
@@ -5523,7 +5749,7 @@ static bool check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
 /****************************************************************************
 ****************************************************************************/
 
-WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri )
+static WERROR add_port_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, const char *portname, const char *uri)
 {
        char *cmd = lp_addport_cmd();
        char *command = NULL;
@@ -5637,7 +5863,9 @@ bool add_printer_hook(TALLOC_CTX *ctx, NT_USER_TOKEN *token, NT_PRINTER_INFO_LEV
        }
 
        /* reload our services immediately */
+       become_root();
        reload_services(false);
+       unbecome_root();
 
        numlines = 0;
        /* Get lines and convert them back to dos-codepage */
@@ -5672,7 +5900,7 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
        NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
        WERROR result;
-       UNISTR2 buffer;
+       DATA_BLOB buffer;
        fstring asc_buffer;
 
        DEBUG(8,("update_printer\n"));
@@ -5782,17 +6010,17 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
         */
 
        if (!strequal(printer->info_2->comment, old_printer->info_2->comment)) {
-               init_unistr2( &buffer, printer->info_2->comment, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->comment);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "description",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_comment(snum, printer->info_2->comment);
        }
 
        if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename)) {
-               init_unistr2( &buffer, printer->info_2->sharename, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->sharename);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shareName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_sharename(snum, printer->info_2->sharename);
        }
@@ -5806,25 +6034,25 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
                        pname = printer->info_2->printername;
 
 
-               init_unistr2( &buffer, pname, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, pname);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "printerName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_printername( snum, pname );
        }
 
        if (!strequal(printer->info_2->portname, old_printer->info_2->portname)) {
-               init_unistr2( &buffer, printer->info_2->portname, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->portname);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "portName",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_port(snum, printer->info_2->portname);
        }
 
        if (!strequal(printer->info_2->location, old_printer->info_2->location)) {
-               init_unistr2( &buffer, printer->info_2->location, UNI_STR_TERMINATE);
+               push_reg_sz(talloc_tos(), &buffer, printer->info_2->location);
                set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "location",
-                       REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+                       REG_SZ, buffer.data, buffer.length);
 
                notify_printer_location(snum, printer->info_2->location);
        }
@@ -5832,17 +6060,17 @@ static WERROR update_printer(pipes_struct *p, struct policy_handle *handle,
        /* here we need to update some more DsSpooler keys */
        /* uNCName, serverName, shortServerName */
 
-       init_unistr2( &buffer, global_myname(), UNI_STR_TERMINATE);
+       push_reg_sz(talloc_tos(), &buffer, global_myname());
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "serverName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "shortServerName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
 
        slprintf( asc_buffer, sizeof(asc_buffer)-1, "\\\\%s\\%s",
                  global_myname(), printer->info_2->sharename );
-       init_unistr2( &buffer, asc_buffer, UNI_STR_TERMINATE);
+       push_reg_sz(talloc_tos(), &buffer, asc_buffer);
        set_printer_dataex( printer, SPOOL_DSSPOOLER_KEY, "uNCName",
-               REG_SZ, (uint8_t *)buffer.buffer, buffer.uni_str_len*2 );
+               REG_SZ, buffer.data, buffer.length);
 
        /* Update printer info */
        result = mod_a_printer(printer, 2);
@@ -6314,24 +6542,27 @@ WERROR _spoolss_SetJob(pipes_struct *p,
 }
 
 /****************************************************************************
- Enumerates all printer drivers at level 1.
+ Enumerates all printer drivers by level and architecture.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
+static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx,
+                                                      const char *servername,
+                                                      const char *architecture,
+                                                      uint32_t level,
+                                                      union spoolss_DriverInfo **info_p,
+                                                      uint32_t *count_p)
 {
        int i;
        int ndrivers;
        uint32_t version;
        fstring *list = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       union spoolss_DriverInfo *driver;
        union spoolss_DriverInfo *info = NULL;
+       uint32_t count = 0;
        WERROR result = WERR_OK;
 
-       *count = 0;
+       *count_p = 0;
+       *info_p = NULL;
 
        for (version=0; version<DRIVER_MAX_VERSION; version++) {
                list = NULL;
@@ -6347,7 +6578,7 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                if (ndrivers != 0) {
                        info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
                                                    union spoolss_DriverInfo,
-                                                   *count + ndrivers);
+                                                   count + ndrivers);
                        if (!info) {
                                DEBUG(0,("enumprinterdrivers_level1: "
                                        "failed to enlarge driver info buffer!\n"));
@@ -6359,22 +6590,51 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                for (i=0; i<ndrivers; i++) {
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       result = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(mem_ctx, &driver, 3, list[i],
                                                      architecture, version);
                        if (!W_ERROR_IS_OK(result)) {
                                goto out;
                        }
-                       result = fill_printer_driver_info1(info, &info[*count+i].info1,
-                                                          &driver, servername,
-                                                          architecture);
+
+                       switch (level) {
+                       case 1:
+                               result = fill_printer_driver_info1(info, &info[count+i].info1,
+                                                                  &driver->info3, servername,
+                                                                  architecture);
+                               break;
+                       case 2:
+                               result = fill_printer_driver_info2(info, &info[count+i].info2,
+                                                                  &driver->info3, servername);
+                               break;
+                       case 3:
+                               result = fill_printer_driver_info3(info, &info[count+i].info3,
+                                                                  &driver->info3, servername);
+                               break;
+                       case 4:
+                               result = fill_printer_driver_info4(info, &info[count+i].info4,
+                                                                  &driver->info3, servername);
+                               break;
+                       case 5:
+                               result = fill_printer_driver_info5(info, &info[count+i].info5,
+                                                                  &driver->info3, servername);
+                               break;
+                       case 6:
+                               result = fill_printer_driver_info6(info, &info[count+i].info6,
+                                                                  &driver->info3, servername);
+                               break;
+                       default:
+                               result = WERR_UNKNOWN_LEVEL;
+                               break;
+                       }
+
+                       free_a_printer_driver(driver);
+
                        if (!W_ERROR_IS_OK(result)) {
-                               free_a_printer_driver(driver, 3);
                                goto out;
                        }
-                       free_a_printer_driver(driver, 3);
                }
 
-               *count += ndrivers;
+               count += ndrivers;
                SAFE_FREE(list);
        }
 
@@ -6383,172 +6643,148 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
 
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(info);
-               *count = 0;
                return result;
        }
 
        *info_p = info;
+       *count_p = count;
 
        return WERR_OK;
 }
 
 /****************************************************************************
- Enumerates all printer drivers at level 2.
+ Enumerates all printer drivers by level.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
-                                       const char *servername,
-                                       const char *architecture,
-                                       union spoolss_DriverInfo **info_p,
-                                       uint32_t *count)
+static WERROR enumprinterdrivers_level(TALLOC_CTX *mem_ctx,
+                                      const char *servername,
+                                      const char *architecture,
+                                      uint32_t level,
+                                      union spoolss_DriverInfo **info_p,
+                                      uint32_t *count_p)
 {
-       int i;
-       int ndrivers;
-       uint32_t version;
-       fstring *list = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       union spoolss_DriverInfo *info = NULL;
+       uint32_t a,i;
        WERROR result = WERR_OK;
 
-       *count = 0;
+       if (strequal(architecture, "all")) {
 
-       for (version=0; version<DRIVER_MAX_VERSION; version++) {
-               list = NULL;
-               ndrivers = get_ntdrivers(&list, architecture, version);
-               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
-                       ndrivers, architecture, version));
+               for (a=0; archi_table[a].long_archi != NULL; a++) {
 
-               if (ndrivers == -1) {
-                       result = WERR_NOMEM;
-                       goto out;
-               }
-
-               if (ndrivers != 0) {
-                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
-                                                   union spoolss_DriverInfo,
-                                                   *count + ndrivers);
-                       if (!info) {
-                               DEBUG(0,("enumprinterdrivers_level2: "
-                                       "failed to enlarge driver info buffer!\n"));
-                               result = WERR_NOMEM;
-                               goto out;
-                       }
-               }
+                       union spoolss_DriverInfo *info = NULL;
+                       uint32_t count = 0;
 
-               for (i=0; i<ndrivers; i++) {
-                       DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
-                       ZERO_STRUCT(driver);
-                       result = get_a_printer_driver(&driver, 3, list[i],
-                                                     architecture, version);
+                       result = enumprinterdrivers_level_by_architecture(mem_ctx,
+                                                                         servername,
+                                                                         archi_table[a].long_archi,
+                                                                         level,
+                                                                         &info,
+                                                                         &count);
                        if (!W_ERROR_IS_OK(result)) {
-                               goto out;
+                               continue;
                        }
-                       result = fill_printer_driver_info2(info, &info[*count+i].info2,
-                                                          &driver, servername);
-                       if (!W_ERROR_IS_OK(result)) {
-                               free_a_printer_driver(driver, 3);
-                               goto out;
+
+                       for (i=0; i < count; i++) {
+                               ADD_TO_ARRAY(mem_ctx, union spoolss_DriverInfo,
+                                            info[i], info_p, count_p);
                        }
-                       free_a_printer_driver(driver, 3);
                }
 
-               *count += ndrivers;
-               SAFE_FREE(list);
-       }
-
- out:
-       SAFE_FREE(list);
-
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
                return result;
        }
 
-       *info_p = info;
-
-       return WERR_OK;
+       return enumprinterdrivers_level_by_architecture(mem_ctx,
+                                                       servername,
+                                                       architecture,
+                                                       level,
+                                                       info_p,
+                                                       count_p);
 }
 
 /****************************************************************************
- Enumerates all printer drivers at level 3.
+ Enumerates all printer drivers at level 1.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
+static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                                        const char *servername,
                                        const char *architecture,
                                        union spoolss_DriverInfo **info_p,
                                        uint32_t *count)
 {
-       int i;
-       int ndrivers;
-       uint32_t version;
-       fstring *list = NULL;
-       union spoolss_DriverInfo *info = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       WERROR result = WERR_OK;
-
-       *count = 0;
-
-       for (version=0; version<DRIVER_MAX_VERSION; version++) {
-               list = NULL;
-               ndrivers = get_ntdrivers(&list, architecture, version);
-               DEBUGADD(4,("we have:[%d] drivers in environment [%s] and version [%d]\n",
-                       ndrivers, architecture, version));
-
-               if (ndrivers == -1) {
-                       result = WERR_NOMEM;
-                       goto out;
-               }
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 1,
+                                       info_p, count);
+}
 
-               if (ndrivers != 0) {
-                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
-                                                   union spoolss_DriverInfo,
-                                                   *count + ndrivers);
-                       if (!info) {
-                               DEBUG(0,("enumprinterdrivers_level3: "
-                                       "failed to enlarge driver info buffer!\n"));
-                               result = WERR_NOMEM;
-                               goto out;
-                       }
-               }
+/****************************************************************************
+ Enumerates all printer drivers at level 2.
+****************************************************************************/
 
-               for (i=0; i<ndrivers; i++) {
-                       DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
-                       ZERO_STRUCT(driver);
-                       result = get_a_printer_driver(&driver, 3, list[i],
-                                                     architecture, version);
-                       if (!W_ERROR_IS_OK(result)) {
-                               goto out;
-                       }
-                       result = fill_printer_driver_info3(info, &info[*count+i].info3,
-                                                          &driver, servername);
-                       if (!W_ERROR_IS_OK(result)) {
-                               free_a_printer_driver(driver, 3);
-                               goto out;
-                       }
+static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
+{
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 2,
+                                       info_p, count);
+}
 
-                       free_a_printer_driver(driver, 3);
-               }
+/****************************************************************************
+ Enumerates all printer drivers at level 3.
+****************************************************************************/
 
-               *count += ndrivers;
-               SAFE_FREE(list);
-       }
+static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
+{
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 3,
+                                       info_p, count);
+}
 
- out:
-       SAFE_FREE(list);
+/****************************************************************************
+ Enumerates all printer drivers at level 4.
+****************************************************************************/
 
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
-       }
+static WERROR enumprinterdrivers_level4(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
+{
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 4,
+                                       info_p, count);
+}
 
-       *info_p = info;
+/****************************************************************************
+ Enumerates all printer drivers at level 5.
+****************************************************************************/
 
-       return WERR_OK;
+static WERROR enumprinterdrivers_level5(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
+{
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 5,
+                                       info_p, count);
+}
+
+/****************************************************************************
+ Enumerates all printer drivers at level 6.
+****************************************************************************/
+
+static WERROR enumprinterdrivers_level6(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
+{
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 6,
+                                       info_p, count);
 }
 
+
 /****************************************************************
  _spoolss_EnumPrinterDrivers
 ****************************************************************/
@@ -6593,6 +6829,21 @@ WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
                                                   r->in.environment,
                                                   r->out.info, r->out.count);
                break;
+       case 4:
+               result = enumprinterdrivers_level4(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
+       case 5:
+               result = enumprinterdrivers_level5(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
+       case 6:
+               result = enumprinterdrivers_level6(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
@@ -6655,7 +6906,7 @@ static WERROR spoolss_enumforms_level1(TALLOC_CTX *mem_ctx,
 
        /* construct the list of form structures */
        for (i=0; i<num_builtin_forms; i++) {
-               DEBUGADD(6,("Filling form number [%d]\n",i));
+               DEBUGADD(6,("Filling builtin form number [%d]\n",i));
                result = fill_form_info_1(info, &info[i].info1,
                                          &builtin_forms[i]);
                if (!W_ERROR_IS_OK(result)) {
@@ -6663,10 +6914,10 @@ static WERROR spoolss_enumforms_level1(TALLOC_CTX *mem_ctx,
                }
        }
 
-       for (; i<num_user_forms; i++) {
-               DEBUGADD(6,("Filling form number [%d]\n",i));
-               result = fill_form_info_1(info, &info[i].info1,
-                                         &user_forms[i-num_builtin_forms]);
+       for (i=0; i<num_user_forms; i++) {
+               DEBUGADD(6,("Filling user form number [%d]\n",i));
+               result = fill_form_info_1(info, &info[i+num_builtin_forms].info1,
+                                         &user_forms[i]);
                if (!W_ERROR_IS_OK(result)) {
                        goto out;
                }
@@ -6884,7 +7135,7 @@ static WERROR fill_port_2(TALLOC_CTX *mem_ctx,
  wrapper around the enumer ports command
 ****************************************************************************/
 
-WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines )
+static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines)
 {
        char *cmd = lp_enumports_cmd();
        char **qlines = NULL;
@@ -7157,7 +7408,7 @@ static WERROR spoolss_addprinterex_level_2(pipes_struct *p,
        }
 
        /* you must be a printer admin to add a new printer */
-       if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
+       if (!print_access_check(p->server_info, snum, PRINTER_ACCESS_ADMINISTER)) {
                free_a_printer(&printer,2);
                return WERR_ACCESS_DENIED;
        }
@@ -7238,6 +7489,30 @@ WERROR _spoolss_AddPrinterEx(pipes_struct *p,
        }
 }
 
+/****************************************************************
+ _spoolss_AddPrinter
+****************************************************************/
+
+WERROR _spoolss_AddPrinter(pipes_struct *p,
+                          struct spoolss_AddPrinter *r)
+{
+       struct spoolss_AddPrinterEx a;
+       struct spoolss_UserLevelCtr userlevel_ctr;
+
+       ZERO_STRUCT(userlevel_ctr);
+
+       userlevel_ctr.level = 1;
+
+       a.in.server             = r->in.server;
+       a.in.info_ctr           = r->in.info_ctr;
+       a.in.devmode_ctr        = r->in.devmode_ctr;
+       a.in.secdesc_ctr        = r->in.secdesc_ctr;
+       a.in.userlevel_ctr      = &userlevel_ctr;
+       a.out.handle            = r->out.handle;
+
+       return _spoolss_AddPrinterEx(p, &a);
+}
+
 /****************************************************************
  _spoolss_AddPrinterDriver
 ****************************************************************/
@@ -7245,11 +7520,8 @@ WERROR _spoolss_AddPrinterEx(pipes_struct *p,
 WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                                 struct spoolss_AddPrinterDriver *r)
 {
-       uint32_t level = r->in.info_ctr->level;
-       struct spoolss_AddDriverInfoCtr *info = r->in.info_ctr;
        WERROR err = WERR_OK;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       const char *driver_name = NULL;
+       char *driver_name = NULL;
        uint32_t version;
        const char *fn;
 
@@ -7266,46 +7538,31 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
 
 
        /* FIXME */
-       if (level != 3 && level != 6) {
+       if (r->in.info_ctr->level != 3 && r->in.info_ctr->level != 6) {
                /* Clever hack from Martin Zielinski <mz@seh.de>
                 * to allow downgrade from level 8 (Vista).
                 */
-               DEBUG(0,("%s: level %d not yet implemented\n", fn, level));
+               DEBUG(0,("%s: level %d not yet implemented\n", fn,
+                       r->in.info_ctr->level));
                return WERR_UNKNOWN_LEVEL;
        }
 
-       ZERO_STRUCT(driver);
-
-       if (!convert_printer_driver_info(info, &driver, level)) {
-               err = WERR_NOMEM;
-               goto done;
-       }
-
        DEBUG(5,("Cleaning driver's information\n"));
-       err = clean_up_driver_struct(p, driver, level);
+       err = clean_up_driver_struct(p, r->in.info_ctr);
        if (!W_ERROR_IS_OK(err))
                goto done;
 
        DEBUG(5,("Moving driver to final destination\n"));
-       if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, driver, level,
+       if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, r->in.info_ctr,
                                                              &err)) ) {
                goto done;
        }
 
-       if (add_a_printer_driver(driver, level)!=0) {
+       if (add_a_printer_driver(p->mem_ctx, r->in.info_ctr, &driver_name, &version)!=0) {
                err = WERR_ACCESS_DENIED;
                goto done;
        }
 
-        switch(level) {
-       case 3:
-               driver_name = driver.info_3->name ? driver.info_3->name : "";
-               break;
-       case 6:
-               driver_name = driver.info_6->name ? driver.info_6->name : "";
-               break;
-        }
-
        /*
         * I think this is where he DrvUpgradePrinter() hook would be
         * be called in a driver's interface DLL on a Windows NT 4.0/2k
@@ -7328,12 +7585,7 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
         * It is necessary to follow the driver install by an initialization step to
         * finish off this process.
        */
-       if (level == 3)
-               version = driver.info_3->cversion;
-       else if (level == 6)
-               version = driver.info_6->version;
-       else
-               version = -1;
+
        switch (version) {
                /*
                 * 9x printer driver - never delete init data
@@ -7349,9 +7601,9 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                */
                case 2:
                {
-                       NT_PRINTER_DRIVER_INFO_LEVEL driver1;
+                       union spoolss_DriverInfo *driver1;
 
-                       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver1, 3, driver_name, "Windows NT x86", 3))) {
+                       if (!W_ERROR_IS_OK(get_a_printer_driver(p->mem_ctx, &driver1, 3, driver_name, "Windows NT x86", 3))) {
                                /*
                                 * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
                                */
@@ -7362,7 +7614,7 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                                /*
                                 * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
                                */
-                               free_a_printer_driver(driver1,3);
+                               free_a_printer_driver(driver1);
                                DEBUG(10,("%s: init data not deleted for Nt driver [%s]\n",
                                        fn, driver_name));
                        }
@@ -7379,13 +7631,13 @@ WERROR _spoolss_AddPrinterDriver(pipes_struct *p,
                        break;
 
                default:
-                       DEBUG(0,("%s: invalid level=%d\n", fn, level));
+                       DEBUG(0,("%s: invalid level=%d\n", fn,
+                               r->in.info_ctr->level));
                        break;
        }
 
 
 done:
-       free_a_printer_driver(driver, level);
        return err;
 }
 
@@ -7562,7 +7814,7 @@ WERROR _spoolss_EnumPrinterData(pipes_struct *p,
        Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
        int             snum;
        WERROR          result;
-       REGISTRY_VALUE  *val = NULL;
+       struct regval_blob      *val = NULL;
        NT_PRINTER_DATA *p_data;
        int             i, key_index, num_values;
        int             name_length;
@@ -7882,9 +8134,10 @@ WERROR _spoolss_AddForm(pipes_struct *p,
 {
        struct spoolss_AddFormInfo1 *form = r->in.info.info1;
        nt_forms_struct tmpForm;
-       int snum;
+       int snum = -1;
        WERROR status = WERR_OK;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
+       SE_PRIV se_printop = SE_PRINT_OPERATOR;
 
        int count=0;
        nt_forms_struct *list=NULL;
@@ -7911,10 +8164,17 @@ WERROR _spoolss_AddForm(pipes_struct *p,
                        goto done;
        }
 
-       if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
-               DEBUG(2,("_spoolss_addform: denied by handle permissions.\n"));
-               status = WERR_ACCESS_DENIED;
-               goto done;
+       /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
+          and not a printer admin, then fail */
+
+       if ((p->server_info->utok.uid != sec_initial_uid()) &&
+            !user_has_privileges(p->server_info->ptok, &se_printop) &&
+            !token_contains_name_in_list(uidtoname(p->server_info->utok.uid),
+                                         NULL, NULL,
+                                         p->server_info->ptok,
+                                         lp_printer_admin(snum))) {
+               DEBUG(2,("_spoolss_Addform: denied by insufficient permissions.\n"));
+               return WERR_ACCESS_DENIED;
        }
 
        /* can't add if builtin */
@@ -7931,7 +8191,9 @@ WERROR _spoolss_AddForm(pipes_struct *p,
                goto done;
        }
 
+       become_root();
        write_ntforms(&list, count);
+       unbecome_root();
 
        /*
         * ChangeID must always be set if this is a printer
@@ -7960,9 +8222,11 @@ WERROR _spoolss_DeleteForm(pipes_struct *p,
        int count=0;
        nt_forms_struct *list=NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
-       int snum;
+       int snum = -1;
        WERROR status = WERR_OK;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
+       SE_PRIV se_printop = SE_PRINT_OPERATOR;
+       bool ret = false;
 
        DEBUG(5,("_spoolss_DeleteForm\n"));
 
@@ -7984,12 +8248,17 @@ WERROR _spoolss_DeleteForm(pipes_struct *p,
                        goto done;
        }
 
-       if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
-               DEBUG(2,("_spoolss_DeleteForm: denied by handle permissions.\n"));
-               status = WERR_ACCESS_DENIED;
-               goto done;
+       if ((p->server_info->utok.uid != sec_initial_uid()) &&
+            !user_has_privileges(p->server_info->ptok, &se_printop) &&
+            !token_contains_name_in_list(uidtoname(p->server_info->utok.uid),
+                                         NULL, NULL,
+                                         p->server_info->ptok,
+                                         lp_printer_admin(snum))) {
+               DEBUG(2,("_spoolss_DeleteForm: denied by insufficient permissions.\n"));
+               return WERR_ACCESS_DENIED;
        }
 
+
        /* can't delete if builtin */
 
        if (get_a_builtin_ntform_by_string(form_name,&tmpForm)) {
@@ -7999,8 +8268,12 @@ WERROR _spoolss_DeleteForm(pipes_struct *p,
 
        count = get_ntforms(&list);
 
-       if ( !delete_a_form(&list, form_name, &count, &status ))
+       become_root();
+       ret = delete_a_form(&list, form_name, &count, &status);
+       unbecome_root();
+       if (ret == false) {
                goto done;
+       }
 
        /*
         * ChangeID must always be set if this is a printer
@@ -8026,9 +8299,10 @@ WERROR _spoolss_SetForm(pipes_struct *p,
 {
        struct spoolss_AddFormInfo1 *form = r->in.info.info1;
        nt_forms_struct tmpForm;
-       int snum;
+       int snum = -1;
        WERROR status = WERR_OK;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
+       SE_PRIV se_printop = SE_PRINT_OPERATOR;
 
        int count=0;
        nt_forms_struct *list=NULL;
@@ -8054,10 +8328,17 @@ WERROR _spoolss_SetForm(pipes_struct *p,
                        goto done;
        }
 
-       if ( !(Printer->access_granted & (PRINTER_ACCESS_ADMINISTER|SERVER_ACCESS_ADMINISTER)) ) {
-               DEBUG(2,("_spoolss_SetForm: denied by handle permissions\n"));
-               status = WERR_ACCESS_DENIED;
-               goto done;
+       /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege,
+          and not a printer admin, then fail */
+
+       if ((p->server_info->utok.uid != sec_initial_uid()) &&
+            !user_has_privileges(p->server_info->ptok, &se_printop) &&
+            !token_contains_name_in_list(uidtoname(p->server_info->utok.uid),
+                                         NULL, NULL,
+                                         p->server_info->ptok,
+                                         lp_printer_admin(snum))) {
+               DEBUG(2,("_spoolss_Setform: denied by insufficient permissions.\n"));
+               return WERR_ACCESS_DENIED;
        }
 
        /* can't set if builtin */
@@ -8068,7 +8349,9 @@ WERROR _spoolss_SetForm(pipes_struct *p,
 
        count = get_ntforms(&list);
        update_a_form(&list, form, count);
+       become_root();
        write_ntforms(&list, count);
+       unbecome_root();
 
        /*
         * ChangeID must always be set if this is a printer
@@ -8613,7 +8896,7 @@ WERROR _spoolss_GetPrinterDataEx(pipes_struct *p,
 {
 
        Printer_entry   *Printer = find_printer_index_by_hnd(p, r->in.handle);
-       REGISTRY_VALUE          *val = NULL;
+       struct regval_blob              *val = NULL;
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
        int                     snum = 0;
        WERROR result = WERR_OK;
@@ -8855,7 +9138,7 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
        WERROR          result = WERR_BADFILE;
        int i;
        const char **array = NULL;
-
+       DATA_BLOB blob;
 
        DEBUG(4,("_spoolss_EnumPrinterKey\n"));
 
@@ -8884,7 +9167,9 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
                goto done;
        }
 
-       *r->out.needed = 4;
+       /* two byte termination (a multisz) */
+
+       *r->out.needed = 2;
 
        array = talloc_zero_array(r->out.key_buffer, const char *, num_keys + 1);
        if (!array) {
@@ -8893,6 +9178,10 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
        }
 
        for (i=0; i < num_keys; i++) {
+
+               DEBUG(10,("_spoolss_EnumPrinterKey: adding keyname: %s\n",
+                       keynames[i]));
+
                array[i] = talloc_strdup(array, keynames[i]);
                if (!array[i]) {
                        result = WERR_NOMEM;
@@ -8909,12 +9198,21 @@ WERROR _spoolss_EnumPrinterKey(pipes_struct *p,
 
        result = WERR_OK;
 
-       *r->out.key_buffer = array;
+       if (!push_reg_multi_sz(p->mem_ctx, &blob, array)) {
+               result = WERR_NOMEM;
+               goto done;
+       }
+
+       if (r->in.offered >= blob.length) {
+               memcpy(r->out.key_buffer, blob.data, blob.length);
+       }
 
  done:
        if (!W_ERROR_IS_OK(result)) {
                TALLOC_FREE(array);
-               ZERO_STRUCTP(r->out.key_buffer);
+               if (!W_ERROR_EQUAL(result, WERR_MORE_DATA)) {
+                       *r->out.needed = 0;
+               }
        }
 
        free_a_printer(&printer, 2);
@@ -8977,7 +9275,7 @@ WERROR _spoolss_DeletePrinterKey(pipes_struct *p,
 ****************************************************************/
 
 static WERROR registry_value_to_printer_enum_value(TALLOC_CTX *mem_ctx,
-                                                  REGISTRY_VALUE *v,
+                                                  struct regval_blob *v,
                                                   struct spoolss_PrinterEnumValues *r)
 {
        WERROR result;
@@ -9094,7 +9392,7 @@ WERROR _spoolss_EnumPrinterDataEx(pipes_struct *p,
 
        for (i=0; i < count; i++) {
 
-               REGISTRY_VALUE  *val;
+               struct regval_blob      *val;
 
                /* lookup the registry value */
 
@@ -9194,8 +9492,12 @@ WERROR _spoolss_GetPrintProcessorDirectory(pipes_struct *p,
 
        /* r->in.level is ignored */
 
+       /* We always should reply with a local print processor directory so that
+        * users are not forced to have a [prnproc$] share on the Samba spoolss
+        * server - Guenther */
+
        result = getprintprocessordirectory_level_1(p->mem_ctx,
-                                                   r->in.server,
+                                                   NULL, /* r->in.server */
                                                    r->in.environment,
                                                    &r->out.info->info1);
        if (!W_ERROR_IS_OK(result)) {
@@ -9541,13 +9843,14 @@ WERROR _spoolss_AddPrintProcessor(pipes_struct *p,
 }
 
 /****************************************************************
- _spoolss_AddPrinter
+ _spoolss_AddPort
 ****************************************************************/
 
-WERROR _spoolss_AddPrinter(pipes_struct *p,
-                          struct spoolss_AddPrinter *r)
+WERROR _spoolss_AddPort(pipes_struct *p,
+                       struct spoolss_AddPort *r)
 {
-       p->rng_fault_state = true;
+       /* do what w2k3 does */
+
        return WERR_NOT_SUPPORTED;
 }
 
@@ -9584,17 +9887,6 @@ WERROR _spoolss_WaitForPrinterChange(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_AddPort
-****************************************************************/
-
-WERROR _spoolss_AddPort(pipes_struct *p,
-                       struct spoolss_AddPort *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_ConfigurePort
 ****************************************************************/
@@ -10024,3 +10316,156 @@ WERROR _spoolss_5f(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
+/****************************************************************
+ _spoolss_60
+****************************************************************/
+
+WERROR _spoolss_60(pipes_struct *p,
+                  struct spoolss_60 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_61
+****************************************************************/
+
+WERROR _spoolss_61(pipes_struct *p,
+                  struct spoolss_61 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_62
+****************************************************************/
+
+WERROR _spoolss_62(pipes_struct *p,
+                  struct spoolss_62 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_63
+****************************************************************/
+
+WERROR _spoolss_63(pipes_struct *p,
+                  struct spoolss_63 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_64
+****************************************************************/
+
+WERROR _spoolss_64(pipes_struct *p,
+                  struct spoolss_64 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_65
+****************************************************************/
+
+WERROR _spoolss_65(pipes_struct *p,
+                  struct spoolss_65 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_GetCorePrinterDrivers
+****************************************************************/
+
+WERROR _spoolss_GetCorePrinterDrivers(pipes_struct *p,
+                                     struct spoolss_GetCorePrinterDrivers *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_67
+****************************************************************/
+
+WERROR _spoolss_67(pipes_struct *p,
+                  struct spoolss_67 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_GetPrinterDriverPackagePath
+****************************************************************/
+
+WERROR _spoolss_GetPrinterDriverPackagePath(pipes_struct *p,
+                                           struct spoolss_GetPrinterDriverPackagePath *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_69
+****************************************************************/
+
+WERROR _spoolss_69(pipes_struct *p,
+                  struct spoolss_69 *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6a
+****************************************************************/
+
+WERROR _spoolss_6a(pipes_struct *p,
+                  struct spoolss_6a *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6b
+****************************************************************/
+
+WERROR _spoolss_6b(pipes_struct *p,
+                  struct spoolss_6b *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6c
+****************************************************************/
+
+WERROR _spoolss_6c(pipes_struct *p,
+                  struct spoolss_6c *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+ _spoolss_6d
+****************************************************************/
+
+WERROR _spoolss_6d(pipes_struct *p,
+                  struct spoolss_6d *r)
+{
+       p->rng_fault_state = true;
+       return WERR_NOT_SUPPORTED;
+}