NTSTATUS ndr_pull_charset(struct ndr_pull *ndr, int ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset) { int ret; if (length == 0) { *var = talloc_strdup(ndr->current_mem_ctx, ""); return NT_STATUS_OK; } if (NDR_BE(ndr) && chset == CH_UTF16) { chset = CH_UTF16BE; } NDR_PULL_NEED_BYTES(ndr, length*byte_mul); ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, length*byte_mul, var, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul)); return NT_STATUS_OK; }
/* parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth */ enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) { enum ndr_err_code status; struct ndr_pull *subndr; if (!(ndr_flags & NDR_SCALARS)) { return NDR_ERR_SUCCESS; } subndr = talloc_zero(ndr, struct ndr_pull); NDR_ERR_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags; subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->data_size = 28; subndr->offset = 0; NDR_CHECK(ndr_pull_advance(ndr, 28)); status = ndr_pull_dom_sid(subndr, ndr_flags, sid); if (!NDR_ERR_CODE_IS_SUCCESS(status)) { /* handle a w2k bug which send random data in the buffer */ ZERO_STRUCTP(sid); } else if (sid->num_auths == 0 && sid->sub_auths) { ZERO_STRUCT(sid->sub_auths); } return NDR_ERR_SUCCESS; }
/* parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only upto 5 sub_auth */ NTSTATUS ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid *sid) { NTSTATUS status; struct ndr_pull *subndr; if (!(ndr_flags & NDR_SCALARS)) { return NT_STATUS_OK; } subndr = talloc_zero(ndr, struct ndr_pull); NT_STATUS_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags; subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->data_size = 28; subndr->offset = 0; NDR_CHECK(ndr_pull_advance(ndr, 28)); status = ndr_pull_dom_sid(subndr, ndr_flags, sid); if (!NT_STATUS_IS_OK(status)) { /* handle a w2k bug which send random data in the buffer */ ZERO_STRUCTP(sid); } return NT_STATUS_OK; }
_PUBLIC_ enum ndr_err_code ndr_pull_dcerpc_sec_vt_count(struct ndr_pull *ndr, int ndr_flags, struct dcerpc_sec_vt_count *r) { uint32_t _saved_ofs = ndr->offset; NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); if (!(ndr_flags & NDR_SCALARS)) { return NDR_ERR_SUCCESS; } r->count = 0; while (true) { uint16_t command; uint16_t length; NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &command)); NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &length)); NDR_CHECK(ndr_pull_advance(ndr, length)); r->count += 1; if (command & DCERPC_SEC_VT_COMMAND_END) { break; } } ndr->offset = _saved_ofs; return NDR_ERR_SUCCESS; }
_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr, struct ndr_pull *subndr, size_t header_size, ssize_t size_is) { uint32_t advance; if (size_is >= 0) { advance = size_is; } else if (header_size > 0) { advance = subndr->data_size; } else { advance = subndr->offset; } NDR_CHECK(ndr_pull_advance(ndr, advance)); return NDR_ERR_SUCCESS; }
_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v3(struct ndr_pull *ndr, int ndr_flags, struct bkrp_access_check_v3 *r) { if (ndr_flags & NDR_SCALARS) { size_t ofs; size_t pad; NDR_CHECK(ndr_pull_align(ndr, 4)); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic)); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonce_len)); NDR_PULL_ALLOC_N(ndr, r->nonce, r->nonce_len); NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len)); NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->sid)); ofs = ndr->offset + 64; pad = ndr_align_size(ofs, 16); NDR_CHECK(ndr_pull_advance(ndr, pad)); NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 64)); NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); } if (ndr_flags & NDR_BUFFERS) { } return NDR_ERR_SUCCESS; }
NTSTATUS ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) { uint32_t i; struct ndr_pull_save save_offset; ndr_pull_save(ndr, &save_offset); ndr_pull_advance(ndr, (count - 1) * element_size); NDR_PULL_NEED_BYTES(ndr, element_size); for (i = 0; i < element_size; i++) { if (ndr->data[ndr->offset+i] != 0) { ndr_pull_restore(ndr, &save_offset); return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries"); } } ndr_pull_restore(ndr, &save_offset); return NT_STATUS_OK; }
/** * @brief Pull a dcerpc_auth structure, taking account of any auth * padding in the blob. For request/response packets we pass * the whole data blob, so auth_data_only must be set to false * as the blob contains data+pad+auth and no just pad+auth. * * @param pkt - The ncacn_packet strcuture * @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements * @param pkt_trailer - The packet trailer data, usually the trailing * auth_info blob, but in the request/response case * this is the stub_and_verifier blob. * @param auth - A preallocated dcerpc_auth *empty* structure * @param auth_length - The length of the auth trail, sum of auth header * lenght and pkt->auth_length * @param auth_data_only - Whether the pkt_trailer includes only the auth_blob * (+ padding) or also other data. * * @return - A NTSTATUS error code. */ NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, TALLOC_CTX *mem_ctx, DATA_BLOB *pkt_trailer, struct dcerpc_auth *auth, uint32_t *auth_length, bool auth_data_only) { struct ndr_pull *ndr; enum ndr_err_code ndr_err; uint32_t data_and_pad; data_and_pad = pkt_trailer->length - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length); /* paranoia check for pad size. This would be caught anyway by the ndr_pull_advance() a few lines down, but it scared Jeremy enough for him to call me, so we might as well check it now, just to prevent someone posting a bogus YouTube video in the future. */ if (data_and_pad > pkt_trailer->length) { return NT_STATUS_INFO_LENGTH_MISMATCH; } *auth_length = pkt_trailer->length - data_and_pad; ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx); if (!ndr) { return NT_STATUS_NO_MEMORY; } if (!(pkt->drep[0] & DCERPC_DREP_LE)) { ndr->flags |= LIBNDR_FLAG_BIGENDIAN; } ndr_err = ndr_pull_advance(ndr, data_and_pad); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(ndr); return ndr_map_error2ntstatus(ndr_err); } ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(ndr); return ndr_map_error2ntstatus(ndr_err); } if (auth_data_only && data_and_pad != auth->auth_pad_length) { DEBUG(1, (__location__ ": WARNING: pad length mismatch. " "Calculated %u got %u\n", (unsigned)data_and_pad, (unsigned)auth->auth_pad_length)); } DEBUG(6,(__location__ ": auth_pad_length %u\n", (unsigned)auth->auth_pad_length)); talloc_steal(mem_ctx, auth->credentials.data); talloc_free(ndr); return NT_STATUS_OK; }
/** pull a general string from the wire */ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) { char *as=NULL; uint32_t len1, ofs, len2; uint16_t len3; int ret; charset_t chset = CH_UTF16LE; unsigned byte_mul = 2; unsigned flags = ndr->flags; unsigned c_len_term = 0; if (!(ndr_flags & NDR_SCALARS)) { return NT_STATUS_OK; } if (NDR_BE(ndr)) { chset = CH_UTF16BE; } if (flags & LIBNDR_FLAG_STR_ASCII) { chset = CH_DOS; byte_mul = 1; flags &= ~LIBNDR_FLAG_STR_ASCII; } if (flags & LIBNDR_FLAG_STR_UTF8) { chset = CH_UTF8; byte_mul = 1; flags &= ~LIBNDR_FLAG_STR_UTF8; } flags &= ~LIBNDR_FLAG_STR_CONFORMANT; if (flags & LIBNDR_FLAG_STR_CHARLEN) { c_len_term = 1; flags &= ~LIBNDR_FLAG_STR_CHARLEN; } switch (flags & LIBNDR_STRING_FLAGS) { case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4: case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); if (ofs != 0) { return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); } NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2)); if (len2 > len1) { return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string lengths len1=%u ofs=%u len2=%u\n", len1, ofs, len2); } NDR_PULL_NEED_BYTES(ndr, (len2 + c_len_term)*byte_mul); if (len2 == 0) { as = talloc_strdup(ndr->current_mem_ctx, ""); } else { ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, (len2 + c_len_term)*byte_mul, &as, True); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } } NDR_CHECK(ndr_pull_advance(ndr, (len2 + c_len_term)*byte_mul)); if (len1 != len2) { DEBUG(6,("len1[%u] != len2[%u] '%s'\n", len1, len2, as)); } /* this is a way of detecting if a string is sent with the wrong termination */ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { if (strlen(as) < (len2 + c_len_term)) { DEBUG(6,("short string '%s'\n", as)); } } else { if (strlen(as) == (len2 + c_len_term)) { DEBUG(6,("long string '%s'\n", as)); } } *s = as; break; case LIBNDR_FLAG_STR_SIZE4: case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM: NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); if (len1 == 0) { as = talloc_strdup(ndr->current_mem_ctx, ""); } else { ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, (len1 + c_len_term)*byte_mul, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } } NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); /* this is a way of detecting if a string is sent with the wrong termination */ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { if (strlen(as) < (len1 + c_len_term)) { DEBUG(6,("short string '%s'\n", as)); } } else { if (strlen(as) == (len1 + c_len_term)) { DEBUG(6,("long string '%s'\n", as)); } } *s = as; break; case LIBNDR_FLAG_STR_LEN4: case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM: NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs)); if (ofs != 0) { return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); } NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1)); NDR_PULL_NEED_BYTES(ndr, (len1 + c_len_term)*byte_mul); if (len1 == 0) { as = talloc_strdup(ndr->current_mem_ctx, ""); } else { ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, (len1 + c_len_term)*byte_mul, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } } NDR_CHECK(ndr_pull_advance(ndr, (len1 + c_len_term)*byte_mul)); /* this is a way of detecting if a string is sent with the wrong termination */ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { if (strlen(as) < (len1 + c_len_term)) { DEBUG(6,("short string '%s'\n", as)); } } else { if (strlen(as) == (len1 + c_len_term)) { DEBUG(6,("long string '%s'\n", as)); } } *s = as; break; case LIBNDR_FLAG_STR_SIZE2: case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM: NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); NDR_PULL_NEED_BYTES(ndr, (len3 + c_len_term)*byte_mul); if (len3 == 0) { as = talloc_strdup(ndr->current_mem_ctx, ""); } else { ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, (len3 + c_len_term)*byte_mul, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } } NDR_CHECK(ndr_pull_advance(ndr, (len3 + c_len_term)*byte_mul)); /* this is a way of detecting if a string is sent with the wrong termination */ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) { if (strlen(as) < (len3 + c_len_term)) { DEBUG(6,("short string '%s'\n", as)); } } else { if (strlen(as) == (len3 + c_len_term)) { DEBUG(6,("long string '%s'\n", as)); } } *s = as; break; case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE: NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3)); NDR_PULL_NEED_BYTES(ndr, len3); if (len3 == 0) { as = talloc_strdup(ndr->current_mem_ctx, ""); } else { ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, len3, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } } NDR_CHECK(ndr_pull_advance(ndr, len3)); *s = as; break; case LIBNDR_FLAG_STR_NULLTERM: if (byte_mul == 1) { len1 = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset); } else { len1 = utf16_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset); } ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, len1, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } NDR_CHECK(ndr_pull_advance(ndr, len1)); *s = as; break; case LIBNDR_FLAG_STR_FIXLEN15: case LIBNDR_FLAG_STR_FIXLEN32: len1 = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15; NDR_PULL_NEED_BYTES(ndr, len1*byte_mul); ret = convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, len1*byte_mul, &as, False); if (ret == -1) { return ndr_pull_error(ndr, NDR_ERR_CHARCNV, "Bad character conversion"); } NDR_CHECK(ndr_pull_advance(ndr, len1*byte_mul)); *s = as; break; default: return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); } return NT_STATUS_OK; }