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 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 prs_append_prs_data(prs_struct *dst, prs_struct *src) { if(!prs_grow(dst, prs_offset(src))) return False; memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src)); dst->data_offset += prs_offset(src); 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 prs_rpcbuffer(const char *desc, prs_struct *ps, int depth, RPC_BUFFER *buffer) { prs_debug(ps, depth, desc, "prs_rpcbuffer"); depth++; /* reading */ if (UNMARSHALLING(ps)) { buffer->size=0; buffer->string_at_end=0; if (!prs_uint32("size", ps, depth, &buffer->size)) return False; /* * JRA. I'm not sure if the data in here is in big-endian format if * the client is big-endian. Leave as default (little endian) for now. */ if (!prs_init(&buffer->prs, buffer->size, prs_get_mem_context(ps), UNMARSHALL)) return False; if (!prs_append_some_prs_data(&buffer->prs, ps, prs_offset(ps), buffer->size)) return False; if (!prs_set_offset(&buffer->prs, 0)) return False; if (!prs_set_offset(ps, buffer->size+prs_offset(ps))) return False; buffer->string_at_end=buffer->size; return True; } else { BOOL ret = False; if (!prs_uint32("size", ps, depth, &buffer->size)) goto out; if (!prs_append_some_prs_data(ps, &buffer->prs, 0, buffer->size)) goto out; ret = True; out: /* We have finished with the data in buffer->prs - free it. */ prs_mem_free(&buffer->prs); return ret; } }
/********************************************************************** Initialize a new spoolss buff for use by a client rpc **********************************************************************/ void rpcbuf_init(RPC_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx) { buffer->size = size; buffer->string_at_end = size; prs_init(&buffer->prs, size, ctx, MARSHALL); buffer->struct_start = prs_offset(&buffer->prs); }
/* useful function to store a structure in rpc wire format */ int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps) { TDB_DATA kbuf, dbuf; kbuf.dptr = keystr; kbuf.dsize = strlen(keystr)+1; dbuf.dptr = prs_data_p(ps); dbuf.dsize = prs_offset(ps); return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); }
BOOL prs_copy_all_data_out(char *dst, prs_struct *src) { uint32 len = prs_offset(src); if (!len) return True; prs_set_offset(src, 0); return prs_copy_data_out(dst, src, len); }
BOOL smb_io_hdrbuf_pre(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 *offset) { (*offset) = prs_offset(ps); if (ps->io) { /* reading. */ if(!smb_io_hdrbuf(desc, hdr, ps, depth)) return False; } else { /* writing. */ if(!prs_set_offset(ps, prs_offset(ps) + (sizeof(uint32) * 2))) return False; } return True; }
static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr, BOOL *first, BOOL *last, uint32 *len) { DEBUG(5,("rpc_check_hdr: rdata->data_size = %u\n", (uint32)prs_data_size(rdata) )); /* Next call sets endian bit. */ if(!smb_io_rpc_hdr("rpc_hdr ", rhdr, rdata, 0)) { DEBUG(0,("rpc_check_hdr: Failed to unmarshall RPC_HDR.\n")); return False; } if (prs_offset(rdata) != RPC_HEADER_LEN) { DEBUG(0,("rpc_check_hdr: offset was %x, should be %x.\n", prs_offset(rdata), RPC_HEADER_LEN)); return False; } (*first) = ((rhdr->flags & RPC_FLG_FIRST) != 0); (*last) = ((rhdr->flags & RPC_FLG_LAST ) != 0); (*len) = (uint32)rhdr->frag_len - prs_data_size(rdata); return (rhdr->pkt_type != RPC_FAULT); }
static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32 rpc_call_id) { prs_struct rpc_out; ssize_t ret; prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */ cli->mem_ctx, MARSHALL); if (!NT_STATUS_IS_OK(create_rpc_bind_resp(cli, rpc_call_id, &rpc_out))) { return False; } if ((ret = cli_write(cli, cli->nt_pipe_fnum, 0x8, prs_data_p(&rpc_out), 0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) { DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret)); prs_mem_free(&rpc_out); return False; } prs_mem_free(&rpc_out); return True; }
BOOL sec_io_ace(const char *desc, SEC_ACE *psa, prs_struct *ps, int depth) { uint32 old_offset; uint32 offset_ace_size; if (psa == NULL) return False; prs_debug(ps, depth, desc, "sec_io_ace"); depth++; old_offset = prs_offset(ps); if(!prs_uint8("type ", ps, depth, &psa->type)) return False; if(!prs_uint8("flags", ps, depth, &psa->flags)) return False; if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size)) return False; if(!sec_io_access("info ", &psa->info, ps, depth)) return False; /* check whether object access is present */ if (!sec_ace_object(psa->type)) { if (!smb_io_dom_sid("trustee ", &psa->trustee , ps, depth)) return False; } else { if (!prs_uint32("obj_flags", ps, depth, &psa->obj_flags)) return False; if (psa->obj_flags & SEC_ACE_OBJECT_PRESENT) if (!smb_io_uuid("obj_guid", &psa->obj_guid, ps,depth)) return False; if (psa->obj_flags & SEC_ACE_OBJECT_INHERITED_PRESENT) if (!smb_io_uuid("inh_guid", &psa->inh_guid, ps,depth)) return False; if(!smb_io_dom_sid("trustee ", &psa->trustee , ps, depth)) return False; } if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset)) return False; return True; }
BOOL smb_io_hdrbuf_post(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 ptr_hdrbuf, uint32 max_len, uint32 len) { if (!ps->io) { /* writing: go back and do a retrospective job. i hate this */ uint32 old_offset = prs_offset(ps); init_buf_hdr(hdr, max_len, len); if(!prs_set_offset(ps, ptr_hdrbuf)) return False; if(!smb_io_hdrbuf(desc, hdr, ps, depth)) return False; if(!prs_set_offset(ps, old_offset)) return False; } return True; }
static uint32 create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len, int auth_len, uint8 flags, uint32 oldid, uint32 data_left) { uint32 alloc_hint; RPC_HDR hdr; RPC_HDR_REQ hdr_req; uint32 callid = oldid ? oldid : get_rpc_call_id(); DEBUG(5,("create_rpc_request: opnum: 0x%x data_len: 0x%x\n", op_num, data_len)); /* create the rpc header RPC_HDR */ init_rpc_hdr(&hdr, RPC_REQUEST, flags, callid, data_len, auth_len); /* * The alloc hint should be the amount of data, not including * RPC headers & footers. */ if (auth_len != 0) alloc_hint = data_len - RPC_HEADER_LEN - RPC_HDR_AUTH_LEN - auth_len; else alloc_hint = data_len - RPC_HEADER_LEN; DEBUG(10,("create_rpc_request: data_len: %x auth_len: %x alloc_hint: %x\n", data_len, auth_len, alloc_hint)); /* Create the rpc request RPC_HDR_REQ */ init_rpc_hdr_req(&hdr_req, alloc_hint, op_num); /* stream-time... */ if(!smb_io_rpc_hdr("hdr ", &hdr, rpc_out, 0)) return 0; if(!smb_io_rpc_hdr_req("hdr_req", &hdr_req, rpc_out, 0)) return 0; if (prs_offset(rpc_out) != RPC_HEADER_LEN + RPC_HDR_REQ_LEN) return 0; return callid; }
BOOL rpcbuf_alloc_size(RPC_BUFFER *buffer, uint32 buffer_size) { prs_struct *ps; uint32 extra_space; uint32 old_offset; /* if we don't need anything. don't do anything */ if ( buffer_size == 0x0 ) return True; if (!buffer) { return False; } ps= &buffer->prs; /* damn, I'm doing the reverse operation of prs_grow() :) */ if (buffer_size < prs_data_size(ps)) extra_space=0; else extra_space = buffer_size - prs_data_size(ps); /* * save the offset and move to the end of the buffer * prs_grow() checks the extra_space against the offset */ old_offset=prs_offset(ps); prs_set_offset(ps, prs_data_size(ps)); if (!prs_grow(ps, extra_space)) return False; prs_set_offset(ps, old_offset); buffer->string_at_end=prs_data_size(ps); return True; }
BOOL sec_io_desc(const char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth) { uint32 old_offset; uint32 max_offset = 0; /* after we're done, move offset to end */ uint32 tmp_offset = 0; SEC_DESC *psd; if (ppsd == NULL) return False; psd = *ppsd; if (psd == NULL) { if(UNMARSHALLING(ps)) { if((psd = (SEC_DESC *)prs_alloc_mem(ps,sizeof(SEC_DESC))) == NULL) return False; *ppsd = psd; } else { /* Marshalling - just ignore. */ return True; } } prs_debug(ps, depth, desc, "sec_io_desc"); depth++; #if 0 /* * if alignment is needed, should be done by the the * caller. Not here. This caused me problems when marshalling * printer info into a buffer. --jerry */ if(!prs_align(ps)) return False; #endif /* start of security descriptor stored for back-calc offset purposes */ old_offset = prs_offset(ps); if(!prs_uint16("revision ", ps, depth, &psd->revision)) return False; if(!prs_uint16("type ", ps, depth, &psd->type)) return False; if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid)) return False; if(!prs_uint32("off_grp_sid ", ps, depth, &psd->off_grp_sid)) return False; if(!prs_uint32("off_sacl ", ps, depth, &psd->off_sacl)) return False; if(!prs_uint32("off_dacl ", ps, depth, &psd->off_dacl)) return False; max_offset = MAX(max_offset, prs_offset(ps)); if (psd->off_owner_sid != 0) { tmp_offset = prs_offset(ps); if(!prs_set_offset(ps, old_offset + psd->off_owner_sid)) return False; if (UNMARSHALLING(ps)) { /* reading */ if((psd->owner_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->owner_sid))) == NULL) return False; } if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth)) return False; max_offset = MAX(max_offset, prs_offset(ps)); if (!prs_set_offset(ps,tmp_offset)) return False; } if (psd->off_grp_sid != 0) { tmp_offset = prs_offset(ps); if(!prs_set_offset(ps, old_offset + psd->off_grp_sid)) return False; if (UNMARSHALLING(ps)) { /* reading */ if((psd->grp_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->grp_sid))) == NULL) return False; } if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth)) return False; max_offset = MAX(max_offset, prs_offset(ps)); if (!prs_set_offset(ps,tmp_offset)) return False; } if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) { tmp_offset = prs_offset(ps); if(!prs_set_offset(ps, old_offset + psd->off_sacl)) return False; if(!sec_io_acl("sacl", &psd->sacl, ps, depth)) return False; max_offset = MAX(max_offset, prs_offset(ps)); if (!prs_set_offset(ps,tmp_offset)) return False; } if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) { tmp_offset = prs_offset(ps); if(!prs_set_offset(ps, old_offset + psd->off_dacl)) return False; if(!sec_io_acl("dacl", &psd->dacl, ps, depth)) return False; max_offset = MAX(max_offset, prs_offset(ps)); if (!prs_set_offset(ps,tmp_offset)) return False; } if(!prs_set_offset(ps, max_offset)) return False; return True; }
BOOL sec_io_acl(const char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth) { unsigned int i; uint32 old_offset; uint32 offset_acl_size; SEC_ACL *psa; /* * Note that the size is always a multiple of 4 bytes due to the * nature of the data structure. Therefore the prs_align() calls * have been removed as they through us off when doing two-layer * marshalling such as in the printing code (NEW_BUFFER). --jerry */ if (ppsa == NULL) return False; psa = *ppsa; if(UNMARSHALLING(ps) && psa == NULL) { /* * This is a read and we must allocate the stuct to read into. */ if((psa = (SEC_ACL *)prs_alloc_mem(ps, sizeof(SEC_ACL))) == NULL) return False; *ppsa = psa; } prs_debug(ps, depth, desc, "sec_io_acl"); depth++; old_offset = prs_offset(ps); if(!prs_uint16("revision", ps, depth, &psa->revision)) return False; if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size)) return False; if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces)) return False; if (UNMARSHALLING(ps)) { /* * Even if the num_aces is zero, allocate memory as there's a difference * between a non-present DACL (allow all access) and a DACL with no ACE's * (allow no access). */ if((psa->ace = (SEC_ACE *)prs_alloc_mem(ps,sizeof(psa->ace[0]) * (psa->num_aces+1))) == NULL) return False; } for (i = 0; i < psa->num_aces; i++) { fstring tmp; slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i); if(!sec_io_ace(tmp, &psa->ace[i], ps, depth)) return False; } if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset)) return False; return True; }
/**************************************************************************** set the security descriptor for a open file ****************************************************************************/ BOOL cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd) { char param[8]; char *rparam=NULL, *rdata=NULL; unsigned int rparam_count=0, rdata_count=0; uint32 sec_info = 0; TALLOC_CTX *mem_ctx; prs_struct pd; BOOL ret = False; if ((mem_ctx = talloc_init("cli_set_secdesc")) == NULL) { DEBUG(0,("talloc_init failed.\n")); goto cleanup; } prs_init(&pd, 0, mem_ctx, MARSHALL); prs_give_memory(&pd, NULL, 0, True); if (!sec_io_desc("sd data", &sd, &pd, 1)) { DEBUG(1,("Failed to marshall secdesc\n")); goto cleanup; } SIVAL(param, 0, fnum); if (sd->off_dacl) sec_info |= DACL_SECURITY_INFORMATION; if (sd->off_owner_sid) sec_info |= OWNER_SECURITY_INFORMATION; if (sd->off_grp_sid) sec_info |= GROUP_SECURITY_INFORMATION; SSVAL(param, 4, sec_info); if (!cli_send_nt_trans(cli, NT_TRANSACT_SET_SECURITY_DESC, 0, NULL, 0, 0, param, 8, 0, prs_data_p(&pd), prs_offset(&pd), 0)) { DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n")); goto cleanup; } if (!cli_receive_nt_trans(cli, &rparam, &rparam_count, &rdata, &rdata_count)) { DEBUG(1,("NT_TRANSACT_SET_SECURITY_DESC failed\n")); goto cleanup; } ret = True; cleanup: SAFE_FREE(rparam); SAFE_FREE(rdata); talloc_destroy(mem_ctx); prs_mem_free(&pd); return ret; }
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; }
static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata, uint8 expected_pkt_type) { uint32 len; char *rparam = NULL; uint32 rparam_len = 0; uint16 setup[2]; BOOL first = True; BOOL last = True; RPC_HDR rhdr; char *pdata = data ? prs_data_p(data) : NULL; uint32 data_len = data ? prs_offset(data) : 0; char *prdata = NULL; uint32 rdata_len = 0; uint32 current_offset = 0; uint32 fragment_start = 0; uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024; int auth_padding_len = 0; /* Create setup parameters - must be in native byte order. */ setup[0] = TRANSACT_DCERPCCMD; setup[1] = cli->nt_pipe_fnum; /* Pipe file handle. */ DEBUG(5,("rpc_api_pipe: fnum:%x\n", (int)cli->nt_pipe_fnum)); /* Send the RPC request and receive a response. For short RPC calls (about 1024 bytes or so) the RPC request and response appears in a SMBtrans request and response. Larger RPC responses are received further on. */ if (!cli_api_pipe(cli, "\\PIPE\\", setup, 2, 0, /* Setup, length, max */ NULL, 0, 0, /* Params, length, max */ pdata, data_len, max_data, /* data, length, max */ &rparam, &rparam_len, /* return params, len */ &prdata, &rdata_len)) /* return data, len */ { DEBUG(0, ("cli_pipe: return critical error. Error was %s\n", cli_errstr(cli))); return False; } /* Throw away returned params - we know we won't use them. */ SAFE_FREE(rparam); if (prdata == NULL) { DEBUG(0,("rpc_api_pipe: pipe %x failed to return data.\n", (int)cli->nt_pipe_fnum)); return False; } /* * Give this memory as dynamically allocated to the return parse * struct. */ prs_give_memory(rdata, prdata, rdata_len, True); current_offset = rdata_len; /* This next call sets the endian bit correctly in rdata. */ if (!rpc_check_hdr(rdata, &rhdr, &first, &last, &len)) { prs_mem_free(rdata); return False; } if (rhdr.pkt_type == RPC_BINDACK) { if (!last && !first) { DEBUG(5,("rpc_api_pipe: bug in server (AS/U?), setting fragment first/last ON.\n")); first = True; last = True; } } if (rhdr.pkt_type == RPC_BINDNACK) { DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum)); prs_mem_free(rdata); return False; } if (rhdr.pkt_type == RPC_RESPONSE) { RPC_HDR_RESP rhdr_resp; if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) { DEBUG(5,("rpc_api_pipe: failed to unmarshal RPC_HDR_RESP.\n")); prs_mem_free(rdata); return False; } } if (rhdr.pkt_type != expected_pkt_type) { DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum, rhdr.pkt_type, expected_pkt_type)); prs_mem_free(rdata); return False; } DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n", (unsigned int)len, (unsigned int)rdata_len )); /* check if data to be sent back was too large for one SMBtrans */ /* err status is only informational: the _real_ check is on the length */ if (len > 0) { /* || err == (0x80000000 | STATUS_BUFFER_OVERFLOW)) */ /* Read the remaining part of the first response fragment */ if (!rpc_read(cli, rdata, len, ¤t_offset)) { prs_mem_free(rdata); return False; } } /* * Now we have a complete PDU, check the auth struct if any was sent. */ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len, rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) { prs_mem_free(rdata); return False; } if (rhdr.auth_len != 0) { /* * Drop the auth footers from the current offset. * We need this if there are more fragments. * The auth footers consist of the auth_data and the * preceeding 8 byte auth_header. */ current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len); } /* * Only one rpc fragment, and it has been read. */ if (first && last) { DEBUG(6,("rpc_api_pipe: fragment first and last both set\n")); return True; } /* * Read more fragments using SMBreadX until we get one with the * last bit set. */ while (!last) { RPC_HDR_RESP rhdr_resp; int num_read; char hdr_data[RPC_HEADER_LEN+RPC_HDR_RESP_LEN]; prs_struct hps; uint8 eclass; uint32 ecode; /* * First read the header of the next PDU. */ prs_init(&hps, 0, cli->mem_ctx, UNMARSHALL); prs_give_memory(&hps, hdr_data, sizeof(hdr_data), False); num_read = cli_read(cli, cli->nt_pipe_fnum, hdr_data, 0, RPC_HEADER_LEN+RPC_HDR_RESP_LEN); if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); if (eclass != ERRDOS && ecode != ERRmoredata) { DEBUG(0,("rpc_api_pipe: cli_read error : %d/%d\n", eclass, ecode)); return False; } } DEBUG(5,("rpc_api_pipe: read header (size:%d)\n", num_read)); if (num_read != RPC_HEADER_LEN+RPC_HDR_RESP_LEN) { DEBUG(0,("rpc_api_pipe: Error : requested %d bytes, got %d.\n", RPC_HEADER_LEN+RPC_HDR_RESP_LEN, num_read )); return False; } /* This call sets the endianness in hps. */ if (!rpc_check_hdr(&hps, &rhdr, &first, &last, &len)) return False; /* Ensure the endianness in rdata is set correctly - must be same as hps. */ if (hps.bigendian_data != rdata->bigendian_data) { DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to %s\n", rdata->bigendian_data ? "big" : "little", hps.bigendian_data ? "big" : "little" )); return False; } if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, &hps, 0)) { DEBUG(0,("rpc_api_pipe: Error in unmarshalling RPC_HDR_RESP.\n")); return False; } if (first) { DEBUG(0,("rpc_api_pipe: secondary PDU rpc header has 'first' set !\n")); return False; } /* * Now read the rest of the PDU. */ if (!rpc_read(cli, rdata, len, ¤t_offset)) { prs_mem_free(rdata); return False; } fragment_start = current_offset - len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; /* * Verify any authentication footer. */ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len, rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) { prs_mem_free(rdata); return False; } if (rhdr.auth_len != 0 ) { /* * Drop the auth footers from the current offset. * The auth footers consist of the auth_data and the * preceeding 8 byte auth_header. * We need this if there are more fragments. */ current_offset -= (auth_padding_len + RPC_HDR_AUTH_LEN + rhdr.auth_len); } } return True; }
static void fill_in_printer_values( NT_PRINTER_INFO_LEVEL_2 *info2, REGVAL_CTR *values ) { DEVICEMODE *devmode; prs_struct prs; uint32 offset; UNISTR2 data; char *p; uint32 printer_status = PRINTER_STATUS_OK; regval_ctr_addvalue( values, "Attributes", REG_DWORD, (char*)&info2->attributes, sizeof(info2->attributes) ); regval_ctr_addvalue( values, "Priority", REG_DWORD, (char*)&info2->priority, sizeof(info2->attributes) ); regval_ctr_addvalue( values, "ChangeID", REG_DWORD, (char*)&info2->changeid, sizeof(info2->changeid) ); regval_ctr_addvalue( values, "Default Priority", REG_DWORD, (char*)&info2->default_priority, sizeof(info2->default_priority) ); /* lie and say everything is ok since we don't want to call print_queue_length() to get the real status */ regval_ctr_addvalue( values, "Status", REG_DWORD, (char*)&printer_status, sizeof(info2->status) ); regval_ctr_addvalue( values, "StartTime", REG_DWORD, (char*)&info2->starttime, sizeof(info2->starttime) ); regval_ctr_addvalue( values, "UntilTime", REG_DWORD, (char*)&info2->untiltime, sizeof(info2->untiltime) ); /* strip the \\server\ from this string */ if ( !(p = strrchr( info2->printername, '\\' ) ) ) p = info2->printername; else p++; init_unistr2( &data, p, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->location, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Location", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->comment, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Description", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->parameters, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Parameters", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->portname, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Port", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->sharename, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Share Name", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->drivername, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Printer Driver", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, info2->sepfile, UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Separator File", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, "WinPrint", UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Print Processor", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); init_unistr2( &data, "RAW", UNI_STR_TERMINATE); regval_ctr_addvalue( values, "Datatype", REG_SZ, (char*)data.buffer, data.uni_str_len*sizeof(uint16) ); /* use a prs_struct for converting the devmode and security descriptor to REG_BINARY */ prs_init( &prs, RPC_MAX_PDU_FRAG_LEN, values, MARSHALL); /* stream the device mode */ if ( (devmode = construct_dev_mode( info2->sharename )) != NULL ) { if ( spoolss_io_devmode( "devmode", &prs, 0, devmode ) ) { offset = prs_offset( &prs ); regval_ctr_addvalue( values, "Default Devmode", REG_BINARY, prs_data_p(&prs), offset ); } } prs_mem_clear( &prs ); prs_set_offset( &prs, 0 ); /* stream the printer security descriptor */ if ( info2->secdesc_buf && info2->secdesc_buf->len ) { if ( sec_io_desc("sec_desc", &info2->secdesc_buf->sec, &prs, 0 ) ) { offset = prs_offset( &prs ); regval_ctr_addvalue( values, "Security", REG_BINARY, prs_data_p(&prs), offset ); } } prs_mem_free( &prs ); return; }
static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) { uint32 ss_padding_len = 0; size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; if(!p->pipe_bound) { DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); set_incoming_fault(p); return False; } /* * Check if we need to do authentication processing. * This is only done on requests, not binds. */ /* * Read the RPC request header. */ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) { DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n")); set_incoming_fault(p); return False; } switch(p->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: break; case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: case PIPE_AUTH_TYPE_NTLMSSP: { NTSTATUS status; if(!api_pipe_ntlmssp_auth_process(p, rpc_in_p, &ss_padding_len, &status)) { DEBUG(0,("process_request_pdu: failed to do auth processing.\n")); DEBUG(0,("process_request_pdu: error was %s.\n", nt_errstr(status) )); set_incoming_fault(p); return False; } break; } case PIPE_AUTH_TYPE_SCHANNEL: if (!api_pipe_schannel_process(p, rpc_in_p, &ss_padding_len)) { DEBUG(3,("process_request_pdu: failed to do schannel processing.\n")); set_incoming_fault(p); return False; } break; default: DEBUG(0,("process_request_pdu: unknown auth type %u set.\n", (unsigned int)p->auth.auth_type )); set_incoming_fault(p); return False; } /* Now we've done the sign/seal we can remove any padding data. */ if (data_len > ss_padding_len) { data_len -= ss_padding_len; } /* * Check the data length doesn't go over the 15Mb limit. * increased after observing a bug in the Windows NT 4.0 SP6a * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ if(prs_offset(&p->in_data.data) + data_len > MAX_RPC_DATA_SIZE) { DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); set_incoming_fault(p); return False; } /* * Append the data portion into the buffer and return. */ if(!prs_append_some_prs_data(&p->in_data.data, rpc_in_p, prs_offset(rpc_in_p), data_len)) { DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n", (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) )); set_incoming_fault(p); return False; } if(p->hdr.flags & RPC_FLG_LAST) { bool ret = False; /* * Ok - we finally have a complete RPC stream. * Call the rpc command to process it. */ /* * Ensure the internal prs buffer size is *exactly* the same * size as the current offset. */ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) { DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n")); set_incoming_fault(p); return False; } /* * Set the parse offset to the start of the data and set the * prs_struct to UNMARSHALL. */ prs_set_offset(&p->in_data.data, 0); prs_switch_type(&p->in_data.data, UNMARSHALL); /* * Process the complete data stream here. */ free_pipe_context(p); if(pipe_init_outgoing_data(p)) { ret = api_pipe_request(p); } free_pipe_context(p); /* * We have consumed the whole data stream. Set back to * marshalling and set the offset back to the start of * the buffer to re-use it (we could also do a prs_mem_free() * and then re_init on the next start of PDU. Not sure which * is best here.... JRA. */ prs_switch_type(&p->in_data.data, MARSHALL); prs_set_offset(&p->in_data.data, 0); return ret; } return True; }
static ssize_t unmarshall_rpc_header(pipes_struct *p) { /* * Unmarshall the header to determine the needed length. */ prs_struct rpc_in; if(p->in_data.pdu_received_len != RPC_HEADER_LEN) { DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n")); set_incoming_fault(p); return -1; } prs_init_empty( &rpc_in, p->mem_ctx, UNMARSHALL); prs_set_endian_data( &rpc_in, p->endian); prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0], p->in_data.pdu_received_len, False); /* * Unmarshall the header as this will tell us how much * data we need to read to get the complete pdu. * This also sets the endian flag in rpc_in. */ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * Validate the RPC header. */ if(p->hdr.major != 5 && p->hdr.minor != 0) { DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * If there's not data in the incoming buffer this should be the start of a new RPC. */ if(prs_offset(&p->in_data.data) == 0) { /* * AS/U doesn't set FIRST flag in a BIND packet it seems. */ if ((p->hdr.pkt_type == RPC_REQUEST) && !(p->hdr.flags & RPC_FLG_FIRST)) { /* * Ensure that the FIRST flag is set. If not then we have * a stream missmatch. */ DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } /* * If this is the first PDU then set the endianness * flag in the pipe. We will need this when parsing all * data in this RPC. */ p->endian = rpc_in.bigendian_data; DEBUG(5,("unmarshall_rpc_header: using %sendian RPC\n", p->endian == RPC_LITTLE_ENDIAN ? "little-" : "big-" )); } else { /* * If this is *NOT* the first PDU then check the endianness * flag in the pipe is the same as that in the PDU. */ if (p->endian != rpc_in.bigendian_data) { DEBUG(0,("unmarshall_rpc_header: FIRST endianness flag (%d) different in next PDU !\n", (int)p->endian)); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } } /* * Ensure that the pdu length is sane. */ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > RPC_MAX_PDU_FRAG_LEN)) { DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n")); set_incoming_fault(p); prs_mem_free(&rpc_in); return -1; } DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type, (unsigned int)p->hdr.flags )); p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN; prs_mem_free(&rpc_in); p->in_data.current_in_pdu = TALLOC_REALLOC_ARRAY( p, p->in_data.current_in_pdu, uint8_t, p->hdr.frag_len); if (p->in_data.current_in_pdu == NULL) { DEBUG(0, ("talloc failed\n")); set_incoming_fault(p); return -1; } return 0; /* No extra data processed. */ }
static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out, uint32 rpc_call_id, RPC_IFACE *abstract, RPC_IFACE *transfer, const char *my_name, const char *domain) { RPC_HDR hdr; RPC_HDR_RB hdr_rb; RPC_HDR_AUTH hdr_auth; int auth_len = 0; int auth_type, auth_level; size_t saved_hdr_offset = 0; prs_struct auth_info; prs_init(&auth_info, RPC_HDR_AUTH_LEN, /* we will need at least this much */ prs_get_mem_context(rpc_out), MARSHALL); if (cli->pipe_auth_flags) { get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); /* * Create the auth structs we will marshall. */ init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level, 0x00, 1); /* * Now marshall the data into the temporary parse_struct. */ if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } saved_hdr_offset = prs_offset(&auth_info); } if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { NTSTATUS nt_status; DATA_BLOB null_blob = data_blob(NULL, 0); DATA_BLOB request; DEBUG(5, ("Processing NTLMSSP Negotiate\n")); nt_status = ntlmssp_update(cli->ntlmssp_pipe_state, null_blob, &request); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { prs_mem_free(&auth_info); return nt_status; } /* Auth len in the rpc header doesn't include auth_header. */ auth_len = request.length; prs_copy_data_in(&auth_info, (char *)request.data, request.length); DEBUG(5, ("NTLMSSP Negotiate:\n")); dump_data(5, (const char *)request.data, request.length); data_blob_free(&request); } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { RPC_AUTH_NETSEC_NEG netsec_neg; /* Use lp_workgroup() if domain not specified */ if (!domain || !domain[0]) { DEBUG(10,("create_rpc_bind_req: no domain; assuming my own\n")); domain = lp_workgroup(); } init_rpc_auth_netsec_neg(&netsec_neg, domain, my_name); /* * Now marshall the data into the temporary parse_struct. */ if(!smb_io_rpc_auth_netsec_neg("netsec_neg", &netsec_neg, &auth_info, 0)) { DEBUG(0,("Failed to marshall RPC_AUTH_NETSEC_NEG.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* Auth len in the rpc header doesn't include auth_header. */ auth_len = prs_offset(&auth_info) - saved_hdr_offset; } /* Create the request RPC_HDR */ init_rpc_hdr(&hdr, RPC_BIND, 0x3, rpc_call_id, RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info), auth_len); if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* create the bind request RPC_HDR_RB */ init_rpc_hdr_rb(&hdr_rb, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN, 0x0, 0x1, 0x0, 0x1, abstract, transfer); /* Marshall the bind request data */ if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) { DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } /* * Grow the outgoing buffer to store any auth info. */ if(auth_len != 0) { if(!prs_append_prs_data( rpc_out, &auth_info)) { DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n")); prs_mem_free(&auth_info); return NT_STATUS_NO_MEMORY; } } prs_mem_free(&auth_info); return NT_STATUS_OK; }
BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num, prs_struct *data, prs_struct *rdata) { uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent; NTSTATUS nt_status; BOOL ret = False; uint32 callid = 0; fstring dump_name; auth_len = 0; real_auth_len = 0; auth_hdr_len = 0; if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; } if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { auth_len = RPC_AUTH_NETSEC_CHK_LEN; } auth_hdr_len = RPC_HDR_AUTH_LEN; } /* * calc how much actual data we can send in a PDU fragment */ max_data = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - auth_hdr_len - auth_len - 8; for (data_left = prs_offset(data), data_sent = 0; data_left > 0;) { prs_struct outgoing_packet; prs_struct sec_blob; uint32 data_len, send_size; uint8 flags = 0; uint32 auth_padding = 0; DATA_BLOB sign_blob; /* * how much will we send this time */ send_size = MIN(data_left, max_data); if (!prs_init(&sec_blob, send_size, /* will need at least this much */ cli->mem_ctx, MARSHALL)) { DEBUG(0,("Could not malloc %u bytes", send_size+auth_padding)); return False; } if(!prs_append_some_prs_data(&sec_blob, data, data_sent, send_size)) { DEBUG(0,("Failed to append data to netsec blob\n")); prs_mem_free(&sec_blob); return False; } /* * NT expects the data that is sealed to be 8-byte * aligned. The padding must be encrypted as well and * taken into account when generating the * authentication verifier. The amount of padding must * be stored in the auth header. */ if (cli->pipe_auth_flags) { size_t data_and_padding_size; int auth_type; int auth_level; prs_align_uint64(&sec_blob); get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level); data_and_padding_size = prs_offset(&sec_blob); auth_padding = data_and_padding_size - send_size; /* insert the auth header */ if(!create_auth_hdr(&sec_blob, auth_type, auth_level, auth_padding)) { prs_mem_free(&sec_blob); return False; } /* create an NTLMSSP signature */ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) { /* * Seal the outgoing data if requested. */ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) { nt_status = ntlmssp_seal_packet(cli->ntlmssp_pipe_state, (unsigned char*)prs_data_p(&sec_blob), data_and_padding_size, &sign_blob); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&sec_blob); return False; } } else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) { nt_status = ntlmssp_sign_packet(cli->ntlmssp_pipe_state, (unsigned char*)prs_data_p(&sec_blob), data_and_padding_size, &sign_blob); if (!NT_STATUS_IS_OK(nt_status)) { prs_mem_free(&sec_blob); return False; } } /* write auth footer onto the packet */ real_auth_len = sign_blob.length; prs_copy_data_in(&sec_blob, (char *)sign_blob.data, sign_blob.length); data_blob_free(&sign_blob); } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) { size_t parse_offset_marker; RPC_AUTH_NETSEC_CHK verf; DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num)); netsec_encode(&cli->auth_info, cli->pipe_auth_flags, SENDER_IS_INITIATOR, &verf, prs_data_p(&sec_blob), data_and_padding_size); cli->auth_info.seq_num++; /* write auth footer onto the packet */ parse_offset_marker = prs_offset(&sec_blob); if (!smb_io_rpc_auth_netsec_chk("", &verf, &sec_blob, 0)) { prs_mem_free(&sec_blob); return False; } real_auth_len = prs_offset(&sec_blob) - parse_offset_marker; } } data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(&sec_blob); /* * Malloc parse struct to hold it (and enough for alignments). */ if(!prs_init(&outgoing_packet, data_len + 8, cli->mem_ctx, MARSHALL)) { DEBUG(0,("rpc_api_pipe_req: Failed to malloc %u bytes.\n", (unsigned int)data_len )); return False; } if (data_left == prs_offset(data)) flags |= RPC_FLG_FIRST; if (data_left <= max_data) flags |= RPC_FLG_LAST; /* * Write out the RPC header and the request header. */ if(!(callid = create_rpc_request(&outgoing_packet, op_num, data_len, real_auth_len, flags, callid, data_left))) { DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n")); prs_mem_free(&outgoing_packet); prs_mem_free(&sec_blob); return False; } prs_append_prs_data(&outgoing_packet, &sec_blob); prs_mem_free(&sec_blob); DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len, prs_offset(&outgoing_packet))); if (flags & RPC_FLG_LAST) ret = rpc_api_pipe(cli, &outgoing_packet, rdata, RPC_RESPONSE); else { cli_write(cli, cli->nt_pipe_fnum, 0x0008, prs_data_p(&outgoing_packet), data_sent, data_len); } prs_mem_free(&outgoing_packet); data_sent += send_size; data_left -= send_size; } /* Also capture received data */ slprintf(dump_name, sizeof(dump_name) - 1, "reply_%s", cli_pipe_get_name(cli)); prs_dump(dump_name, op_num, rdata); return ret; }
static ssize_t unmarshall_rpc_header(pipes_struct *p) { /* * Unmarshall the header to determine the needed length. */ prs_struct rpc_in; if(p->in_data.pdu_received_len != RPC_HEADER_LEN) { DEBUG(0,("unmarshall_rpc_header: assert on rpc header length failed.\n")); set_incoming_fault(p); return -1; } prs_init( &rpc_in, 0, 4, UNMARSHALL); prs_give_memory( &rpc_in, (char *)&p->in_data.current_in_pdu[0], p->in_data.pdu_received_len, False); /* * Unmarshall the header as this will tell us how much * data we need to read to get the complete pdu. */ if(!smb_io_rpc_hdr("", &p->hdr, &rpc_in, 0)) { DEBUG(0,("unmarshall_rpc_header: failed to unmarshall RPC_HDR.\n")); set_incoming_fault(p); return -1; } /* * Validate the RPC header. */ if(p->hdr.major != 5 && p->hdr.minor != 0) { DEBUG(0,("unmarshall_rpc_header: invalid major/minor numbers in RPC_HDR.\n")); set_incoming_fault(p); return -1; } /* * If there is no data in the incoming buffer and it's a requst pdu then * ensure that the FIRST flag is set. If not then we have * a stream missmatch. */ if((p->hdr.pkt_type == RPC_REQUEST) && (prs_offset(&p->in_data.data) == 0) && !(p->hdr.flags & RPC_FLG_FIRST)) { DEBUG(0,("unmarshall_rpc_header: FIRST flag not set in first PDU !\n")); set_incoming_fault(p); return -1; } /* * Ensure that the pdu length is sane. */ if((p->hdr.frag_len < RPC_HEADER_LEN) || (p->hdr.frag_len > MAX_PDU_FRAG_LEN)) { DEBUG(0,("unmarshall_rpc_header: assert on frag length failed.\n")); set_incoming_fault(p); return -1; } DEBUG(10,("unmarshall_rpc_header: type = %u, flags = %u\n", (unsigned int)p->hdr.pkt_type, (unsigned int)p->hdr.flags )); /* * Adjust for the header we just ate. */ p->in_data.pdu_received_len = 0; p->in_data.pdu_needed_len = (uint32)p->hdr.frag_len - RPC_HEADER_LEN; /* * Null the data we just ate. */ memset((char *)&p->in_data.current_in_pdu[0], '\0', RPC_HEADER_LEN); return 0; /* No extra data processed. */ }
BOOL create_next_pdu(pipes_struct *p) { RPC_HDR_RESP hdr_resp; BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0); BOOL auth_seal = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SEAL) != 0); uint32 ss_padding_len = 0; uint32 data_len; uint32 data_space_available; uint32 data_len_left; prs_struct outgoing_pdu; uint32 data_pos; /* * If we're in the fault state, keep returning fault PDU's until * the pipe gets closed. JRA. */ if(p->fault_state) { setup_fault_pdu(p, NT_STATUS(0x1c010002)); return True; } memset((char *)&hdr_resp, '\0', sizeof(hdr_resp)); /* Change the incoming request header to a response. */ p->hdr.pkt_type = RPC_RESPONSE; /* Set up rpc header flags. */ if (p->out_data.data_sent_length == 0) { p->hdr.flags = RPC_FLG_FIRST; } else { p->hdr.flags = 0; } /* * Work out how much we can fit in a single PDU. */ data_space_available = sizeof(p->out_data.current_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; if(p->ntlmssp_auth_validated) { data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN); } else if(p->netsec_auth_validated) { data_space_available -= (RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN); } /* * The amount we send is the minimum of the available * space and the amount left to send. */ data_len_left = prs_offset(&p->out_data.rdata) - p->out_data.data_sent_length; /* * Ensure there really is data left to send. */ if(!data_len_left) { DEBUG(0,("create_next_pdu: no data left to send !\n")); return False; } data_len = MIN(data_len_left, data_space_available); /* * Set up the alloc hint. This should be the data left to * send. */ hdr_resp.alloc_hint = data_len_left; /* * Work out if this PDU will be the last. */ if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) { p->hdr.flags |= RPC_FLG_LAST; if ((auth_seal || auth_verify) && (data_len_left % 8)) { ss_padding_len = 8 - (data_len_left % 8); DEBUG(10,("create_next_pdu: adding sign/seal padding of %u\n", ss_padding_len )); } } /* * Set up the header lengths. */ if (p->ntlmssp_auth_validated) { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len + RPC_HDR_AUTH_LEN + RPC_AUTH_NTLMSSP_CHK_LEN; p->hdr.auth_len = RPC_AUTH_NTLMSSP_CHK_LEN; } else if (p->netsec_auth_validated) { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len + RPC_HDR_AUTH_LEN + RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN; p->hdr.auth_len = RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN; } else { p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len; p->hdr.auth_len = 0; } /* * Init the parse struct to point at the outgoing * data. */ prs_init( &outgoing_pdu, 0, p->mem_ctx, MARSHALL); prs_give_memory( &outgoing_pdu, (char *)p->out_data.current_pdu, sizeof(p->out_data.current_pdu), False); /* Store the header in the data stream. */ if(!smb_io_rpc_hdr("hdr", &p->hdr, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR.\n")); prs_mem_free(&outgoing_pdu); return False; } if(!smb_io_rpc_hdr_resp("resp", &hdr_resp, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_RESP.\n")); prs_mem_free(&outgoing_pdu); return False; } /* Store the current offset. */ data_pos = prs_offset(&outgoing_pdu); /* Copy the data into the PDU. */ if(!prs_append_some_prs_data(&outgoing_pdu, &p->out_data.rdata, p->out_data.data_sent_length, data_len)) { DEBUG(0,("create_next_pdu: failed to copy %u bytes of data.\n", (unsigned int)data_len)); prs_mem_free(&outgoing_pdu); return False; } /* Copy the sign/seal padding data. */ if (ss_padding_len) { char pad[8]; memset(pad, '\0', 8); if (!prs_copy_data_in(&outgoing_pdu, pad, ss_padding_len)) { DEBUG(0,("create_next_pdu: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len)); prs_mem_free(&outgoing_pdu); return False; } } if (p->ntlmssp_auth_validated) { /* * NTLMSSP processing. Mutually exclusive with Schannel. */ uint32 crc32 = 0; char *data; DEBUG(5,("create_next_pdu: sign: %s seal: %s data %d auth %d\n", BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len + ss_padding_len, p->hdr.auth_len)); /* * Set data to point to where we copied the data into. */ data = prs_data_p(&outgoing_pdu) + data_pos; if (auth_seal) { crc32 = crc32_calc_buffer(data, data_len + ss_padding_len); NTLMSSPcalc_p(p, (uchar*)data, data_len + ss_padding_len); } if (auth_seal || auth_verify) { RPC_HDR_AUTH auth_info; init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, auth_seal ? RPC_PIPE_AUTH_SEAL_LEVEL : RPC_PIPE_AUTH_SIGN_LEVEL, (auth_verify ? ss_padding_len : 0), (auth_verify ? 1 : 0)); if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&outgoing_pdu); return False; } } if (auth_verify) { RPC_AUTH_NTLMSSP_CHK ntlmssp_chk; char *auth_data = prs_data_p(&outgoing_pdu); p->ntlmssp_seq_num++; init_rpc_auth_ntlmssp_chk(&ntlmssp_chk, NTLMSSP_SIGN_VERSION, crc32, p->ntlmssp_seq_num++); auth_data = prs_data_p(&outgoing_pdu) + prs_offset(&outgoing_pdu) + 4; if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &ntlmssp_chk, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_AUTH_NTLMSSP_CHK.\n")); prs_mem_free(&outgoing_pdu); return False; } NTLMSSPcalc_p(p, (uchar*)auth_data, RPC_AUTH_NTLMSSP_CHK_LEN - 4); } } else if (p->netsec_auth_validated) { /* * Schannel processing. Mutually exclusive with NTLMSSP. */ int auth_type, auth_level; char *data; RPC_HDR_AUTH auth_info; RPC_AUTH_NETSEC_CHK verf; prs_struct rverf; prs_struct rauth; data = prs_data_p(&outgoing_pdu) + data_pos; /* Check it's the type of reply we were expecting to decode */ get_auth_type_level(p->netsec_auth.auth_flags, &auth_type, &auth_level); init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1); if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) { DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n")); prs_mem_free(&outgoing_pdu); return False; } prs_init(&rverf, 0, p->mem_ctx, MARSHALL); prs_init(&rauth, 0, p->mem_ctx, MARSHALL); netsec_encode(&p->netsec_auth, p->netsec_auth.auth_flags, SENDER_IS_ACCEPTOR, &verf, data, data_len + ss_padding_len); smb_io_rpc_auth_netsec_chk("", RPC_AUTH_NETSEC_SIGN_OR_SEAL_CHK_LEN, &verf, &outgoing_pdu, 0); p->netsec_auth.seq_num++; } /* * Setup the counts for this PDU. */ p->out_data.data_sent_length += data_len; p->out_data.current_pdu_len = p->hdr.frag_len; p->out_data.current_pdu_sent = 0; prs_mem_free(&outgoing_pdu); 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; }
static BOOL process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) { BOOL auth_verify = ((p->ntlmssp_chal_flags & NTLMSSP_NEGOTIATE_SIGN) != 0); size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - (auth_verify ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; if(!p->pipe_bound) { DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); set_incoming_fault(p); return False; } /* * Check if we need to do authentication processing. * This is only done on requests, not binds. */ /* * Read the RPC request header. */ if(!smb_io_rpc_hdr_req("req", &p->hdr_req, rpc_in_p, 0)) { DEBUG(0,("process_request_pdu: failed to unmarshall RPC_HDR_REQ.\n")); set_incoming_fault(p); return False; } if(p->ntlmssp_auth_validated && !api_pipe_auth_process(p, rpc_in_p)) { DEBUG(0,("process_request_pdu: failed to do auth processing.\n")); set_incoming_fault(p); return False; } if (p->ntlmssp_auth_requested && !p->ntlmssp_auth_validated) { /* * Authentication _was_ requested and it already failed. */ DEBUG(0,("process_request_pdu: RPC request received on pipe %s " "where authentication failed. Denying the request.\n", p->name)); set_incoming_fault(p); return False; } if (p->netsec_auth_validated && !api_pipe_netsec_process(p, rpc_in_p)) { DEBUG(3,("process_request_pdu: failed to do schannel processing.\n")); set_incoming_fault(p); return False; } /* * Check the data length doesn't go over the 15Mb limit. * increased after observing a bug in the Windows NT 4.0 SP6a * spoolsv.exe when the response to a GETPRINTERDRIVER2 RPC * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ if(prs_offset(&p->in_data.data) + data_len > 15*1024*1024) { DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); set_incoming_fault(p); return False; } /* * Append the data portion into the buffer and return. */ if(!prs_append_some_prs_data(&p->in_data.data, rpc_in_p, prs_offset(rpc_in_p), data_len)) { DEBUG(0,("process_request_pdu: Unable to append data size %u to parse buffer of size %u.\n", (unsigned int)data_len, (unsigned int)prs_data_size(&p->in_data.data) )); set_incoming_fault(p); return False; } if(p->hdr.flags & RPC_FLG_LAST) { BOOL ret = False; /* * Ok - we finally have a complete RPC stream. * Call the rpc command to process it. */ /* * Ensure the internal prs buffer size is *exactly* the same * size as the current offset. */ if(!prs_set_buffer_size(&p->in_data.data, prs_offset(&p->in_data.data))) { DEBUG(0,("process_request_pdu: Call to prs_set_buffer_size failed!\n")); set_incoming_fault(p); return False; } /* * Set the parse offset to the start of the data and set the * prs_struct to UNMARSHALL. */ prs_set_offset(&p->in_data.data, 0); prs_switch_type(&p->in_data.data, UNMARSHALL); /* * Process the complete data stream here. */ free_pipe_context(p); if(pipe_init_outgoing_data(p)) ret = api_pipe_request(p); free_pipe_context(p); /* * We have consumed the whole data stream. Set back to * marshalling and set the offset back to the start of * the buffer to re-use it (we could also do a prs_mem_free() * and then re_init on the next start of PDU. Not sure which * is best here.... JRA. */ prs_switch_type(&p->in_data.data, MARSHALL); prs_set_offset(&p->in_data.data, 0); return ret; } return True; }