fix a typo
[tprouty/samba.git] / source / rpc_parse / parse_spoolss.c
index 2663b09381225a46e60375427cfe7c156eb4f6b0..38141515dc1fa8aa73884c8c26c077fe62cac34b 100644 (file)
@@ -3,7 +3,7 @@
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
  *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
- *  Copyright (C) Jean François Micouleau      1998-2000,
+ *  Copyright (C) Jean François Micouleau      1998-2000,
  *  Copyright (C) Gerald Carter                2000-2002,
  *  Copyright (C) Tim Potter                  2001-2002.
  *
@@ -230,6 +230,10 @@ static BOOL smb_io_notify_option_type_data(const char *desc, SPOOL_NOTIFY_OPTION
        if (type->count2 != type->count)
                DEBUG(4,("What a mess, count was %x now is %x !\n", type->count, type->count2));
 
+       if (type->count2 > MAX_NOTIFY_TYPE_FOR_NOW) {
+               return False;
+       }
+
        /* parse the option type data */
        for(i=0;i<type->count2;i++)
                if(!prs_uint16("fields",ps,depth,&type->fields[i]))
@@ -252,7 +256,7 @@ static BOOL smb_io_notify_option_type_ctr(const char *desc, SPOOL_NOTIFY_OPTION_
                return False;
 
        /* reading */
-       if (UNMARSHALLING(ps))
+       if (UNMARSHALLING(ps) && ctr->count)
                if((ctr->type=PRS_ALLOC_MEM(ps,SPOOL_NOTIFY_OPTION_TYPE,ctr->count)) == NULL)
                        return False;
                
@@ -411,7 +415,7 @@ BOOL smb_io_notify_info_data_strings(const char *desc,SPOOL_NOTIFY_INFO_DATA *da
                if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length))
                        return False;
 
-               if (UNMARSHALLING(ps)) {
+               if (UNMARSHALLING(ps) && data->notify_data.data.length) {
                        data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16,
                                                                data->notify_data.data.length);
 
@@ -430,7 +434,7 @@ BOOL smb_io_notify_info_data_strings(const char *desc,SPOOL_NOTIFY_INFO_DATA *da
 
        case NOTIFY_POINTER:
 
-               if (UNMARSHALLING(ps)) {
+               if (UNMARSHALLING(ps) && data->notify_data.data.length) {
                        data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16,
                                                                data->notify_data.data.length);
 
@@ -490,9 +494,13 @@ BOOL smb_io_notify_info_data_strings(const char *desc,SPOOL_NOTIFY_INFO_DATA *da
 
                        /* Tallocate memory for string */
 
-                       data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16, x * 2);
-                       if (!data->notify_data.data.string) 
-                               return False;
+                       if (x) {
+                               data->notify_data.data.string = PRS_ALLOC_MEM(ps, uint16, x * 2);
+                               if (!data->notify_data.data.string) 
+                                       return False;
+                       } else {
+                               data->notify_data.data.string = NULL;
+                       }
 
                        if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
                                return False;
@@ -606,7 +614,7 @@ static BOOL spool_io_user_level(const char *desc, SPOOL_USER_CTR *q_u, prs_struc
        switch ( q_u->level ) 
        {       
                case 1:
-                       if ( !prs_pointer( "" , ps, depth, (void**)&q_u->user.user1, 
+                       if ( !prs_pointer( "" , ps, depth, (void*)&q_u->user.user1, 
                                sizeof(SPOOL_USER_1), (PRS_POINTER_CAST)spool_io_user_level_1 )) 
                        {
                                return False;
@@ -631,6 +639,8 @@ BOOL spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE
        int available_space;            /* size of the device mode left to parse */
                                        /* only important on unmarshalling       */
        int i = 0;
+       uint16 *unistr_buffer;
+       int j;
                                        
        struct optional_fields {
                fstring         name;
@@ -662,12 +672,20 @@ BOOL spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE
        depth++;
 
        if (UNMARSHALLING(ps)) {
-               devmode->devicename.buffer = PRS_ALLOC_MEM(ps, uint16, 32);
+               devmode->devicename.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
                if (devmode->devicename.buffer == NULL)
                        return False;
+               unistr_buffer = devmode->devicename.buffer;
        }
-
-       if (!prs_uint16uni(True,"devicename", ps, depth, devmode->devicename.buffer, MAXDEVICENAME))
+       else {
+               /* devicename is a static sized string but the buffer we set is not */
+               unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+               memset( unistr_buffer, 0x0, MAXDEVICENAME );
+               for ( j=0; devmode->devicename.buffer[j]; j++ )
+                       unistr_buffer[j] = devmode->devicename.buffer[j];
+       }
+               
+       if (!prs_uint16uni(True,"devicename", ps, depth, unistr_buffer, MAXDEVICENAME))
                return False;
        
        if (!prs_uint16("specversion",      ps, depth, &devmode->specversion))
@@ -709,12 +727,20 @@ BOOL spoolss_io_devmode(const char *desc, prs_struct *ps, int depth, DEVICEMODE
                return False;
 
        if (UNMARSHALLING(ps)) {
-               devmode->formname.buffer = PRS_ALLOC_MEM(ps, uint16, 32);
+               devmode->formname.buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
                if (devmode->formname.buffer == NULL)
                        return False;
+               unistr_buffer = devmode->formname.buffer;
        }
-
-       if (!prs_uint16uni(True, "formname",  ps, depth, devmode->formname.buffer, 32))
+       else {
+               /* devicename is a static sized string but the buffer we set is not */
+               unistr_buffer = PRS_ALLOC_MEM(ps, uint16, MAXDEVICENAME);
+               memset( unistr_buffer, 0x0, MAXDEVICENAME );
+               for ( j=0; devmode->formname.buffer[j]; j++ )
+                       unistr_buffer[j] = devmode->formname.buffer[j];
+       }
+       
+       if (!prs_uint16uni(True, "formname",  ps, depth, unistr_buffer, MAXDEVICENAME))
                return False;
        if (!prs_uint16("logpixels",        ps, depth, &devmode->logpixels))
                return False;
@@ -881,6 +907,9 @@ BOOL make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
        DEBUG(5,("make_spoolss_q_open_printer_ex\n"));
 
        q_u->printername = TALLOC_P( get_talloc_ctx(), UNISTR2 );
+       if (!q_u->printername) {
+               return False;
+       }
        init_unistr2(q_u->printername, printername, UNI_STR_TERMINATE);
 
        q_u->printer_default.datatype_ptr = 0;
@@ -894,6 +923,9 @@ BOOL make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
        
        q_u->user_ctr.level                 = 1;
        q_u->user_ctr.user.user1            = TALLOC_P( get_talloc_ctx(), SPOOL_USER_1 );
+       if (!q_u->user_ctr.user.user1) {
+               return False;
+       }
        q_u->user_ctr.user.user1->size      = strlen(clientname) + strlen(user_name) + 10;
        q_u->user_ctr.user.user1->build     = 1381;
        q_u->user_ctr.user.user1->major     = 2;
@@ -901,7 +933,13 @@ BOOL make_spoolss_q_open_printer_ex(SPOOL_Q_OPEN_PRINTER_EX *q_u,
        q_u->user_ctr.user.user1->processor = 0;
 
        q_u->user_ctr.user.user1->client_name = TALLOC_P( get_talloc_ctx(), UNISTR2 );
+       if (!q_u->user_ctr.user.user1->client_name) {
+               return False;
+       }
        q_u->user_ctr.user.user1->user_name   = TALLOC_P( get_talloc_ctx(), UNISTR2 );
+       if (!q_u->user_ctr.user.user1->user_name) {
+               return False;
+       }
 
        init_unistr2(q_u->user_ctr.user.user1->client_name, clientname, UNI_STR_TERMINATE);
        init_unistr2(q_u->user_ctr.user.user1->user_name, user_name, UNI_STR_TERMINATE);
@@ -919,12 +957,15 @@ BOOL make_spoolss_q_addprinterex( TALLOC_CTX *mem_ctx, SPOOL_Q_ADDPRINTEREX *q_u
 {
        DEBUG(5,("make_spoolss_q_addprinterex\n"));
        
-       if (!ctr) 
+       if (!ctr || !ctr->printers_2
                return False;
 
        ZERO_STRUCTP(q_u);
 
        q_u->server_name = TALLOC_P( mem_ctx, UNISTR2 );
+       if (!q_u->server_name) {
+               return False;
+       }
        init_unistr2(q_u->server_name, srv_name, UNI_FLAGS_NONE);
 
        q_u->level = level;
@@ -947,14 +988,22 @@ BOOL make_spoolss_q_addprinterex( TALLOC_CTX *mem_ctx, SPOOL_Q_ADDPRINTEREX *q_u
 
        q_u->user_ctr.level                 = 1;
        q_u->user_ctr.user.user1            = TALLOC_P( get_talloc_ctx(), SPOOL_USER_1 );
+       if (!q_u->user_ctr.user.user1) {
+               return False;
+       }
        q_u->user_ctr.user.user1->build     = 1381;
        q_u->user_ctr.user.user1->major     = 2; 
        q_u->user_ctr.user.user1->minor     = 0;
        q_u->user_ctr.user.user1->processor = 0;
 
        q_u->user_ctr.user.user1->client_name = TALLOC_P( mem_ctx, UNISTR2 );
+       if (!q_u->user_ctr.user.user1->client_name) {
+               return False;
+       }
        q_u->user_ctr.user.user1->user_name   = TALLOC_P( mem_ctx, UNISTR2 );
-
+       if (!q_u->user_ctr.user.user1->user_name) {
+               return False;
+       }
        init_unistr2(q_u->user_ctr.user.user1->client_name, clientname, UNI_STR_TERMINATE);
        init_unistr2(q_u->user_ctr.user.user1->user_name, user_name, UNI_STR_TERMINATE);
 
@@ -2347,6 +2396,7 @@ BOOL smb_io_printer_info_2(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_2
 
 BOOL smb_io_printer_info_3(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_3 *info, int depth)
 {
+       uint32 offset = 0;
        prs_struct *ps=&buffer->prs;
 
        prs_debug(ps, depth, desc, "smb_io_printer_info_3");
@@ -2354,8 +2404,41 @@ BOOL smb_io_printer_info_3(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_3
        
        buffer->struct_start=prs_offset(ps);
        
-       if (!prs_uint32("flags", ps, depth, &info->flags))
-               return False;
+       if (MARSHALLING(ps)) {
+               /* Ensure the SD is 8 byte aligned in the buffer. */
+               uint start = prs_offset(ps); /* Remember the start position. */
+               uint off_val = 0;
+
+               /* Write a dummy value. */
+               if (!prs_uint32("offset", ps, depth, &off_val))
+                       return False;
+
+               /* 8 byte align. */
+               if (!prs_align_uint64(ps))
+                       return False;
+
+               /* Remember where we must seek back to write the SD. */
+               offset = prs_offset(ps);
+
+               /* Calculate the real offset for the SD. */
+
+               off_val = offset - start;
+
+               /* Seek back to where we store the SD offset & store. */
+               prs_set_offset(ps, start);
+               if (!prs_uint32("offset", ps, depth, &off_val))
+                       return False;
+
+               /* Return to after the 8 byte align. */
+               prs_set_offset(ps, offset);
+
+       } else {
+               if (!prs_uint32("offset", ps, depth, &offset))
+                       return False;
+               /* Seek within the buffer. */
+               if (!prs_set_offset(ps, offset))
+                       return False;
+       }
        if (!sec_io_desc("sec_desc", &info->secdesc, ps, depth))
                return False;
 
@@ -2410,6 +2493,24 @@ BOOL smb_io_printer_info_5(const char *desc, RPC_BUFFER *buffer, PRINTER_INFO_5
        return True;
 }
 
+/*******************************************************************
+ Parse a PRINTER_INFO_6 structure.
+********************************************************************/  
+
+BOOL smb_io_printer_info_6(const char *desc, RPC_BUFFER *buffer,
+                          PRINTER_INFO_6 *info, int depth)
+{
+       prs_struct *ps=&buffer->prs;
+
+       prs_debug(ps, depth, desc, "smb_io_printer_info_6");
+       depth++;        
+       
+       if (!prs_uint32("status", ps, depth, &info->status))
+               return False;
+
+       return True;
+}
+
 /*******************************************************************
  Parse a PRINTER_INFO_7 structure.
 ********************************************************************/  
@@ -2602,9 +2703,7 @@ BOOL smb_io_printer_driver_info_6(const char *desc, RPC_BUFFER *buffer, DRIVER_I
        if (!smb_io_relarraystr("previousdrivernames", buffer, depth, &info->previousdrivernames))
                return False;
 
-       if (!prs_uint32("date.low", ps, depth, &info->driver_date.low))
-               return False;
-       if (!prs_uint32("date.high", ps, depth, &info->driver_date.high))
+       if (!prs_uint64("date", ps, depth, &info->driver_date))
                return False;
 
        if (!prs_uint32("padding", ps, depth, &info->padding))
@@ -3071,6 +3170,14 @@ uint32 spoolss_size_printer_info_5(PRINTER_INFO_5 *info)
        return size;
 }
 
+/*******************************************************************
+return the size required by a struct in the stream
+********************************************************************/
+
+uint32 spoolss_size_printer_info_6(PRINTER_INFO_6 *info)
+{
+       return sizeof(uint32);
+}
 
 /*******************************************************************
 return the size required by a struct in the stream
@@ -3078,9 +3185,8 @@ return the size required by a struct in the stream
 
 uint32 spoolss_size_printer_info_3(PRINTER_INFO_3 *info)
 {
-       /* The 4 is for the self relative pointer.. */
-       /* JRA !!!! TESTME - WHAT ABOUT prs_align.... !!! */
-       return 4 + (uint32)sec_desc_size( info->secdesc );
+       /* The 8 is for the self relative pointer - 8 byte aligned.. */
+       return 8 + (uint32)sec_desc_size( info->secdesc );
 }
 
 /*******************************************************************
@@ -3715,14 +3821,14 @@ BOOL make_spoolss_q_setprinter(TALLOC_CTX *mem_ctx, SPOOL_Q_SETPRINTER *q_u,
        SEC_DESC *secdesc;
        DEVICEMODE *devmode;
 
-       if (q_u == NULL)
+       if (!q_u || !info)
                return False;
        
        memcpy(&q_u->handle, hnd, sizeof(q_u->handle));
 
        q_u->level = level;
        q_u->info.level = level;
-       q_u->info.info_ptr = (info != NULL) ? 1 : 0;
+       q_u->info.info_ptr = 1; /* Info is != NULL, see above */
        switch (level) {
 
          /* There's no such thing as a setprinter level 1 */
@@ -3852,7 +3958,16 @@ BOOL spoolss_io_q_setprinter(const char *desc, SPOOL_Q_SETPRINTER *q_u, prs_stru
                }
                case 3:
                {
-                       ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+                       /* FIXME ! Our parsing here is wrong I think,
+                        * but for a level3 it makes no sense for
+                        * ptr_sec_desc to be NULL. JRA. Based on
+                        * a Vista sniff from Martin Zielinski <mz@seh.de>.
+                        */
+                       if (UNMARSHALLING(ps)) {
+                               ptr_sec_desc = 1;
+                       } else {
+                               ptr_sec_desc = q_u->info.info_3->secdesc_ptr;
+                       }
                        break;
                }
        }
@@ -3869,8 +3984,8 @@ BOOL spoolss_io_q_setprinter(const char *desc, SPOOL_Q_SETPRINTER *q_u, prs_stru
                prs_debug(ps, depth, "", "sec_io_desc_buf");
                if (!prs_uint32("size", ps, depth + 1, &dummy))
                        return False;
-               if (!prs_uint32("ptr", ps, depth + 1, &dummy)) return
-                                                                      False;
+               if (!prs_uint32("ptr", ps, depth + 1, &dummy))
+                       return False;
        }
        
        if(!prs_uint32("command", ps, depth, &q_u->command))
@@ -4948,9 +5063,10 @@ BOOL spool_io_printer_driver_info_level_6(const char *desc, SPOOL_PRINTER_DRIVER
  dynamically allocate memory
  
 ********************************************************************/  
+
 static BOOL uniarray_2_dosarray(BUFFER5 *buf5, fstring **ar)
 {
-       fstring f, *tar;
+       fstring f;
        int n = 0;
        char *src;
 
@@ -4958,27 +5074,27 @@ static BOOL uniarray_2_dosarray(BUFFER5 *buf5, fstring **ar)
                return False;
 
        src = (char *)buf5->buffer;
-       *ar = NULL;
+       *ar = SMB_MALLOC_ARRAY(fstring, 1);
+       if (!*ar) {
+               return False;
+       }
 
        while (src < ((char *)buf5->buffer) + buf5->buf_len*2) {
                rpcstr_pull(f, src, sizeof(f)-1, -1, STR_TERMINATE);
                src = skip_unibuf(src, 2*buf5->buf_len - PTR_DIFF(src,buf5->buffer));
-               tar = SMB_REALLOC_ARRAY(*ar, fstring, n+2);
-               if (!tar)
+               *ar = SMB_REALLOC_ARRAY(*ar, fstring, n+2);
+               if (!*ar) {
                        return False;
-               else
-                       *ar = tar;
+               }
                fstrcpy((*ar)[n], f);
                n++;
        }
+
        fstrcpy((*ar)[n], "");
  
        return True;
 }
 
-
-
-
 /*******************************************************************
  read a UNICODE array with null terminated strings 
  and null terminated array 
@@ -5045,13 +5161,17 @@ BOOL make_spoolss_q_addprinterdriver(TALLOC_CTX *mem_ctx,
 {
        DEBUG(5,("make_spoolss_q_addprinterdriver\n"));
        
-       q_u->server_name_ptr = (srv_name!=NULL)?1:0;
+       if (!srv_name || !info) {
+               return False;
+       }
+
+       q_u->server_name_ptr = 1; /* srv_name is != NULL, see above */
        init_unistr2(&q_u->server_name, srv_name, UNI_STR_TERMINATE);
        
        q_u->level = level;
        
        q_u->info.level = level;
-       q_u->info.ptr = (info!=NULL)?1:0;
+       q_u->info.ptr = 1;      /* Info is != NULL, see above */
        switch (level)
        {
        /* info level 3 is supported by Windows 95/98, WinNT and Win2k */
@@ -5072,9 +5192,6 @@ BOOL make_spoolss_driver_info_3(TALLOC_CTX *mem_ctx,
                                DRIVER_INFO_3 *info3)
 {
        uint32          len = 0;
-       uint16          *ptr = info3->dependentfiles;
-       BOOL            done = False;
-       BOOL            null_char = False;
        SPOOL_PRINTER_DRIVER_INFO_LEVEL_3 *inf;
 
        if (!(inf=TALLOC_ZERO_P(mem_ctx, SPOOL_PRINTER_DRIVER_INFO_LEVEL_3)))
@@ -5099,31 +5216,35 @@ BOOL make_spoolss_driver_info_3(TALLOC_CTX *mem_ctx,
        init_unistr2_from_unistr(&inf->monitorname, &info3->monitorname);
        init_unistr2_from_unistr(&inf->defaultdatatype, &info3->defaultdatatype);
 
-       while (!done)
-       {
-               switch (*ptr)
-               {
-                       case 0:
-                               /* the null_char BOOL is used to help locate
-                                  two '\0's back to back */
-                               if (null_char)
-                                       done = True;
-                               else
-                                       null_char = True;
-                               break;
+       if (info3->dependentfiles) {
+               BOOL done = False;
+               BOOL null_char = False;
+               uint16 *ptr = info3->dependentfiles;
+
+               while (!done) {
+                       switch (*ptr) {
+                               case 0:
+                                       /* the null_char BOOL is used to help locate
+                                          two '\0's back to back */
+                                       if (null_char) {
+                                               done = True;
+                                       } else {
+                                               null_char = True;
+                                       }
+                                       break;
                                        
-                       default:
-                               null_char = False;
-                               ;;
-                               break;                          
+                               default:
+                                       null_char = False;
+                                       break;                          
+                       }
+                       len++;
+                       ptr++;
                }
-               len++;
-               ptr++;
        }
+
        inf->dependentfiles_ptr = (info3->dependentfiles != NULL) ? 1 : 0;
-       inf->dependentfilessize = len;
-       if(!make_spoolss_buffer5(mem_ctx, &inf->dependentfiles, len, info3->dependentfiles))
-       {
+       inf->dependentfilessize = (info3->dependentfiles != NULL) ? len : 0;
+       if(!make_spoolss_buffer5(mem_ctx, &inf->dependentfiles, len, info3->dependentfiles)) {
                SAFE_FREE(inf);
                return False;
        }
@@ -5136,13 +5257,22 @@ BOOL make_spoolss_driver_info_3(TALLOC_CTX *mem_ctx,
 /*******************************************************************
  make a BUFFER5 struct from a uint16*
  ******************************************************************/
+
 BOOL make_spoolss_buffer5(TALLOC_CTX *mem_ctx, BUFFER5 *buf5, uint32 len, uint16 *src)
 {
 
        buf5->buf_len = len;
-       if((buf5->buffer=(uint16*)TALLOC_MEMDUP(mem_ctx, src, sizeof(uint16)*len)) == NULL) {
-               DEBUG(0,("make_spoolss_buffer5: Unable to malloc memory for buffer!\n"));
-               return False;
+       if (src) {
+               if (len) {
+                       if((buf5->buffer=(uint16*)TALLOC_MEMDUP(mem_ctx, src, sizeof(uint16)*len)) == NULL) {
+                               DEBUG(0,("make_spoolss_buffer5: Unable to malloc memory for buffer!\n"));
+                               return False;
+                       }
+               } else {
+                       buf5->buffer = NULL;
+               }
+       } else {
+               buf5->buffer=NULL;
        }
        
        return True;
@@ -5338,32 +5468,10 @@ error:
 }
 
 BOOL uni_2_asc_printer_info_2(const SPOOL_PRINTER_INFO_LEVEL_2 *uni,
-                              NT_PRINTER_INFO_LEVEL_2  **asc)
+                              NT_PRINTER_INFO_LEVEL_2  *d)
 {
-       NT_PRINTER_INFO_LEVEL_2 *d;
-       time_t time_unix;
-       
        DEBUG(7,("Converting from UNICODE to ASCII\n"));
-       time_unix=time(NULL);
        
-       if (*asc==NULL) {
-               DEBUGADD(8,("allocating memory\n"));
-
-               *asc=SMB_MALLOC_P(NT_PRINTER_INFO_LEVEL_2);
-               if(*asc == NULL)
-                       return False;
-               ZERO_STRUCTP(*asc);
-               
-               /* we allocate memory iff called from 
-                * addprinter(ex) so we can do one time stuff here.
-                */
-               (*asc)->setuptime=time_unix;
-
-       }       
-       DEBUGADD(8,("start converting\n"));
-
-       d=*asc;
-               
        d->attributes=uni->attributes;
        d->priority=uni->priority;
        d->default_priority=uni->default_priority;
@@ -5901,14 +6009,14 @@ BOOL spoolss_io_q_setprinterdata(const char *desc, SPOOL_Q_SETPRINTERDATA *q_u,
                case REG_BINARY:
                case REG_DWORD:
                case REG_MULTI_SZ:
-            if (q_u->max_len) {
-                if (UNMARSHALLING(ps))
-                               q_u->data=PRS_ALLOC_MEM(ps, uint8, q_u->max_len);
-                       if(q_u->data == NULL)
-                               return False;
-                       if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
-                               return False;
-            }
+                       if (q_u->max_len) {
+                               if (UNMARSHALLING(ps))
+                                       q_u->data=PRS_ALLOC_MEM(ps, uint8, q_u->max_len);
+                               if(q_u->data == NULL)
+                                       return False;
+                               if(!prs_uint8s(False,"data", ps, depth, q_u->data, q_u->max_len))
+                                       return False;
+                       }
                        if(!prs_align(ps))
                                return False;
                        break;
@@ -6239,6 +6347,11 @@ void free_printer_info_5(PRINTER_INFO_5 *printer)
        SAFE_FREE(printer);
 }
 
+void free_printer_info_6(PRINTER_INFO_6 *printer)
+{
+       SAFE_FREE(printer);
+}
+
 void free_printer_info_7(PRINTER_INFO_7 *printer)
 {
        SAFE_FREE(printer);
@@ -6913,10 +7026,10 @@ static BOOL spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps,
                data_offset,
                current_offset;
        const uint32 basic_unit = 20; /* size of static portion of enum_values */
-       
+
        prs_debug(ps, depth, desc, "spoolss_io_printer_enum_values_ctr");
        depth++;        
-       
+
        /* 
         * offset data begins at 20 bytes per structure * size_of_array.
         * Don't forget the uint32 at the beginning 
@@ -6926,17 +7039,36 @@ static BOOL spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps,
        
        /* first loop to write basic enum_value information */
        
-       if (UNMARSHALLING(ps)) {
+       if (UNMARSHALLING(ps) && ctr->size_of_array) {
                ctr->values = PRS_ALLOC_MEM(ps, PRINTER_ENUM_VALUES, ctr->size_of_array);
                if (!ctr->values)
                        return False;
        }
 
        for (i=0; i<ctr->size_of_array; i++) {
+               uint32 base_offset, return_offset;
+
+               base_offset = prs_offset(ps);
+
                valuename_offset = current_offset;
                if (!prs_uint32("valuename_offset", ps, depth, &valuename_offset))
                        return False;
 
+               /* Read or write the value. */
+
+               return_offset = prs_offset(ps);
+
+               if (!prs_set_offset(ps, base_offset + valuename_offset)) {
+                       return False;
+               }
+
+               if (!prs_unistr("valuename", ps, depth, &ctr->values[i].valuename))
+                       return False;
+
+               /* And go back. */
+               if (!prs_set_offset(ps, return_offset))
+                       return False;
+
                if (!prs_uint32("value_len", ps, depth, &ctr->values[i].value_len))
                        return False;
        
@@ -6951,21 +7083,14 @@ static BOOL spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps,
                if (!prs_uint32("data_len", ps, depth, &ctr->values[i].data_len))
                        return False;
                        
-               current_offset  = data_offset + ctr->values[i].data_len - basic_unit;
-               /* account for 2 byte alignment */
-               current_offset += (current_offset % 2);
-       }
+               /* Read or write the data. */
 
-       /* 
-        * loop #2 for writing the dynamically size objects; pay 
-        * attention to 2-byte alignment here....
-        */
-       
-       for (i=0; i<ctr->size_of_array; i++) {
-       
-               if (!prs_unistr("valuename", ps, depth, &ctr->values[i].valuename))
+               return_offset = prs_offset(ps);
+
+               if (!prs_set_offset(ps, base_offset + data_offset)) {
                        return False;
-               
+               }
+
                if ( ctr->values[i].data_len ) {
                        if ( UNMARSHALLING(ps) ) {
                                ctr->values[i].data = PRS_ALLOC_MEM(ps, uint8, ctr->values[i].data_len);
@@ -6975,11 +7100,30 @@ static BOOL spoolss_io_printer_enum_values_ctr(const char *desc, prs_struct *ps,
                        if (!prs_uint8s(False, "data", ps, depth, ctr->values[i].data, ctr->values[i].data_len))
                                return False;
                }
-                       
-               if ( !prs_align_uint16(ps) )
+
+               current_offset  = data_offset + ctr->values[i].data_len - basic_unit;
+               /* account for 2 byte alignment */
+               current_offset += (current_offset % 2);
+
+               /* Remember how far we got. */
+               data_offset = prs_offset(ps);
+
+               /* And go back. */
+               if (!prs_set_offset(ps, return_offset))
                        return False;
+
        }
 
+       /* Go to the last data offset we got to. */
+
+       if (!prs_set_offset(ps, data_offset))
+               return False;
+
+       /* And ensure we're 2 byte aligned. */
+
+       if ( !prs_align_uint16(ps) )
+               return False;
+
        return True;    
 }
 
@@ -7410,3 +7554,174 @@ BOOL make_spoolss_q_rffpcnex(SPOOL_Q_RFFPCNEX *q_u, POLICY_HND *handle,
 
        return True;
 }
+
+
+/*******************************************************************
+ ********************************************************************/  
+
+BOOL spoolss_io_q_xcvdataport(const char *desc, SPOOL_Q_XCVDATAPORT *q_u, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "spoolss_io_q_xcvdataport");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;   
+
+       if(!smb_io_pol_hnd("printer handle", &q_u->handle, ps, depth))
+               return False;
+               
+       if(!smb_io_unistr2("", &q_u->dataname, True, ps, depth))
+               return False;
+
+       if (!prs_align(ps))
+               return False;
+
+       if(!prs_rpcbuffer("", ps, depth, &q_u->indata))
+               return False;
+               
+       if (!prs_align(ps))
+               return False;
+
+       if (!prs_uint32("indata_len", ps, depth, &q_u->indata_len))
+               return False;
+       if (!prs_uint32("offered", ps, depth, &q_u->offered))
+               return False;
+       if (!prs_uint32("unknown", ps, depth, &q_u->unknown))
+               return False;
+       
+       return True;
+}
+
+/*******************************************************************
+ ********************************************************************/  
+
+BOOL spoolss_io_r_xcvdataport(const char *desc, SPOOL_R_XCVDATAPORT *r_u, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "spoolss_io_r_xcvdataport");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+       if(!prs_rpcbuffer("", ps, depth, &r_u->outdata))
+               return False;
+               
+       if (!prs_align(ps))
+               return False;
+
+       if (!prs_uint32("needed", ps, depth, &r_u->needed))
+               return False;
+       if (!prs_uint32("unknown", ps, depth, &r_u->unknown))
+               return False;
+
+       if(!prs_werror("status", ps, depth, &r_u->status))
+               return False;
+
+       return True;
+}
+
+/*******************************************************************
+ ********************************************************************/  
+
+BOOL make_monitorui_buf( RPC_BUFFER *buf, const char *dllname )
+{
+       UNISTR string;
+       
+       if ( !buf )
+               return False;
+
+       init_unistr( &string, dllname );
+
+       if ( !prs_unistr( "ui_dll", &buf->prs, 0, &string ) )
+               return False;
+
+       return True;
+}
+
+/*******************************************************************
+ ********************************************************************/  
+#define PORT_DATA_1_PAD    540
+
+static BOOL smb_io_port_data_1( const char *desc, RPC_BUFFER *buf, int depth, SPOOL_PORT_DATA_1 *p1 )
+{
+       prs_struct *ps = &buf->prs;
+       uint8 padding[PORT_DATA_1_PAD];
+
+       prs_debug(ps, depth, desc, "smb_io_port_data_1");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;   
+
+       if( !prs_uint16s(True, "portname", ps, depth, p1->portname, MAX_PORTNAME))
+               return False;
+
+       if (!prs_uint32("version", ps, depth, &p1->version))
+               return False;
+       if (!prs_uint32("protocol", ps, depth, &p1->protocol))
+               return False;
+       if (!prs_uint32("size", ps, depth, &p1->size))
+               return False;
+       if (!prs_uint32("reserved", ps, depth, &p1->reserved))
+               return False;
+
+       if( !prs_uint16s(True, "hostaddress", ps, depth, p1->hostaddress, MAX_NETWORK_NAME))
+               return False;
+       if( !prs_uint16s(True, "snmpcommunity", ps, depth, p1->snmpcommunity, MAX_SNMP_COMM_NAME))
+               return False;
+
+       if (!prs_uint32("dblspool", ps, depth, &p1->dblspool))
+               return False;
+               
+       if( !prs_uint16s(True, "queue", ps, depth, p1->queue, MAX_QUEUE_NAME))
+               return False;
+       if( !prs_uint16s(True, "ipaddress", ps, depth, p1->ipaddress, MAX_IPADDR_STRING))
+               return False;
+
+       if( !prs_uint8s(False, "", ps, depth, padding, PORT_DATA_1_PAD))
+               return False;
+               
+       if (!prs_uint32("port", ps, depth, &p1->port))
+               return False;
+       if (!prs_uint32("snmpenabled", ps, depth, &p1->snmpenabled))
+               return False;
+       if (!prs_uint32("snmpdevindex", ps, depth, &p1->snmpdevindex))
+               return False;
+               
+       return True;
+}
+
+/*******************************************************************
+ ********************************************************************/  
+
+BOOL convert_port_data_1( NT_PORT_DATA_1 *port1, RPC_BUFFER *buf ) 
+{
+       SPOOL_PORT_DATA_1 spdata_1;
+       
+       ZERO_STRUCT( spdata_1 );
+       
+       if ( !smb_io_port_data_1( "port_data_1", buf, 0, &spdata_1 ) )
+               return False;
+               
+       rpcstr_pull(port1->name, spdata_1.portname, sizeof(port1->name), -1, 0);
+       rpcstr_pull(port1->queue, spdata_1.queue, sizeof(port1->queue), -1, 0);
+       rpcstr_pull(port1->hostaddr, spdata_1.hostaddress, sizeof(port1->hostaddr), -1, 0);
+       
+       port1->port = spdata_1.port;
+       
+       switch ( spdata_1.protocol ) {
+       case 1:
+               port1->protocol = PORT_PROTOCOL_DIRECT;
+               break;
+       case 2:
+               port1->protocol = PORT_PROTOCOL_LPR;
+               break;
+       default:
+               DEBUG(3,("convert_port_data_1: unknown protocol [%d]!\n", 
+                       spdata_1.protocol));
+               return False;
+       }
+
+       return True;
+}
+