BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size) { char *q; int i; len = MIN(len, (max_buf_size-1)); q = prs_mem_get(ps, len+1); if (q == NULL) return False; for(i = 0; i < len; i++) { if (UNMARSHALLING(ps)) str[i] = q[i]; else q[i] = str[i]; } /* The terminating null. */ str[i] = '\0'; if (MARSHALLING(ps)) { q[i] = '\0'; } ps->data_offset += len+1; dump_data(5+depth, q, len); return True; }
bool prs_init(prs_struct *ps, uint32_t size, TALLOC_CTX *ctx, bool io) { ZERO_STRUCTP(ps); ps->io = io; ps->bigendian_data = RPC_LITTLE_ENDIAN; ps->align = RPC_PARSE_ALIGN; ps->is_dynamic = False; ps->data_offset = 0; ps->buffer_size = 0; ps->data_p = NULL; ps->mem_ctx = ctx; if (size != 0) { ps->buffer_size = size; ps->data_p = (char *)talloc_zero_size(ps->mem_ctx, size); if(ps->data_p == NULL) { DEBUG(0,("prs_init: talloc fail for %u bytes.\n", (unsigned int)size)); return False; } ps->is_dynamic = True; /* We own this memory. */ } else if (MARSHALLING(ps)) { /* If size is zero and we're marshalling we should allocate memory on demand. */ ps->is_dynamic = True; } return True; }
/****************************************************************** do IO on a byte array ********************************************************************/ BOOL io_uint8s(char *name, io_struct *ps, int depth, uint8 **data8s, int len, unsigned flags) { char *q; size_t num_bytes = len * sizeof(uint8); if (MARSHALLING(ps) && num_bytes == 0) { *data8s = NULL; return True; } if (!(flags & PARSE_SCALARS)) return True; q = io_mem_get(ps, num_bytes); if (q == NULL) return False; if (MARSHALLING(ps)) { if (*data8s != NULL) DBG_RW_PCVAL(True, name, depth, ps->data_offset, ps->io, q, *data8s, len) else memset(q, 0, num_bytes); } else {
BOOL smb_io_relsecdesc(const char *desc, RPC_BUFFER *buffer, int depth, SEC_DESC **secdesc) { prs_struct *ps= &buffer->prs; prs_debug(ps, depth, desc, "smb_io_relsecdesc"); depth++; if (MARSHALLING(ps)) { uint32 struct_offset = prs_offset(ps); uint32 relative_offset; if (! *secdesc) { relative_offset = 0; if (!prs_uint32("offset", ps, depth, &relative_offset)) return False; return True; } if (*secdesc != NULL) { buffer->string_at_end -= sec_desc_size(*secdesc); if(!prs_set_offset(ps, buffer->string_at_end)) return False; /* write the secdesc */ if (!sec_io_desc(desc, secdesc, ps, depth)) return False; if(!prs_set_offset(ps, struct_offset)) return False; } relative_offset=buffer->string_at_end - buffer->struct_start; /* write its offset */ if (!prs_uint32("offset", ps, depth, &relative_offset)) return False; } else { uint32 old_offset; /* read the offset */ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end)) return False; old_offset = prs_offset(ps); if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start)) return False; /* read the sd */ if (!sec_io_desc(desc, secdesc, ps, depth)) return False; if(!prs_set_offset(ps, old_offset)) return False; } return True; }
BOOL smb_io_relstr(const char *desc, RPC_BUFFER *buffer, int depth, UNISTR *string) { prs_struct *ps=&buffer->prs; if (MARSHALLING(ps)) { uint32 struct_offset = prs_offset(ps); uint32 relative_offset; buffer->string_at_end -= (size_of_relative_string(string) - 4); if(!prs_set_offset(ps, buffer->string_at_end)) return False; #if 0 /* JERRY */ /* * Win2k does not align strings in a buffer * Tested against WinNT 4.0 SP 6a & 2k SP2 --jerry */ if (!prs_align(ps)) return False; #endif buffer->string_at_end = prs_offset(ps); /* write the string */ if (!smb_io_unistr(desc, string, ps, depth)) return False; if(!prs_set_offset(ps, struct_offset)) return False; relative_offset=buffer->string_at_end - buffer->struct_start; /* write its offset */ if (!prs_uint32("offset", ps, depth, &relative_offset)) return False; } else { uint32 old_offset; /* read the offset */ if (!prs_uint32("offset", ps, depth, &(buffer->string_at_end))) return False; if (buffer->string_at_end == 0) return True; old_offset = prs_offset(ps); if(!prs_set_offset(ps, buffer->string_at_end+buffer->struct_start)) return False; /* read the string */ if (!smb_io_unistr(desc, string, ps, depth)) return False; if(!prs_set_offset(ps, old_offset)) return False; } return True; }
BOOL sec_io_desc_buf(const char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth) { uint32 off_len; uint32 off_max_len; uint32 old_offset; uint32 size; SEC_DESC_BUF *psdb; if (ppsdb == NULL) return False; psdb = *ppsdb; if (UNMARSHALLING(ps) && psdb == NULL) { if((psdb = (SEC_DESC_BUF *)prs_alloc_mem(ps,sizeof(SEC_DESC_BUF))) == NULL) return False; *ppsdb = psdb; } prs_debug(ps, depth, desc, "sec_io_desc_buf"); depth++; if(!prs_align(ps)) return False; if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len)) return False; if(!prs_uint32 ("ptr ", ps, depth, &psdb->ptr)) return False; if(!prs_uint32_pre("len ", ps, depth, &psdb->len, &off_len)) return False; old_offset = prs_offset(ps); /* reading, length is non-zero; writing, descriptor is non-NULL */ if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) { if(!sec_io_desc("sec ", &psdb->sec, ps, depth)) return False; } if(!prs_align(ps)) return False; size = prs_offset(ps) - old_offset; if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size)) return False; if(!prs_uint32_post("len ", ps, depth, &psdb->len, off_len, size)) return False; return True; }
bool smb_io_rpc_hdr(const char *desc, RPC_HDR *rpc, prs_struct *ps, int depth) { if (rpc == NULL) return False; prs_debug(ps, depth, desc, "smb_io_rpc_hdr"); depth++; if(!prs_uint8 ("major ", ps, depth, &rpc->major)) return False; if(!prs_uint8 ("minor ", ps, depth, &rpc->minor)) return False; if(!prs_uint8 ("pkt_type ", ps, depth, &rpc->pkt_type)) return False; if(!prs_uint8 ("flags ", ps, depth, &rpc->flags)) return False; /* We always marshall in little endian format. */ if (MARSHALLING(ps)) rpc->pack_type[0] = 0x10; if(!prs_uint8("pack_type0", ps, depth, &rpc->pack_type[0])) return False; if(!prs_uint8("pack_type1", ps, depth, &rpc->pack_type[1])) return False; if(!prs_uint8("pack_type2", ps, depth, &rpc->pack_type[2])) return False; if(!prs_uint8("pack_type3", ps, depth, &rpc->pack_type[3])) return False; /* * If reading and pack_type[0] == 0 then the data is in big-endian * format. Set the flag in the prs_struct to specify reverse-endainness. */ if (UNMARSHALLING(ps) && rpc->pack_type[0] == 0) { DEBUG(10,("smb_io_rpc_hdr: PDU data format is big-endian. Setting flag.\n")); prs_set_endian_data(ps, RPC_BIG_ENDIAN); } if(!prs_uint16("frag_len ", ps, depth, &rpc->frag_len)) return False; if(!prs_uint16("auth_len ", ps, depth, &rpc->auth_len)) return False; if(!prs_uint32("call_id ", ps, depth, &rpc->call_id)) return False; return True; }
BOOL prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 ptr_uint32, uint32 data_size) { if (MARSHALLING(ps)) { /* * Writing - temporarily move the offset pointer. */ uint32 old_offset = ps->data_offset; ps->data_offset = ptr_uint32; if(!prs_uint32(name, ps, depth, &data_size)) { ps->data_offset = old_offset; return False; } ps->data_offset = old_offset; } return True; }
BOOL prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 ptr_uint16, uint32 start_offset) { if (MARSHALLING(ps)) { /* * Writing - temporarily move the offset pointer. */ uint16 data_size = ps->data_offset - start_offset; uint32 old_offset = ps->data_offset; ps->data_offset = ptr_uint16; if(!prs_uint16(name, ps, depth, &data_size)) { ps->data_offset = old_offset; return False; } ps->data_offset = old_offset; } else { ps->data_offset = start_offset + (uint32)(*data16); } return True; }
BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str) { int len = 0; unsigned char *p = (unsigned char *)str->buffer; uint8 *start; char *q; uint32 max_len; uint16* ptr; if (MARSHALLING(ps)) { for(len = 0; str->buffer[len] != 0; len++) ; q = prs_mem_get(ps, (len+1)*2); if (q == NULL) return False; start = (uint8*)q; for(len = 0; str->buffer[len] != 0; len++) { if(ps->bigendian_data) { /* swap bytes - p is little endian, q is big endian. */ q[0] = (char)p[1]; q[1] = (char)p[0]; p += 2; q += 2; } else { q[0] = (char)p[0]; q[1] = (char)p[1]; p += 2; q += 2; } } /* * even if the string is 'empty' (only an \0 char) * at this point the leading \0 hasn't been parsed. * so parse it now */ q[0] = 0; q[1] = 0; q += 2; len++; dump_data(5+depth, (char *)start, len * 2); } else { /* unmarshalling */ uint32 alloc_len = 0; q = prs_data_p(ps) + prs_offset(ps); /* * Work out how much space we need and talloc it. */ max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16); /* the test of the value of *ptr helps to catch the circumstance where we have an emtpty (non-existent) string in the buffer */ for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++) /* do nothing */ ; /* should we allocate anything at all? */ str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16)); if ((str->buffer == NULL) && (alloc_len > 0)) return False; p = (unsigned char *)str->buffer; len = 0; /* the (len < alloc_len) test is to prevent us from overwriting memory that is not ours...if we get that far, we have a non-null terminated string in the buffer and have messed up somewhere */ while ((len < alloc_len) && (*(uint16 *)q != 0)) { if(ps->bigendian_data) { /* swap bytes - q is big endian, p is little endian. */ p[0] = (unsigned char)q[1]; p[1] = (unsigned char)q[0]; p += 2; q += 2; } else { p[0] = (unsigned char)q[0]; p[1] = (unsigned char)q[1]; p += 2; q += 2; } len++; } if (len < alloc_len) { /* NULL terminate the UNISTR */ str->buffer[len++] = '\0'; } } /* set the offset in the prs_struct; 'len' points to the terminiating NULL in the UNISTR so we need to go one more uint16 */ ps->data_offset += (len)*2; return True; }
BOOL smb_io_relarraystr(const char *desc, RPC_BUFFER *buffer, int depth, uint16 **string) { UNISTR chaine; prs_struct *ps=&buffer->prs; if (MARSHALLING(ps)) { uint32 struct_offset = prs_offset(ps); uint32 relative_offset; uint16 *p; uint16 *q; uint16 zero=0; p=*string; q=*string; /* first write the last 0 */ buffer->string_at_end -= 2; if(!prs_set_offset(ps, buffer->string_at_end)) return False; if(!prs_uint16("leading zero", ps, depth, &zero)) return False; while (p && (*p!=0)) { while (*q!=0) q++; /* Yes this should be malloc not talloc. Don't change. */ chaine.buffer = (uint16 *) SMB_MALLOC((q-p+1)*sizeof(uint16)); if (chaine.buffer == NULL) return False; memcpy(chaine.buffer, p, (q-p+1)*sizeof(uint16)); buffer->string_at_end -= (q-p+1)*sizeof(uint16); if(!prs_set_offset(ps, buffer->string_at_end)) { SAFE_FREE(chaine.buffer); return False; } /* write the string */ if (!smb_io_unistr(desc, &chaine, ps, depth)) { SAFE_FREE(chaine.buffer); return False; } q++; p=q; SAFE_FREE(chaine.buffer); } if(!prs_set_offset(ps, struct_offset)) return False; relative_offset=buffer->string_at_end - buffer->struct_start; /* write its offset */ if (!prs_uint32("offset", ps, depth, &relative_offset)) return False; } else { /* UNMARSHALLING */ uint32 old_offset; uint16 *chaine2=NULL; int l_chaine=0; int l_chaine2=0; size_t realloc_size = 0; *string=NULL; /* read the offset */ if (!prs_uint32("offset", ps, depth, &buffer->string_at_end)) return False; old_offset = prs_offset(ps); if(!prs_set_offset(ps, buffer->string_at_end + buffer->struct_start)) return False; do { if (!smb_io_unistr(desc, &chaine, ps, depth)) return False; l_chaine=str_len_uni(&chaine); /* we're going to add two more bytes here in case this is the last string in the array and we need to add an extra NULL for termination */ if (l_chaine > 0) { realloc_size = (l_chaine2+l_chaine+2)*sizeof(uint16); /* Yes this should be realloc - it's freed below. JRA */ if((chaine2=(uint16 *)SMB_REALLOC(chaine2, realloc_size)) == NULL) { return False; } memcpy(chaine2+l_chaine2, chaine.buffer, (l_chaine+1)*sizeof(uint16)); l_chaine2+=l_chaine+1; } } while(l_chaine!=0); /* the end should be bould NULL terminated so add the second one here */ if (chaine2) { chaine2[l_chaine2] = '\0'; *string=(uint16 *)TALLOC_MEMDUP(prs_get_mem_context(ps),chaine2,realloc_size); if (!*string) { return False; } SAFE_FREE(chaine2); } if(!prs_set_offset(ps, old_offset)) return False; } return True; }
/******************************************************************* do IO on a uint8. ********************************************************************/ BOOL io_format(char *name, io_struct *ps, int depth, void *data, uint32 struct_offset, unsigned flags) { char *q; size_t item_size = 0; int nitems = 0; BOOL is_string = False; if (!io_format_interp(ps, &item_size, &nitems, &is_string)) return False; if (is_string) { uint32 old_offset; uint32 str_offset; SMBCHR *str = (SMBCHR*)(((char*)data) + struct_offset); if (item_size != 1) return False; if (MARSHALLING(ps) && (flags & PARSE_SCALARS)) { /* skip offset */ q = io_mem_get_end(ps, sizeof(uint32)); if (q == NULL) return False; DEBUG(5+depth, ("%s: %04x z\n", name, ps->data_offset)); ps->data_offset += sizeof(uint32); return True; } else if (MARSHALLING(ps) && (flags & PARSE_OFFSETS)) { BOOL ret; if (str != NULL) { q = io_mem_get(ps, strlen(*str)); q = io_mem_get_end(ps, strlen(*str)); if (q == NULL) return False; str_offset = PTR_DIFF(q, ps->data_p); } else { str_offset = 0; } DEBUG(5+depth, ("%s:", name)); if (!io_uint32("offset", ps, depth, &str_offset, PARSE_SCALARS)) return False; if (str_offset == 0) return True; DEBUG(5+depth, ("%s:", name)); old_offset = ps->data_offset; ps->data_offset = str_offset; ret = io_SMBCHR("z", ps, depth, str, PARSE_SCALARS); ps->data_offset = old_offset; return ret; } if (!(flags & PARSE_SCALARS)) return True; DEBUG(5+depth, ("%s:", name)); if (!io_uint32("offset", ps, depth, &str_offset, PARSE_SCALARS)) return False; str_offset &= 0xffff; /* spec says ignore above 16 bits */ old_offset = ps->data_offset; ps->data_offset = str_offset; DEBUG(5+depth, ("%s:", name)); if (!io_SMBCHR("z", ps, depth, str, PARSE_SCALARS)) return False; ps->data_offset = old_offset; return True; } if ((flags & PARSE_OFFSETS)) { ps->data_offset += nitems * item_size; return True; } if (!(flags & PARSE_SCALARS)) return True; DEBUG(5+depth, ("%s:", name)); if (item_size == 1) { uint8 *u8 = (uint8*)(((char*)data) + struct_offset); if (nitems == 1) { return io_uint8("B", ps, depth, u8, PARSE_SCALARS); } return io_uint8s("B", ps, depth, &u8, nitems, PARSE_SCALARS); } else if (item_size == 2) { uint16 *u16 = (uint16*)(((char*)data) + struct_offset); if (nitems == 1) { return io_uint16("W", ps, depth, u16, PARSE_SCALARS); } return io_uint16s("W", ps, depth, u16, nitems, PARSE_SCALARS); } else if (item_size == 4) { uint32 *u32 = (uint32*)(((char*)data) + struct_offset); if (nitems == 1) { return io_uint32("D", ps, depth, u32, PARSE_SCALARS); } return io_uint32s("D", ps, depth, u32, nitems, PARSE_SCALARS); } return True; }