Make "struct policy" private to srv_lsa_hnd.c
[ira/wip.git] / source3 / rpc_server / srv_spoolss_nt.c
index 15c137a88cf398f7e1088807510d221693c93d17..629e41c0033444c1b3da3df170fd8a415b67e9aa 100644 (file)
@@ -445,7 +445,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 +591,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;
 }
@@ -4084,6 +4085,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 +4129,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);
 
@@ -4636,6 +4666,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;
@@ -4799,7 +4833,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);
@@ -4812,6 +4846,121 @@ static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
        return WERR_OK;
 }
 
+/********************************************************************
+ * fill a spoolss_DriverInfo4 struct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo4 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+
+       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->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->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 NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
+{
+       const char *cservername = canon_servername(servername);
+
+       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);
+
+       r->driver_attributes    = 0;
+       r->config_version       = 0;
+       r->driver_version       = 0;
+
+       return WERR_OK;
+}
 /********************************************************************
  * fill a spoolss_DriverInfo6 struct
  ********************************************************************/
@@ -4860,7 +5009,7 @@ 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->monitor_name         = talloc_strdup(mem_ctx, driver->info_3->monitorname);
        W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
@@ -4889,6 +5038,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 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
  ********************************************************************/
@@ -5077,6 +5394,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
 ****************************************************************/
@@ -5146,13 +5526,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;
        }
@@ -6339,14 +6721,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;
@@ -6354,9 +6737,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;
@@ -6372,7 +6757,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"));
@@ -6389,9 +6774,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;
@@ -6399,7 +6813,7 @@ static WERROR enumprinterdrivers_level1(TALLOC_CTX *mem_ctx,
                        free_a_printer_driver(driver, 3);
                }
 
-               *count += ndrivers;
+               count += ndrivers;
                SAFE_FREE(list);
        }
 
@@ -6408,91 +6822,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);
 }
 
 /****************************************************************************
@@ -6505,75 +6869,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
 ****************************************************************/
@@ -6618,6 +6960,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;
        }
@@ -7910,6 +8267,7 @@ WERROR _spoolss_AddForm(pipes_struct *p,
        int snum;
        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;
@@ -7936,10 +8294,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 */
@@ -7956,7 +8321,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
@@ -7988,6 +8355,8 @@ WERROR _spoolss_DeleteForm(pipes_struct *p,
        int snum;
        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"));
 
@@ -8009,12 +8378,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)) {
@@ -8024,8 +8398,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
@@ -8054,6 +8432,7 @@ WERROR _spoolss_SetForm(pipes_struct *p,
        int snum;
        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;
@@ -8079,10 +8458,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 */
@@ -8093,7 +8479,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
@@ -9565,6 +9953,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
 ****************************************************************/
@@ -9609,17 +10009,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
 ****************************************************************/