s3-samr: Fix samr access checks in _samr_RemoveMemberFromForeignDomain().
[ira/wip.git] / source3 / rpc_server / srv_spoolss_nt.c
index 01438fc7d6038594cd721ffee66143c3bb0f7ee4..8280011cc207a2e985a3282c030db9cd5243845c 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 {
@@ -445,7 +439,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 +585,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 +1633,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(
@@ -2078,7 +2073,7 @@ WERROR _spoolss_DeletePrinter(pipes_struct *p,
 static int get_version_id(const char *arch)
 {
        int i;
-       struct table_node archi_table[]= {
+       struct print_architecture_table_node archi_table[]= {
 
                {"Windows 4.0",          "WIN40",       0 },
                {"Windows NT x86",       "W32X86",      2 },
@@ -2116,7 +2111,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,
@@ -2216,7 +2211,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,
@@ -2546,7 +2541,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,
@@ -4084,6 +4079,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 +4123,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 +4228,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 +4318,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 +4423,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,("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;
+       DEBUG(4,("enum_all_printers_info_2\n"));
 
-       return WERR_OK;
+       return enum_all_printers_info_level(mem_ctx, 2, 0, info, count);
 }
 
 /********************************************************************
@@ -4459,6 +4487,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 +4513,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 +4557,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,14 +4569,14 @@ WERROR _spoolss_EnumPrinters(pipes_struct *p,
                result = enumprinters_level2(p->mem_ctx, r->in.flags, name,
                                             r->out.info, r->out.count);
                break;
+       case 4:
+               result = enumprinters_level4(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,
                                             r->out.info, r->out.count);
                break;
-       case 3:
-       case 4:
-               result = WERR_OK; /* ??? */
-               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
@@ -4611,6 +4660,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;
@@ -4774,7 +4827,7 @@ static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
        } 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);
        W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
@@ -4788,11 +4841,11 @@ static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
 }
 
 /********************************************************************
- * fill a spoolss_DriverInfo6 struct
+ * fill a spoolss_DriverInfo4 struct
  ********************************************************************/
 
-static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
-                                       struct spoolss_DriverInfo6 *r,
+static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo4 *r,
                                        const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
                                        const char *servername)
 {
@@ -4835,88 +4888,371 @@ static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
        } 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->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->info_3->dependentfiles,
+                                                          cservername);
+
 
        r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
        W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
        r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
        W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
 
-       r->dependent_files = string_array_from_driver_info(mem_ctx,
-                                                          driver->info_3->dependentfiles,
-                                                          cservername);
        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
+ * fill a spoolss_DriverInfo5 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo1 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
+static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo5 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 {
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       WERROR result;
+       const char *cservername = canon_servername(servername);
 
-       ZERO_STRUCT(driver);
+       r->version              = driver->info_3->cversion;
 
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
 
-       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
-               free_a_printer(&printer, 2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
+       if (strlen(driver->info_3->driverpath)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->driverpath);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
 
-       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       free_a_printer(&printer,2);
+       if (strlen(driver->info_3->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       return result;
-}
+       r->driver_attributes    = 0;
+       r->config_version       = 0;
+       r->driver_version       = 0;
 
+       return WERR_OK;
+}
 /********************************************************************
- * construct_printer_driver_info_2
- * fill a printer_info_2 struct
+ * fill a spoolss_DriverInfo6 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
-                                             struct spoolss_DriverInfo2 *r,
-                                             int snum,
-                                             const char *servername,
-                                             const char *architecture,
-                                             uint32_t version)
+static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo6 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 {
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       WERROR result;
-
-       ZERO_STRUCT(printer);
-       ZERO_STRUCT(driver);
+       const char *cservername = canon_servername(servername);
 
-       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
-               return WERR_INVALID_PRINTER_NAME;
+       r->version              = driver->info_3->cversion;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+       if (strlen(driver->info_3->driverpath)) {
+               r->driver_path  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->driverpath);
+       } else {
+               r->driver_path  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->driver_path);
+
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
+
+       if (strlen(driver->info_3->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
+
+       if (strlen(driver->info_3->helpfile)) {
+               r->help_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->helpfile);
+       } else {
+               r->help_file    = talloc_strdup(mem_ctx, "");
+       }
+       W_ERROR_HAVE_NO_MEMORY(r->help_file);
+
+       r->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->info_3->dependentfiles,
+                                                          cservername);
+       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;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+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 NT_PRINTER_DRIVER_INFO_LEVEL *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->info_3->driverpath)) {
+               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->info_3->driverpath,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_RENDERING,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->info_3->configfile)) {
+               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->info_3->configfile,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->info_3->datafile)) {
+               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->info_3->datafile,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_DATA,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       if (strlen(driver->info_3->helpfile)) {
+               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->info_3->helpfile,
+                                                    SPOOLSS_DRIVER_FILE_TYPE_HELP,
+                                                    0);
+               W_ERROR_NOT_OK_RETURN(result);
+               count++;
+       }
+
+       for (i=0; driver->info_3->dependentfiles[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->info_3->dependentfiles[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 NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                         const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+       WERROR result;
+
+       r->version              = driver->info_3->cversion;
+
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+       r->architecture         = talloc_strdup(mem_ctx, driver->info_3->environment);
+       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->info_3->monitorname);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+
+       r->default_datatype     = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+       W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+       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
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_1(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo1 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
+{
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       WERROR result;
+
+       ZERO_STRUCT(driver);
+
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
+               return WERR_INVALID_PRINTER_NAME;
+
+       if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
+               free_a_printer(&printer, 2);
+               return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
+
+       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
+
+       free_a_printer(&printer,2);
+
+       return result;
+}
+
+/********************************************************************
+ * construct_printer_driver_info_2
+ * fill a printer_info_2 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_2(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo2 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
+{
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       NT_PRINTER_DRIVER_INFO_LEVEL driver;
+       WERROR result;
+
+       ZERO_STRUCT(printer);
+       ZERO_STRUCT(driver);
+
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, lp_const_servicename(snum))))
+               return WERR_INVALID_PRINTER_NAME;
 
        if (!W_ERROR_IS_OK(get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version))) {
                free_a_printer(&printer, 2);
@@ -5052,6 +5388,69 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
        return status;
 }
 
+/********************************************************************
+ * construct_printer_info_101
+ * fill a printer_info_101 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
+                                               struct spoolss_DriverInfo101 *r,
+                                               int snum,
+                                               const char *servername,
+                                               const char *architecture,
+                                               uint32_t version)
+{
+       NT_PRINTER_INFO_LEVEL           *printer = NULL;
+       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       WERROR                          result;
+
+       ZERO_STRUCT(driver);
+
+       result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
+
+       DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+               win_errstr(result)));
+
+       if (!W_ERROR_IS_OK(result)) {
+               return WERR_INVALID_PRINTER_NAME;
+       }
+
+       result = get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+                                     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(&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, servername);
+
+       free_a_printer(&printer, 2);
+       free_a_printer_driver(driver, 3);
+
+       return result;
+}
+
 /****************************************************************
  _spoolss_GetPrinterDriver2
 ****************************************************************/
@@ -5121,13 +5520,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;
        }
@@ -5323,20 +5724,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 +5852,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;
        }
@@ -6314,14 +6709,15 @@ WERROR _spoolss_SetJob(pipes_struct *p,
 }
 
 /****************************************************************************
- Enumerates all printer drivers at level 1.
+ Enumerates all printer drivers by level.
 ****************************************************************************/
 
-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(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;
@@ -6329,9 +6725,11 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
        fstring *list = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL 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 +6745,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"));
@@ -6364,9 +6762,38 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                        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, servername,
+                                                                  architecture);
+                               break;
+                       case 2:
+                               result = fill_printer_driver_info2(info, &info[count+i].info2,
+                                                                  &driver, servername);
+                               break;
+                       case 3:
+                               result = fill_printer_driver_info3(info, &info[count+i].info3,
+                                                                  &driver, servername);
+                               break;
+                       case 4:
+                               result = fill_printer_driver_info4(info, &info[count+i].info4,
+                                                                  &driver, servername);
+                               break;
+                       case 5:
+                               result = fill_printer_driver_info5(info, &info[count+i].info5,
+                                                                  &driver, servername);
+                               break;
+                       case 6:
+                               result = fill_printer_driver_info6(info, &info[count+i].info6,
+                                                                  &driver, servername);
+                               break;
+                       default:
+                               result = WERR_UNKNOWN_LEVEL;
+                               break;
+                       }
+
                        if (!W_ERROR_IS_OK(result)) {
                                free_a_printer_driver(driver, 3);
                                goto out;
@@ -6374,7 +6801,7 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                        free_a_printer_driver(driver, 3);
                }
 
-               *count += ndrivers;
+               count += ndrivers;
                SAFE_FREE(list);
        }
 
@@ -6383,91 +6810,41 @@ 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 at level 1.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level2(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;
-       NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       union spoolss_DriverInfo *info = NULL;
-       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;
-               }
-
-               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;
-                       }
-               }
-
-               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_info2(info, &info[*count+i].info2,
-                                                          &driver, servername);
-                       if (!W_ERROR_IS_OK(result)) {
-                               free_a_printer_driver(driver, 3);
-                               goto out;
-                       }
-                       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;
-       }
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 1,
+                                       info_p, count);
+}
 
-       *info_p = info;
+/****************************************************************************
+ Enumerates all printer drivers at level 2.
+****************************************************************************/
 
-       return WERR_OK;
+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);
 }
 
 /****************************************************************************
@@ -6480,75 +6857,53 @@ static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
                                        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;
-               }
-
-               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;
-                       }
-               }
-
-               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;
-                       }
+       return enumprinterdrivers_level(mem_ctx, servername, architecture, 3,
+                                       info_p, count);
+}
 
-                       free_a_printer_driver(driver, 3);
-               }
+/****************************************************************************
+ Enumerates all printer drivers at level 4.
+****************************************************************************/
 
-               *count += ndrivers;
-               SAFE_FREE(list);
-       }
+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);
+}
 
- out:
-       SAFE_FREE(list);
+/****************************************************************************
+ Enumerates all printer drivers at level 5.
+****************************************************************************/
 
-       if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(info);
-               *count = 0;
-               return result;
-       }
+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);
+}
 
-       *info_p = info;
+/****************************************************************************
+ Enumerates all printer drivers at level 6.
+****************************************************************************/
 
-       return WERR_OK;
+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 +6948,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;
        }
@@ -7562,7 +7932,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 +8252,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 +8282,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 +8309,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 +8340,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 +8366,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 +8386,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 +8417,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 +8446,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 +8467,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 +9014,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;
@@ -8977,7 +9378,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 +9495,7 @@ WERROR _spoolss_EnumPrinterDataEx(pipes_struct *p,
 
        for (i=0; i < count; i++) {
 
-               REGISTRY_VALUE  *val;
+               struct regval_blob      *val;
 
                /* lookup the registry value */
 
@@ -9540,6 +9941,18 @@ WERROR _spoolss_AddPrintProcessor(pipes_struct *p,
        return WERR_OK;
 }
 
+/****************************************************************
+ _spoolss_AddPort
+****************************************************************/
+
+WERROR _spoolss_AddPort(pipes_struct *p,
+                       struct spoolss_AddPort *r)
+{
+       /* do what w2k3 does */
+
+       return WERR_NOT_SUPPORTED;
+}
+
 /****************************************************************
  _spoolss_AddPrinter
 ****************************************************************/
@@ -9584,17 +9997,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
 ****************************************************************/