s3-spoolss: add pull_spoolss_PrinterData().
[jra/samba/.git] / source3 / rpc_server / srv_spoolss_nt.c
index a3daa7f372819bbe3ebdbcad25f59975f8d40ed9..8ce0b28db04aad39a678943403ddd480854a115d 100644 (file)
 
 #include "includes.h"
 
+/* macros stolen from s4 spoolss server */
+#define SPOOLSS_BUFFER_UNION(fn,ic,info,level) \
+       ((info)?ndr_size_##fn(info, level, ic, 0):0)
+
+#define SPOOLSS_BUFFER_UNION_ARRAY(mem_ctx,fn,ic,info,level,count) \
+       ((info)?ndr_size_##fn##_info(mem_ctx, ic, level, count, info):0)
+
+#define SPOOLSS_BUFFER_OK(val_true,val_false) ((r->in.offered >= *r->out.needed)?val_true:val_false)
+
+
 extern userdom_struct current_user_info;
 
 #undef DBGC_CLASS
@@ -110,7 +120,7 @@ static int nt_printj_status(int v)
        case LPQ_DELETED:
                return JOB_STATUS_DELETED;
        case LPQ_BLOCKED:
-               return JOB_STATUS_BLOCKED;
+               return JOB_STATUS_BLOCKED_DEVQ;
        case LPQ_USER_INTERVENTION:
                return JOB_STATUS_USER_INTERVENTION;
        }
@@ -130,19 +140,6 @@ static int nt_printq_status(int v)
        return 0;
 }
 
-/****************************************************************************
- Functions to handle SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
-****************************************************************************/
-
-static void free_spool_notify_option(SPOOL_NOTIFY_OPTION **pp)
-{
-       if (*pp == NULL)
-               return;
-
-       SAFE_FREE((*pp)->ctr.type);
-       SAFE_FREE(*pp);
-}
-
 /***************************************************************************
  Disconnect from the client
 ****************************************************************************/
@@ -215,8 +212,7 @@ static int printer_entry_destructor(Printer_entry *Printer)
        Printer->notify.options=0;
        Printer->notify.localmachine[0]='\0';
        Printer->notify.printerlocal=0;
-       free_spool_notify_option(&Printer->notify.option);
-       Printer->notify.option=NULL;
+       TALLOC_FREE(Printer->notify.option);
        Printer->notify.client_connected=False;
 
        free_nt_devicemode( &Printer->nt_devmode );
@@ -227,35 +223,6 @@ static int printer_entry_destructor(Printer_entry *Printer)
        return 0;
 }
 
-/****************************************************************************
- Functions to duplicate a SPOOL_NOTIFY_OPTION struct stored in Printer_entry.
-****************************************************************************/
-
-static SPOOL_NOTIFY_OPTION *dup_spool_notify_option(SPOOL_NOTIFY_OPTION *sp)
-{
-       SPOOL_NOTIFY_OPTION *new_sp = NULL;
-
-       if (!sp)
-               return NULL;
-
-       new_sp = SMB_MALLOC_P(SPOOL_NOTIFY_OPTION);
-       if (!new_sp)
-               return NULL;
-
-       *new_sp = *sp;
-
-       if (sp->ctr.count) {
-               new_sp->ctr.type = (SPOOL_NOTIFY_OPTION_TYPE *)memdup(sp->ctr.type, sizeof(SPOOL_NOTIFY_OPTION_TYPE) * sp->ctr.count);
-
-               if (!new_sp->ctr.type) {
-                       SAFE_FREE(new_sp);
-                       return NULL;
-               }
-       }
-
-       return new_sp;
-}
-
 /****************************************************************************
   find printer index by handle
 ****************************************************************************/
@@ -633,7 +600,7 @@ static bool is_monitoring_event_flags(uint32 flags, uint16 notify_type,
 static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
                                uint16 notify_field)
 {
-       SPOOL_NOTIFY_OPTION *option = p->notify.option;
+       struct spoolss_NotifyOption *option = p->notify.option;
        uint32 i, j;
 
        /*
@@ -655,13 +622,13 @@ static bool is_monitoring_event(Printer_entry *p, uint16 notify_type,
 
                /* Check match for notify_type */
 
-               if (option->ctr.type[i].type != notify_type)
+               if (option->types[i].type != notify_type)
                        continue;
 
                /* Check match for field */
 
-               for (j = 0; j < option->ctr.type[i].count; j++) {
-                       if (option->ctr.type[i].fields[j] == notify_field) {
+               for (j = 0; j < option->types[i].count; j++) {
+                       if (option->types[i].fields[j] == notify_field) {
                                return True;
                        }
                }
@@ -2494,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.
 ********************************************************************/
@@ -2885,26 +2868,73 @@ static bool srv_spoolss_replyopenprinter(int snum, const char *printer,
        return (W_ERROR_IS_OK(result));
 }
 
-/********************************************************************
- * _spoolss_rffpcnex
- * ReplyFindFirstPrinterChangeNotifyEx
+/****************************************************************
+ ****************************************************************/
+
+static struct spoolss_NotifyOption *dup_spoolss_NotifyOption(TALLOC_CTX *mem_ctx,
+                                                            const struct spoolss_NotifyOption *r)
+{
+       struct spoolss_NotifyOption *option;
+       uint32_t i,k;
+
+       if (!r) {
+               return NULL;
+       }
+
+       option = talloc_zero(mem_ctx, struct spoolss_NotifyOption);
+       if (!option) {
+               return NULL;
+       }
+
+       *option = *r;
+
+       if (!option->count) {
+               return option;
+       }
+
+       option->types = talloc_zero_array(option,
+               struct spoolss_NotifyOptionType, option->count);
+       if (!option->types) {
+               talloc_free(option);
+               return NULL;
+       }
+
+       for (i=0; i < option->count; i++) {
+               option->types[i] = r->types[i];
+
+               if (option->types[i].count) {
+                       option->types[i].fields = talloc_zero_array(option,
+                               enum spoolss_Field, option->types[i].count);
+                       if (!option->types[i].fields) {
+                               talloc_free(option);
+                               return NULL;
+                       }
+                       for (k=0; k<option->types[i].count; k++) {
+                               option->types[i].fields[k] =
+                                       r->types[i].fields[k];
+                       }
+               }
+       }
+
+       return option;
+}
+
+/****************************************************************
+ * _spoolss_RemoteFindFirstPrinterChangeNotifyEx
  *
  * before replying OK: status=0 a rpc call is made to the workstation
  * asking ReplyOpenPrinter
  *
  * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe
  * called from api_spoolss_rffpcnex
- ********************************************************************/
+****************************************************************/
 
-WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNEX *r_u)
+WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
+                                                    struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r)
 {
-       POLICY_HND *handle = &q_u->handle;
-       uint32 flags = q_u->flags;
-       uint32 options = q_u->options;
-       UNISTR2 *localmachine = &q_u->localmachine;
-       uint32 printerlocal = q_u->printerlocal;
+       POLICY_HND *handle = r->in.handle;
        int snum = -1;
-       SPOOL_NOTIFY_OPTION *option = q_u->option;
+       struct spoolss_NotifyOption *option = r->in.notify_options;
        struct sockaddr_storage client_ss;
 
        /* store the notify value in the printer struct */
@@ -2912,21 +2942,19 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
        Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
 
        if (!Printer) {
-               DEBUG(2,("_spoolss_rffpcnex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: "
+                       "Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       Printer->notify.flags=flags;
-       Printer->notify.options=options;
-       Printer->notify.printerlocal=printerlocal;
-
-       if (Printer->notify.option)
-               free_spool_notify_option(&Printer->notify.option);
+       Printer->notify.flags           = r->in.flags;
+       Printer->notify.options         = r->in.options;
+       Printer->notify.printerlocal    = r->in.printer_local;
 
-       Printer->notify.option=dup_spool_notify_option(option);
+       TALLOC_FREE(Printer->notify.option);
+       Printer->notify.option = dup_spoolss_NotifyOption(Printer, option);
 
-       unistr2_to_ascii(Printer->notify.localmachine, localmachine,
-                      sizeof(Printer->notify.localmachine));
+       fstrcpy(Printer->notify.localmachine, r->in.local_machine);
 
        /* Connect to the client machine and send a ReplyOpenPrinter */
 
@@ -3484,7 +3512,6 @@ static const struct s_notify_info_data_table notify_info_data_table[] =
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_PAGES,             "JOB_NOTIFY_TOTAL_PAGES",             NOTIFY_TABLE_DWORD,    spoolss_notify_total_pages },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PAGES_PRINTED,           "JOB_NOTIFY_PAGES_PRINTED",           NOTIFY_TABLE_DWORD,    spoolss_notify_pages_printed },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_BYTES,             "JOB_NOTIFY_TOTAL_BYTES",             NOTIFY_TABLE_DWORD,    spoolss_notify_job_size },
-{ PRINT_TABLE_END, 0x0, NULL, 0x0, NULL },
 };
 
 /*******************************************************************
@@ -3511,11 +3538,13 @@ static uint32_t variable_type_of_notify_info_data(enum spoolss_NotifyType type,
 /****************************************************************************
 ****************************************************************************/
 
-static bool search_notify(uint16 type, uint16 field, int *value)
+static bool search_notify(enum spoolss_NotifyType type,
+                         enum spoolss_Field field,
+                         int *value)
 {
        int i;
 
-       for (i = 0; notify_info_data_table[i].type != PRINT_TABLE_END; i++) {
+       for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) {
                if (notify_info_data_table[i].type == type &&
                    notify_info_data_table[i].field == field &&
                    notify_info_data_table[i].fn != NULL) {
@@ -3530,7 +3559,10 @@ static bool search_notify(uint16 type, uint16 field, int *value)
 /****************************************************************************
 ****************************************************************************/
 
-void construct_info_data(struct spoolss_Notify *info_data, uint16 type, uint16 field, int id)
+void construct_info_data(struct spoolss_Notify *info_data,
+                        enum spoolss_NotifyType type,
+                        enum spoolss_Field field,
+                        int id)
 {
        info_data->type                 = type;
        info_data->field                = field;
@@ -3544,29 +3576,31 @@ void construct_info_data(struct spoolss_Notify *info_data, uint16 type, uint16 f
  *
  ********************************************************************/
 
-static bool construct_notify_printer_info(Printer_entry *print_hnd, struct spoolss_NotifyInfo *info, int
-                                         snum, SPOOL_NOTIFY_OPTION_TYPE
-                                         *option_type, uint32 id,
+static bool construct_notify_printer_info(Printer_entry *print_hnd,
+                                         struct spoolss_NotifyInfo *info,
+                                         int snum,
+                                         const struct spoolss_NotifyOptionType *option_type,
+                                         uint32_t id,
                                          TALLOC_CTX *mem_ctx)
 {
        int field_num,j;
-       uint16 type;
-       uint16 field;
+       enum spoolss_NotifyType type;
+       enum spoolss_Field field;
 
        struct spoolss_Notify *current_data;
        NT_PRINTER_INFO_LEVEL *printer = NULL;
        print_queue_struct *queue=NULL;
 
-       type=option_type->type;
+       type = option_type->type;
 
        DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n",
-               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+               (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"),
                option_type->count, lp_servicename(snum)));
 
        if (!W_ERROR_IS_OK(get_a_printer(print_hnd, &printer, 2, lp_const_servicename(snum))))
                return False;
 
-       for(field_num=0; field_num<option_type->count; field_num++) {
+       for(field_num=0; field_num < option_type->count; field_num++) {
                field = option_type->fields[field_num];
 
                DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field));
@@ -3609,14 +3643,14 @@ static bool construct_notify_printer_info(Printer_entry *print_hnd, struct spool
 static bool construct_notify_jobs_info(print_queue_struct *queue,
                                       struct spoolss_NotifyInfo *info,
                                       NT_PRINTER_INFO_LEVEL *printer,
-                                      int snum, SPOOL_NOTIFY_OPTION_TYPE
-                                      *option_type, uint32 id,
+                                      int snum,
+                                      const struct spoolss_NotifyOptionType *option_type,
+                                      uint32_t id,
                                       TALLOC_CTX *mem_ctx)
 {
        int field_num,j;
-       uint16 type;
-       uint16 field;
-
+       enum spoolss_NotifyType type;
+       enum spoolss_Field field;
        struct spoolss_Notify *current_data;
 
        DEBUG(4,("construct_notify_jobs_info\n"));
@@ -3624,7 +3658,7 @@ static bool construct_notify_jobs_info(print_queue_struct *queue,
        type = option_type->type;
 
        DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n",
-               (option_type->type==PRINTER_NOTIFY_TYPE?"PRINTER_NOTIFY_TYPE":"JOB_NOTIFY_TYPE"),
+               (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"),
                option_type->count));
 
        for(field_num=0; field_num<option_type->count; field_num++) {
@@ -3690,15 +3724,15 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
        Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
        int n_services=lp_numservices();
        int i;
-       SPOOL_NOTIFY_OPTION *option;
-       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+       struct spoolss_NotifyOption *option;
+       struct spoolss_NotifyOptionType option_type;
 
        DEBUG(4,("printserver_notify_info\n"));
 
        if (!Printer)
                return WERR_BADFID;
 
-       option=Printer->notify.option;
+       option = Printer->notify.option;
 
        info->version   = 2;
        info->notifies  = NULL;
@@ -3711,15 +3745,15 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
                return WERR_BADFID;
 
        for (i=0; i<option->count; i++) {
-               option_type=&(option->ctr.type[i]);
+               option_type = option->types[i];
 
-               if (option_type->type!=PRINTER_NOTIFY_TYPE)
+               if (option_type.type != PRINTER_NOTIFY_TYPE)
                        continue;
 
                for (snum=0; snum<n_services; snum++)
                {
                        if ( lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum) )
-                               construct_notify_printer_info ( Printer, info, snum, option_type, snum, mem_ctx );
+                               construct_notify_printer_info ( Printer, info, snum, &option_type, snum, mem_ctx );
                }
        }
 
@@ -3755,8 +3789,8 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, struct spool
        Printer_entry *Printer=find_printer_index_by_hnd(p, hnd);
        int i;
        uint32 id;
-       SPOOL_NOTIFY_OPTION *option;
-       SPOOL_NOTIFY_OPTION_TYPE *option_type;
+       struct spoolss_NotifyOption *option;
+       struct spoolss_NotifyOptionType option_type;
        int count,j;
        print_queue_struct *queue=NULL;
        print_status_struct status;
@@ -3766,7 +3800,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, struct spool
        if (!Printer)
                return WERR_BADFID;
 
-       option=Printer->notify.option;
+       option = Printer->notify.option;
        id = 0x0;
 
        info->version   = 2;
@@ -3782,12 +3816,12 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, struct spool
        get_printer_snum(p, hnd, &snum, NULL);
 
        for (i=0; i<option->count; i++) {
-               option_type=&option->ctr.type[i];
+               option_type = option->types[i];
 
-               switch ( option_type->type ) {
+               switch (option_type.type) {
                case PRINTER_NOTIFY_TYPE:
                        if(construct_notify_printer_info(Printer, info, snum,
-                                                        option_type, id,
+                                                        &option_type, id,
                                                         mem_ctx))
                                id--;
                        break;
@@ -3803,7 +3837,7 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, struct spool
                        for (j=0; j<count; j++) {
                                construct_notify_jobs_info(&queue[j], info,
                                                           printer, snum,
-                                                          option_type,
+                                                          &option_type,
                                                           queue[j].job,
                                                           mem_ctx);
                        }
@@ -3883,7 +3917,7 @@ WERROR _spoolss_RouterRefreshPrinterChangeNotify(pipes_struct *p,
                Printer->notify.change = r->in.change_low;
        }
 
-       /* just ignore the SPOOL_NOTIFY_OPTION */
+       /* just ignore the spoolss_NotifyOption */
 
        switch (Printer->printer_type) {
                case SPLHND_SERVER:
@@ -3906,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);
-}
-
-/********************************************************************
- * 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);
+       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;
 
-       free_a_printer(&ntprinter,2);
-
-       return True;
+       return WERR_OK;
 }
 
 /****************************************************************************
@@ -4064,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
@@ -4112,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:
@@ -4152,299 +4186,378 @@ 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 = SPOOL_DS_PUBLISH;
+               r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid));
+               r->action = DSPRINT_PUBLISH;
        } else {
-               init_unistr(&printer->guid, "");
-               printer->action = SPOOL_DS_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;
-
-       DEBUG(4,("enum_all_printers_info_1\n"));
-
-       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));
+       char *chaine = NULL;
+       r->flags                = flags;
 
-                               memcpy(&printers[*returned], &current_prt, sizeof(PRINTER_INFO_1));
-                               (*returned)++;
-                       }
-               }
+       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);
 
-       /* check the required size. */
-       for (i=0; i<*returned; i++)
-               (*needed) += spoolss_size_printer_info_1(&printers[i]);
+       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);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       return WERR_OK;
+}
+
+/********************************************************************
+ * construct_printer_info2
+ * fill a spoolss_PrinterInfo2 struct
+********************************************************************/
+
+static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx,
+                                     const NT_PRINTER_INFO_LEVEL *ntprinter,
+                                     struct spoolss_PrinterInfo2 *r,
+                                     int snum)
+{
+       int count;
+
+       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);
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       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);
+
+       r->attributes           = ntprinter->info_2->attributes;
+
+       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;
+
+       r->devmode = construct_dev_mode_new(mem_ctx, lp_const_servicename(snum));
+       if (!r->devmode) {
+               DEBUG(8,("Returning NULL Devicemode!\n"));
        }
 
-       /* fill the buffer with the structures */
-       for (i=0; i<*returned; i++)
-               smb_io_printer_info_1("", buffer, &printers[i], 0);
+       r->secdesc              = NULL;
 
-out:
-       /* clear memory */
+       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 */
+
+               r->secdesc      = dup_sec_desc(mem_ctx, ntprinter->info_2->secdesc_buf->sd);
+       }
 
-       SAFE_FREE(printers);
+       return WERR_OK;
+}
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+/********************************************************************
+********************************************************************/
 
-       return result;
+static bool snum_is_shared_printer(int snum)
+{
+       return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum));
+}
+
+/********************************************************************
+ Spoolss_enumprinters.
+********************************************************************/
+
+static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx,
+                                      uint32_t flags,
+                                      union spoolss_PrinterInfo **info_p,
+                                      uint32_t *count)
+{
+       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(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+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(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
+       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(fstring name, RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enum_all_printers_info_1_name(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_name\n"));
 
-       if ((name[0] == '\\') && (name[1] == '\\'))
+       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
+
+       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 */
@@ -4515,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"));
 
@@ -4529,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);
 }
 
 /********************************************************************
@@ -4544,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 */
 }
@@ -4638,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;
 }
@@ -4663,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:
@@ -4720,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;
+       default:
+               return WERR_UNKNOWN_LEVEL;
        }
-       return WERR_UNKNOWN_LEVEL;
+
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
+
+       *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 SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_GetPrinter
+****************************************************************/
 
-static WERROR getprinter_level_0(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_0 *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_0)) == NULL)
-               return WERR_NOMEM;
+       int snum;
 
-       construct_printer_info_0(print_hnd, printer, snum);
+       /* that's an [in out] buffer */
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_0(printer);
+       if (!r->in.buffer && (r->in.offered != 0)) {
+               return WERR_INVALID_PARAM;
+       }
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
+       *r->out.needed = 0;
+
+       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 */
-       smb_io_printer_info_0("", buffer, printer, 0);
+       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;
+       }
 
-out:
-       /* clear memory */
+       free_a_printer(&ntprinter, 2);
 
-       SAFE_FREE(printer);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
+       }
 
-       return result;
+       *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 SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ ********************************************************************/
 
-static WERROR getprinter_level_1(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_1 *printer=NULL;
-       WERROR result = WERR_OK;
+       int i, num_strings = 0;
+       const char **array = NULL;
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_1)) == NULL)
-               return WERR_NOMEM;
+       for (i=0; fstring_array && fstring_array[i][0] != '\0'; i++) {
 
-       construct_printer_info_1(print_hnd, PRINTER_ENUM_ICON8, printer, snum);
+               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_1(printer);
 
-       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_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);
-
-       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 */
-       if (!smb_io_printer_info_2("", buffer, printer, 0))
-               result = WERR_NOMEM;
-
-out:
-       /* clear memory */
-       free_printer_info_2(printer);
-
-       return result;
+       return array;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * fill a spoolss_DriverInfo1 struct
+ ********************************************************************/
 
-static WERROR getprinter_level_3(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_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);
+       r->driver_name          = talloc_strdup(mem_ctx, driver->info_3->name);
+       W_ERROR_HAVE_NO_MEMORY(r->driver_name);
 
-       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_info_3("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_3(printer);
-
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
-
-static WERROR getprinter_level_4(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_4 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_4))==NULL)
-               return WERR_NOMEM;
-
-       if (!construct_printer_info_4(print_hnd, printer, snum)) {
-               SAFE_FREE(printer);
-               return WERR_NOMEM;
-       }
-
-       /* check the required size. */
-       *needed += spoolss_size_printer_info_4(printer);
-
-       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_info_4("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_4(printer);
-
-       return result;
-}
+/********************************************************************
+ * fill a spoolss_DriverInfo2 struct
+ ********************************************************************/
 
-/****************************************************************************
-****************************************************************************/
+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_5(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
-       PRINTER_INFO_5 *printer=NULL;
-       WERROR result = WERR_OK;
+       const char *cservername = canon_servername(servername);
 
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_5))==NULL)
-               return WERR_NOMEM;
+       r->version              = driver->info_3->cversion;
 
-       if (!construct_printer_info_5(print_hnd, printer, snum)) {
-               free_printer_info_5(printer);
-               return WERR_NOMEM;
-       }
+       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_5(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);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_5("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_5(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_6(Printer_entry *print_hnd,
-                                int snum,
-                                RPC_BUFFER *buffer, uint32 offered,
-                                uint32 *needed)
-{
-       PRINTER_INFO_6 *printer;
-       WERROR result = WERR_OK;
+/********************************************************************
+ * fill a spoolss_DriverInfo3 struct
+ ********************************************************************/
 
-       if ((printer = SMB_MALLOC_P(PRINTER_INFO_6)) == NULL) {
-               return WERR_NOMEM;
-       }
+static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx,
+                                       struct spoolss_DriverInfo3 *r,
+                                       const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+                                       const char *servername)
+{
+       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 (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               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);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_6("", buffer, printer, 0);
-
-out:
-       /* clear memory */
-       free_printer_info_6(printer);
-
-       return result;
-}
-
-static WERROR getprinter_level_7(Printer_entry *print_hnd, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
-{
-       PRINTER_INFO_7 *printer=NULL;
-       WERROR result = WERR_OK;
-
-       if((printer=SMB_MALLOC_P(PRINTER_INFO_7))==NULL)
-               return WERR_NOMEM;
-
-       if (!construct_printer_info_7(print_hnd, printer, snum)) {
-               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);
 
-       /* 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->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
        }
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
-
+       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);
 
-       /* fill the buffer with the structures */
-       smb_io_printer_info_7("", buffer, printer, 0);
-
-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;
-
-       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->configfile)) {
+               r->config_file  = talloc_asprintf(mem_ctx, "\\\\%s%s",
+                               cservername, driver->info_3->configfile);
+       } else {
+               r->config_file  = talloc_strdup(mem_ctx, "");
        }
-       return WERR_UNKNOWN_LEVEL;
-}
+       W_ERROR_HAVE_NO_MEMORY(r->config_file);
 
-/********************************************************************
- * fill a DRIVER_INFO_1 struct
- ********************************************************************/
+       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);
+
+       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);
 
@@ -5117,58 +5215,11 @@ static WERROR construct_printer_driver_info_1(DRIVER_INFO_1 *info, int snum, con
                return WERR_UNKNOWN_PRINTER_DRIVER;
        }
 
-       fill_printer_driver_info_1(info, driver, servername, architecture);
+       result = fill_printer_driver_info1(mem_ctx, r, &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);
-
-       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, "" );
+       return result;
 }
 
 /********************************************************************
@@ -5176,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);
@@ -5192,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;
 }
 
 /********************************************************************
@@ -5277,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;
@@ -5382,387 +5379,168 @@ static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, con
                if (!W_ERROR_IS_OK(status)) {
                        free_a_printer(&printer,2);
                        return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-#if 0  /* JERRY */
-       }
-#endif
-
-
-       fill_printer_driver_info_3(info, 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, "");
-}
-
-/********************************************************************
- * construct_printer_info_6
- * 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)
-{
-       NT_PRINTER_INFO_LEVEL           *printer = NULL;
-       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
-       WERROR                          status;
-
-       ZERO_STRUCT(driver);
-
-       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-               return WERR_INVALID_PRINTER_NAME;
-
-       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-
-       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-
-       if (!W_ERROR_IS_OK(status))
-       {
-               /*
-                * Is this a W2k client ?
-                */
-
-               if (version < 3) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-
-               /* Yes - try again with a WinNT driver. */
-               version = 2;
-               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
-               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
-               if (!W_ERROR_IS_OK(status)) {
-                       free_a_printer(&printer,2);
-                       return WERR_UNKNOWN_PRINTER_DRIVER;
-               }
-       }
-
-       fill_printer_driver_info_6(info, 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 0  /* JERRY */
        }
+#endif
 
-       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);
+       status = fill_printer_driver_info3(mem_ctx, r, &driver, servername);
 
-out:
-       free_printer_driver_info_3(&info);
+       free_a_printer(&printer,2);
 
-       return result;
+       return status;
 }
 
-/****************************************************************************
-****************************************************************************/
+/********************************************************************
+ * construct_printer_info_6
+ * fill a printer_info_6 struct
+ ********************************************************************/
 
-static WERROR getprinterdriver2_level6(const char *servername, fstring architecture, uint32 version, int snum, RPC_BUFFER *buffer, uint32 offered, uint32 *needed)
+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)
 {
-       DRIVER_INFO_6 info;
-       WERROR result;
+       NT_PRINTER_INFO_LEVEL           *printer = NULL;
+       NT_PRINTER_DRIVER_INFO_LEVEL    driver;
+       WERROR                          status;
 
-       ZERO_STRUCT(info);
+       ZERO_STRUCT(driver);
 
-       result = construct_printer_driver_info_6(&info, snum, servername, architecture, version);
-       if (!W_ERROR_IS_OK(result))
-               goto out;
+       status=get_a_printer(NULL, &printer, 2, lp_const_servicename(snum) );
 
-       /* check the required size. */
-       *needed += spoolss_size_printer_driver_info_6(&info);
+       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       if (!W_ERROR_IS_OK(status))
+               return WERR_INVALID_PRINTER_NAME;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       status = get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+
+       DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
+
+       if (!W_ERROR_IS_OK(status))
+       {
+               /*
+                * Is this a W2k client ?
+                */
+
+               if (version < 3) {
+                       free_a_printer(&printer,2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
+
+               /* Yes - try again with a WinNT driver. */
+               version = 2;
+               status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);
+               DEBUG(8,("construct_printer_driver_info_6: status: %s\n", win_errstr(status)));
+               if (!W_ERROR_IS_OK(status)) {
+                       free_a_printer(&printer,2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
        }
 
-       /* fill the buffer with the structures */
-       smb_io_printer_driver_info_6("", buffer, &info, 0);
+       status = fill_printer_driver_info6(mem_ctx, r, &driver, servername);
 
-out:
-       free_printer_driver_info_6(&info);
+       free_a_printer(&printer,2);
+       free_a_printer_driver(driver, 3);
 
-       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);
 }
 
 
@@ -5860,7 +5638,7 @@ WERROR _spoolss_StartDocPrinter(pipes_struct *p,
        }
 
        Printer->jobid = print_job_start(p->server_info, snum,
-                                        CONST_DISCARD(char *,info_1->document_name),
+                                        info_1->document_name,
                                         Printer->nt_devmode);
 
        /* An error occured in print_job_start() so return an appropriate
@@ -6590,8 +6368,7 @@ WERROR _spoolss_FindClosePrinterNotify(pipes_struct *p,
        Printer->notify.options=0;
        Printer->notify.localmachine[0]='\0';
        Printer->notify.printerlocal=0;
-       if (Printer->notify.option)
-               free_spool_notify_option(&Printer->notify.option);
+       TALLOC_FREE(Printer->notify.option);
        Printer->notify.client_connected=False;
 
        return WERR_OK;
@@ -6611,255 +6388,284 @@ WERROR _spoolss_AddJob(pipes_struct *p,
        /* this is what a NT server returns for AddJob. AddJob must fail on
         * non-local printers */
 
+       if (r->in.level != 1) {
+               return WERR_UNKNOWN_LEVEL;
+       }
+
        return WERR_INVALID_PARAM;
 }
 
 /****************************************************************************
+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;
-       }
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       for (i=0; i<*returned; i++)
-               fill_job_info_1( &info[i], &queue[i], i, snum, ntprinter );
-
-       /* 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);
 }
 
 /****************************************************************
@@ -6923,463 +6729,479 @@ 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;
                        }
-                       fill_printer_driver_info_3(&driver_info_3[*returned+i], driver, servername);
+                       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;
+                       }
+
                        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;
+       }
 
-static void fill_form_1(FORM_1 *form, nt_forms_struct *list)
-{
-       form->flag=list->flag;
-       init_unistr(&form->name, list->name);
-       form->width=list->width;
-       form->length=list->length;
-       form->left=list->left;
-       form->top=list->top;
-       form->right=list->right;
-       form->bottom=list->bottom;
+       *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)
 {
-       form->form_name         = talloc_strdup(mem_ctx, list->name);
-       W_ERROR_HAVE_NO_MEMORY(form->form_name);
+       r->form_name    = talloc_strdup(mem_ctx, form->name);
+       W_ERROR_HAVE_NO_MEMORY(r->form_name);
 
-       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;
+       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
+****************************************************************/
 
-WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMFORMS *r_u)
+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)
 {
-       uint32 level = q_u->level;
-       RPC_BUFFER *buffer = NULL;
-       uint32 offered = q_u->offered;
-       uint32 *needed = &r_u->needed;
-       uint32 *numofforms = &r_u->numofforms;
-       uint32 numbuiltinforms;
-
-       nt_forms_struct *list=NULL;
-       nt_forms_struct *builtinlist=NULL;
-       FORM_1 *forms_1;
-       int buffer_size=0;
+       union spoolss_FormInfo *info;
+       WERROR result = WERR_OK;
        int i;
 
-       /* that's an [in out] buffer */
+       *count = num_builtin_forms + num_user_forms;
 
-       if (!q_u->buffer && (offered!=0) ) {
-               return WERR_INVALID_PARAM;
+       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;
+               }
        }
 
-       if (offered > MAX_RPC_DATA_SIZE) {
-               return WERR_INVALID_PARAM;
+       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;
        }
 
-       rpcbuf_move(q_u->buffer, &r_u->buffer);
-       buffer = r_u->buffer;
+       *info_p = info;
+
+       return WERR_OK;
+}
+
+/****************************************************************
+ _spoolss_EnumForms
+****************************************************************/
 
-       DEBUG(4,("_spoolss_enumforms\n"));
-       DEBUGADD(5,("Offered buffer size [%d]\n", offered));
-       DEBUGADD(5,("Info level [%d]\n",          level));
+WERROR _spoolss_EnumForms(pipes_struct *p,
+                         struct spoolss_EnumForms *r)
+{
+       WERROR result;
+       nt_forms_struct *user_forms = NULL;
+       nt_forms_struct *builtin_forms = NULL;
+       uint32_t num_user_forms;
+       uint32_t num_builtin_forms;
 
-       numbuiltinforms = get_builtin_ntforms(&builtinlist);
-       DEBUGADD(5,("Number of builtin forms [%d]\n",     numbuiltinforms));
-       *numofforms = get_ntforms(&list);
-       DEBUGADD(5,("Number of user forms [%d]\n",     *numofforms));
-       *numofforms += numbuiltinforms;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       if (*numofforms == 0) {
-               SAFE_FREE(builtinlist);
-               SAFE_FREE(list);
+       /* that's an [in out] buffer */
+
+       if (!r->in.buffer && (r->in.offered != 0) ) {
+               return WERR_INVALID_PARAM;
+       }
+
+       DEBUG(4,("_spoolss_EnumForms\n"));
+       DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered));
+       DEBUGADD(5,("Info level [%d]\n",          r->in.level));
+
+       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 (num_user_forms + num_builtin_forms == 0) {
+               SAFE_FREE(builtin_forms);
+               SAFE_FREE(user_forms);
                return WERR_NO_MORE_ITEMS;
        }
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               if ((forms_1=SMB_MALLOC_ARRAY(FORM_1, *numofforms)) == NULL) {
-                       SAFE_FREE(builtinlist);
-                       SAFE_FREE(list);
-                       *numofforms=0;
-                       return WERR_NOMEM;
-               }
+               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;
+       }
 
-               /* construct the list of form structures */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_1(&forms_1[i], &builtinlist[i]);
-               }
+       SAFE_FREE(user_forms);
+       SAFE_FREE(builtin_forms);
 
-               SAFE_FREE(builtinlist);
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
+       }
 
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("Filling form number [%d]\n",i));
-                       fill_form_1(&forms_1[i], &list[i-numbuiltinforms]);
-               }
+       *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);
 
-               SAFE_FREE(list);
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
 
-               /* check the required size. */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += spoolss_size_form_1(&forms_1[i]);
-               }
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("adding form [%d]'s size\n",i));
-                       buffer_size += spoolss_size_form_1(&forms_1[i]);
-               }
+/****************************************************************
+****************************************************************/
 
-               *needed=buffer_size;
+static WERROR find_form_byname(const char *name,
+                              nt_forms_struct *form)
+{
+       nt_forms_struct *list = NULL;
+       int num_forms = 0, i = 0;
 
-               if (*needed > offered) {
-                       SAFE_FREE(forms_1);
-                       *numofforms=0;
-                       return WERR_INSUFFICIENT_BUFFER;
-               }
+       if (get_a_builtin_ntform_by_string(name, form)) {
+               return WERR_OK;
+       }
 
-               if (!rpcbuf_alloc_size(buffer, buffer_size)){
-                       SAFE_FREE(forms_1);
-                       *numofforms=0;
-                       return WERR_NOMEM;
-               }
+       num_forms = get_ntforms(&list);
+       DEBUGADD(5,("Number of forms [%d]\n", num_forms));
 
-               /* fill the buffer with the form structures */
-               for (i=0; i<numbuiltinforms; i++) {
-                       DEBUGADD(6,("adding form [%d] to buffer\n",i));
-                       smb_io_form_1("", buffer, &forms_1[i], 0);
-               }
-               for (; i<*numofforms; i++) {
-                       DEBUGADD(6,("adding form [%d] to buffer\n",i));
-                       smb_io_form_1("", buffer, &forms_1[i], 0);
-               }
+       if (num_forms == 0) {
+               return WERR_BADFID;
+       }
 
-               SAFE_FREE(forms_1);
+       /* Check if the requested name is in the list of form structures */
+       for (i = 0; i < num_forms; i++) {
 
-               return WERR_OK;
+               DEBUG(4,("checking form %s (want %s)\n", list[i].name, name));
 
-       default:
-               SAFE_FREE(list);
-               SAFE_FREE(builtinlist);
-               return WERR_UNKNOWN_LEVEL;
+               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;
 }
 
 /****************************************************************
@@ -7389,94 +7211,60 @@ WERROR _spoolss_enumforms(pipes_struct *p, SPOOL_Q_ENUMFORMS *q_u, SPOOL_R_ENUMF
 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);
 }
 
 /****************************************************************************
 ****************************************************************************/
 
-static void fill_port_1(PORT_INFO_1 *port, const char *name)
+static WERROR fill_port_1(TALLOC_CTX *mem_ctx,
+                         struct spoolss_PortInfo1 *r,
+                         const char *name)
 {
-       init_unistr(&port->port_name, name);
+       r->port_name = talloc_strdup(mem_ctx, name);
+       W_ERROR_HAVE_NO_MEMORY(r->port_name);
+
+       return WERR_OK;
 }
 
 /****************************************************************************
@@ -7484,13 +7272,23 @@ static void fill_port_1(PORT_INFO_1 *port, const char *name)
  somehow.
 ****************************************************************************/
 
-static void fill_port_2(PORT_INFO_2 *port, const char *name)
+static WERROR fill_port_2(TALLOC_CTX *mem_ctx,
+                         struct spoolss_PortInfo2 *r,
+                         const char *name)
 {
-       init_unistr(&port->port_name, name);
-       init_unistr(&port->monitor_name, "Local Monitor");
-       init_unistr(&port->description, SPL_LOCAL_PORT );
-       port->port_type=PORT_TYPE_WRITE;
-       port->reserved=0x0;
+       r->port_name = talloc_strdup(mem_ctx, name);
+       W_ERROR_HAVE_NO_MEMORY(r->port_name);
+
+       r->monitor_name = talloc_strdup(mem_ctx, "Local Monitor");
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+
+       r->description = talloc_strdup(mem_ctx, SPL_LOCAL_PORT); /* FIXME */
+       W_ERROR_HAVE_NO_MEMORY(r->description);
+
+       r->port_type = SPOOLSS_PORT_TYPE_WRITE;
+       r->reserved = 0;
+
+       return WERR_OK;
 }
 
 
@@ -7558,9 +7356,11 @@ WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines )
  enumports level 1.
 ****************************************************************************/
 
-static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumports_level_1(TALLOC_CTX *mem_ctx,
+                               union spoolss_PortInfo **info_p,
+                               uint32_t *count)
 {
-       PORT_INFO_1 *ports=NULL;
+       union spoolss_PortInfo *info = NULL;
        int i=0;
        WERROR result = WERR_OK;
        char **qlines = NULL;
@@ -7568,161 +7368,140 @@ static WERROR enumports_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *need
 
        result = enumports_hook(talloc_tos(), &numlines, &qlines );
        if (!W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(qlines);
-               return result;
+               goto out;
        }
 
-       if(numlines) {
-               if((ports=SMB_MALLOC_ARRAY( PORT_INFO_1, numlines )) == NULL) {
-                       DEBUG(10,("Returning WERR_NOMEM [%s]\n",
-                                 win_errstr(WERR_NOMEM)));
-                       TALLOC_FREE(qlines);
-                       return WERR_NOMEM;
+       if (numlines) {
+               info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines);
+               if (!info) {
+                       DEBUG(10,("Returning WERR_NOMEM\n"));
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
                for (i=0; i<numlines; i++) {
                        DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
-                       fill_port_1(&ports[i], qlines[i]);
+                       result = fill_port_1(info, &info[i].info1, qlines[i]);
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
                }
        }
        TALLOC_FREE(qlines);
 
-       *returned = numlines;
-
-       /* check the required size. */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d]'s size\n", i));
-               *needed += spoolss_size_port_info_1(&ports[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 ports structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d] to buffer\n", i));
-               smb_io_port_1("", buffer, &ports[i], 0);
-       }
-
 out:
-       SAFE_FREE(ports);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               TALLOC_FREE(qlines);
+               *count = 0;
+               *info_p = NULL;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
+       *count = numlines;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  enumports level 2.
 ****************************************************************************/
 
-static WERROR enumports_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumports_level_2(TALLOC_CTX *mem_ctx,
+                               union spoolss_PortInfo **info_p,
+                               uint32_t *count)
 {
-       PORT_INFO_2 *ports=NULL;
+       union spoolss_PortInfo *info = NULL;
        int i=0;
        WERROR result = WERR_OK;
        char **qlines = NULL;
        int numlines = 0;
 
        result = enumports_hook(talloc_tos(), &numlines, &qlines );
-       if ( !W_ERROR_IS_OK(result)) {
-               TALLOC_FREE(qlines);
-               return result;
+       if (!W_ERROR_IS_OK(result)) {
+               goto out;
        }
 
-       if(numlines) {
-               if((ports=SMB_MALLOC_ARRAY( PORT_INFO_2, numlines)) == NULL) {
-                       TALLOC_FREE(qlines);
-                       return WERR_NOMEM;
+       if (numlines) {
+               info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines);
+               if (!info) {
+                       DEBUG(10,("Returning WERR_NOMEM\n"));
+                       result = WERR_NOMEM;
+                       goto out;
                }
 
                for (i=0; i<numlines; i++) {
                        DEBUG(6,("Filling port number [%d] with port [%s]\n", i, qlines[i]));
-                       fill_port_2(&(ports[i]), qlines[i]);
+                       result = fill_port_2(info, &info[i].info2, qlines[i]);
+                       if (!W_ERROR_IS_OK(result)) {
+                               goto out;
+                       }
                }
        }
-
        TALLOC_FREE(qlines);
 
-       *returned = numlines;
-
-       /* check the required size. */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d]'s size\n", i));
-               *needed += spoolss_size_port_info_2(&ports[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 ports structures */
-       for (i=0; i<*returned; i++) {
-               DEBUGADD(6,("adding port [%d] to buffer\n", i));
-               smb_io_port_2("", buffer, &ports[i], 0);
-       }
-
 out:
-       SAFE_FREE(ports);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               TALLOC_FREE(qlines);
+               *count = 0;
+               *info_p = NULL;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
+       *count = numlines;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
- enumports.
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPorts
+****************************************************************/
 
-WERROR _spoolss_enumports( pipes_struct *p, SPOOL_Q_ENUMPORTS *q_u, SPOOL_R_ENUMPORTS *r_u)
+WERROR _spoolss_EnumPorts(pipes_struct *p,
+                         struct spoolss_EnumPorts *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;
+       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_enumports\n"));
+       DEBUG(4,("_spoolss_EnumPorts\n"));
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumports_level_1(buffer, offered, needed, returned);
+               result = enumports_level_1(p->mem_ctx, r->out.info,
+                                          r->out.count);
+               break;
        case 2:
-               return enumports_level_2(buffer, offered, needed, returned);
+               result = enumports_level_2(p->mem_ctx, 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_EnumPorts, 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);
 }
 
 /****************************************************************************
@@ -8051,48 +7830,100 @@ WERROR _spoolss_AddPrinterDriverEx(pipes_struct *p,
 /****************************************************************************
 ****************************************************************************/
 
-static WERROR getprinterdriverdir_level_1(TALLOC_CTX *mem_ctx,
+struct _spoolss_paths {
+       int type;
+       const char *share;
+       const char *dir;
+};
+
+enum { SPOOLSS_DRIVER_PATH, SPOOLSS_PRTPROCS_PATH };
+
+static const struct _spoolss_paths spoolss_paths[]= {
+       { SPOOLSS_DRIVER_PATH,          "print$",       "DRIVERS" },
+       { SPOOLSS_PRTPROCS_PATH,        "prnproc$",     "PRTPROCS" }
+};
+
+static WERROR compose_spoolss_server_path(TALLOC_CTX *mem_ctx,
                                          const char *servername,
                                          const char *environment,
-                                         struct spoolss_DriverDirectoryInfo1 *info1,
-                                         uint32_t offered,
-                                         uint32_t *needed)
+                                         int component,
+                                         char **path)
 {
-       char *path = NULL;
        const char *pservername = NULL;
        const char *long_archi = SPOOLSS_ARCHITECTURE_NT_X86;
        const char *short_archi;
 
-       if (environment) {
+       *path = NULL;
+
+       /* environment may be empty */
+       if (environment && strlen(environment)) {
                long_archi = environment;
        }
 
-       pservername = canon_servername(servername);
+       /* servername may be empty */
+       if (servername && strlen(servername)) {
+               pservername = canon_servername(servername);
 
-       if ( !is_myname_or_ipaddr(pservername))
-               return WERR_INVALID_PARAM;
+               if (!is_myname_or_ipaddr(pservername)) {
+                       return WERR_INVALID_PARAM;
+               }
+       }
 
-       if (!(short_archi = get_short_archi(long_archi)))
+       if (!(short_archi = get_short_archi(long_archi))) {
                return WERR_INVALID_ENVIRONMENT;
+       }
+
+       switch (component) {
+       case SPOOLSS_PRTPROCS_PATH:
+       case SPOOLSS_DRIVER_PATH:
+               if (pservername) {
+                       *path = talloc_asprintf(mem_ctx,
+                                       "\\\\%s\\%s\\%s",
+                                       pservername,
+                                       spoolss_paths[component].share,
+                                       short_archi);
+               } else {
+                       *path = talloc_asprintf(mem_ctx, "%s\\%s\\%s",
+                                       SPOOLSS_DEFAULT_SERVER_PATH,
+                                       spoolss_paths[component].dir,
+                                       short_archi);
+               }
+               break;
+       default:
+               return WERR_INVALID_PARAM;
+       }
 
-       path = talloc_asprintf(mem_ctx,
-                       "\\\\%s\\print$\\%s", pservername, short_archi);
-       if (!path) {
+       if (!*path) {
                return WERR_NOMEM;
        }
 
-       DEBUG(4,("printer driver directory: [%s]\n", path));
+       return WERR_OK;
+}
 
-       info1->directory_name = path;
+/****************************************************************************
+****************************************************************************/
 
-       *needed += ndr_size_spoolss_DriverDirectoryInfo1(info1, NULL, 0);
+static WERROR getprinterdriverdir_level_1(TALLOC_CTX *mem_ctx,
+                                         const char *servername,
+                                         const char *environment,
+                                         struct spoolss_DriverDirectoryInfo1 *r)
+{
+       WERROR werr;
+       char *path = NULL;
 
-       if (*needed > offered) {
-               talloc_free(path);
-               ZERO_STRUCTP(info1);
-               return WERR_INSUFFICIENT_BUFFER;
+       werr = compose_spoolss_server_path(mem_ctx,
+                                          servername,
+                                          environment,
+                                          SPOOLSS_DRIVER_PATH,
+                                          &path);
+       if (!W_ERROR_IS_OK(werr)) {
+               return werr;
        }
 
+       DEBUG(4,("printer driver directory: [%s]\n", path));
+
+       r->directory_name = path;
+
        return WERR_OK;
 }
 
@@ -8111,31 +7942,27 @@ WERROR _spoolss_GetPrinterDriverDirectory(pipes_struct *p,
                return WERR_INVALID_PARAM;
        }
 
-       if (r->in.offered > MAX_RPC_DATA_SIZE) {
-               return WERR_INVALID_PARAM;
-       }
-
-       DEBUG(4,("_spoolss_GetPrinterDriverDirectory\n"));
+       DEBUG(5,("_spoolss_GetPrinterDriverDirectory: level %d\n",
+               r->in.level));
 
        *r->out.needed = 0;
 
-       switch (r->in.level) {
-       case 1:
-               werror = getprinterdriverdir_level_1(p->mem_ctx,
-                                                    r->in.server,
-                                                    r->in.environment,
-                                                    &r->out.info->info1,
-                                                    r->in.offered,
-                                                    r->out.needed);
-               if (!W_ERROR_IS_OK(werror)) {
-                       TALLOC_FREE(r->out.info);
-               }
-               break;
-       default:
-               return WERR_UNKNOWN_LEVEL;
+       /* r->in.level is ignored */
+
+       werror = getprinterdriverdir_level_1(p->mem_ctx,
+                                            r->in.server,
+                                            r->in.environment,
+                                            &r->out.info->info1);
+       if (!W_ERROR_IS_OK(werror)) {
+               TALLOC_FREE(r->out.info);
+               return werror;
        }
 
-       return werror;
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_DriverDirectoryInfo, 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);
 }
 
 /****************************************************************************
@@ -8705,69 +8532,68 @@ done:
 }
 
 /****************************************************************************
- enumprintprocessors level 1.
+ fill_print_processor1
 ****************************************************************************/
 
-static WERROR enumprintprocessors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_print_processor1(TALLOC_CTX *mem_ctx,
+                                   struct spoolss_PrintProcessorInfo1 *r,
+                                   const char *print_processor_name)
 {
-       PRINTPROCESSOR_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       r->print_processor_name = talloc_strdup(mem_ctx, print_processor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->print_processor_name);
 
-       if((info_1 = SMB_MALLOC_P(PRINTPROCESSOR_1)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
+
+/****************************************************************************
+ enumprintprocessors level 1.
+****************************************************************************/
 
-       (*returned) = 0x1;
+static WERROR enumprintprocessors_level_1(TALLOC_CTX *mem_ctx,
+                                         union spoolss_PrintProcessorInfo **info_p,
+                                         uint32_t *count)
+{
+       union spoolss_PrintProcessorInfo *info;
+       WERROR result;
 
-       init_unistr(&info_1->name, "winprint");
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcessorInfo, 1);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       *needed += spoolss_size_printprocessor_info_1(info_1);
+       *count = 1;
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
+       result = fill_print_processor1(info, &info[0].info1, "winprint");
+       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;
        }
 
-       smb_io_printprocessor_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
-
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrintProcessors
+****************************************************************/
 
-WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS *q_u, SPOOL_R_ENUMPRINTPROCESSORS *r_u)
+WERROR _spoolss_EnumPrintProcessors(pipes_struct *p,
+                                   struct spoolss_EnumPrintProcessors *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;
+       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(5,("spoolss_enumprintprocessors\n"));
+       DEBUG(5,("_spoolss_EnumPrintProcessors\n"));
 
        /*
         * Enumerate the print processors ...
@@ -8776,213 +8602,254 @@ WERROR _spoolss_enumprintprocessors(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCESSORS
         * and I can use my nice printer checker.
         */
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintprocessors_level_1(buffer, offered, needed, returned);
+               result = enumprintprocessors_level_1(p->mem_ctx, 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_EnumPrintProcessors, 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);
 }
 
 /****************************************************************************
- enumprintprocdatatypes level 1.
+ fill_printprocdatatype1
 ****************************************************************************/
 
-static WERROR enumprintprocdatatypes_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_printprocdatatype1(TALLOC_CTX *mem_ctx,
+                                     struct spoolss_PrintProcDataTypesInfo1 *r,
+                                     const char *name_array)
 {
-       PRINTPROCDATATYPE_1 *info_1=NULL;
-       WERROR result = WERR_OK;
+       r->name_array = talloc_strdup(mem_ctx, name_array);
+       W_ERROR_HAVE_NO_MEMORY(r->name_array);
 
-       if((info_1 = SMB_MALLOC_P(PRINTPROCDATATYPE_1)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
 
-       (*returned) = 0x1;
+/****************************************************************************
+ enumprintprocdatatypes level 1.
+****************************************************************************/
 
-       init_unistr(&info_1->name, "RAW");
+static WERROR enumprintprocdatatypes_level_1(TALLOC_CTX *mem_ctx,
+                                            union spoolss_PrintProcDataTypesInfo **info_p,
+                                            uint32_t *count)
+{
+       WERROR result;
+       union spoolss_PrintProcDataTypesInfo *info;
 
-       *needed += spoolss_size_printprocdatatype_info_1(info_1);
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcDataTypesInfo, 1);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+       *count = 1;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       result = fill_printprocdatatype1(info, &info[0].info1, "RAW");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       smb_io_printprocdatatype_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
+ out:
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumPrintProcDataTypes
+****************************************************************/
 
-WERROR _spoolss_enumprintprocdatatypes(pipes_struct *p, SPOOL_Q_ENUMPRINTPROCDATATYPES *q_u, SPOOL_R_ENUMPRINTPROCDATATYPES *r_u)
+WERROR _spoolss_EnumPrintProcDataTypes(pipes_struct *p,
+                                      struct spoolss_EnumPrintProcDataTypes *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;
+       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(5,("_spoolss_enumprintprocdatatypes\n"));
+       DEBUG(5,("_spoolss_EnumPrintProcDataTypes\n"));
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintprocdatatypes_level_1(buffer, offered, needed, returned);
+               result = enumprintprocdatatypes_level_1(p->mem_ctx, r->out.info,
+                                                       r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
+
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumPrintProcDataTypes, 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);
 }
 
 /****************************************************************************
- enumprintmonitors level 1.
+ fill_monitor_1
 ****************************************************************************/
 
-static WERROR enumprintmonitors_level_1(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR fill_monitor_1(TALLOC_CTX *mem_ctx,
+                            struct spoolss_MonitorInfo1 *r,
+                            const char *monitor_name)
 {
-       PRINTMONITOR_1 *info_1;
-       WERROR result = WERR_OK;
-       int i;
+       r->monitor_name                 = talloc_strdup(mem_ctx, monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
 
-       if((info_1 = SMB_MALLOC_ARRAY(PRINTMONITOR_1, 2)) == NULL)
-               return WERR_NOMEM;
+       return WERR_OK;
+}
+
+/****************************************************************************
+ fill_monitor_2
+****************************************************************************/
 
-       *returned = 2;
+static WERROR fill_monitor_2(TALLOC_CTX *mem_ctx,
+                            struct spoolss_MonitorInfo2 *r,
+                            const char *monitor_name,
+                            const char *environment,
+                            const char *dll_name)
+{
+       r->monitor_name                 = talloc_strdup(mem_ctx, monitor_name);
+       W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+       r->environment                  = talloc_strdup(mem_ctx, environment);
+       W_ERROR_HAVE_NO_MEMORY(r->environment);
+       r->dll_name                     = talloc_strdup(mem_ctx, dll_name);
+       W_ERROR_HAVE_NO_MEMORY(r->dll_name);
 
-       init_unistr(&(info_1[0].name), SPL_LOCAL_PORT );
-       init_unistr(&(info_1[1].name), SPL_TCPIP_PORT );
+       return WERR_OK;
+}
 
-       for ( i=0; i<*returned; i++ ) {
-               *needed += spoolss_size_printmonitor_info_1(&info_1[i]);
-       }
+/****************************************************************************
+ enumprintmonitors level 1.
+****************************************************************************/
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+static WERROR enumprintmonitors_level_1(TALLOC_CTX *mem_ctx,
+                                       union spoolss_MonitorInfo **info_p,
+                                       uint32_t *count)
+{
+       union spoolss_MonitorInfo *info;
+       WERROR result = WERR_OK;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2);
+       W_ERROR_HAVE_NO_MEMORY(info);
+
+       *count = 2;
+
+       result = fill_monitor_1(info, &info[0].info1,
+                               SPL_LOCAL_PORT /* FIXME */);
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       for ( i=0; i<*returned; i++ ) {
-               smb_io_printmonitor_info_1("", buffer, &info_1[i], 0);
+       result = fill_monitor_1(info, &info[1].info1,
+                               SPL_TCPIP_PORT /* FIXME */);
+       if (!W_ERROR_IS_OK(result)) {
+               goto out;
        }
 
 out:
-       SAFE_FREE(info_1);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
 /****************************************************************************
  enumprintmonitors level 2.
 ****************************************************************************/
 
-static WERROR enumprintmonitors_level_2(RPC_BUFFER *buffer, uint32 offered, uint32 *needed, uint32 *returned)
+static WERROR enumprintmonitors_level_2(TALLOC_CTX *mem_ctx,
+                                       union spoolss_MonitorInfo **info_p,
+                                       uint32_t *count)
 {
-       PRINTMONITOR_2 *info_2;
+       union spoolss_MonitorInfo *info;
        WERROR result = WERR_OK;
-       int i;
-
-       if((info_2 = SMB_MALLOC_ARRAY(PRINTMONITOR_2, 2)) == NULL)
-               return WERR_NOMEM;
-
-       *returned = 2;
 
-       init_unistr( &(info_2[0].name), SPL_LOCAL_PORT );
-       init_unistr( &(info_2[0].environment), "Windows NT X86" );
-       init_unistr( &(info_2[0].dll_name), "localmon.dll" );
+       info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2);
+       W_ERROR_HAVE_NO_MEMORY(info);
 
-       init_unistr( &(info_2[1].name), SPL_TCPIP_PORT );
-       init_unistr( &(info_2[1].environment), "Windows NT X86" );
-       init_unistr( &(info_2[1].dll_name), "tcpmon.dll" );
+       *count = 2;
 
-       for ( i=0; i<*returned; i++ ) {
-               *needed += spoolss_size_printmonitor_info_2(&info_2[i]);
-       }
-
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
+       result = fill_monitor_2(info, &info[0].info2,
+                               SPL_LOCAL_PORT, /* FIXME */
+                               "Windows NT X86", /* FIXME */
+                               "localmon.dll");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
+       result = fill_monitor_2(info, &info[1].info2,
+                               SPL_TCPIP_PORT, /* FIXME */
+                               "Windows NT X86", /* FIXME */
+                               "tcpmon.dll");
+       if (!W_ERROR_IS_OK(result)) {
                goto out;
        }
 
-       for ( i=0; i<*returned; i++ ) {
-               smb_io_printmonitor_info_2("", buffer, &info_2[i], 0);
-       }
-
 out:
-       SAFE_FREE(info_2);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(info);
+               *count = 0;
+               return result;
+       }
 
-       if ( !W_ERROR_IS_OK(result) )
-               *returned = 0;
+       *info_p = info;
 
-       return result;
+       return WERR_OK;
 }
 
-/****************************************************************************
-****************************************************************************/
+/****************************************************************
+ _spoolss_EnumMonitors
+****************************************************************/
 
-WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_u, SPOOL_R_ENUMPRINTMONITORS *r_u)
+WERROR _spoolss_EnumMonitors(pipes_struct *p,
+                            struct spoolss_EnumMonitors *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;
+       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(5,("spoolss_enumprintmonitors\n"));
+       DEBUG(5,("_spoolss_EnumMonitors\n"));
 
        /*
         * Enumerate the print monitors ...
@@ -8991,102 +8858,95 @@ WERROR _spoolss_enumprintmonitors(pipes_struct *p, SPOOL_Q_ENUMPRINTMONITORS *q_
         * and I can use my nice printer checker.
         */
 
-       *returned=0;
-       *needed=0;
+       *r->out.count = 0;
+       *r->out.needed = 0;
+       *r->out.info = NULL;
 
-       switch (level) {
+       switch (r->in.level) {
        case 1:
-               return enumprintmonitors_level_1(buffer, offered, needed, returned);
+               result = enumprintmonitors_level_1(p->mem_ctx, r->out.info,
+                                                  r->out.count);
+               break;
        case 2:
-               return enumprintmonitors_level_2(buffer, offered, needed, returned);
+               result = enumprintmonitors_level_2(p->mem_ctx, r->out.info,
+                                                  r->out.count);
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
-}
-
-/****************************************************************************
-****************************************************************************/
-
-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)
-{
-       int i=0;
-       bool found=False;
-       JOB_INFO_1 *info_1=NULL;
-       WERROR result = WERR_OK;
-
-       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;
+       if (!W_ERROR_IS_OK(result)) {
+               return result;
        }
 
-       if (found==False) {
-               SAFE_FREE(info_1);
-               /* NT treats not found as bad param... yet another bad choice */
-               return WERR_INVALID_PARAM;
-       }
+       *r->out.needed  = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx,
+                                                    spoolss_EnumMonitors, 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);
 
-       fill_job_info_1( info_1, &((*queue)[i-1]), i, snum, ntprinter );
+       return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER);
+}
 
-       *needed += spoolss_size_job_info_1(info_1);
+/****************************************************************************
+****************************************************************************/
 
-       if (*needed > offered) {
-               result = WERR_INSUFFICIENT_BUFFER;
-               goto out;
-       }
+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;
 
-       if (!rpcbuf_alloc_size(buffer, *needed)) {
-               result = WERR_NOMEM;
-               goto out;
+       for (i=0; i<count && found == false; i++) {
+               if (queue[i].job == (int)jobid) {
+                       found = true;
+               }
        }
 
-       smb_io_job_info_1("", buffer, info_1, 0);
-
-out:
-       SAFE_FREE(info_1);
+       if (found == false) {
+               /* NT treats not found as bad param... yet another bad choice */
+               return WERR_INVALID_PARAM;
+       }
 
-       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;
        }
 
        /*
@@ -9095,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;
@@ -9151,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);
 }
 
 /****************************************************************
@@ -9720,38 +9568,23 @@ done:
 static WERROR getprintprocessordirectory_level_1(TALLOC_CTX *mem_ctx,
                                                 const char *servername,
                                                 const char *environment,
-                                                struct spoolss_PrintProcessorDirectoryInfo1 *info1,
-                                                uint32_t offered,
-                                                uint32_t *needed)
+                                                struct spoolss_PrintProcessorDirectoryInfo1 *r)
 {
-       const char *long_archi = SPOOLSS_ARCHITECTURE_NT_X86;
-       const char *short_archi;
-
-       if (environment) {
-               long_archi = environment;
-       }
-
-       short_archi = get_short_archi(long_archi);
-       if (!short_archi) {
-               return WERR_INVALID_ENVIRONMENT;
-       }
-
-       /* I think this should look like this - gd
-       info1->directory_name = talloc_asprintf(mem_ctx,
-               "C:\\WINNT\\System32\\spool\\PRTPROCS\\%s", short_archi);
-       */
-       info1->directory_name = talloc_strdup(mem_ctx,
-               "C:\\WINNT\\System32\\spool\\PRTPROCS\\W32X86");
+       WERROR werr;
+       char *path = NULL;
 
-       if (!info1->directory_name) {
-               return WERR_NOMEM;
+       werr = compose_spoolss_server_path(mem_ctx,
+                                          servername,
+                                          environment,
+                                          SPOOLSS_PRTPROCS_PATH,
+                                          &path);
+       if (!W_ERROR_IS_OK(werr)) {
+               return werr;
        }
 
-       *needed += ndr_size_spoolss_PrintProcessorDirectoryInfo1(info1, NULL, 0);
+       DEBUG(4,("print processor directory: [%s]\n", path));
 
-       if (*needed > offered) {
-               return WERR_INSUFFICIENT_BUFFER;
-       }
+       r->directory_name = path;
 
        return WERR_OK;
 }
@@ -9771,31 +9604,27 @@ WERROR _spoolss_GetPrintProcessorDirectory(pipes_struct *p,
                return WERR_INVALID_PARAM;
        }
 
-       if (r->in.offered > MAX_RPC_DATA_SIZE) {
-               return WERR_INVALID_PARAM;
-       }
-
-       DEBUG(5,("_spoolss_GetPrintProcessorDirectory\n"));
+       DEBUG(5,("_spoolss_GetPrintProcessorDirectory: level %d\n",
+               r->in.level));
 
        *r->out.needed = 0;
 
-       switch (r->in.level) {
-       case 1:
-               result = getprintprocessordirectory_level_1(p->mem_ctx,
-                                                           r->in.server,
-                                                           r->in.environment,
-                                                           &r->out.info->info1,
-                                                           r->in.offered,
-                                                           r->out.needed);
-               if (!W_ERROR_IS_OK(result)) {
-                       TALLOC_FREE(r->out.info);
-               }
-               break;
-       default:
-               result = WERR_UNKNOWN_LEVEL;
+       /* r->in.level is ignored */
+
+       result = getprintprocessordirectory_level_1(p->mem_ctx,
+                                                   r->in.server,
+                                                   r->in.environment,
+                                                   &r->out.info->info1);
+       if (!W_ERROR_IS_OK(result)) {
+               TALLOC_FREE(r->out.info);
+               return result;
        }
 
-       return result;
+       *r->out.needed  = SPOOLSS_BUFFER_UNION(spoolss_PrintProcessorDirectoryInfo, 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);
 }
 
 /*******************************************************************
@@ -10051,7 +9880,7 @@ WERROR _spoolss_XcvData(pipes_struct *p,
                        struct spoolss_XcvData *r)
 {
        Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle);
-       DATA_BLOB out_data;
+       DATA_BLOB out_data = data_blob_null;
        WERROR werror;
 
        if (!Printer) {
@@ -10128,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
 ****************************************************************/
@@ -10172,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
 ****************************************************************/
@@ -10205,17 +9979,6 @@ WERROR _spoolss_GetPrinterDriver(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumPrintProcessors
-****************************************************************/
-
-WERROR _spoolss_EnumPrintProcessors(pipes_struct *p,
-                                   struct spoolss_EnumPrintProcessors *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_ReadPrinter
 ****************************************************************/
@@ -10260,39 +10023,6 @@ WERROR _spoolss_WaitForPrinterChange(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumForms
-****************************************************************/
-
-WERROR _spoolss_EnumForms(pipes_struct *p,
-                         struct spoolss_EnumForms *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_EnumPorts
-****************************************************************/
-
-WERROR _spoolss_EnumPorts(pipes_struct *p,
-                         struct spoolss_EnumPorts *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
- _spoolss_EnumMonitors
-****************************************************************/
-
-WERROR _spoolss_EnumMonitors(pipes_struct *p,
-                            struct spoolss_EnumMonitors *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_AddPort
 ****************************************************************/
@@ -10447,28 +10177,6 @@ WERROR _spoolss_DeletePrintProvidor(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_EnumPrintProcDataTypes
-****************************************************************/
-
-WERROR _spoolss_EnumPrintProcDataTypes(pipes_struct *p,
-                                      struct spoolss_EnumPrintProcDataTypes *r)
-{
-       p->rng_fault_state = true;
-       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
 ****************************************************************/
@@ -10579,17 +10287,6 @@ WERROR _spoolss_ResetPrinterEx(pipes_struct *p,
        return WERR_NOT_SUPPORTED;
 }
 
-/****************************************************************
- _spoolss_RemoteFindFirstPrinterChangeNotifyEx
-****************************************************************/
-
-WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(pipes_struct *p,
-                                                    struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
 /****************************************************************
  _spoolss_RouterReplyPrinterEx
 ****************************************************************/