s3-spoolss: add pull_spoolss_PrinterData().
[vlendec/samba-autobuild/.git] / source3 / rpc_server / srv_spoolss_nt.c
index c4355b6f580533dd2ef5f579fb2f0cd38e74c9f9..8ce0b28db04aad39a678943403ddd480854a115d 100644 (file)
@@ -2461,6 +2461,22 @@ WERROR set_printer_dataex( NT_PRINTER_INFO_LEVEL *printer, const char *key, cons
        return add_printer_data( printer->info_2, key, value, type, data, real_len );
 }
 
+/*******************************************************************
+ ********************************************************************/
+
+static WERROR push_spoolss_PrinterData(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+                                      enum winreg_Type type,
+                                      union spoolss_PrinterData *data)
+{
+       enum ndr_err_code ndr_err;
+       ndr_err = ndr_push_union_blob(blob, mem_ctx, NULL, data, type,
+                       (ndr_push_flags_fn_t)ndr_push_spoolss_PrinterData);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return WERR_GENERAL_FAILURE;
+       }
+       return WERR_OK;
+}
+
 /********************************************************************
  GetPrinterData on a printer server Handle.
 ********************************************************************/
@@ -3924,149 +3940,81 @@ done:
  * fill a printer_info_0 struct
  ********************************************************************/
 
-static bool construct_printer_info_0(Printer_entry *print_hnd, PRINTER_INFO_0 *printer, int snum)
+static WERROR construct_printer_info0(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo0 *r,
+                                     int snum)
 {
-       char *chaine = NULL;
        int count;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        counter_printer_0 *session_counter;
-       uint32 global_counter;
-       struct tm *t;
        time_t setuptime;
        print_status_struct status;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
 
-       init_unistr(&printer->printername, ntprinter->info_2->printername);
+       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
 
-       chaine = talloc_asprintf(ctx, "\\\\%s", get_server_name(print_hnd));
-       if (!chaine) {
-               free_a_printer(&ntprinter,2);
-               return false;
-       }
+       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
 
        count = print_queue_length(snum, &status);
 
        /* check if we already have a counter for this printer */
-       for(session_counter = counter_list; session_counter; session_counter = session_counter->next) {
+       for (session_counter = counter_list; session_counter; session_counter = session_counter->next) {
                if (session_counter->snum == snum)
                        break;
        }
 
-       init_unistr(&printer->servername, chaine);
-
        /* it's the first time, add it to the list */
-       if (session_counter==NULL) {
-               if((session_counter=SMB_MALLOC_P(counter_printer_0)) == NULL) {
-                       free_a_printer(&ntprinter, 2);
-                       return False;
-               }
+       if (session_counter == NULL) {
+               session_counter = SMB_MALLOC_P(counter_printer_0);
+               W_ERROR_HAVE_NO_MEMORY(session_counter);
                ZERO_STRUCTP(session_counter);
-               session_counter->snum=snum;
-               session_counter->counter=0;
+               session_counter->snum           = snum;
+               session_counter->counter        = 0;
                DLIST_ADD(counter_list, session_counter);
        }
 
        /* increment it */
        session_counter->counter++;
 
-       /* JFM:
-        * the global_counter should be stored in a TDB as it's common to all the clients
-        * and should be zeroed on samba startup
-        */
-       global_counter=session_counter->counter;
-       printer->cjobs = count;
-       printer->total_jobs = 0;
-       printer->total_bytes = 0;
+       r->cjobs                        = count;
+       r->total_jobs                   = 0;
+       r->total_bytes                  = 0;
 
        setuptime = (time_t)ntprinter->info_2->setuptime;
-       t=gmtime(&setuptime);
 
-       printer->year = t->tm_year+1900;
-       printer->month = t->tm_mon+1;
-       printer->dayofweek = t->tm_wday;
-       printer->day = t->tm_mday;
-       printer->hour = t->tm_hour;
-       printer->minute = t->tm_min;
-       printer->second = t->tm_sec;
-       printer->milliseconds = 0;
-
-       printer->global_counter = global_counter;
-       printer->total_pages = 0;
+       init_systemtime(&r->time, gmtime(&setuptime));
 
+       /* JFM:
+        * the global_counter should be stored in a TDB as it's common to all the clients
+        * and should be zeroed on samba startup
+        */
+       r->global_counter               = session_counter->counter;
+       r->total_pages                  = 0;
        /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */
-       printer->major_version = 0x0005;        /* NT 5 */
-       printer->build_version = 0x0893;        /* build 2195 */
-
-       printer->unknown7 = 0x1;
-       printer->unknown8 = 0x0;
-       printer->unknown9 = 0x0;
-       printer->session_counter = session_counter->counter;
-       printer->unknown11 = 0x0;
-       printer->printer_errors = 0x0;          /* number of print failure */
-       printer->unknown13 = 0x0;
-       printer->unknown14 = 0x1;
-       printer->unknown15 = 0x024a;            /* 586 Pentium ? */
-       printer->unknown16 =  0x0;
-       printer->change_id = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
-       printer->unknown18 =  0x0;
-       printer->status = nt_printq_status(status.status);
-       printer->unknown20 =  0x0;
-       printer->c_setprinter = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
-       printer->unknown22 = 0x0;
-       printer->unknown23 = 0x6;               /* 6  ???*/
-       printer->unknown24 = 0;                 /* unknown 24 to 26 are always 0 */
-       printer->unknown25 = 0;
-       printer->unknown26 = 0;
-       printer->unknown27 = 0;
-       printer->unknown28 = 0;
-       printer->unknown29 = 0;
-
-       free_a_printer(&ntprinter,2);
-       return (True);
-}
+       r->version                      = 0x0005;       /* NT 5 */
+       r->free_build                   = 0x0893;       /* build 2195 */
+       r->spooling                     = 0;
+       r->max_spooling                 = 0;
+       r->session_counter              = session_counter->counter;
+       r->num_error_out_of_paper       = 0x0;
+       r->num_error_not_ready          = 0x0;          /* number of print failure */
+       r->job_error                    = 0x0;
+       r->number_of_processors         = 0x1;
+       r->processor_type               = PROCESSOR_INTEL_PENTIUM; /* 586 Pentium ? */
+       r->high_part_total_bytes        = 0x0;
+       r->change_id                    = ntprinter->info_2->changeid; /* ChangeID in milliseconds*/
+       r->last_error                   = WERR_OK;
+       r->status                       = nt_printq_status(status.status);
+       r->enumerate_network_printers   = 0x0;
+       r->c_setprinter                 = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
+       r->processor_architecture       = 0x0;
+       r->processor_level              = 0x6;          /* 6  ???*/
+       r->ref_ic                       = 0;
+       r->reserved2                    = 0;
+       r->reserved3                    = 0;
 
-/********************************************************************
- * construct_printer_info_1
- * fill a printer_info_1 struct
- ********************************************************************/
-static bool construct_printer_info_1(Printer_entry *print_hnd, uint32 flags, PRINTER_INFO_1 *printer, int snum)
-{
-       char *chaine = NULL;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-       TALLOC_CTX *ctx = talloc_tos();
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return false;
-
-       printer->flags=flags;
-
-       if (*ntprinter->info_2->comment == '\0') {
-               init_unistr(&printer->comment, lp_comment(snum));
-               chaine = talloc_asprintf(ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, lp_comment(snum));
-       }
-       else {
-               init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
-               chaine = talloc_asprintf(ctx,
-                               "%s,%s,%s", ntprinter->info_2->printername,
-                               ntprinter->info_2->drivername, ntprinter->info_2->comment);
-       }
-
-       if (!chaine) {
-               free_a_printer(&ntprinter,2);
-               return false;
-       }
-
-       init_unistr(&printer->description, chaine);
-       init_unistr(&printer->name, ntprinter->info_2->printername);
-
-       free_a_printer(&ntprinter,2);
-
-       return True;
+       return WERR_OK;
 }
 
 /****************************************************************************
@@ -4082,6 +4030,73 @@ static void free_dev_mode(DEVICEMODE *dev)
        SAFE_FREE(dev);
 }
 
+/****************************************************************************
+ Convert an NT_DEVICEMODE to a spoolss_DeviceMode structure.  Both pointers
+ should be valid upon entry
+****************************************************************************/
+
+static WERROR convert_nt_devicemode_new(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DeviceMode *r,
+                                       const NT_DEVICEMODE *ntdevmode)
+{
+       if (!r || !ntdevmode) {
+               return WERR_INVALID_PARAM;
+       }
+
+       r->devicename           = talloc_strdup(mem_ctx, ntdevmode->devicename);
+       W_ERROR_HAVE_NO_MEMORY(r->devicename);
+
+       r->specversion          = ntdevmode->specversion;
+       r->driverversion        = ntdevmode->driverversion;
+       r->size                 = ntdevmode->size;
+       r->__driverextra_length = ntdevmode->driverextra;
+       r->fields               = ntdevmode->fields;
+
+       r->orientation          = ntdevmode->orientation;
+       r->papersize            = ntdevmode->papersize;
+       r->paperlength          = ntdevmode->paperlength;
+       r->paperwidth           = ntdevmode->paperwidth;
+       r->scale                = ntdevmode->scale;
+       r->copies               = ntdevmode->copies;
+       r->defaultsource        = ntdevmode->defaultsource;
+       r->printquality         = ntdevmode->printquality;
+       r->color                = ntdevmode->color;
+       r->duplex               = ntdevmode->duplex;
+       r->yresolution          = ntdevmode->yresolution;
+       r->ttoption             = ntdevmode->ttoption;
+       r->collate              = ntdevmode->collate;
+
+       r->formname             = talloc_strdup(mem_ctx, ntdevmode->formname);
+       W_ERROR_HAVE_NO_MEMORY(r->formname);
+
+       /* all 0 below are values that have not been set in the old parsing/copy
+        * function, maybe they should... - gd */
+
+       r->logpixels            = 0;
+       r->bitsperpel           = 0;
+       r->pelswidth            = 0;
+       r->pelsheight           = 0;
+       r->displayflags         = 0;
+       r->displayfrequency     = 0;
+       r->icmmethod            = ntdevmode->icmmethod;
+       r->icmintent            = ntdevmode->icmintent;
+       r->mediatype            = ntdevmode->mediatype;
+       r->dithertype           = ntdevmode->dithertype;
+       r->reserved1            = 0;
+       r->reserved2            = 0;
+       r->panningwidth         = 0;
+       r->panningheight        = 0;
+
+       if (ntdevmode->nt_dev_private != NULL) {
+               r->driverextra_data = data_blob_talloc(mem_ctx,
+                       ntdevmode->nt_dev_private,
+                       ntdevmode->driverextra);
+               W_ERROR_HAVE_NO_MEMORY(r->driverextra_data.data);
+       }
+
+       return WERR_OK;
+}
+
 
 /****************************************************************************
  Convert an NT_DEVICEMODE to a DEVICEMODE structure.  Both pointers
@@ -4130,38 +4145,39 @@ static bool convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode
 }
 
 /****************************************************************************
- Create a DEVMODE struct. Returns malloced memory.
+ Create a spoolss_DeviceMode struct. Returns talloced memory.
 ****************************************************************************/
 
-DEVICEMODE *construct_dev_mode(const char *servicename)
+struct spoolss_DeviceMode *construct_dev_mode_new(TALLOC_CTX *mem_ctx,
+                                                 const char *servicename)
 {
+       WERROR result;
        NT_PRINTER_INFO_LEVEL   *printer = NULL;
-       DEVICEMODE              *devmode = NULL;
+       struct spoolss_DeviceMode *devmode = NULL;
 
-       DEBUG(7,("construct_dev_mode\n"));
+       DEBUG(7,("construct_dev_mode_new\n"));
 
        DEBUGADD(8,("getting printer characteristics\n"));
 
        if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
                return NULL;
 
-       if ( !printer->info_2->devmode ) {
+       if (!printer->info_2->devmode) {
                DEBUG(5, ("BONG! There was no device mode!\n"));
                goto done;
        }
 
-       if ((devmode = SMB_MALLOC_P(DEVICEMODE)) == NULL) {
-               DEBUG(2,("construct_dev_mode: malloc fail.\n"));
+       devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
+       if (!devmode) {
+               DEBUG(2,("construct_dev_mode_new: talloc fail.\n"));
                goto done;
        }
 
-       ZERO_STRUCTP(devmode);
-
        DEBUGADD(8,("loading DEVICEMODE\n"));
 
-       if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
-               free_dev_mode( devmode );
-               devmode = NULL;
+       result = convert_nt_devicemode_new(mem_ctx, devmode, printer->info_2->devmode);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(devmode);
        }
 
 done:
@@ -4170,313 +4186,392 @@ done:
        return devmode;
 }
 
-/********************************************************************
- * construct_printer_info_2
- * fill a printer_info_2 struct
- ********************************************************************/
+/****************************************************************************
+ Create a DEVMODE struct. Returns malloced memory.
+****************************************************************************/
 
-static bool construct_printer_info_2(Printer_entry *print_hnd, PRINTER_INFO_2 *printer, int snum)
+DEVICEMODE *construct_dev_mode(const char *servicename)
 {
-       int count;
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-
-       print_status_struct status;
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
-
-       count = print_queue_length(snum, &status);
-
-       init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
-       init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
-       init_unistr(&printer->sharename, lp_servicename(snum));                 /* sharename */
-       init_unistr(&printer->portname, ntprinter->info_2->portname);                   /* port */
-       init_unistr(&printer->drivername, ntprinter->info_2->drivername);       /* drivername */
+       NT_PRINTER_INFO_LEVEL   *printer = NULL;
+       DEVICEMODE              *devmode = NULL;
 
-       if (*ntprinter->info_2->comment == '\0')
-               init_unistr(&printer->comment, lp_comment(snum));                       /* comment */
-       else
-               init_unistr(&printer->comment, ntprinter->info_2->comment); /* saved comment. */
+       DEBUG(7,("construct_dev_mode\n"));
 
-       init_unistr(&printer->location, ntprinter->info_2->location);           /* location */
-       init_unistr(&printer->sepfile, ntprinter->info_2->sepfile);             /* separator file */
-       init_unistr(&printer->printprocessor, ntprinter->info_2->printprocessor);/* print processor */
-       init_unistr(&printer->datatype, ntprinter->info_2->datatype);           /* datatype */
-       init_unistr(&printer->parameters, ntprinter->info_2->parameters);       /* parameters (of print processor) */
+       DEBUGADD(8,("getting printer characteristics\n"));
 
-       printer->attributes = ntprinter->info_2->attributes;
+       if (!W_ERROR_IS_OK(get_a_printer(NULL, &printer, 2, servicename)))
+               return NULL;
 
-       printer->priority = ntprinter->info_2->priority;                                /* priority */
-       printer->defaultpriority = ntprinter->info_2->default_priority;         /* default priority */
-       printer->starttime = ntprinter->info_2->starttime;                      /* starttime */
-       printer->untiltime = ntprinter->info_2->untiltime;                      /* untiltime */
-       printer->status = nt_printq_status(status.status);                      /* status */
-       printer->cjobs = count;                                                 /* jobs */
-       printer->averageppm = ntprinter->info_2->averageppm;                    /* average pages per minute */
+       if ( !printer->info_2->devmode ) {
+               DEBUG(5, ("BONG! There was no device mode!\n"));
+               goto done;
+       }
 
-       if ( !(printer->devmode = construct_dev_mode(
-                      lp_const_servicename(snum))) )
-               DEBUG(8, ("Returning NULL Devicemode!\n"));
+       if ((devmode = SMB_MALLOC_P(DEVICEMODE)) == NULL) {
+               DEBUG(2,("construct_dev_mode: malloc fail.\n"));
+               goto done;
+       }
 
-       printer->secdesc = NULL;
+       ZERO_STRUCTP(devmode);
 
-       if ( ntprinter->info_2->secdesc_buf
-               && ntprinter->info_2->secdesc_buf->sd_size != 0 )
-       {
-               /* don't use talloc_steal() here unless you do a deep steal of all
-                  the SEC_DESC members */
+       DEBUGADD(8,("loading DEVICEMODE\n"));
 
-               printer->secdesc = dup_sec_desc( talloc_tos(),
-                       ntprinter->info_2->secdesc_buf->sd );
+       if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
+               free_dev_mode( devmode );
+               devmode = NULL;
        }
 
-       free_a_printer(&ntprinter, 2);
+done:
+       free_a_printer(&printer,2);
 
-       return True;
+       return devmode;
 }
 
 /********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
+ * construct_printer_info3
+ * fill a spoolss_PrinterInfo3 struct
  ********************************************************************/
 
-static bool construct_printer_info_3(Printer_entry *print_hnd, PRINTER_INFO_3 **pp_printer, int snum)
+static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo3 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-       PRINTER_INFO_3 *printer = NULL;
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
-
-       *pp_printer = NULL;
-       if ((printer = SMB_MALLOC_P(PRINTER_INFO_3)) == NULL) {
-               DEBUG(2,("construct_printer_info_3: malloc fail.\n"));
-               free_a_printer(&ntprinter, 2);
-               return False;
-       }
-
-       ZERO_STRUCTP(printer);
-
        /* These are the components of the SD we are returning. */
 
        if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
                /* don't use talloc_steal() here unless you do a deep steal of all
                   the SEC_DESC members */
 
-               printer->secdesc = dup_sec_desc( talloc_tos(),
-                       ntprinter->info_2->secdesc_buf->sd );
+               r->secdesc = dup_sec_desc(mem_ctx,
+                                         ntprinter->info_2->secdesc_buf->sd);
+               W_ERROR_HAVE_NO_MEMORY(r->secdesc);
        }
 
-       free_a_printer(&ntprinter, 2);
-
-       *pp_printer = printer;
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_4
- * fill a printer_info_4 struct
+ * construct_printer_info4
+ * fill a spoolss_PrinterInfo4 struct
  ********************************************************************/
 
-static bool construct_printer_info_4(Printer_entry *print_hnd, PRINTER_INFO_4 *printer, int snum)
+static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo4 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->servername   = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
-
-       init_unistr(&printer->printername, ntprinter->info_2->printername);                             /* printername*/
-       init_unistr(&printer->servername, ntprinter->info_2->servername); /* servername*/
-       printer->attributes = ntprinter->info_2->attributes;
+       r->attributes   = ntprinter->info_2->attributes;
 
-       free_a_printer(&ntprinter, 2);
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_5
- * fill a printer_info_5 struct
+ * construct_printer_info5
+ * fill a spoolss_PrinterInfo5 struct
  ********************************************************************/
 
-static bool construct_printer_info_5(Printer_entry *print_hnd, PRINTER_INFO_5 *printer, int snum)
+static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo5 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2, lp_const_servicename(snum))))
-               return False;
+       r->printername  = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->portname     = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       W_ERROR_HAVE_NO_MEMORY(r->portname);
 
-       init_unistr(&printer->printername, ntprinter->info_2->printername);
-       init_unistr(&printer->portname, ntprinter->info_2->portname);
-       printer->attributes = ntprinter->info_2->attributes;
+       r->attributes   = ntprinter->info_2->attributes;
 
        /* these two are not used by NT+ according to MSDN */
 
-       printer->device_not_selected_timeout = 0x0;  /* have seen 0x3a98 */
-       printer->transmission_retry_timeout  = 0x0;  /* have seen 0xafc8 */
+       r->device_not_selected_timeout          = 0x0;  /* have seen 0x3a98 */
+       r->transmission_retry_timeout           = 0x0;  /* have seen 0xafc8 */
 
-       free_a_printer(&ntprinter, 2);
-
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
  * construct_printer_info_6
- * fill a printer_info_6 struct
+ * fill a spoolss_PrinterInfo6 struct
  ********************************************************************/
 
-static bool construct_printer_info_6(Printer_entry *print_hnd,
-                                    PRINTER_INFO_6 *printer,
-                                    int snum)
+static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo6 *r,
+                                     int snum)
 {
-       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int count;
        print_status_struct status;
 
-       if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &ntprinter, 2,
-                                        lp_const_servicename(snum))))
-               return False;
-
        count = print_queue_length(snum, &status);
 
-       printer->status = nt_printq_status(status.status);
+       r->status = nt_printq_status(status.status);
 
-       free_a_printer(&ntprinter, 2);
-
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- * construct_printer_info_7
- * fill a printer_info_7 struct
+ * construct_printer_info7
+ * fill a spoolss_PrinterInfo7 struct
  ********************************************************************/
 
-static bool construct_printer_info_7(Printer_entry *print_hnd, PRINTER_INFO_7 *printer, int snum)
+static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx,
+                                     Printer_entry *print_hnd,
+                                     struct spoolss_PrinterInfo7 *r,
+                                     int snum)
 {
-       char *guid_str = NULL;
        struct GUID guid;
 
        if (is_printer_published(print_hnd, snum, &guid)) {
-               if (asprintf(&guid_str, "{%s}",
-                            GUID_string(talloc_tos(), &guid)) == -1) {
-                       return false;
-               }
-               strupper_m(guid_str);
-               init_unistr(&printer->guid, guid_str);
-               SAFE_FREE(guid_str);
-               printer->action = DSPRINT_PUBLISH;
+               r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
+               r->action = DSPRINT_PUBLISH;
        } else {
-               init_unistr(&printer->guid, "");
-               printer->action = DSPRINT_UNPUBLISH;
+               r->guid = talloc_strdup(mem_ctx, "");
+               r->action = DSPRINT_UNPUBLISH;
        }
+       W_ERROR_HAVE_NO_MEMORY(r->guid);
 
-       return True;
+       return WERR_OK;
 }
 
 /********************************************************************
- Spoolss_enumprinters.
+ * construct_printer_info1
+ * fill a spoolss_PrinterInfo1 struct
 ********************************************************************/
 
-static WERROR enum_all_printers_info_1(uint32 flags, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     uint32_t flags,
+                                     struct spoolss_PrinterInfo1 *r,
+                                     int snum)
 {
-       int snum;
-       int i;
-       int n_services=lp_numservices();
-       PRINTER_INFO_1 *printers=NULL;
-       PRINTER_INFO_1 current_prt;
-       WERROR result = WERR_OK;
+       char *chaine = NULL;
+       r->flags                = flags;
 
-       DEBUG(4,("enum_all_printers_info_1\n"));
+       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);
 
-       for (snum=0; snum<n_services; snum++) {
-               if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
-                       DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
-
-                       if (construct_printer_info_1(NULL, flags, &current_prt, snum)) {
-                               if((printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_1, *returned +1)) == NULL) {
-                                       DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
-                                       *returned=0;
-                                       return WERR_NOMEM;
-                               }
-                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *returned));
+       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);
 
-                               memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
-                               (*returned)++;
-                       }
-               }
-       }
+       return WERR_OK;
+}
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_printer_info_1(&printers[i]);
+/********************************************************************
+ * construct_printer_info2
+ * fill a spoolss_PrinterInfo2 struct
+********************************************************************/
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo2 *r,
+                                     int snum)
+{
+       int count;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       print_status_struct status;
+
+       count = print_queue_length(snum, &status);
+
+       r->servername           = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->servername);
+       r->printername          = talloc_strdup(mem_ctx, ntprinter->info_2->printername);
+       W_ERROR_HAVE_NO_MEMORY(r->printername);
+       r->sharename            = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->sharename);
+       r->portname             = talloc_strdup(mem_ctx, ntprinter->info_2->portname);
+       W_ERROR_HAVE_NO_MEMORY(r->portname);
+       r->drivername           = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
+       W_ERROR_HAVE_NO_MEMORY(r->drivername);
+
+       if (*ntprinter->info_2->comment == '\0') {
+               r->comment      = talloc_strdup(mem_ctx, lp_comment(snum));
+       } else {
+               r->comment      = talloc_strdup(mem_ctx, ntprinter->info_2->comment);
        }
+       W_ERROR_HAVE_NO_MEMORY(r->comment);
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_printer_info_1("", buffer, &printers[i], 0);
+       r->location             = talloc_strdup(mem_ctx, ntprinter->info_2->location);
+       W_ERROR_HAVE_NO_MEMORY(r->location);
+       r->sepfile              = talloc_strdup(mem_ctx, ntprinter->info_2->sepfile);
+       W_ERROR_HAVE_NO_MEMORY(r->sepfile);
+       r->printprocessor       = talloc_strdup(mem_ctx, ntprinter->info_2->printprocessor);
+       W_ERROR_HAVE_NO_MEMORY(r->printprocessor);
+       r->datatype             = talloc_strdup(mem_ctx, ntprinter->info_2->datatype);
+       W_ERROR_HAVE_NO_MEMORY(r->datatype);
+       r->parameters           = talloc_strdup(mem_ctx, ntprinter->info_2->parameters);
+       W_ERROR_HAVE_NO_MEMORY(r->parameters);
 
-out:
-       /* clear memory */
+       r->attributes           = ntprinter->info_2->attributes;
 
-       SAFE_FREE(printers);
+       r->priority             = ntprinter->info_2->priority;
+       r->defaultpriority      = ntprinter->info_2->default_priority;
+       r->starttime            = ntprinter->info_2->starttime;
+       r->untiltime            = ntprinter->info_2->untiltime;
+       r->status               = nt_printq_status(status.status);
+       r->cjobs                = count;
+       r->averageppm           = ntprinter->info_2->averageppm;
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       r->devmode = construct_dev_mode_new(mem_ctx, lp_const_servicename(snum));
+       if (!r->devmode) {
+               DEBUG(8,("Returning NULL Devicemode!\n"));
+       }
 
-       return result;
-}
+       r->secdesc              = NULL;
 
-/********************************************************************
- enum_all_printers_info_1_local.
-*********************************************************************/
+       if (ntprinter->info_2->secdesc_buf && ntprinter->info_2->secdesc_buf->sd_size != 0) {
+               /* don't use talloc_steal() here unless you do a deep steal of all
+                  the SEC_DESC members */
 
-static WERROR enum_all_printers_info_1_local(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
-{
-       DEBUG(4,("enum_all_printers_info_1_local\n"));
+               r->secdesc      = dup_sec_desc(mem_ctx, ntprinter->info_2->secdesc_buf->sd);
+       }
 
-       return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+       return WERR_OK;
 }
 
 /********************************************************************
- enum_all_printers_info_1_name.
-*********************************************************************/
+********************************************************************/
 
-static WERROR enum_all_printers_info_1_name(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static bool snum_is_shared_printer(int snum)
 {
-       char *s = name;
-
-       DEBUG(4,("enum_all_printers_info_1_name\n"));
-
-       if ((name[0] == '\\') && (name[1] == '\\'))
-               s = name + 2;
-
-       if (is_myname_or_ipaddr(s)) {
-               return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
-       }
-       else
-               return WERR_INVALID_NAME;
+       return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
 }
 
-#if 0  /* JERRY -- disabled for now.  Don't think this is used, tested, or correct */
 /********************************************************************
enum_all_printers_info_1_remote.
-*********************************************************************/
Spoolss_enumprinters.
+********************************************************************/
 
-static WERROR enum_all_printers_info_1_remote(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
+                                      uint32_t flags,
+                                      union spoolss_PrinterInfo **info_p,
+                                      uint32_t *count)
 {
-       PRINTER_INFO_1 *printer;
-       fstring printername;
-       fstring desc;
-       fstring comment;
-       DEBUG(4,("enum_all_printers_info_1_remote\n"));
+       int snum;
+       int n_services = lp_numservices();
+       union spoolss_PrinterInfo *info = NULL;
+       WERROR result = WERR_OK;
+
+       DEBUG(4,("enum_all_printers_info_1\n"));
+
+       *count = 0;
+
+       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));
+
+               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
+
+               result = construct_printer_info1(info, ntprinter, flags, &info1, 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_1: failed to enlarge printers buffer!\n"));
+                       result = WERR_NOMEM;
+                       goto out;
+               }
+
+               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_1\n", *count));
+
+               info[*count].info1 = info1;
+               (*count)++;
+       }
+
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
+
+       *info_p = info;
+
+       return WERR_OK;
+}
+
+/********************************************************************
+ enum_all_printers_info_1_local.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_local(TALLOC_CTX *mem_ctx,
+                                            union spoolss_PrinterInfo **info,
+                                            uint32_t *count)
+{
+       DEBUG(4,("enum_all_printers_info_1_local\n"));
+
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_ICON8, info, count);
+}
+
+/********************************************************************
+ enum_all_printers_info_1_name.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_name(TALLOC_CTX *mem_ctx,
+                                           const char *name,
+                                           union spoolss_PrinterInfo **info,
+                                           uint32_t *count)
+{
+       const char *s = name;
+
+       DEBUG(4,("enum_all_printers_info_1_name\n"));
+
+       if ((name[0] == '\\') && (name[1] == '\\')) {
+               s = name + 2;
+       }
+
+       if (!is_myname_or_ipaddr(s)) {
+               return WERR_INVALID_NAME;
+       }
+
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_ICON8, info, count);
+}
+
+#if 0  /* JERRY -- disabled for now.  Don't think this is used, tested, or correct */
+/********************************************************************
+ enum_all_printers_info_1_remote.
+*********************************************************************/
+
+static WERROR enum_all_printers_info_1_remote(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+{
+       PRINTER_INFO_1 *printer;
+       fstring printername;
+       fstring desc;
+       fstring comment;
+       DEBUG(4,("enum_all_printers_info_1_remote\n"));
        WERROR result = WERR_OK;
 
        /* JFM: currently it's more a place holder than anything else.
@@ -4533,9 +4628,12 @@ out:
  enum_all_printers_info_1_network.
 *********************************************************************/
 
-static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1_network(TALLOC_CTX *mem_ctx,
+                                              const char *name,
+                                              union spoolss_PrinterInfo **info,
+                                              uint32_t *count)
 {
-       char *s = name;
+       const char *s = name;
 
        DEBUG(4,("enum_all_printers_info_1_network\n"));
 
@@ -4547,13 +4645,15 @@ static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer,
           listed. Windows responds to this call with a
           WERR_CAN_NOT_COMPLETE so we should do the same. */
 
-       if (name[0] == '\\' && name[1] == '\\')
+       if (name[0] == '\\' && name[1] == '\\') {
                 s = name + 2;
+       }
 
-       if (is_myname_or_ipaddr(s))
+       if (is_myname_or_ipaddr(s)) {
                 return WERR_CAN_NOT_COMPLETE;
+       }
 
-       return enum_all_printers_info_1(PRINTER_ENUM_NAME, buffer, offered, needed, returned);
+       return enum_all_printers_info_1(mem_ctx, PRINTER_ENUM_NAME, info, count);
 }
 
 /********************************************************************
@@ -4562,92 +4662,96 @@ static WERROR enum_all_printers_info_1_network(fstring name, RPC_BUFFER *buffer,
  * called from api_spoolss_enumprinters (see this to understand)
  ********************************************************************/
 
-static WERROR enum_all_printers_info_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_2(TALLOC_CTX *mem_ctx,
+                                      union spoolss_PrinterInfo **info_p,
+                                      uint32_t *count)
 {
        int snum;
-       int i;
-       int n_services=lp_numservices();
-       PRINTER_INFO_2 *printers=NULL;
-       PRINTER_INFO_2 current_prt;
+       int n_services = lp_numservices();
+       union spoolss_PrinterInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned = 0;
+       *count = 0;
 
        for (snum=0; snum<n_services; snum++) {
-               if (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) ) {
-                       DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
-
-                       if (construct_printer_info_2(NULL, &current_prt, snum)) {
-                               if ( !(printers=SMB_REALLOC_ARRAY(printers, PRINTER_INFO_2, *returned +1)) ) {
-                                       DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
-                                       *returned = 0;
-                                       return WERR_NOMEM;
-                               }
 
-                               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *returned + 1));
+               struct spoolss_PrinterInfo2 info2;
+               NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
 
-                               memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_2));
-
-                               (*returned)++;
-                       }
+               if (!snum_is_shared_printer(snum)) {
+                       continue;
                }
-       }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_printer_info_2(&printers[i]);
+               DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", lp_servicename(snum), snum));
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+               result = get_a_printer(NULL, &ntprinter, 2, lp_const_servicename(snum));
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+               result = construct_printer_info2(info, ntprinter, &info2, snum);
+               free_a_printer(&ntprinter, 2);
+               if (!W_ERROR_IS_OK(result)) {
+                       continue;
+               }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_printer_info_2("", buffer, &(printers[i]), 0);
+               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;
+               }
 
-out:
-       /* clear memory */
+               DEBUG(4,("ReAlloced memory for [%d] PRINTER_INFO_2\n", *count + 1));
 
-       for (i=0; i<*returned; i++)
-               free_devmode(printers[i].devmode);
+               info[*count].info2 = info2;
 
-       SAFE_FREE(printers);
+               (*count)++;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       return result;
+       *info_p = info;
+
+       return WERR_OK;
 }
 
 /********************************************************************
  * handle enumeration of printers at level 1
  ********************************************************************/
 
-static WERROR enumprinters_level1( uint32 flags, fstring name,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level1(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *name,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
        /* Not all the flags are equals */
 
-       if (flags & PRINTER_ENUM_LOCAL)
-               return enum_all_printers_info_1_local(buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_LOCAL) {
+               return enum_all_printers_info_1_local(mem_ctx, info, count);
+       }
 
-       if (flags & PRINTER_ENUM_NAME)
-               return enum_all_printers_info_1_name(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_NAME) {
+               return enum_all_printers_info_1_name(mem_ctx, name, info, count);
+       }
 
 #if 0  /* JERRY - disabled for now */
-       if (flags & PRINTER_ENUM_REMOTE)
-               return enum_all_printers_info_1_remote(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_REMOTE) {
+               return enum_all_printers_info_1_remote(mem_ctx, name, info, count);
+       }
 #endif
 
-       if (flags & PRINTER_ENUM_NETWORK)
-               return enum_all_printers_info_1_network(name, buffer, offered, needed, returned);
+       if (flags & PRINTER_ENUM_NETWORK) {
+               return enum_all_printers_info_1_network(mem_ctx, name, info, count);
+       }
 
        return WERR_OK; /* NT4sp5 does that */
 }
@@ -4656,23 +4760,27 @@ static WERROR enumprinters_level1( uint32 flags, fstring name,
  * handle enumeration of printers at level 2
  ********************************************************************/
 
-static WERROR enumprinters_level2( uint32 flags, const char *servername,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level2(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
        if (flags & PRINTER_ENUM_LOCAL) {
-                       return enum_all_printers_info_2(buffer, offered, needed, returned);
+               return enum_all_printers_info_2(mem_ctx, info, count);
        }
 
        if (flags & PRINTER_ENUM_NAME) {
-               if (is_myname_or_ipaddr(canon_servername(servername)))
-                       return enum_all_printers_info_2(buffer, offered, needed, returned);
-               else
+               if (!is_myname_or_ipaddr(canon_servername(servername))) {
                        return WERR_INVALID_NAME;
+               }
+
+               return enum_all_printers_info_2(mem_ctx, info, count);
        }
 
-       if (flags & PRINTER_ENUM_REMOTE)
+       if (flags & PRINTER_ENUM_REMOTE) {
                return WERR_UNKNOWN_LEVEL;
+       }
 
        return WERR_OK;
 }
@@ -4681,49 +4789,37 @@ static WERROR enumprinters_level2( uint32 flags, const char *servername,
  * handle enumeration of printers at level 5
  ********************************************************************/
 
-static WERROR enumprinters_level5( uint32 flags, const char *servername,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed, uint32 *returned)
+static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx,
+                                 uint32_t flags,
+                                 const char *servername,
+                                 union spoolss_PrinterInfo **info,
+                                 uint32_t *count)
 {
-/*     return enum_all_printers_info_5(buffer, offered, needed, returned);*/
+/*     return enum_all_printers_info_5(mem_ctx, info, offered, needed, count);*/
        return WERR_OK;
 }
 
-/********************************************************************
- * api_spoolss_enumprinters
- *
- * called from api_spoolss_enumprinters (see this to understand)
- ********************************************************************/
+/****************************************************************
+ _spoolss_EnumPrinters
+****************************************************************/
 
-WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_R_ENUMPRINTERS *r_u)
+WERROR _spoolss_EnumPrinters(pipes_struct *p,
+                            struct spoolss_EnumPrinters *r)
 {
-       uint32 flags = q_u->flags;
-       UNISTR2 *servername = &q_u->servername;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
-
-       fstring name;
+       const char *name;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
-       }
-
-       if (offered > MAX_RPC_DATA_SIZE) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(4,("_spoolss_enumprinters\n"));
+       DEBUG(4,("_spoolss_EnumPrinters\n"));
 
-       *needed=0;
-       *returned=0;
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
        /*
         * Level 1:
@@ -4738,392 +4834,376 @@ WERROR _spoolss_enumprinters( pipes_struct *p, SPOOL_Q_ENUMPRINTERS *q_u, SPOOL_
         * Level 5: same as Level 2
         */
 
-       unistr2_to_ascii(name, servername, sizeof(name));
-       strupper_m(name);
+       name = talloc_strdup_upper(p->mem_ctx, r->in.server);
+       W_ERROR_HAVE_NO_MEMORY(name);
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprinters_level1(flags, name, buffer, offered, needed, returned);
+               result = enumprinters_level1(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 2:
-               return enumprinters_level2(flags, name, buffer, offered, needed, returned);
+               result = enumprinters_level2(p->mem_ctx, r->in.flags, name,
+                                            r->out.info, r->out.count);
+               break;
        case 5:
-               return enumprinters_level5(flags, name, buffer, offered, needed, returned);
+               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;
-       }
-       return WERR_UNKNOWN_LEVEL;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_0(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_0 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_0)) == NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_0(print_hnd, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_0(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       default:
+               return WERR_UNKNOWN_LEVEL;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_0("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-
-       SAFE_FREE(printer);
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrinters, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
 
-       return result;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinter
+****************************************************************/
 
-static WERROR getprinter_level_1(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+WERROR _spoolss_GetPrinter(pipes_struct *p,
+                          struct spoolss_GetPrinter *r)
 {
-       PRINTER_INFO_1 *printer=NULL;
+       Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
+       NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        WERROR result = WERR_OK;
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_1(printer);
+       int snum;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       /* that's an [in out] buffer */
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (!r->in.buffer && (r->in.offered != 0)) {
+               return WERR_INVALID_PARAM;
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_1("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(printer);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_2(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_2 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_2))==NULL)
-               return WERR_NOMEM;
-
-       construct_printer_info_2(print_hnd, printer, snum);
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_2(printer);
+       *r->out.needed = 0;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
+               return WERR_BADFID;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       result = get_a_printer(Printer, &ntprinter, 2,
+                              lp_const_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       if (!smb_io_printer_info_2("", buffer, printer, 0))
-               result = WERR_NOMEM;
-
-out:
-       /* clear memory */
-       free_printer_info_2(printer);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_3(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_3 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if (!construct_printer_info_3(print_hnd, &printer, snum))
-               return WERR_NOMEM;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_3(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       switch (r->in.level) {
+       case 0:
+               result = construct_printer_info0(p->mem_ctx, ntprinter,
+                                                &r->out.info->info0, snum);
+               break;
+       case 1:
+               result = construct_printer_info1(p->mem_ctx, ntprinter,
+                                                PRINTER_ENUM_ICON8,
+                                                &r->out.info->info1, snum);
+               break;
+       case 2:
+               result = construct_printer_info2(p->mem_ctx, ntprinter,
+                                                &r->out.info->info2, snum);
+               break;
+       case 3:
+               result = construct_printer_info3(p->mem_ctx, ntprinter,
+                                                &r->out.info->info3, snum);
+               break;
+       case 4:
+               result = construct_printer_info4(p->mem_ctx, ntprinter,
+                                                &r->out.info->info4, snum);
+               break;
+       case 5:
+               result = construct_printer_info5(p->mem_ctx, ntprinter,
+                                                &r->out.info->info5, snum);
+               break;
+       case 6:
+               result = construct_printer_info6(p->mem_ctx, ntprinter,
+                                                &r->out.info->info6, snum);
+               break;
+       case 7:
+               result = construct_printer_info7(p->mem_ctx, Printer,
+                                                &r->out.info->info7, snum);
+               break;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+       free_a_printer(&ntprinter, 2);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_3("", buffer, printer, 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
 
-out:
-       /* clear memory */
-       free_printer_info_3(printer);
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_PrinterInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       return result;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ ********************************************************************/
 
-static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+static const char **string_array_from_driver_info(TALLOC_CTX *mem_ctx,
+                                                 fstring *fstring_array,
+                                                 const char *cservername)
 {
-       PRINTER_INFO_4 *printer=NULL;
-       WERROR result = WERR_OK;
+       int i, num_strings = 0;
+       const char **array = NULL;
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_4))==NULL)
-               return WERR_NOMEM;
+       for (i=0; fstring_array && fstring_array[i][0] != '\0'; i++) {
 
-       if (!construct_printer_info_4(print_hnd, printer, snum)) {
-               SAFE_FREE(printer);
-               return WERR_NOMEM;
-       }
+               const char *str = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                                                 cservername, fstring_array[i]);
+               if (!str) {
+                       TALLOC_FREE(array);
+                       return NULL;
+               }
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_4(printer);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+               if (!add_string_to_array(mem_ctx, str, &array, &num_strings)) {
+                       TALLOC_FREE(array);
+                       return NULL;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (i > 0) {
+               ADD_TO_ARRAY(mem_ctx, const char *, NULL,
+                            &array, &num_strings);
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_4("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_4(printer);
-
-       return result;
+       return array;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * fill a spoolss_DriverInfo1 struct
+ ********************************************************************/
 
-static WERROR getprinter_level_5(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo1 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername,
+                                       const char *architecture)
 {
-       PRINTER_INFO_5 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_5))==NULL)
-               return WERR_NOMEM;
-
-       if (!construct_printer_info_5(print_hnd, printer, snum)) {
-               free_printer_info_5(printer);
-               return WERR_NOMEM;
-       }
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_5(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_5("", buffer, printer, 0);
+       return WERR_OK;
+}
 
-out:
-       /* clear memory */
-       free_printer_info_5(printer);
+/********************************************************************
+ * fill a spoolss_DriverInfo2 struct
+ ********************************************************************/
 
-       return result;
-}
+static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo2 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 
-static WERROR getprinter_level_6(Printer_entry *print_hnd,
-                                int snum,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed)
 {
-       PRINTER_INFO_6 *printer;
-       WERROR result = WERR_OK;
-
-       if ((printer = SMB_MALLOC_P(PRINTER_INFO_6)) == NULL) {
-               return WERR_NOMEM;
-       }
+       const char *cservername = canon_servername(servername);
 
-       if (!construct_printer_info_6(print_hnd, printer, snum)) {
-               free_printer_info_6(printer);
-               return WERR_NOMEM;
-       }
+       r->version              = driver->info_3->cversion;
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_6(printer);
+       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 (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       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 (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       if (strlen(driver->info_3->datafile)) {
+               r->data_file    = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->datafile);
+       } else {
+               r->data_file    = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->data_file);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_6("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_6(printer);
+       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;
+       return WERR_OK;
 }
 
-static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+/********************************************************************
+ * fill a spoolss_DriverInfo3 struct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo3 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 {
-       PRINTER_INFO_7 *printer=NULL;
-       WERROR result = WERR_OK;
+       const char *cservername = canon_servername(servername);
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_7))==NULL)
-               return WERR_NOMEM;
+       r->version              = driver->info_3->cversion;
 
-       if (!construct_printer_info_7(print_hnd, printer, snum)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+       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);
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_7(printer);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       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 (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       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);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_7("", buffer, printer, 0);
+       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->config_file);
 
-out:
-       /* clear memory */
-       free_printer_info_7(printer);
+       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);
 
-       return result;
+       r->dependent_files = string_array_from_driver_info(mem_ctx,
+                                                          driver->info_3->dependentfiles,
+                                                          cservername);
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * fill a spoolss_DriverInfo6 struct
+ ********************************************************************/
 
-WERROR _spoolss_getprinter(pipes_struct *p, SPOOL_Q_GETPRINTER *q_u, SPOOL_R_GETPRINTER *r_u)
+static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo6 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
+       const char *cservername = canon_servername(servername);
 
-       int snum;
+       r->version              = driver->info_3->cversion;
 
-       /* that's an [in out] buffer */
+       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 (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
+       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 (offered > MAX_RPC_DATA_SIZE) {
-               return WERR_INVALID_PARAM;
+       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);
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       *needed=0;
-
-       if (!get_printer_snum(p, handle, &snum, NULL))
-               return WERR_BADFID;
+       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);
 
-       switch (level) {
-       case 0:
-               return getprinter_level_0(Printer, snum, buffer, offered, needed);
-       case 1:
-               return getprinter_level_1(Printer, snum, buffer, offered, needed);
-       case 2:
-               return getprinter_level_2(Printer, snum, buffer, offered, needed);
-       case 3:
-               return getprinter_level_3(Printer, snum, buffer, offered, needed);
-       case 4:
-               return getprinter_level_4(Printer, snum, buffer, offered, needed);
-       case 5:
-               return getprinter_level_5(Printer, snum, buffer, offered, needed);
-       case 6:
-               return getprinter_level_6(Printer, snum, buffer, offered, needed);
-       case 7:
-               return getprinter_level_7(Printer, snum, buffer, offered, needed);
+       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, "");
        }
-       return WERR_UNKNOWN_LEVEL;
-}
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-/********************************************************************
- * fill a DRIVER_INFO_1 struct
- ********************************************************************/
+       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);
 
-static void fill_printer_driver_info_1(DRIVER_INFO_1 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername, fstring architecture)
-{
-       init_unistr( &info->name, driver.info_3->name);
+       return WERR_OK;
 }
 
 /********************************************************************
  * construct_printer_driver_info_1
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, const char *servername, fstring architecture, uint32 version)
+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);
 
@@ -5132,61 +5212,14 @@ static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, con
 
        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;
-       }
-
-       fill_printer_driver_info_1(info, driver, servername, architecture);
-
-       free_a_printer(&printer,2);
-
-       return WERR_OK;
-}
-
-/********************************************************************
- * construct_printer_driver_info_2
- * fill a printer_info_2 struct
- ********************************************************************/
-
-static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
-{
-       TALLOC_CTX *ctx = talloc_tos();
-       char *temp = NULL;
-       const char *cservername = canon_servername(servername);
+               return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
 
-       info->version=driver.info_3->cversion;
+       result = fill_printer_driver_info1(mem_ctx, r, &driver, servername, architecture);
 
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
+       free_a_printer(&printer,2);
 
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else {
-               init_unistr( &info->driverpath, "" );
-       }
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
+       return result;
 }
 
 /********************************************************************
@@ -5194,10 +5227,16 @@ static void fill_printer_driver_info_2(DRIVER_INFO_2 *info, NT_PRINTER_DRIVER_IN
  * fill a printer_info_2 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, const char *servername, fstring architecture, uint32 version)
+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);
@@ -5210,11 +5249,11 @@ static WERROR construct_printer_driver_info_2(DRIVER_INFO_2 *info, int snum, con
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       fill_printer_driver_info_2(info, driver, servername);
+       result = fill_printer_driver_info2(mem_ctx, r, &driver, servername);
 
        free_a_printer(&printer,2);
 
-       return WERR_OK;
+       return result;
 }
 
 /********************************************************************
@@ -5295,72 +5334,12 @@ static uint32 init_unistr_array(uint16 **uni_array, fstring *char_array, const c
  * fill a printer_info_3 struct
  ********************************************************************/
 
-static void fill_printer_driver_info_3(DRIVER_INFO_3 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
-{
-       char *temp = NULL;
-       TALLOC_CTX *ctx = talloc_tos();
-       const char *cservername = canon_servername(servername);
-
-       ZERO_STRUCTP(info);
-
-       info->version=driver.info_3->cversion;
-
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
-
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else
-               init_unistr( &info->driverpath, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->helpfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->helpfile);
-               init_unistr( &info->helpfile, temp );
-       } else
-               init_unistr( &info->helpfile, "" );
-
-       TALLOC_FREE(temp);
-       init_unistr( &info->monitorname, driver.info_3->monitorname );
-       init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
-
-       info->dependentfiles=NULL;
-       init_unistr_array(&info->dependentfiles, driver.info_3->dependentfiles, cservername);
-}
-
-/********************************************************************
- * construct_printer_info_3
- * fill a printer_info_3 struct
- ********************************************************************/
-
-static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, const char *servername, fstring architecture, uint32 version)
+static WERROR construct_printer_driver_info_3(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo3 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
@@ -5407,92 +5386,11 @@ static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, con
 #endif
 
 
-       fill_printer_driver_info_3(info, driver, servername);
+       status = fill_printer_driver_info3(mem_ctx, r, &driver, servername);
 
        free_a_printer(&printer,2);
 
-       return WERR_OK;
-}
-
-/********************************************************************
- * construct_printer_info_6
- * fill a printer_info_6 struct - we know that driver is really level 3. This sucks. JRA.
- ********************************************************************/
-
-static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_INFO_LEVEL driver, const char *servername)
-{
-       char *temp = NULL;
-       fstring nullstr;
-       TALLOC_CTX *ctx = talloc_tos();
-       const char *cservername = canon_servername(servername);
-
-       ZERO_STRUCTP(info);
-       memset(&nullstr, '\0', sizeof(fstring));
-
-       info->version=driver.info_3->cversion;
-
-       init_unistr( &info->name, driver.info_3->name );
-       init_unistr( &info->architecture, driver.info_3->environment );
-
-       if (strlen(driver.info_3->driverpath)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->driverpath);
-               init_unistr( &info->driverpath, temp );
-       } else
-               init_unistr( &info->driverpath, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->datafile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->datafile);
-               init_unistr( &info->datafile, temp );
-       } else
-               init_unistr( &info->datafile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->configfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->configfile);
-               init_unistr( &info->configfile, temp );
-       } else
-               init_unistr( &info->configfile, "" );
-
-       TALLOC_FREE(temp);
-       if (strlen(driver.info_3->helpfile)) {
-               temp = talloc_asprintf(ctx,
-                               "\\\\%s%s",
-                               cservername,
-                               driver.info_3->helpfile);
-               init_unistr( &info->helpfile, temp );
-       } else
-               init_unistr( &info->helpfile, "" );
-
-       TALLOC_FREE(temp);
-       init_unistr( &info->monitorname, driver.info_3->monitorname );
-       init_unistr( &info->defaultdatatype, driver.info_3->defaultdatatype );
-
-       info->dependentfiles = NULL;
-       init_unistr_array( &info->dependentfiles, driver.info_3->dependentfiles, servername );
-
-       info->previousdrivernames=NULL;
-       init_unistr_array(&info->previousdrivernames, &nullstr, servername);
-
-       info->driver_date=0;
-
-       info->padding=0;
-       info->driver_version_low=0;
-       info->driver_version_high=0;
-
-       init_unistr( &info->mfgname, "");
-       init_unistr( &info->oem_url, "");
-       init_unistr( &info->hardware_id, "");
-       init_unistr( &info->provider, "");
+       return status;
 }
 
 /********************************************************************
@@ -5500,8 +5398,12 @@ static void fill_printer_driver_info_6(DRIVER_INFO_6 *info, NT_PRINTER_DRIVER_IN
  * fill a printer_info_6 struct
  ********************************************************************/
 
-static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
-              const char *servername, fstring architecture, uint32 version)
+static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
+                                             struct spoolss_DriverInfo6 *r,
+                                             int snum,
+                                             const char *servername,
+                                             const char *architecture,
+                                             uint32_t version)
 {
        NT_PRINTER_INFO_LEVEL           *printer = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL    driver;
@@ -5541,246 +5443,104 @@ static WERROR construct_printer_driver_info_6(DRIVER_INFO_6 *info, int snum,
                }
        }
 
-       fill_printer_driver_info_6(info, driver, servername);
+       status = fill_printer_driver_info6(mem_ctx, r, &driver, servername);
 
        free_a_printer(&printer,2);
        free_a_printer_driver(driver, 3);
 
-       return WERR_OK;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static void free_printer_driver_info_3(DRIVER_INFO_3 *info)
-{
-       SAFE_FREE(info->dependentfiles);
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static void free_printer_driver_info_6(DRIVER_INFO_6 *info)
-{
-       SAFE_FREE(info->dependentfiles);
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level1(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_1 *info=NULL;
-       WERROR result;
-
-       if((info=SMB_MALLOC_P(DRIVER_INFO_1)) == NULL)
-               return WERR_NOMEM;
-
-       result = construct_printer_driver_info_1(info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_1(info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_1("", buffer, info, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level2(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_2 *info=NULL;
-       WERROR result;
-
-       if((info=SMB_MALLOC_P(DRIVER_INFO_2)) == NULL)
-               return WERR_NOMEM;
-
-       result = construct_printer_driver_info_2(info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_2(info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_2("", buffer, info, 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level3(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_3 info;
-       WERROR result;
-
-       ZERO_STRUCT(info);
-
-       result = construct_printer_driver_info_3(&info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_3(&info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_3("", buffer, &info, 0);
-
-out:
-       free_printer_driver_info_3(&info);
-
-       return result;
-}
-
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinterdriver2_level6(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       DRIVER_INFO_6 info;
-       WERROR result;
-
-       ZERO_STRUCT(info);
-
-       result = construct_printer_driver_info_6(&info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_6(&info);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_6("", buffer, &info, 0);
-
-out:
-       free_printer_driver_info_6(&info);
-
-       return result;
+       return status;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinterDriver2
+****************************************************************/
 
-WERROR _spoolss_getprinterdriver2(pipes_struct *p, SPOOL_Q_GETPRINTERDRIVER2 *q_u, SPOOL_R_GETPRINTERDRIVER2 *r_u)
+WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
+                                 struct spoolss_GetPrinterDriver2 *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       UNISTR2 *uni_arch = &q_u->architecture;
-       uint32 level = q_u->level;
-       uint32 clientmajorversion = q_u->clientmajorversion;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *servermajorversion = &r_u->servermajorversion;
-       uint32 *serverminorversion = &r_u->serverminorversion;
        Printer_entry *printer;
+       WERROR result;
 
-       fstring servername;
-       fstring architecture;
+       const char *servername;
        int snum;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
-       }
-
-       if (offered > MAX_RPC_DATA_SIZE) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(4,("_spoolss_getprinterdriver2\n"));
+       DEBUG(4,("_spoolss_GetPrinterDriver2\n"));
 
-       if ( !(printer = find_printer_index_by_hnd( p, handle )) ) {
-               DEBUG(0,("_spoolss_getprinterdriver2: invalid printer handle!\n"));
+       if (!(printer = find_printer_index_by_hnd( p, r->in.handle))) {
+               DEBUG(0,("_spoolss_GetPrinterDriver2: invalid printer handle!\n"));
                return WERR_INVALID_PRINTER_NAME;
        }
 
-       *needed = 0;
-       *servermajorversion = 0;
-       *serverminorversion = 0;
+       *r->out.needed = 0;
+       *r->out.server_major_version = 0;
+       *r->out.server_minor_version = 0;
 
-       fstrcpy(servername, get_server_name( printer ));
-       unistr2_to_ascii(architecture, uni_arch, sizeof(architecture));
+       servername = get_server_name(printer);
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return getprinterdriver2_level1(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_1(p->mem_ctx,
+                                                        &r->out.info->info1,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 2:
-               return getprinterdriver2_level2(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_2(p->mem_ctx,
+                                                        &r->out.info->info2,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 3:
-               return getprinterdriver2_level3(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_3(p->mem_ctx,
+                                                        &r->out.info->info3,
+                                                        snum,
+                                                        servername,
+                                                        r->in.architecture,
+                                                        r->in.client_major_version);
+               break;
        case 6:
-               return getprinterdriver2_level6(servername, architecture, clientmajorversion, snum, buffer, offered, needed);
+               result = construct_printer_driver_info_6(p->mem_ctx,
+                                                        &r->out.info->info6,
+                                                        snum,
+                                                        servername,
+                                                        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 */
                break;
 #endif
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
-       return WERR_UNKNOWN_LEVEL;
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_DriverInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 
@@ -6636,251 +6396,276 @@ WERROR _spoolss_AddJob(pipes_struct *p,
 }
 
 /****************************************************************************
+fill_job_info1
 ****************************************************************************/
 
-static void fill_job_info_1(JOB_INFO_1 *job_info, const print_queue_struct *queue,
-                            int position, int snum,
-                            const NT_PRINTER_INFO_LEVEL *ntprinter)
+static WERROR fill_job_info1(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo1 *r,
+                            const print_queue_struct *queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter)
 {
        struct tm *t;
 
-       t=gmtime(&queue->time);
+       t = gmtime(&queue->time);
 
-       job_info->jobid=queue->job;
-       init_unistr(&job_info->printername, lp_servicename(snum));
-       init_unistr(&job_info->machinename, ntprinter->info_2->servername);
-       init_unistr(&job_info->username, queue->fs_user);
-       init_unistr(&job_info->document, queue->fs_file);
-       init_unistr(&job_info->datatype, "RAW");
-       init_unistr(&job_info->text_status, "");
-       job_info->status=nt_printj_status(queue->status);
-       job_info->priority=queue->priority;
-       job_info->position=position;
-       job_info->totalpages=queue->page_count;
-       job_info->pagesprinted=0;
+       r->job_id               = queue->job;
 
-       make_systemtime(&job_info->submitted, t);
+       r->printer_name         = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->printer_name);
+       r->server_name          = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->server_name);
+       r->user_name            = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->user_name);
+       r->document_name        = talloc_strdup(mem_ctx, queue->fs_file);
+       W_ERROR_HAVE_NO_MEMORY(r->document_name);
+       r->data_type            = talloc_strdup(mem_ctx, "RAW");
+       W_ERROR_HAVE_NO_MEMORY(r->data_type);
+       r->text_status          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->text_status);
+
+       r->status               = nt_printj_status(queue->status);
+       r->priority             = queue->priority;
+       r->position             = position;
+       r->total_pages          = queue->page_count;
+       r->pages_printed        = 0; /* ??? */
+
+       init_systemtime(&r->submitted, t);
+
+       return WERR_OK;
 }
 
 /****************************************************************************
+fill_job_info2
 ****************************************************************************/
 
-static bool fill_job_info_2(JOB_INFO_2 *job_info, const print_queue_struct *queue,
-                            int position, int snum,
-                           const NT_PRINTER_INFO_LEVEL *ntprinter,
-                           DEVICEMODE *devmode)
+static WERROR fill_job_info2(TALLOC_CTX *mem_ctx,
+                            struct spoolss_JobInfo2 *r,
+                            const print_queue_struct *queue,
+                            int position, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            struct spoolss_DeviceMode *devmode)
 {
        struct tm *t;
 
-       t=gmtime(&queue->time);
-
-       job_info->jobid=queue->job;
-
-       init_unistr(&job_info->printername, ntprinter->info_2->printername);
-
-       init_unistr(&job_info->machinename, ntprinter->info_2->servername);
-       init_unistr(&job_info->username, queue->fs_user);
-       init_unistr(&job_info->document, queue->fs_file);
-       init_unistr(&job_info->notifyname, queue->fs_user);
-       init_unistr(&job_info->datatype, "RAW");
-       init_unistr(&job_info->printprocessor, "winprint");
-       init_unistr(&job_info->parameters, "");
-       init_unistr(&job_info->drivername, ntprinter->info_2->drivername);
-       init_unistr(&job_info->text_status, "");
+       t = gmtime(&queue->time);
+
+       r->job_id               = queue->job;
+
+       r->printer_name         = talloc_strdup(mem_ctx, lp_servicename(snum));
+       W_ERROR_HAVE_NO_MEMORY(r->printer_name);
+       r->server_name          = talloc_strdup(mem_ctx, ntprinter->info_2->servername);
+       W_ERROR_HAVE_NO_MEMORY(r->server_name);
+       r->user_name            = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->user_name);
+       r->document_name        = talloc_strdup(mem_ctx, queue->fs_file);
+       W_ERROR_HAVE_NO_MEMORY(r->document_name);
+       r->notify_name          = talloc_strdup(mem_ctx, queue->fs_user);
+       W_ERROR_HAVE_NO_MEMORY(r->notify_name);
+       r->data_type            = talloc_strdup(mem_ctx, "RAW");
+       W_ERROR_HAVE_NO_MEMORY(r->data_type);
+       r->print_processor      = talloc_strdup(mem_ctx, "winprint");
+       W_ERROR_HAVE_NO_MEMORY(r->print_processor);
+       r->parameters           = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->parameters);
+       r->driver_name          = talloc_strdup(mem_ctx, ntprinter->info_2->drivername);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+
+       r->devmode              = devmode;
+
+       r->text_status          = talloc_strdup(mem_ctx, "");
+       W_ERROR_HAVE_NO_MEMORY(r->text_status);
+
+       r->secdesc              = NULL;
+
+       r->status               = nt_printj_status(queue->status);
+       r->priority             = queue->priority;
+       r->position             = position;
+       r->start_time           = 0;
+       r->until_time           = 0;
+       r->total_pages          = queue->page_count;
+       r->size                 = queue->size;
+       init_systemtime(&r->submitted, t);
+       r->time                 = 0;
+       r->pages_printed        = 0; /* ??? */
 
-/* and here the security descriptor */
-
-       job_info->status=nt_printj_status(queue->status);
-       job_info->priority=queue->priority;
-       job_info->position=position;
-       job_info->starttime=0;
-       job_info->untiltime=0;
-       job_info->totalpages=queue->page_count;
-       job_info->size=queue->size;
-       make_systemtime(&(job_info->submitted), t);
-       job_info->timeelapsed=0;
-       job_info->pagesprinted=0;
-
-       job_info->devmode = devmode;
-
-       return (True);
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumjobs at level 1.
 ****************************************************************************/
 
-static WERROR enumjobs_level1(const print_queue_struct *queue, int snum,
+static WERROR enumjobs_level1(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
                               const NT_PRINTER_INFO_LEVEL *ntprinter,
-                             RPC_BUFFER *buffer, uint32 offered,
-                             uint32 *needed, uint32 *returned)
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
 {
-       JOB_INFO_1 *info;
+       union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
 
-       info=SMB_MALLOC_ARRAY(JOB_INFO_1,*returned);
-       if (info==NULL) {
-               *returned=0;
-               return WERR_NOMEM;
-       }
-
-       for (i=0; i<*returned; i++)
-               fill_job_info_1( &info[i], &queue[i], i, snum, ntprinter );
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_job_info_1(&info[i]);
+       *count = num_queues;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       for (i=0; i<*count; i++) {
+               result = fill_job_info1(info,
+                                       &info[i].info1,
+                                       &queue[i],
+                                       i,
+                                       snum,
+                                       ntprinter);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_job_info_1("", buffer, &info[i], 0);
-
-out:
-       /* clear memory */
-       SAFE_FREE(info);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumjobs at level 2.
 ****************************************************************************/
 
-static WERROR enumjobs_level2(const print_queue_struct *queue, int snum,
+static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx,
+                             const print_queue_struct *queue,
+                             uint32_t num_queues, int snum,
                               const NT_PRINTER_INFO_LEVEL *ntprinter,
-                             RPC_BUFFER *buffer, uint32 offered,
-                             uint32 *needed, uint32 *returned)
+                             union spoolss_JobInfo **info_p,
+                             uint32_t *count)
 {
-       JOB_INFO_2 *info = NULL;
+       union spoolss_JobInfo *info;
        int i;
        WERROR result = WERR_OK;
-       DEVICEMODE *devmode = NULL;
 
-       if ( !(info = SMB_MALLOC_ARRAY(JOB_INFO_2,*returned)) ) {
-               *returned=0;
-               return WERR_NOMEM;
-       }
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       /* this should not be a failure condition if the devmode is NULL */
+       *count = num_queues;
 
-       devmode = construct_dev_mode(lp_const_servicename(snum));
+       for (i=0; i<*count; i++) {
 
-       for (i=0; i<*returned; i++)
-               fill_job_info_2(&(info[i]), &queue[i], i, snum, ntprinter, devmode);
+               struct spoolss_DeviceMode *devmode;
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_job_info_2(&info[i]);
+               devmode = construct_dev_mode_new(info, lp_const_servicename(snum));
+               if (!devmode) {
+                       result = WERR_NOMEM;
+                       goto out;
+               }
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+               result = fill_job_info2(info,
+                                       &info[i].info2,
+                                       &queue[i],
+                                       i,
+                                       snum,
+                                       ntprinter,
+                                       devmode);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_job_info_2("", buffer, &info[i], 0);
-
-out:
-       free_devmode(devmode);
-       SAFE_FREE(info);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
-
-       return result;
+       *info_p = info;
 
+       return WERR_OK;
 }
 
-/****************************************************************************
- Enumjobs.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumJobs
+****************************************************************/
 
-WERROR _spoolss_enumjobs( pipes_struct *p, SPOOL_Q_ENUMJOBS *q_u, SPOOL_R_ENUMJOBS *r_u)
+WERROR _spoolss_EnumJobs(pipes_struct *p,
+                        struct spoolss_EnumJobs *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
-       WERROR wret;
+       WERROR result;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int snum;
        print_status_struct prt_status;
-       print_queue_struct *queue=NULL;
+       print_queue_struct *queue = NULL;
+       uint32_t count;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
-       }
-
-       if (offered > MAX_RPC_DATA_SIZE) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(4,("_spoolss_enumjobs\n"));
+       DEBUG(4,("_spoolss_EnumJobs\n"));
 
-       *needed=0;
-       *returned=0;
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
        /* lookup the printer snum and tdb entry */
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       wret = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
-       if ( !W_ERROR_IS_OK(wret) )
-               return wret;
+       result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-       *returned = print_queue_status(snum, &queue, &prt_status);
-       DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", *returned, prt_status.status, prt_status.message));
+       count = print_queue_status(snum, &queue, &prt_status);
+       DEBUGADD(4,("count:[%d], status:[%d], [%s]\n",
+               count, prt_status.status, prt_status.message));
 
-       if (*returned == 0) {
+       if (count == 0) {
                SAFE_FREE(queue);
                free_a_printer(&ntprinter, 2);
                return WERR_OK;
        }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               wret = enumjobs_level1(queue, snum, ntprinter, buffer, offered, needed, returned);
+               result = enumjobs_level1(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
                break;
        case 2:
-               wret = enumjobs_level2(queue, snum, ntprinter, buffer, offered, needed, returned);
+               result = enumjobs_level2(p->mem_ctx, queue, count, snum,
+                                        ntprinter, r->out.info, r->out.count);
                break;
        default:
-               *returned=0;
-               wret = WERR_UNKNOWN_LEVEL;
+               result = WERR_UNKNOWN_LEVEL;
                break;
        }
 
        SAFE_FREE(queue);
-       free_a_printer( &ntprinter, 2 );
-       return wret;
+       free_a_printer(&ntprinter, 2);
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumJobs, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************
@@ -6944,330 +6729,369 @@ WERROR _spoolss_SetJob(pipes_struct *p,
  Enumerates all printer drivers at level 1.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level1(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+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 version;
+       uint32_t version;
        fstring *list = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       DRIVER_INFO_1 *driver_info_1=NULL;
+       union spoolss_DriverInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *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));
+               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) {
-                       SAFE_FREE(driver_info_1);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_1=SMB_REALLOC_ARRAY(driver_info_1, DRIVER_INFO_1, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level1: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               if (ndrivers != 0) {
+                       info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+                                                   union spoolss_DriverInfo,
+                                                   *count + ndrivers);
+                       if (!info) {
+                               DEBUG(0,("enumprinterdrivers_level1: "
+                                       "failed to enlarge driver info buffer!\n"));
+                               result = WERR_NOMEM;
+                               goto out;
                        }
                }
 
                for (i=0; i<ndrivers; i++) {
-                       WERROR status;
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_1);
-                               return status;
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
+                       result = fill_printer_driver_info1(info, &info[*count+i].info1,
+                                                          &driver, servername,
+                                                          architecture);
+                       if (!W_ERROR_IS_OK(result)) {
+                               free_a_printer_driver(driver, 3);
+                               goto out;
                        }
-                       fill_printer_driver_info_1(&driver_info_1[*returned+i], driver, servername, architecture );
                        free_a_printer_driver(driver, 3);
                }
 
-               *returned+=ndrivers;
+               *count += ndrivers;
                SAFE_FREE(list);
        }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d]'s size\n",i));
-               *needed += spoolss_size_printer_driver_info_1(&driver_info_1[i]);
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+ out:
+       SAFE_FREE(list);
 
-       /* fill the buffer with the driver structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_1("", buffer, &driver_info_1[i], 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-out:
-       SAFE_FREE(driver_info_1);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumerates all printer drivers at level 2.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level2(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprinterdrivers_level2(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
 {
        int i;
        int ndrivers;
-       uint32 version;
+       uint32_t version;
        fstring *list = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
-       DRIVER_INFO_2 *driver_info_2=NULL;
+       union spoolss_DriverInfo *info = NULL;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *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));
+               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) {
-                       SAFE_FREE(driver_info_2);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_2=SMB_REALLOC_ARRAY(driver_info_2, DRIVER_INFO_2, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level2: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               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++) {
-                       WERROR status;
-
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_2);
-                               return status;
+                       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;
                        }
-                       fill_printer_driver_info_2(&driver_info_2[*returned+i], driver, servername);
                        free_a_printer_driver(driver, 3);
                }
 
-               *returned+=ndrivers;
+               *count += ndrivers;
                SAFE_FREE(list);
        }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d]'s size\n",i));
-               *needed += spoolss_size_printer_driver_info_2(&(driver_info_2[i]));
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
+ out:
+       SAFE_FREE(list);
 
-       /* fill the buffer with the form structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_2("", buffer, &(driver_info_2[i]), 0);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-out:
-       SAFE_FREE(driver_info_2);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Enumerates all printer drivers at level 3.
 ****************************************************************************/
 
-static WERROR enumprinterdrivers_level3(const char *servername, fstring architecture, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprinterdrivers_level3(TALLOC_CTX *mem_ctx,
+                                       const char *servername,
+                                       const char *architecture,
+                                       union spoolss_DriverInfo **info_p,
+                                       uint32_t *count)
 {
        int i;
        int ndrivers;
-       uint32 version;
+       uint32_t version;
        fstring *list = NULL;
-       DRIVER_INFO_3 *driver_info_3=NULL;
+       union spoolss_DriverInfo *info = NULL;
        NT_PRINTER_DRIVER_INFO_LEVEL driver;
        WERROR result = WERR_OK;
 
-       *returned=0;
+       *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));
+               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) {
-                       SAFE_FREE(driver_info_3);
-                       return WERR_NOMEM;
+               if (ndrivers == -1) {
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
-               if(ndrivers != 0) {
-                       if((driver_info_3=SMB_REALLOC_ARRAY(driver_info_3, DRIVER_INFO_3, *returned+ndrivers )) == NULL) {
-                               DEBUG(0,("enumprinterdrivers_level3: failed to enlarge driver info buffer!\n"));
-                               SAFE_FREE(list);
-                               return WERR_NOMEM;
+               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++) {
-                       WERROR status;
-
                        DEBUGADD(5,("\tdriver: [%s]\n", list[i]));
                        ZERO_STRUCT(driver);
-                       status = get_a_printer_driver(&driver, 3, list[i],
+                       result = get_a_printer_driver(&driver, 3, list[i],
                                                      architecture, version);
-                       if (!W_ERROR_IS_OK(status)) {
-                               SAFE_FREE(list);
-                               SAFE_FREE(driver_info_3);
-                               return status;
+                       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;
                        }
-                       fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);
+
                        free_a_printer_driver(driver, 3);
                }
 
-               *returned+=ndrivers;
+               *count += ndrivers;
                SAFE_FREE(list);
        }
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d]'s size\n",i));
-               *needed += spoolss_size_printer_driver_info_3(&driver_info_3[i]);
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       /* fill the buffer with the driver structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding driver [%d] to buffer\n",i));
-               smb_io_printer_driver_info_3("", buffer, &driver_info_3[i], 0);
-       }
+ out:
+       SAFE_FREE(list);
 
-out:
-       for (i=0; i<*returned; i++) {
-               SAFE_FREE(driver_info_3[i].dependentfiles);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
        }
 
-       SAFE_FREE(driver_info_3);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
- Enumerates all printer drivers.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrinterDrivers
+****************************************************************/
 
-WERROR _spoolss_enumprinterdrivers( pipes_struct *p, SPOOL_Q_ENUMPRINTERDRIVERS *q_u, SPOOL_R_ENUMPRINTERDRIVERS *r_u)
+WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
+                                  struct spoolss_EnumPrinterDrivers *r)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *returned = &r_u->returned;
        const char *cservername;
-       fstring servername;
-       fstring architecture;
+       WERROR result;
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
-       }
-
-       if (offered > MAX_RPC_DATA_SIZE) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       DEBUG(4,("_spoolss_EnumPrinterDrivers\n"));
 
-       DEBUG(4,("_spoolss_enumprinterdrivers\n"));
-
-       *needed   = 0;
-       *returned = 0;
-
-       unistr2_to_ascii(architecture, &q_u->environment, sizeof(architecture));
-       unistr2_to_ascii(servername, &q_u->name, sizeof(servername));
+       *r->out.needed = 0;
+       *r->out.count = 0;
+       *r->out.info = NULL;
 
-       cservername = canon_servername(servername);
+       cservername = canon_servername(r->in.server);
 
-       if (!is_myname_or_ipaddr(cservername))
+       if (!is_myname_or_ipaddr(cservername)) {
                return WERR_UNKNOWN_PRINTER_DRIVER;
+       }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprinterdrivers_level1(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level1(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        case 2:
-               return enumprinterdrivers_level2(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level2(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        case 3:
-               return enumprinterdrivers_level3(cservername, architecture, buffer, offered, needed, returned);
+               result = enumprinterdrivers_level3(p->mem_ctx, cservername,
+                                                  r->in.environment,
+                                                  r->out.info, r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrinterDrivers, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
+
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
 static WERROR fill_form_info_1(TALLOC_CTX *mem_ctx,
-                              struct spoolss_FormInfo1 *form,
-                              nt_forms_struct *list)
+                              struct spoolss_FormInfo1 *r,
+                              const nt_forms_struct *form)
+{
+       r->form_name    = talloc_strdup(mem_ctx, form->name);
+       W_ERROR_HAVE_NO_MEMORY(r->form_name);
+
+       r->flags        = form->flag;
+       r->size.width   = form->width;
+       r->size.height  = form->length;
+       r->area.left    = form->left;
+       r->area.top     = form->top;
+       r->area.right   = form->right;
+       r->area.bottom  = form->bottom;
+
+       return WERR_OK;
+}
+
+/****************************************************************
+ spoolss_enumforms_level1
+****************************************************************/
+
+static WERROR spoolss_enumforms_level1(TALLOC_CTX *mem_ctx,
+                                      const nt_forms_struct *builtin_forms,
+                                      uint32_t num_builtin_forms,
+                                      const nt_forms_struct *user_forms,
+                                      uint32_t num_user_forms,
+                                      union spoolss_FormInfo **info_p,
+                                      uint32_t *count)
 {
-       form->form_name         = talloc_strdup(mem_ctx, list->name);
-       W_ERROR_HAVE_NO_MEMORY(form->form_name);
+       union spoolss_FormInfo *info;
+       WERROR result = WERR_OK;
+       int i;
+
+       *count = num_builtin_forms + num_user_forms;
+
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_FormInfo, *count);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       /* construct the list of form structures */
+       for (i=0; i<num_builtin_forms; i++) {
+               DEBUGADD(6,("Filling form number [%d]\n",i));
+               result = fill_form_info_1(info, &info[i].info1,
+                                         &builtin_forms[i]);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+       for (; i<num_user_forms; i++) {
+               DEBUGADD(6,("Filling form number [%d]\n",i));
+               result = fill_form_info_1(info, &info[i].info1,
+                                         &user_forms[i-num_builtin_forms]);
+               if (!W_ERROR_IS_OK(result)) {
+                       goto out;
+               }
+       }
+
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       form->flags             = list->flag;
-       form->size.width        = list->width;
-       form->size.height       = list->length;
-       form->area.left         = list->left;
-       form->area.top          = list->top;
-       form->area.right        = list->right;
-       form->area.bottom       = list->bottom;
+       *info_p = info;
 
        return WERR_OK;
 }
@@ -7279,15 +7103,15 @@ static WERROR fill_form_info_1(TALLOC_CTX *mem_ctx,
 WERROR _spoolss_EnumForms(pipes_struct *p,
                          struct spoolss_EnumForms *r)
 {
-       nt_forms_struct *list=NULL;
-       nt_forms_struct *builtinlist=NULL;
-       union spoolss_FormInfo *info;
-       uint32_t count;
-       uint32_t numbuiltinforms;
-       size_t buffer_size = 0;
-       int i;
+       WERROR result;
+       nt_forms_struct *user_forms = NULL;
+       nt_forms_struct *builtin_forms = NULL;
+       uint32_t num_user_forms;
+       uint32_t num_builtin_forms;
 
        *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
        /* that's an [in out] buffer */
 
@@ -7299,69 +7123,85 @@ WERROR _spoolss_EnumForms(pipes_struct *p,
        DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered));
        DEBUGADD(5,("Info level [%d]\n",          r->in.level));
 
-       numbuiltinforms = get_builtin_ntforms(&builtinlist);
-       DEBUGADD(5,("Number of builtin forms [%d]\n",     numbuiltinforms));
-       count = get_ntforms(&list);
-       DEBUGADD(5,("Number of user forms [%d]\n",     count));
-       count += numbuiltinforms;
+       num_builtin_forms = get_builtin_ntforms(&builtin_forms);
+       DEBUGADD(5,("Number of builtin forms [%d]\n", num_builtin_forms));
+       num_user_forms = get_ntforms(&user_forms);
+       DEBUGADD(5,("Number of user forms [%d]\n", num_user_forms));
 
-       if (count == 0) {
-               SAFE_FREE(builtinlist);
-               SAFE_FREE(list);
+       if (num_user_forms + num_builtin_forms == 0) {
+               SAFE_FREE(builtin_forms);
+               SAFE_FREE(user_forms);
                return WERR_NO_MORE_ITEMS;
        }
 
-       info = TALLOC_ARRAY(p->mem_ctx, union spoolss_FormInfo, count);
-       if (!info) {
-               SAFE_FREE(builtinlist);
-               SAFE_FREE(list);
-               return WERR_NOMEM;
-       }
-
        switch (r->in.level) {
        case 1:
-               /* construct the list of form structures */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_info_1(info, &info[i].info1, &builtinlist[i]);
-               }
-
-               SAFE_FREE(builtinlist);
+               result = spoolss_enumforms_level1(p->mem_ctx,
+                                                 builtin_forms,
+                                                 num_builtin_forms,
+                                                 user_forms,
+                                                 num_user_forms,
+                                                 r->out.info,
+                                                 r->out.count);
+               break;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
-               for (; i<count; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_info_1(info, &info[i].info1, &list[i-numbuiltinforms]);
-               }
+       SAFE_FREE(user_forms);
+       SAFE_FREE(builtin_forms);
 
-               SAFE_FREE(list);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-               /* check the required size. */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += ndr_size_spoolss_FormInfo1(&info[i].info1, NULL, 0);
-               }
-               for (; i<count; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += ndr_size_spoolss_FormInfo1(&info[i].info1, NULL, 0);
-               }
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumForms, NULL,
+                                                    *r->out.info, r->in.level,
+                                                    *r->out.count);
+       *r->out.info    = SPOOLSS_BUFFER_OK(*r->out.info, NULL);
+       *r->out.count   = SPOOLSS_BUFFER_OK(*r->out.count, 0);
 
-               *r->out.needed = buffer_size;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
 
-               if (*r->out.needed > r->in.offered) {
-                       TALLOC_FREE(info);
-                       return WERR_INSUFFICIENT_BUFFER;
-               }
+/****************************************************************
+****************************************************************/
 
-               *r->out.count = count;
-               *r->out.info = info;
+static WERROR find_form_byname(const char *name,
+                              nt_forms_struct *form)
+{
+       nt_forms_struct *list = NULL;
+       int num_forms = 0, i = 0;
 
+       if (get_a_builtin_ntform_by_string(name, form)) {
                return WERR_OK;
+       }
 
-       default:
-               SAFE_FREE(list);
-               SAFE_FREE(builtinlist);
-               return WERR_UNKNOWN_LEVEL;
+       num_forms = get_ntforms(&list);
+       DEBUGADD(5,("Number of forms [%d]\n", num_forms));
+
+       if (num_forms == 0) {
+               return WERR_BADFID;
+       }
+
+       /* Check if the requested name is in the list of form structures */
+       for (i = 0; i < num_forms; i++) {
+
+               DEBUG(4,("checking form %s (want %s)\n", list[i].name, name));
+
+               if (strequal(name, list[i].name)) {
+                       DEBUGADD(6,("Found form %s number [%d]\n", name, i));
+                       *form = list[i];
+                       SAFE_FREE(list);
+                       return WERR_OK;
+               }
        }
+
+       SAFE_FREE(list);
+
+       return WERR_BADFID;
 }
 
 /****************************************************************
@@ -7371,86 +7211,47 @@ WERROR _spoolss_EnumForms(pipes_struct *p,
 WERROR _spoolss_GetForm(pipes_struct *p,
                        struct spoolss_GetForm *r)
 {
-       uint32 level = r->in.level;
-       uint32 offered = r->in.offered;
-       uint32 *needed = r->out.needed;
-
-       nt_forms_struct *list=NULL;
-       nt_forms_struct builtin_form;
-       bool foundBuiltin;
-       union spoolss_FormInfo info;
-       struct spoolss_FormInfo1 form_1;
-       int numofforms=0, i=0;
+       WERROR result;
+       nt_forms_struct form;
 
        /* that's an [in out] buffer */
 
-       if (!r->in.buffer && (offered!=0)) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
        DEBUG(4,("_spoolss_GetForm\n"));
-       DEBUGADD(5,("Offered buffer size [%d]\n", offered));
-       DEBUGADD(5,("Info level [%d]\n",          level));
-
-       foundBuiltin = get_a_builtin_ntform_by_string(r->in.form_name, &builtin_form);
-       if (!foundBuiltin) {
-               numofforms = get_ntforms(&list);
-               DEBUGADD(5,("Number of forms [%d]\n",     numofforms));
+       DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered));
+       DEBUGADD(5,("Info level [%d]\n",          r->in.level));
 
-               if (numofforms == 0)
-                       return WERR_BADFID;
+       result = find_form_byname(r->in.form_name, &form);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
        }
 
-       ZERO_STRUCT(form_1);
-
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               if (foundBuiltin) {
-                       fill_form_info_1(p->mem_ctx, &form_1, &builtin_form);
-               } else {
-
-                       /* Check if the requested name is in the list of form structures */
-                       for (i=0; i<numofforms; i++) {
-
-                               DEBUG(4,("_spoolss_GetForm: checking form %s (want %s)\n",
-                                       list[i].name, r->in.form_name));
-
-                               if (strequal(r->in.form_name, list[i].name)) {
-                                       DEBUGADD(6,("Found form %s number [%d]\n",
-                                               r->in.form_name, i));
-                                       fill_form_info_1(p->mem_ctx, &form_1, &list[i]);
-                                       break;
-                               }
-                       }
-
-                       SAFE_FREE(list);
-                       if (i == numofforms) {
-                               return WERR_BADFID;
-                       }
-               }
-               /* check the required size. */
-
-               info.info1 = form_1;
-
-               *needed = ndr_size_spoolss_FormInfo(&info, 1, NULL, 0);
-
-               if (*needed > offered) {
-                       r->out.info = NULL;
-                       return WERR_INSUFFICIENT_BUFFER;
-               }
+               result = fill_form_info_1(p->mem_ctx,
+                                         &r->out.info->info1,
+                                         &form);
+               break;
 
-               r->out.info->info1 = form_1;
+       default:
+               result = WERR_UNKNOWN_LEVEL;
+               break;
+       }
 
-               /* fill the buffer with the form structures */
-               DEBUGADD(6,("adding form %s [%d] to buffer\n",
-                       r->in.form_name, i));
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
 
-               return WERR_OK;
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_FormInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       default:
-               SAFE_FREE(list);
-               return WERR_UNKNOWN_LEVEL;
-       }
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************************
@@ -9091,86 +8892,61 @@ WERROR _spoolss_EnumMonitors(pipes_struct *p,
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_1(print_queue_struct **queue, int count, int snum,
-                             NT_PRINTER_INFO_LEVEL *ntprinter,
-                             uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
-                            uint32 *needed)
+static WERROR getjob_level_1(TALLOC_CTX *mem_ctx,
+                            const print_queue_struct *queue,
+                            int count, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            uint32_t jobid,
+                            struct spoolss_JobInfo1 *r)
 {
-       int i=0;
-       bool found=False;
-       JOB_INFO_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       int i = 0;
+       bool found = false;
 
-       info_1=SMB_MALLOC_P(JOB_INFO_1);
-
-       if (info_1 == NULL) {
-               return WERR_NOMEM;
-       }
-
-       for (i=0; i<count && found==False; i++) {
-               if ((*queue)[i].job==(int)jobid)
-                       found=True;
+       for (i=0; i<count && found == false; i++) {
+               if (queue[i].job == (int)jobid) {
+                       found = true;
+               }
        }
 
-       if (found==False) {
-               SAFE_FREE(info_1);
+       if (found == false) {
                /* NT treats not found as bad param... yet another bad choice */
                return WERR_INVALID_PARAM;
        }
 
-       fill_job_info_1( info_1, &((*queue)[i-1]), i, snum, ntprinter );
-
-       *needed += spoolss_size_job_info_1(info_1);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-       }
-
-       smb_io_job_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
-
-       return result;
+       return fill_job_info1(mem_ctx,
+                             r,
+                             &queue[i-1],
+                             i,
+                             snum,
+                             ntprinter);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum,
-                             NT_PRINTER_INFO_LEVEL *ntprinter,
-                             uint32 jobid, RPC_BUFFER *buffer, uint32 offered,
-                            uint32 *needed)
-{
-       int             i = 0;
-       bool            found = False;
-       JOB_INFO_2      *info_2;
-       WERROR          result;
-       DEVICEMODE      *devmode = NULL;
-       NT_DEVICEMODE   *nt_devmode = NULL;
-
-       if ( !(info_2=SMB_MALLOC_P(JOB_INFO_2)) )
-               return WERR_NOMEM;
-
-       ZERO_STRUCTP(info_2);
+static WERROR getjob_level_2(TALLOC_CTX *mem_ctx,
+                            const print_queue_struct *queue,
+                            int count, int snum,
+                            const NT_PRINTER_INFO_LEVEL *ntprinter,
+                            uint32_t jobid,
+                            struct spoolss_JobInfo2 *r)
+{
+       int i = 0;
+       bool found = false;
+       struct spoolss_DeviceMode *devmode;
+       NT_DEVICEMODE *nt_devmode;
+       WERROR result;
 
-       for ( i=0; i<count && found==False; i++ )
-       {
-               if ((*queue)[i].job == (int)jobid)
-                       found = True;
+       for (i=0; i<count && found == false; i++) {
+               if (queue[i].job == (int)jobid) {
+                       found = true;
+               }
        }
 
-       if ( !found ) {
+       if (found == false) {
                /* NT treats not found as bad param... yet another bad
                   choice */
-               result = WERR_INVALID_PARAM;
-               goto done;
+               return WERR_INVALID_PARAM;
        }
 
        /*
@@ -9179,54 +8955,36 @@ static WERROR getjob_level_2(print_queue_struct **queue, int count, int snum,
         *  a failure condition
         */
 
-       if ( !(nt_devmode=print_job_devmode( lp_const_servicename(snum), jobid )) )
-               devmode = construct_dev_mode(lp_const_servicename(snum));
-       else {
-               if ((devmode = SMB_MALLOC_P(DEVICEMODE)) != NULL) {
-                       ZERO_STRUCTP( devmode );
-                       convert_nt_devicemode( devmode, nt_devmode );
+       nt_devmode = print_job_devmode(lp_const_servicename(snum), jobid);
+       if (nt_devmode) {
+               devmode = TALLOC_ZERO_P(mem_ctx, struct spoolss_DeviceMode);
+               W_ERROR_HAVE_NO_MEMORY(devmode);
+               result = convert_nt_devicemode_new(devmode, devmode, nt_devmode);
+               if (!W_ERROR_IS_OK(result)) {
+                       return result;
                }
+       } else {
+               devmode = construct_dev_mode_new(mem_ctx, lp_const_servicename(snum));
+               W_ERROR_HAVE_NO_MEMORY(devmode);
        }
 
-       fill_job_info_2(info_2, &((*queue)[i-1]), i, snum, ntprinter, devmode);
-
-       *needed += spoolss_size_job_info_2(info_2);
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto done;
-       }
-
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto done;
-       }
-
-       smb_io_job_info_2("", buffer, info_2, 0);
-
-       result = WERR_OK;
-
- done:
-       /* Cleanup allocated memory */
-
-       free_job_info_2(info_2);        /* Also frees devmode */
-       SAFE_FREE(info_2);
-
-       return result;
+       return fill_job_info2(mem_ctx,
+                             r,
+                             &queue[i-1],
+                             i,
+                             snum,
+                             ntprinter,
+                             devmode);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetJob
+****************************************************************/
 
-WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_u)
+WERROR _spoolss_GetJob(pipes_struct *p,
+                      struct spoolss_GetJob *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 jobid = q_u->jobid;
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       WERROR          wstatus = WERR_OK;
+       WERROR result = WERR_OK;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
        int snum;
        int count;
@@ -9235,51 +8993,57 @@ WERROR _spoolss_getjob( pipes_struct *p, SPOOL_Q_GETJOB *q_u, SPOOL_R_GETJOB *r_
 
        /* that's an [in out] buffer */
 
-       if (!q_u->buffer && (offered!=0)) {
-               return WERR_INVALID_PARAM;
-       }
-
-       if (offered > MAX_RPC_DATA_SIZE) {
+       if (!r->in.buffer && (r->in.offered != 0)) {
                return WERR_INVALID_PARAM;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
-
-       DEBUG(5,("spoolss_getjob\n"));
+       DEBUG(5,("_spoolss_GetJob\n"));
 
-       *needed = 0;
+       *r->out.needed = 0;
 
-       if (!get_printer_snum(p, handle, &snum, NULL))
+       if (!get_printer_snum(p, r->in.handle, &snum, NULL)) {
                return WERR_BADFID;
+       }
 
-       wstatus = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
-       if ( !W_ERROR_IS_OK(wstatus) )
-               return wstatus;
+       result = get_a_printer(NULL, &ntprinter, 2, lp_servicename(snum));
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
        count = print_queue_status(snum, &queue, &prt_status);
 
        DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n",
                     count, prt_status.status, prt_status.message));
 
-       switch ( level ) {
+       switch (r->in.level) {
        case 1:
-                       wstatus = getjob_level_1(&queue, count, snum, ntprinter, jobid,
-                               buffer, offered, needed);
-                       break;
+               result = getjob_level_1(p->mem_ctx,
+                                       queue, count, snum, ntprinter,
+                                       r->in.job_id, &r->out.info->info1);
+               break;
        case 2:
-                       wstatus = getjob_level_2(&queue, count, snum, ntprinter, jobid,
-                               buffer, offered, needed);
-                       break;
+               result = getjob_level_2(p->mem_ctx,
+                                       queue, count, snum, ntprinter,
+                                       r->in.job_id, &r->out.info->info2);
+               break;
        default:
-                       wstatus = WERR_UNKNOWN_LEVEL;
-                       break;
+               result = WERR_UNKNOWN_LEVEL;
+               break;
        }
 
        SAFE_FREE(queue);
-       free_a_printer( &ntprinter, 2 );
+       free_a_printer(&ntprinter, 2);
+
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_JobInfo, NULL,
+                                              r->out.info, r->in.level);
+       r->out.info     = SPOOLSS_BUFFER_OK(r->out.info, NULL);
 
-       return wstatus;
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
 /****************************************************************
@@ -10193,39 +9957,6 @@ WERROR _spoolss_AddPrintProcessor(pipes_struct *p,
        return WERR_OK;
 }
 
-/****************************************************************
- _spoolss_EnumPrinters
-****************************************************************/
-
-WERROR _spoolss_EnumPrinters(pipes_struct *p,
-                            struct spoolss_EnumPrinters *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_GetJob
-****************************************************************/
-
-WERROR _spoolss_GetJob(pipes_struct *p,
-                      struct spoolss_GetJob *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_EnumJobs
-****************************************************************/
-
-WERROR _spoolss_EnumJobs(pipes_struct *p,
-                        struct spoolss_EnumJobs *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_AddPrinter
 ****************************************************************/
@@ -10237,28 +9968,6 @@ WERROR _spoolss_AddPrinter(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_GetPrinter
-****************************************************************/
-
-WERROR _spoolss_GetPrinter(pipes_struct *p,
-                          struct spoolss_GetPrinter *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_EnumPrinterDrivers
-****************************************************************/
-
-WERROR _spoolss_EnumPrinterDrivers(pipes_struct *p,
-                                  struct spoolss_EnumPrinterDrivers *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_GetPrinterDriver
 ****************************************************************/
@@ -10468,17 +10177,6 @@ WERROR _spoolss_DeletePrintProvidor(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_GetPrinterDriver2
-****************************************************************/
-
-WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
-                                 struct spoolss_GetPrinterDriver2 *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_FindFirstPrinterChangeNotification
 ****************************************************************/