rpc_parse/parse_prs.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    Samba memory buffer functions
00004    Copyright (C) Andrew Tridgell              1992-1997
00005    Copyright (C) Luke Kenneth Casson Leighton 1996-1997
00006    Copyright (C) Jeremy Allison               1999
00007    Copyright (C) Andrew Bartlett              2003.
00008    
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #include "includes.h"
00025 
00026 #undef DBGC_CLASS
00027 #define DBGC_CLASS DBGC_RPC_PARSE
00028 
00029 /**
00030  * Dump a prs to a file: from the current location through to the end.
00031  **/
00032 void prs_dump(char *name, int v, prs_struct *ps)
00033 {
00034         prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size);
00035 }
00036 
00037 /**
00038  * Dump from the start of the prs to the current location.
00039  **/
00040 void prs_dump_before(char *name, int v, prs_struct *ps)
00041 {
00042         prs_dump_region(name, v, ps, 0, ps->data_offset);
00043 }
00044 
00045 /**
00046  * Dump everything from the start of the prs up to the current location.
00047  **/
00048 void prs_dump_region(char *name, int v, prs_struct *ps,
00049                      int from_off, int to_off)
00050 {
00051         int fd, i;
00052         pstring fname;
00053         ssize_t sz;
00054         if (DEBUGLEVEL < 50) return;
00055         for (i=1;i<100;i++) {
00056                 if (v != -1) {
00057                         slprintf(fname,sizeof(fname)-1, "/tmp/%s_%d.%d.prs", name, v, i);
00058                 } else {
00059                         slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.prs", name, i);
00060                 }
00061                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
00062                 if (fd != -1 || errno != EEXIST) break;
00063         }
00064         if (fd != -1) {
00065                 sz = write(fd, ps->data_p + from_off, to_off - from_off);
00066                 i = close(fd);
00067                 if ( (sz != to_off-from_off) || (i != 0) ) {
00068                         DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i ));
00069                 } else {
00070                         DEBUG(0,("created %s\n", fname));
00071                 }
00072         }
00073 }
00074 
00075 /*******************************************************************
00076  Debug output for parsing info
00077 
00078  XXXX side-effect of this function is to increase the debug depth XXXX.
00079 
00080 ********************************************************************/
00081 
00082 void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
00083 {
00084         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
00085 }
00086 
00087 /**
00088  * Initialise an expandable parse structure.
00089  *
00090  * @param size Initial buffer size.  If >0, a new buffer will be
00091  * created with malloc().
00092  *
00093  * @return False if allocation fails, otherwise True.
00094  **/
00095 
00096 BOOL prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, BOOL io)
00097 {
00098         ZERO_STRUCTP(ps);
00099         ps->io = io;
00100         ps->bigendian_data = RPC_LITTLE_ENDIAN;
00101         ps->align = RPC_PARSE_ALIGN;
00102         ps->is_dynamic = False;
00103         ps->data_offset = 0;
00104         ps->buffer_size = 0;
00105         ps->data_p = NULL;
00106         ps->mem_ctx = ctx;
00107 
00108         if (size != 0) {
00109                 ps->buffer_size = size;
00110                 if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) {
00111                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
00112                         return False;
00113                 }
00114                 memset(ps->data_p, '\0', (size_t)size);
00115                 ps->is_dynamic = True; /* We own this memory. */
00116         } else if (MARSHALLING(ps)) {
00117                 /* If size is zero and we're marshalling we should allocate memory on demand. */
00118                 ps->is_dynamic = True;
00119         }
00120 
00121         return True;
00122 }
00123 
00124 /*******************************************************************
00125  Delete the memory in a parse structure - if we own it.
00126  ********************************************************************/
00127 
00128 void prs_mem_free(prs_struct *ps)
00129 {
00130         if(ps->is_dynamic)
00131                 SAFE_FREE(ps->data_p);
00132         ps->is_dynamic = False;
00133         ps->buffer_size = 0;
00134         ps->data_offset = 0;
00135 }
00136 
00137 /*******************************************************************
00138  Clear the memory in a parse structure.
00139  ********************************************************************/
00140 
00141 void prs_mem_clear(prs_struct *ps)
00142 {
00143         if (ps->buffer_size)
00144                 memset(ps->data_p, '\0', (size_t)ps->buffer_size);
00145 }
00146 
00147 /*******************************************************************
00148  Allocate memory when unmarshalling... Always zero clears.
00149  ********************************************************************/
00150 
00151 #if defined(PARANOID_MALLOC_CHECKER)
00152 char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
00153 #else
00154 char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
00155 #endif
00156 {
00157         char *ret = NULL;
00158 
00159         if (size && count) {
00160                 /* We can't call the type-safe version here. */
00161                 ret = (char *)_talloc_zero_array_zeronull(ps->mem_ctx, size, count,
00162                                                  "parse_prs");
00163         }
00164         return ret;
00165 }
00166 
00167 /*******************************************************************
00168  Return the current talloc context we're using.
00169  ********************************************************************/
00170 
00171 TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
00172 {
00173         return ps->mem_ctx;
00174 }
00175 
00176 /*******************************************************************
00177  Hand some already allocated memory to a prs_struct.
00178  ********************************************************************/
00179 
00180 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
00181 {
00182         ps->is_dynamic = is_dynamic;
00183         ps->data_p = buf;
00184         ps->buffer_size = size;
00185 }
00186 
00187 /*******************************************************************
00188  Take some memory back from a prs_struct.
00189  ********************************************************************/
00190 
00191 char *prs_take_memory(prs_struct *ps, uint32 *psize)
00192 {
00193         char *ret = ps->data_p;
00194         if(psize)
00195                 *psize = ps->buffer_size;
00196         ps->is_dynamic = False;
00197         prs_mem_free(ps);
00198         return ret;
00199 }
00200 
00201 /*******************************************************************
00202  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
00203  ********************************************************************/
00204 
00205 BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
00206 {
00207         if (newsize > ps->buffer_size)
00208                 return prs_force_grow(ps, newsize - ps->buffer_size);
00209 
00210         if (newsize < ps->buffer_size) {
00211                 ps->buffer_size = newsize;
00212 
00213                 /* newsize == 0 acts as a free and set pointer to NULL */
00214                 if (newsize == 0) {
00215                         SAFE_FREE(ps->data_p);
00216                 } else {
00217                         ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize);
00218 
00219                         if (ps->data_p == NULL) {
00220                                 DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
00221                                         (unsigned int)newsize));
00222                                 DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
00223                                 return False;
00224                         }
00225                 }
00226         }
00227 
00228         return True;
00229 }
00230 
00231 /*******************************************************************
00232  Attempt, if needed, to grow a data buffer.
00233  Also depends on the data stream mode (io).
00234  ********************************************************************/
00235 
00236 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
00237 {
00238         uint32 new_size;
00239 
00240         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
00241 
00242         if(ps->data_offset + extra_space <= ps->buffer_size)
00243                 return True;
00244 
00245         /*
00246          * We cannot grow the buffer if we're not reading
00247          * into the prs_struct, or if we don't own the memory.
00248          */
00249 
00250         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
00251                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
00252                                 (unsigned int)extra_space));
00253                 return False;
00254         }
00255         
00256         /*
00257          * Decide how much extra space we really need.
00258          */
00259 
00260         extra_space -= (ps->buffer_size - ps->data_offset);
00261         if(ps->buffer_size == 0) {
00262                 /*
00263                  * Ensure we have at least a PDU's length, or extra_space, whichever
00264                  * is greater.
00265                  */
00266 
00267                 new_size = MAX(RPC_MAX_PDU_FRAG_LEN,extra_space);
00268 
00269                 if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) {
00270                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
00271                         return False;
00272                 }
00273                 memset(ps->data_p, '\0', (size_t)new_size );
00274         } else {
00275                 /*
00276                  * If the current buffer size is bigger than the space needed, just 
00277                  * double it, else add extra_space.
00278                  */
00279                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
00280 
00281                 if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
00282                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
00283                                 (unsigned int)new_size));
00284                         return False;
00285                 }
00286 
00287                 memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
00288         }
00289         ps->buffer_size = new_size;
00290 
00291         return True;
00292 }
00293 
00294 /*******************************************************************
00295  Attempt to force a data buffer to grow by len bytes.
00296  This is only used when appending more data onto a prs_struct
00297  when reading an rpc reply, before unmarshalling it.
00298  ********************************************************************/
00299 
00300 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
00301 {
00302         uint32 new_size = ps->buffer_size + extra_space;
00303 
00304         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
00305                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
00306                                 (unsigned int)extra_space));
00307                 return False;
00308         }
00309 
00310         if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
00311                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
00312                         (unsigned int)new_size));
00313                 return False;
00314         }
00315 
00316         memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
00317 
00318         ps->buffer_size = new_size;
00319 
00320         return True;
00321 }
00322 
00323 /*******************************************************************
00324  Get the data pointer (external interface).
00325 ********************************************************************/
00326 
00327 char *prs_data_p(prs_struct *ps)
00328 {
00329         return ps->data_p;
00330 }
00331 
00332 /*******************************************************************
00333  Get the current data size (external interface).
00334  ********************************************************************/
00335 
00336 uint32 prs_data_size(prs_struct *ps)
00337 {
00338         return ps->buffer_size;
00339 }
00340 
00341 /*******************************************************************
00342  Fetch the current offset (external interface).
00343  ********************************************************************/
00344 
00345 uint32 prs_offset(prs_struct *ps)
00346 {
00347         return ps->data_offset;
00348 }
00349 
00350 /*******************************************************************
00351  Set the current offset (external interface).
00352  ********************************************************************/
00353 
00354 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
00355 {
00356         if(offset <= ps->data_offset) {
00357                 ps->data_offset = offset;
00358                 return True;
00359         }
00360 
00361         if(!prs_grow(ps, offset - ps->data_offset))
00362                 return False;
00363 
00364         ps->data_offset = offset;
00365         return True;
00366 }
00367 
00368 /*******************************************************************
00369  Append the data from one parse_struct into another.
00370  ********************************************************************/
00371 
00372 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
00373 {
00374         if (prs_offset(src) == 0)
00375                 return True;
00376 
00377         if(!prs_grow(dst, prs_offset(src)))
00378                 return False;
00379 
00380         memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src));
00381         dst->data_offset += prs_offset(src);
00382 
00383         return True;
00384 }
00385 
00386 /*******************************************************************
00387  Append some data from one parse_struct into another.
00388  ********************************************************************/
00389 
00390 BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
00391 {       
00392         if (len == 0)
00393                 return True;
00394 
00395         if(!prs_grow(dst, len))
00396                 return False;
00397         
00398         memcpy(&dst->data_p[dst->data_offset], src->data_p + start, (size_t)len);
00399         dst->data_offset += len;
00400 
00401         return True;
00402 }
00403 
00404 /*******************************************************************
00405  Append the data from a buffer into a parse_struct.
00406  ********************************************************************/
00407 
00408 BOOL prs_copy_data_in(prs_struct *dst, const char *src, uint32 len)
00409 {
00410         if (len == 0)
00411                 return True;
00412 
00413         if(!prs_grow(dst, len))
00414                 return False;
00415 
00416         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
00417         dst->data_offset += len;
00418 
00419         return True;
00420 }
00421 
00422 /*******************************************************************
00423  Copy some data from a parse_struct into a buffer.
00424  ********************************************************************/
00425 
00426 BOOL prs_copy_data_out(char *dst, prs_struct *src, uint32 len)
00427 {
00428         if (len == 0)
00429                 return True;
00430 
00431         if(!prs_mem_get(src, len))
00432                 return False;
00433 
00434         memcpy(dst, &src->data_p[src->data_offset], (size_t)len);
00435         src->data_offset += len;
00436 
00437         return True;
00438 }
00439 
00440 /*******************************************************************
00441  Copy all the data from a parse_struct into a buffer.
00442  ********************************************************************/
00443 
00444 BOOL prs_copy_all_data_out(char *dst, prs_struct *src)
00445 {
00446         uint32 len = prs_offset(src);
00447 
00448         if (!len)
00449                 return True;
00450 
00451         prs_set_offset(src, 0);
00452         return prs_copy_data_out(dst, src, len);
00453 }
00454 
00455 /*******************************************************************
00456  Set the data as X-endian (external interface).
00457  ********************************************************************/
00458 
00459 void prs_set_endian_data(prs_struct *ps, BOOL endian)
00460 {
00461         ps->bigendian_data = endian;
00462 }
00463 
00464 /*******************************************************************
00465  Align a the data_len to a multiple of align bytes - filling with
00466  zeros.
00467  ********************************************************************/
00468 
00469 BOOL prs_align(prs_struct *ps)
00470 {
00471         uint32 mod = ps->data_offset & (ps->align-1);
00472 
00473         if (ps->align != 0 && mod != 0) {
00474                 uint32 extra_space = (ps->align - mod);
00475                 if(!prs_grow(ps, extra_space))
00476                         return False;
00477                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
00478                 ps->data_offset += extra_space;
00479         }
00480 
00481         return True;
00482 }
00483 
00484 /******************************************************************
00485  Align on a 2 byte boundary
00486  *****************************************************************/
00487  
00488 BOOL prs_align_uint16(prs_struct *ps)
00489 {
00490         BOOL ret;
00491         uint8 old_align = ps->align;
00492 
00493         ps->align = 2;
00494         ret = prs_align(ps);
00495         ps->align = old_align;
00496         
00497         return ret;
00498 }
00499 
00500 /******************************************************************
00501  Align on a 8 byte boundary
00502  *****************************************************************/
00503  
00504 BOOL prs_align_uint64(prs_struct *ps)
00505 {
00506         BOOL ret;
00507         uint8 old_align = ps->align;
00508 
00509         ps->align = 8;
00510         ret = prs_align(ps);
00511         ps->align = old_align;
00512         
00513         return ret;
00514 }
00515 
00516 /******************************************************************
00517  Align on a specific byte boundary
00518  *****************************************************************/
00519  
00520 BOOL prs_align_custom(prs_struct *ps, uint8 boundary)
00521 {
00522         BOOL ret;
00523         uint8 old_align = ps->align;
00524 
00525         ps->align = boundary;
00526         ret = prs_align(ps);
00527         ps->align = old_align;
00528         
00529         return ret;
00530 }
00531 
00532 
00533 
00534 /*******************************************************************
00535  Align only if required (for the unistr2 string mainly)
00536  ********************************************************************/
00537 
00538 BOOL prs_align_needed(prs_struct *ps, uint32 needed)
00539 {
00540         if (needed==0)
00541                 return True;
00542         else
00543                 return prs_align(ps);
00544 }
00545 
00546 /*******************************************************************
00547  Ensure we can read/write to a given offset.
00548  ********************************************************************/
00549 
00550 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
00551 {
00552         if(UNMARSHALLING(ps)) {
00553                 /*
00554                  * If reading, ensure that we can read the requested size item.
00555                  */
00556                 if (ps->data_offset + extra_size > ps->buffer_size) {
00557                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
00558                                 "buffer by %u bytes.\n",
00559                                 (unsigned int)extra_size,
00560                                 (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
00561                         return NULL;
00562                 }
00563         } else {
00564                 /*
00565                  * Writing - grow the buffer if needed.
00566                  */
00567                 if(!prs_grow(ps, extra_size))
00568                         return NULL;
00569         }
00570         return &ps->data_p[ps->data_offset];
00571 }
00572 
00573 /*******************************************************************
00574  Change the struct type.
00575  ********************************************************************/
00576 
00577 void prs_switch_type(prs_struct *ps, BOOL io)
00578 {
00579         if ((ps->io ^ io) == True)
00580                 ps->io=io;
00581 }
00582 
00583 /*******************************************************************
00584  Force a prs_struct to be dynamic even when it's size is 0.
00585  ********************************************************************/
00586 
00587 void prs_force_dynamic(prs_struct *ps)
00588 {
00589         ps->is_dynamic=True;
00590 }
00591 
00592 /*******************************************************************
00593  Associate a session key with a parse struct.
00594  ********************************************************************/
00595 
00596 void prs_set_session_key(prs_struct *ps, const char sess_key[16])
00597 {
00598         ps->sess_key = sess_key;
00599 }
00600 
00601 /*******************************************************************
00602  Stream a uint8.
00603  ********************************************************************/
00604 
00605 BOOL prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8)
00606 {
00607         char *q = prs_mem_get(ps, 1);
00608         if (q == NULL)
00609                 return False;
00610 
00611         if (UNMARSHALLING(ps))
00612                 *data8 = CVAL(q,0);
00613         else
00614                 SCVAL(q,0,*data8);
00615 
00616         DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
00617 
00618         ps->data_offset += 1;
00619 
00620         return True;
00621 }
00622 
00623 /*******************************************************************
00624  Stream a uint16* (allocate memory if unmarshalling)
00625  ********************************************************************/
00626 
00627 BOOL prs_pointer( const char *name, prs_struct *ps, int depth, 
00628                  void *dta, size_t data_size,
00629                  BOOL(*prs_fn)(const char*, prs_struct*, int, void*) )
00630 {
00631         void ** data = (void **)dta;
00632         uint32 data_p;
00633 
00634         /* output f000baaa to stream if the pointer is non-zero. */
00635 
00636         data_p = *data ? 0xf000baaa : 0;
00637 
00638         if ( !prs_uint32("ptr", ps, depth, &data_p ))
00639                 return False;
00640 
00641         /* we're done if there is no data */
00642 
00643         if ( !data_p )
00644                 return True;
00645 
00646         if (UNMARSHALLING(ps)) {
00647                 if (data_size) {
00648                         if ( !(*data = PRS_ALLOC_MEM(ps, char, data_size)) )
00649                                 return False;
00650                 } else {
00651                         *data = NULL;
00652                 }
00653         }
00654 
00655         return prs_fn(name, ps, depth, *data);
00656 }
00657 
00658 
00659 /*******************************************************************
00660  Stream a uint16.
00661  ********************************************************************/
00662 
00663 BOOL prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16)
00664 {
00665         char *q = prs_mem_get(ps, sizeof(uint16));
00666         if (q == NULL)
00667                 return False;
00668 
00669         if (UNMARSHALLING(ps)) {
00670                 if (ps->bigendian_data)
00671                         *data16 = RSVAL(q,0);
00672                 else
00673                         *data16 = SVAL(q,0);
00674         } else {
00675                 if (ps->bigendian_data)
00676                         RSSVAL(q,0,*data16);
00677                 else
00678                         SSVAL(q,0,*data16);
00679         }
00680 
00681         DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16));
00682 
00683         ps->data_offset += sizeof(uint16);
00684 
00685         return True;
00686 }
00687 
00688 /*******************************************************************
00689  Stream a uint32.
00690  ********************************************************************/
00691 
00692 BOOL prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
00693 {
00694         char *q = prs_mem_get(ps, sizeof(uint32));
00695         if (q == NULL)
00696                 return False;
00697 
00698         if (UNMARSHALLING(ps)) {
00699                 if (ps->bigendian_data)
00700                         *data32 = RIVAL(q,0);
00701                 else
00702                         *data32 = IVAL(q,0);
00703         } else {
00704                 if (ps->bigendian_data)
00705                         RSIVAL(q,0,*data32);
00706                 else
00707                         SIVAL(q,0,*data32);
00708         }
00709 
00710         DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
00711 
00712         ps->data_offset += sizeof(uint32);
00713 
00714         return True;
00715 }
00716 
00717 /*******************************************************************
00718  Stream an int32.
00719  ********************************************************************/
00720 
00721 BOOL prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32)
00722 {
00723         char *q = prs_mem_get(ps, sizeof(int32));
00724         if (q == NULL)
00725                 return False;
00726 
00727         if (UNMARSHALLING(ps)) {
00728                 if (ps->bigendian_data)
00729                         *data32 = RIVALS(q,0);
00730                 else
00731                         *data32 = IVALS(q,0);
00732         } else {
00733                 if (ps->bigendian_data)
00734                         RSIVALS(q,0,*data32);
00735                 else
00736                         SIVALS(q,0,*data32);
00737         }
00738 
00739         DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
00740 
00741         ps->data_offset += sizeof(int32);
00742 
00743         return True;
00744 }
00745 
00746 /*******************************************************************
00747  Stream a NTSTATUS
00748  ********************************************************************/
00749 
00750 BOOL prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
00751 {
00752         char *q = prs_mem_get(ps, sizeof(uint32));
00753         if (q == NULL)
00754                 return False;
00755 
00756         if (UNMARSHALLING(ps)) {
00757                 if (ps->bigendian_data)
00758                         *status = NT_STATUS(RIVAL(q,0));
00759                 else
00760                         *status = NT_STATUS(IVAL(q,0));
00761         } else {
00762                 if (ps->bigendian_data)
00763                         RSIVAL(q,0,NT_STATUS_V(*status));
00764                 else
00765                         SIVAL(q,0,NT_STATUS_V(*status));
00766         }
00767 
00768         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
00769                  nt_errstr(*status)));
00770 
00771         ps->data_offset += sizeof(uint32);
00772 
00773         return True;
00774 }
00775 
00776 /*******************************************************************
00777  Stream a DCE error code
00778  ********************************************************************/
00779 
00780 BOOL prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
00781 {
00782         char *q = prs_mem_get(ps, sizeof(uint32));
00783         if (q == NULL)
00784                 return False;
00785 
00786         if (UNMARSHALLING(ps)) {
00787                 if (ps->bigendian_data)
00788                         *status = NT_STATUS(RIVAL(q,0));
00789                 else
00790                         *status = NT_STATUS(IVAL(q,0));
00791         } else {
00792                 if (ps->bigendian_data)
00793                         RSIVAL(q,0,NT_STATUS_V(*status));
00794                 else
00795                         SIVAL(q,0,NT_STATUS_V(*status));
00796         }
00797 
00798         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
00799                  dcerpc_errstr(NT_STATUS_V(*status))));
00800 
00801         ps->data_offset += sizeof(uint32);
00802 
00803         return True;
00804 }
00805 
00806 
00807 /*******************************************************************
00808  Stream a WERROR
00809  ********************************************************************/
00810 
00811 BOOL prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
00812 {
00813         char *q = prs_mem_get(ps, sizeof(uint32));
00814         if (q == NULL)
00815                 return False;
00816 
00817         if (UNMARSHALLING(ps)) {
00818                 if (ps->bigendian_data)
00819                         *status = W_ERROR(RIVAL(q,0));
00820                 else
00821                         *status = W_ERROR(IVAL(q,0));
00822         } else {
00823                 if (ps->bigendian_data)
00824                         RSIVAL(q,0,W_ERROR_V(*status));
00825                 else
00826                         SIVAL(q,0,W_ERROR_V(*status));
00827         }
00828 
00829         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
00830                  dos_errstr(*status)));
00831 
00832         ps->data_offset += sizeof(uint32);
00833 
00834         return True;
00835 }
00836 
00837 
00838 /******************************************************************
00839  Stream an array of uint8s. Length is number of uint8s.
00840  ********************************************************************/
00841 
00842 BOOL prs_uint8s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
00843 {
00844         int i;
00845         char *q = prs_mem_get(ps, len);
00846         if (q == NULL)
00847                 return False;
00848 
00849         if (UNMARSHALLING(ps)) {
00850                 for (i = 0; i < len; i++)
00851                         data8s[i] = CVAL(q,i);
00852         } else {
00853                 for (i = 0; i < len; i++)
00854                         SCVAL(q, i, data8s[i]);
00855         }
00856 
00857         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
00858         if (charmode)
00859                 print_asc(5, (unsigned char*)data8s, len);
00860         else {
00861                 for (i = 0; i < len; i++)
00862                         DEBUG(5,("%02x ", data8s[i]));
00863         }
00864         DEBUG(5,("\n"));
00865 
00866         ps->data_offset += len;
00867 
00868         return True;
00869 }
00870 
00871 /******************************************************************
00872  Stream an array of uint16s. Length is number of uint16s.
00873  ********************************************************************/
00874 
00875 BOOL prs_uint16s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
00876 {
00877         int i;
00878         char *q = prs_mem_get(ps, len * sizeof(uint16));
00879         if (q == NULL)
00880                 return False;
00881 
00882         if (UNMARSHALLING(ps)) {
00883                 if (ps->bigendian_data) {
00884                         for (i = 0; i < len; i++)
00885                                 data16s[i] = RSVAL(q, 2*i);
00886                 } else {
00887                         for (i = 0; i < len; i++)
00888                                 data16s[i] = SVAL(q, 2*i);
00889                 }
00890         } else {
00891                 if (ps->bigendian_data) {
00892                         for (i = 0; i < len; i++)
00893                                 RSSVAL(q, 2*i, data16s[i]);
00894                 } else {
00895                         for (i = 0; i < len; i++)
00896                                 SSVAL(q, 2*i, data16s[i]);
00897                 }
00898         }
00899 
00900         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
00901         if (charmode)
00902                 print_asc(5, (unsigned char*)data16s, 2*len);
00903         else {
00904                 for (i = 0; i < len; i++)
00905                         DEBUG(5,("%04x ", data16s[i]));
00906         }
00907         DEBUG(5,("\n"));
00908 
00909         ps->data_offset += (len * sizeof(uint16));
00910 
00911         return True;
00912 }
00913 
00914 /******************************************************************
00915  Start using a function for streaming unicode chars. If unmarshalling,
00916  output must be little-endian, if marshalling, input must be little-endian.
00917  ********************************************************************/
00918 
00919 static void dbg_rw_punival(BOOL charmode, const char *name, int depth, prs_struct *ps,
00920                                                         char *in_buf, char *out_buf, int len)
00921 {
00922         int i;
00923 
00924         if (UNMARSHALLING(ps)) {
00925                 if (ps->bigendian_data) {
00926                         for (i = 0; i < len; i++)
00927                                 SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
00928                 } else {
00929                         for (i = 0; i < len; i++)
00930                                 SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
00931                 }
00932         } else {
00933                 if (ps->bigendian_data) {
00934                         for (i = 0; i < len; i++)
00935                                 RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
00936                 } else {
00937                         for (i = 0; i < len; i++)
00938                                 SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
00939                 }
00940         }
00941 
00942         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
00943         if (charmode)
00944                 print_asc(5, (unsigned char*)out_buf, 2*len);
00945         else {
00946                 for (i = 0; i < len; i++)
00947                         DEBUG(5,("%04x ", out_buf[i]));
00948         }
00949         DEBUG(5,("\n"));
00950 }
00951 
00952 /******************************************************************
00953  Stream a unistr. Always little endian.
00954  ********************************************************************/
00955 
00956 BOOL prs_uint16uni(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
00957 {
00958         char *q = prs_mem_get(ps, len * sizeof(uint16));
00959         if (q == NULL)
00960                 return False;
00961 
00962         dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
00963         ps->data_offset += (len * sizeof(uint16));
00964 
00965         return True;
00966 }
00967 
00968 /******************************************************************
00969  Stream an array of uint32s. Length is number of uint32s.
00970  ********************************************************************/
00971 
00972 BOOL prs_uint32s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
00973 {
00974         int i;
00975         char *q = prs_mem_get(ps, len * sizeof(uint32));
00976         if (q == NULL)
00977                 return False;
00978 
00979         if (UNMARSHALLING(ps)) {
00980                 if (ps->bigendian_data) {
00981                         for (i = 0; i < len; i++)
00982                                 data32s[i] = RIVAL(q, 4*i);
00983                 } else {
00984                         for (i = 0; i < len; i++)
00985                                 data32s[i] = IVAL(q, 4*i);
00986                 }
00987         } else {
00988                 if (ps->bigendian_data) {
00989                         for (i = 0; i < len; i++)
00990                                 RSIVAL(q, 4*i, data32s[i]);
00991                 } else {
00992                         for (i = 0; i < len; i++)
00993                                 SIVAL(q, 4*i, data32s[i]);
00994                 }
00995         }
00996 
00997         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
00998         if (charmode)
00999                 print_asc(5, (unsigned char*)data32s, 4*len);
01000         else {
01001                 for (i = 0; i < len; i++)
01002                         DEBUG(5,("%08x ", data32s[i]));
01003         }
01004         DEBUG(5,("\n"));
01005 
01006         ps->data_offset += (len * sizeof(uint32));
01007 
01008         return True;
01009 }
01010 
01011 /******************************************************************
01012  Stream an array of unicode string, length/buffer specified separately,
01013  in uint16 chars. The unicode string is already in little-endian format.
01014  ********************************************************************/
01015 
01016 BOOL prs_buffer5(BOOL charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str)
01017 {
01018         char *p;
01019         char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
01020         if (q == NULL)
01021                 return False;
01022 
01023         /* If the string is empty, we don't have anything to stream */
01024         if (str->buf_len==0)
01025                 return True;
01026 
01027         if (UNMARSHALLING(ps)) {
01028                 str->buffer = PRS_ALLOC_MEM(ps,uint16,str->buf_len);
01029                 if (str->buffer == NULL)
01030                         return False;
01031         }
01032 
01033         p = (char *)str->buffer;
01034 
01035         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
01036         
01037         ps->data_offset += (str->buf_len * sizeof(uint16));
01038 
01039         return True;
01040 }
01041 
01042 /******************************************************************
01043  Stream a "not" unicode string, length/buffer specified separately,
01044  in byte chars. String is in little-endian format.
01045  ********************************************************************/
01046 
01047 BOOL prs_regval_buffer(BOOL charmode, const char *name, prs_struct *ps, int depth, REGVAL_BUFFER *buf)
01048 {
01049         char *p;
01050         char *q = prs_mem_get(ps, buf->buf_len);
01051         if (q == NULL)
01052                 return False;
01053 
01054         if (UNMARSHALLING(ps)) {
01055                 if (buf->buf_len > buf->buf_max_len) {
01056                         return False;
01057                 }
01058                 if ( buf->buf_max_len ) {
01059                         buf->buffer = PRS_ALLOC_MEM(ps, uint16, buf->buf_max_len);
01060                         if ( buf->buffer == NULL )
01061                                 return False;
01062                 } else {
01063                         buf->buffer = NULL;
01064                 }
01065         }
01066 
01067         p = (char *)buf->buffer;
01068 
01069         dbg_rw_punival(charmode, name, depth, ps, q, p, buf->buf_len/2);
01070         ps->data_offset += buf->buf_len;
01071 
01072         return True;
01073 }
01074 
01075 /******************************************************************
01076  Stream a string, length/buffer specified separately,
01077  in uint8 chars.
01078  ********************************************************************/
01079 
01080 BOOL prs_string2(BOOL charmode, const char *name, prs_struct *ps, int depth, STRING2 *str)
01081 {
01082         unsigned int i;
01083         char *q = prs_mem_get(ps, str->str_str_len);
01084         if (q == NULL)
01085                 return False;
01086 
01087         if (UNMARSHALLING(ps)) {
01088                 if (str->str_str_len > str->str_max_len) {
01089                         return False;
01090                 }
01091                 if (str->str_max_len) {
01092                         str->buffer = PRS_ALLOC_MEM(ps,unsigned char, str->str_max_len);
01093                         if (str->buffer == NULL)
01094                                 return False;
01095                 } else {
01096                         str->buffer = NULL;
01097                         /* Return early to ensure Coverity isn't confused. */
01098                         DEBUG(5,("%s%04x %s: \n", tab_depth(depth), ps->data_offset, name));
01099                         return True;
01100                 }
01101         }
01102 
01103         if (UNMARSHALLING(ps)) {
01104                 for (i = 0; i < str->str_str_len; i++)
01105                         str->buffer[i] = CVAL(q,i);
01106         } else {
01107                 for (i = 0; i < str->str_str_len; i++)
01108                         SCVAL(q, i, str->buffer[i]);
01109         }
01110 
01111         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
01112         if (charmode)
01113                 print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
01114         else {
01115                 for (i = 0; i < str->str_str_len; i++)
01116                         DEBUG(5,("%02x ", str->buffer[i]));
01117         }
01118         DEBUG(5,("\n"));
01119 
01120         ps->data_offset += str->str_str_len;
01121 
01122         return True;
01123 }
01124 
01125 /******************************************************************
01126  Stream a unicode string, length/buffer specified separately,
01127  in uint16 chars. The unicode string is already in little-endian format.
01128  ********************************************************************/
01129 
01130 BOOL prs_unistr2(BOOL charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str)
01131 {
01132         char *p;
01133         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
01134         if (q == NULL)
01135                 return False;
01136 
01137         /* If the string is empty, we don't have anything to stream */
01138         if (str->uni_str_len==0)
01139                 return True;
01140 
01141         if (UNMARSHALLING(ps)) {
01142                 if (str->uni_str_len > str->uni_max_len) {
01143                         return False;
01144                 }
01145                 if (str->uni_max_len) {
01146                         str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len);
01147                         if (str->buffer == NULL)
01148                                 return False;
01149                 } else {
01150                         str->buffer = NULL;
01151                 }
01152         }
01153 
01154         p = (char *)str->buffer;
01155 
01156         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
01157         
01158         ps->data_offset += (str->uni_str_len * sizeof(uint16));
01159 
01160         return True;
01161 }
01162 
01163 /******************************************************************
01164  Stream a unicode string, length/buffer specified separately,
01165  in uint16 chars. The unicode string is already in little-endian format.
01166  ********************************************************************/
01167 
01168 BOOL prs_unistr3(BOOL charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth)
01169 {
01170         char *p;
01171         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
01172         if (q == NULL)
01173                 return False;
01174 
01175         if (UNMARSHALLING(ps)) {
01176                 if (str->uni_str_len) {
01177                         str->str.buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_str_len);
01178                         if (str->str.buffer == NULL)
01179                                 return False;
01180                 } else {
01181                         str->str.buffer = NULL;
01182                 }
01183         }
01184 
01185         p = (char *)str->str.buffer;
01186 
01187         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
01188         ps->data_offset += (str->uni_str_len * sizeof(uint16));
01189 
01190         return True;
01191 }
01192 
01193 /*******************************************************************
01194  Stream a unicode  null-terminated string. As the string is already
01195  in little-endian format then do it as a stream of bytes.
01196  ********************************************************************/
01197 
01198 BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
01199 {
01200         unsigned int len = 0;
01201         unsigned char *p = (unsigned char *)str->buffer;
01202         uint8 *start;
01203         char *q;
01204         uint32 max_len;
01205         uint16* ptr;
01206 
01207         if (MARSHALLING(ps)) {
01208 
01209                 for(len = 0; str->buffer[len] != 0; len++)
01210                         ;
01211 
01212                 q = prs_mem_get(ps, (len+1)*2);
01213                 if (q == NULL)
01214                         return False;
01215 
01216                 start = (uint8*)q;
01217 
01218                 for(len = 0; str->buffer[len] != 0; len++) {
01219                         if(ps->bigendian_data) {
01220                                 /* swap bytes - p is little endian, q is big endian. */
01221                                 q[0] = (char)p[1];
01222                                 q[1] = (char)p[0];
01223                                 p += 2;
01224                                 q += 2;
01225                         } 
01226                         else 
01227                         {
01228                                 q[0] = (char)p[0];
01229                                 q[1] = (char)p[1];
01230                                 p += 2;
01231                                 q += 2;
01232                         }
01233                 }
01234 
01235                 /*
01236                  * even if the string is 'empty' (only an \0 char)
01237                  * at this point the leading \0 hasn't been parsed.
01238                  * so parse it now
01239                  */
01240 
01241                 q[0] = 0;
01242                 q[1] = 0;
01243                 q += 2;
01244 
01245                 len++;
01246 
01247                 DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
01248                 print_asc(5, (unsigned char*)start, 2*len);     
01249                 DEBUG(5, ("\n"));
01250         }
01251         else { /* unmarshalling */
01252         
01253                 uint32 alloc_len = 0;
01254                 q = ps->data_p + prs_offset(ps);
01255 
01256                 /*
01257                  * Work out how much space we need and talloc it.
01258                  */
01259                 max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
01260 
01261                 /* the test of the value of *ptr helps to catch the circumstance
01262                    where we have an emtpty (non-existent) string in the buffer */
01263                 for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
01264                         /* do nothing */ 
01265                         ;
01266 
01267                 if (alloc_len < max_len)
01268                         alloc_len += 1;
01269 
01270                 /* should we allocate anything at all? */
01271                 str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len);
01272                 if ((str->buffer == NULL) && (alloc_len > 0))
01273                         return False;
01274 
01275                 p = (unsigned char *)str->buffer;
01276 
01277                 len = 0;
01278                 /* the (len < alloc_len) test is to prevent us from overwriting
01279                    memory that is not ours...if we get that far, we have a non-null
01280                    terminated string in the buffer and have messed up somewhere */
01281                 while ((len < alloc_len) && (*(uint16 *)q != 0)) {
01282                         if(ps->bigendian_data) 
01283                         {
01284                                 /* swap bytes - q is big endian, p is little endian. */
01285                                 p[0] = (unsigned char)q[1];
01286                                 p[1] = (unsigned char)q[0];
01287                                 p += 2;
01288                                 q += 2;
01289                         } else {
01290 
01291                                 p[0] = (unsigned char)q[0];
01292                                 p[1] = (unsigned char)q[1];
01293                                 p += 2;
01294                                 q += 2;
01295                         }
01296 
01297                         len++;
01298                 } 
01299                 if (len < alloc_len) {
01300                         /* NULL terminate the UNISTR */
01301                         str->buffer[len++] = '\0';
01302                 }
01303 
01304                 DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
01305                 print_asc(5, (unsigned char*)str->buffer, 2*len);       
01306                 DEBUG(5, ("\n"));
01307         }
01308 
01309         /* set the offset in the prs_struct; 'len' points to the
01310            terminiating NULL in the UNISTR so we need to go one more
01311            uint16 */
01312         ps->data_offset += (len)*2;
01313         
01314         return True;
01315 }
01316 
01317 
01318 /*******************************************************************
01319  Stream a null-terminated string.  len is strlen, and therefore does
01320  not include the null-termination character.
01321  ********************************************************************/
01322 
01323 BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size)
01324 {
01325         char *q;
01326         int i;
01327         int len;
01328 
01329         if (UNMARSHALLING(ps))
01330                 len = strlen(&ps->data_p[ps->data_offset]);
01331         else
01332                 len = strlen(str);
01333 
01334         len = MIN(len, (max_buf_size-1));
01335 
01336         q = prs_mem_get(ps, len+1);
01337         if (q == NULL)
01338                 return False;
01339 
01340         for(i = 0; i < len; i++) {
01341                 if (UNMARSHALLING(ps))
01342                         str[i] = q[i];
01343                 else
01344                         q[i] = str[i];
01345         }
01346 
01347         /* The terminating null. */
01348         str[i] = '\0';
01349 
01350         if (MARSHALLING(ps)) {
01351                 q[i] = '\0';
01352         }
01353 
01354         ps->data_offset += len+1;
01355 
01356         dump_data(5+depth, q, len);
01357 
01358         return True;
01359 }
01360 
01361 BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str)
01362 {
01363         size_t len;
01364         char *tmp_str;
01365 
01366         if (UNMARSHALLING(ps)) {
01367                 len = strlen(&ps->data_p[ps->data_offset]);
01368         } else {
01369                 len = strlen(*str);
01370         }
01371 
01372         tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
01373 
01374         if (tmp_str == NULL) {
01375                 return False;
01376         }
01377 
01378         if (MARSHALLING(ps)) {
01379                 strncpy(tmp_str, *str, len);
01380         }
01381 
01382         if (!prs_string(name, ps, depth, tmp_str, len+1)) {
01383                 return False;
01384         }
01385 
01386         *str = tmp_str;
01387         return True;
01388 }
01389 
01390 /*******************************************************************
01391  prs_uint16 wrapper. Call this and it sets up a pointer to where the
01392  uint16 should be stored, or gets the size if reading.
01393  ********************************************************************/
01394 
01395 BOOL prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
01396 {
01397         *offset = ps->data_offset;
01398         if (UNMARSHALLING(ps)) {
01399                 /* reading. */
01400                 return prs_uint16(name, ps, depth, data16);
01401         } else {
01402                 char *q = prs_mem_get(ps, sizeof(uint16));
01403                 if(q ==NULL)
01404                         return False;
01405                 ps->data_offset += sizeof(uint16);
01406         }
01407         return True;
01408 }
01409 
01410 /*******************************************************************
01411  prs_uint16 wrapper.  call this and it retrospectively stores the size.
01412  does nothing on reading, as that is already handled by ...._pre()
01413  ********************************************************************/
01414 
01415 BOOL prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
01416                                 uint32 ptr_uint16, uint32 start_offset)
01417 {
01418         if (MARSHALLING(ps)) {
01419                 /* 
01420                  * Writing - temporarily move the offset pointer.
01421                  */
01422                 uint16 data_size = ps->data_offset - start_offset;
01423                 uint32 old_offset = ps->data_offset;
01424 
01425                 ps->data_offset = ptr_uint16;
01426                 if(!prs_uint16(name, ps, depth, &data_size)) {
01427                         ps->data_offset = old_offset;
01428                         return False;
01429                 }
01430                 ps->data_offset = old_offset;
01431         } else {
01432                 ps->data_offset = start_offset + (uint32)(*data16);
01433         }
01434         return True;
01435 }
01436 
01437 /*******************************************************************
01438  prs_uint32 wrapper. Call this and it sets up a pointer to where the
01439  uint32 should be stored, or gets the size if reading.
01440  ********************************************************************/
01441 
01442 BOOL prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
01443 {
01444         *offset = ps->data_offset;
01445         if (UNMARSHALLING(ps) && (data32 != NULL)) {
01446                 /* reading. */
01447                 return prs_uint32(name, ps, depth, data32);
01448         } else {
01449                 ps->data_offset += sizeof(uint32);
01450         }
01451         return True;
01452 }
01453 
01454 /*******************************************************************
01455  prs_uint32 wrapper.  call this and it retrospectively stores the size.
01456  does nothing on reading, as that is already handled by ...._pre()
01457  ********************************************************************/
01458 
01459 BOOL prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
01460                                 uint32 ptr_uint32, uint32 data_size)
01461 {
01462         if (MARSHALLING(ps)) {
01463                 /* 
01464                  * Writing - temporarily move the offset pointer.
01465                  */
01466                 uint32 old_offset = ps->data_offset;
01467                 ps->data_offset = ptr_uint32;
01468                 if(!prs_uint32(name, ps, depth, &data_size)) {
01469                         ps->data_offset = old_offset;
01470                         return False;
01471                 }
01472                 ps->data_offset = old_offset;
01473         }
01474         return True;
01475 }
01476 
01477 /* useful function to store a structure in rpc wire format */
01478 int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
01479 {
01480         TDB_DATA kbuf, dbuf;
01481         kbuf.dptr = keystr;
01482         kbuf.dsize = strlen(keystr)+1;
01483         dbuf.dptr = ps->data_p;
01484         dbuf.dsize = prs_offset(ps);
01485         return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE);
01486 }
01487 
01488 /* useful function to fetch a structure into rpc wire format */
01489 int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx)
01490 {
01491         TDB_DATA kbuf, dbuf;
01492         kbuf.dptr = keystr;
01493         kbuf.dsize = strlen(keystr)+1;
01494 
01495         prs_init(ps, 0, mem_ctx, UNMARSHALL);
01496 
01497         dbuf = tdb_fetch(tdb, kbuf);
01498         if (!dbuf.dptr)
01499                 return -1;
01500 
01501         prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
01502 
01503         return 0;
01504 }
01505 
01506 /*******************************************************************
01507  hash a stream.
01508  ********************************************************************/
01509 
01510 BOOL prs_hash1(prs_struct *ps, uint32 offset, int len)
01511 {
01512         char *q;
01513 
01514         q = ps->data_p;
01515         q = &q[offset];
01516 
01517 #ifdef DEBUG_PASSWORD
01518         DEBUG(100, ("prs_hash1\n"));
01519         dump_data(100, ps->sess_key, 16);
01520         dump_data(100, q, len);
01521 #endif
01522         SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);
01523 
01524 #ifdef DEBUG_PASSWORD
01525         dump_data(100, q, len);
01526 #endif
01527 
01528         return True;
01529 }
01530 
01531 /*******************************************************************
01532  Create a digest over the entire packet (including the data), and 
01533  MD5 it with the session key.
01534  ********************************************************************/
01535 
01536 static void schannel_digest(struct schannel_auth_struct *a,
01537                           enum pipe_auth_level auth_level,
01538                           RPC_AUTH_SCHANNEL_CHK * verf,
01539                           char *data, size_t data_len,
01540                           uchar digest_final[16]) 
01541 {
01542         uchar whole_packet_digest[16];
01543         static uchar zeros[4];
01544         struct MD5Context ctx3;
01545         
01546         /* verfiy the signature on the packet by MD5 over various bits */
01547         MD5Init(&ctx3);
01548         /* use our sequence number, which ensures the packet is not
01549            out of order */
01550         MD5Update(&ctx3, zeros, sizeof(zeros));
01551         MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
01552         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
01553                 MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder));
01554         }
01555         MD5Update(&ctx3, (const unsigned char *)data, data_len);
01556         MD5Final(whole_packet_digest, &ctx3);
01557         dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
01558         
01559         /* MD5 this result and the session key, to prove that
01560            only a valid client could had produced this */
01561         hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
01562 }
01563 
01564 /*******************************************************************
01565  Calculate the key with which to encode the data payload 
01566  ********************************************************************/
01567 
01568 static void schannel_get_sealing_key(struct schannel_auth_struct *a,
01569                                    RPC_AUTH_SCHANNEL_CHK *verf,
01570                                    uchar sealing_key[16]) 
01571 {
01572         static uchar zeros[4];
01573         uchar digest2[16];
01574         uchar sess_kf0[16];
01575         int i;
01576 
01577         for (i = 0; i < sizeof(sess_kf0); i++) {
01578                 sess_kf0[i] = a->sess_key[i] ^ 0xf0;
01579         }
01580         
01581         dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
01582         
01583         /* MD5 of sess_kf0 and 4 zero bytes */
01584         hmac_md5(sess_kf0, zeros, 0x4, digest2);
01585         dump_data_pw("digest2:\n", digest2, sizeof(digest2));
01586         
01587         /* MD5 of the above result, plus 8 bytes of sequence number */
01588         hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
01589         dump_data_pw("sealing_key:\n", sealing_key, 16);
01590 }
01591 
01592 /*******************************************************************
01593  Encode or Decode the sequence number (which is symmetric)
01594  ********************************************************************/
01595 
01596 static void schannel_deal_with_seq_num(struct schannel_auth_struct *a,
01597                                      RPC_AUTH_SCHANNEL_CHK *verf)
01598 {
01599         static uchar zeros[4];
01600         uchar sequence_key[16];
01601         uchar digest1[16];
01602 
01603         hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
01604         dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
01605 
01606         hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
01607 
01608         dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
01609 
01610         dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
01611         SamOEMhash(verf->seq_num, sequence_key, 8);
01612         dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
01613 }
01614 
01615 /*******************************************************************
01616 creates an RPC_AUTH_SCHANNEL_CHK structure.
01617 ********************************************************************/
01618 
01619 static BOOL init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk,
01620                               const uchar sig[8],
01621                               const uchar packet_digest[8],
01622                               const uchar seq_num[8], const uchar confounder[8])
01623 {
01624         if (chk == NULL)
01625                 return False;
01626 
01627         memcpy(chk->sig, sig, sizeof(chk->sig));
01628         memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
01629         memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
01630         memcpy(chk->confounder, confounder, sizeof(chk->confounder));
01631 
01632         return True;
01633 }
01634 
01635 /*******************************************************************
01636  Encode a blob of data using the schannel alogrithm, also produceing
01637  a checksum over the original data.  We currently only support
01638  signing and sealing togeather - the signing-only code is close, but not
01639  quite compatible with what MS does.
01640  ********************************************************************/
01641 
01642 void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
01643                    enum schannel_direction direction,
01644                    RPC_AUTH_SCHANNEL_CHK * verf,
01645                    char *data, size_t data_len)
01646 {
01647         uchar digest_final[16];
01648         uchar confounder[8];
01649         uchar seq_num[8];
01650         static const uchar nullbytes[8] = { 0, };
01651 
01652         static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
01653         static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
01654         const uchar *schannel_sig = NULL;
01655 
01656         DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
01657         
01658         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
01659                 schannel_sig = schannel_seal_sig;
01660         } else {
01661                 schannel_sig = schannel_sign_sig;
01662         }
01663 
01664         /* fill the 'confounder' with random data */
01665         generate_random_buffer(confounder, sizeof(confounder));
01666 
01667         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
01668 
01669         RSIVAL(seq_num, 0, a->seq_num);
01670 
01671         switch (direction) {
01672         case SENDER_IS_INITIATOR:
01673                 SIVAL(seq_num, 4, 0x80);
01674                 break;
01675         case SENDER_IS_ACCEPTOR:
01676                 SIVAL(seq_num, 4, 0x0);
01677                 break;
01678         }
01679 
01680         dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));
01681 
01682         init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes,
01683                                  seq_num, confounder);
01684                                 
01685         /* produce a digest of the packet to prove it's legit (before we seal it) */
01686         schannel_digest(a, auth_level, verf, data, data_len, digest_final);
01687         memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
01688 
01689         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
01690                 uchar sealing_key[16];
01691 
01692                 /* get the key to encode the data with */
01693                 schannel_get_sealing_key(a, verf, sealing_key);
01694 
01695                 /* encode the verification data */
01696                 dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
01697                 SamOEMhash(verf->confounder, sealing_key, 8);
01698 
01699                 dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
01700                 
01701                 /* encode the packet payload */
01702                 dump_data_pw("data:\n", (const unsigned char *)data, data_len);
01703                 SamOEMhash((unsigned char *)data, sealing_key, data_len);
01704                 dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
01705         }
01706 
01707         /* encode the sequence number (key based on packet digest) */
01708         /* needs to be done after the sealing, as the original version 
01709            is used in the sealing stuff... */
01710         schannel_deal_with_seq_num(a, verf);
01711 
01712         return;
01713 }
01714 
01715 /*******************************************************************
01716  Decode a blob of data using the schannel alogrithm, also verifiying
01717  a checksum over the original data.  We currently can verify signed messages,
01718  as well as decode sealed messages
01719  ********************************************************************/
01720 
01721 BOOL schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
01722                    enum schannel_direction direction, 
01723                    RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len)
01724 {
01725         uchar digest_final[16];
01726 
01727         static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
01728         static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
01729         const uchar *schannel_sig = NULL;
01730 
01731         uchar seq_num[8];
01732 
01733         DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
01734         
01735         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
01736                 schannel_sig = schannel_seal_sig;
01737         } else {
01738                 schannel_sig = schannel_sign_sig;
01739         }
01740 
01741         /* Create the expected sequence number for comparison */
01742         RSIVAL(seq_num, 0, a->seq_num);
01743 
01744         switch (direction) {
01745         case SENDER_IS_INITIATOR:
01746                 SIVAL(seq_num, 4, 0x80);
01747                 break;
01748         case SENDER_IS_ACCEPTOR:
01749                 SIVAL(seq_num, 4, 0x0);
01750                 break;
01751         }
01752 
01753         DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
01754         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
01755 
01756         dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
01757 
01758         /* extract the sequence number (key based on supplied packet digest) */
01759         /* needs to be done before the sealing, as the original version 
01760            is used in the sealing stuff... */
01761         schannel_deal_with_seq_num(a, verf);
01762 
01763         if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
01764                 /* don't even bother with the below if the sequence number is out */
01765                 /* The sequence number is MD5'ed with a key based on the whole-packet
01766                    digest, as supplied by the client.  We check that it's a valid 
01767                    checksum after the decode, below
01768                 */
01769                 DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n"));
01770                 dump_data(2, (const char*)verf->seq_num, sizeof(verf->seq_num));
01771                 DEBUG(2, ("should be:\n"));
01772                 dump_data(2, (const char*)seq_num, sizeof(seq_num));
01773 
01774                 return False;
01775         }
01776 
01777         if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) {
01778                 /* Validate that the other end sent the expected header */
01779                 DEBUG(2, ("schannel_decode: FAILED: packet header:\n"));
01780                 dump_data(2, (const char*)verf->sig, sizeof(verf->sig));
01781                 DEBUG(2, ("should be:\n"));
01782                 dump_data(2, (const char*)schannel_sig, sizeof(schannel_sig));
01783                 return False;
01784         }
01785 
01786         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
01787                 uchar sealing_key[16];
01788                 
01789                 /* get the key to extract the data with */
01790                 schannel_get_sealing_key(a, verf, sealing_key);
01791 
01792                 /* extract the verification data */
01793                 dump_data_pw("verf->confounder:\n", verf->confounder, 
01794                              sizeof(verf->confounder));
01795                 SamOEMhash(verf->confounder, sealing_key, 8);
01796 
01797                 dump_data_pw("verf->confounder_dec:\n", verf->confounder, 
01798                              sizeof(verf->confounder));
01799                 
01800                 /* extract the packet payload */
01801                 dump_data_pw("data   :\n", (const unsigned char *)data, data_len);
01802                 SamOEMhash((unsigned char *)data, sealing_key, data_len);
01803                 dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);      
01804         }
01805 
01806         /* digest includes 'data' after unsealing */
01807         schannel_digest(a, auth_level, verf, data, data_len, digest_final);
01808 
01809         dump_data_pw("Calculated digest:\n", digest_final, 
01810                      sizeof(digest_final));
01811         dump_data_pw("verf->packet_digest:\n", verf->packet_digest, 
01812                      sizeof(verf->packet_digest));
01813         
01814         /* compare - if the client got the same result as us, then
01815            it must know the session key */
01816         return (memcmp(digest_final, verf->packet_digest, 
01817                        sizeof(verf->packet_digest)) == 0);
01818 }
01819 
01820 /*******************************************************************
01821 creates a new prs_struct containing a DATA_BLOB
01822 ********************************************************************/
01823 BOOL prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
01824 {
01825         if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL ))
01826                 return False;
01827 
01828 
01829         if (!prs_copy_data_in(prs, (char *)blob->data, blob->length))
01830                 return False;
01831 
01832         return True;
01833 }
01834 
01835 /*******************************************************************
01836 return the contents of a prs_struct in a DATA_BLOB
01837 ********************************************************************/
01838 BOOL prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
01839 {
01840         blob->length = prs_data_size(prs);
01841         blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length);
01842         
01843         /* set the pointer at the end of the buffer */
01844         prs_set_offset( prs, prs_data_size(prs) );
01845 
01846         if (!prs_copy_all_data_out((char *)blob->data, prs))
01847                 return False;
01848         
01849         return True;
01850 }

Sambaに対してSat Aug 29 21:23:17 2009に生成されました。  doxygen 1.4.7