1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00
samba-mirror/librpc/ndr/ndr_cab.c
Jeremy Allison 446851c861 librpc: cab: Fix ndr_size_cab_file() to detect integer wrap.
Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>

Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Dec  1 05:53:43 CET 2016 on sn-devel-144
2016-12-01 05:53:43 +01:00

274 lines
7.5 KiB
C

/*
Unix SMB/CIFS implementation.
routines for marshalling/unmarshalling cab structures
Copyright (C) Guenther Deschner 2016
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "librpc/gen_ndr/ndr_cab.h"
_PUBLIC_ void ndr_print_cf_time(struct ndr_print *ndr, const char *name, const struct cf_time *r)
{
uint8_t hour = 0, minute = 0, seconds = 0;
char *s;
if (r == NULL) { ndr_print_null(ndr); return; }
hour = r->time >> 11;
minute = (r->time >> 5) & 0x3f;
seconds = (r->time << 1) & 0x3e;
s = talloc_asprintf(ndr, "%02d:%02d:%02d", hour, minute, seconds);
if (s == NULL) { return; }
ndr_print_string(ndr, "time", s);
talloc_free(s);
}
_PUBLIC_ void ndr_print_cf_date(struct ndr_print *ndr, const char *name, const struct cf_date *r)
{
uint16_t year = 0;
uint8_t month = 0, day = 0;
char *s;
if (r == NULL) { ndr_print_null(ndr); return; }
year = (r->date >> 9);
year += 1980;
month = (r->date >> 5 & 0xf);
day = (r->date & 0x1f);
s = talloc_asprintf(ndr, "%02d/%02d/%04d", day, month, year);
if (s == NULL) { return; }
ndr_print_string(ndr, "date", s);
talloc_free(s);
}
uint32_t ndr_count_cfdata(const struct cab_file *r)
{
uint32_t count = 0, i;
for (i = 0; i < r->cfheader.cFolders; i++) {
if (count + r->cffolders[i].cCFData < count) {
/* Integer wrap. */
return 0;
}
count += r->cffolders[i].cCFData;
}
return count;
}
static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed)
{
int num_ulong;
uint32_t checksum;
uint8_t *pb;
uint32_t ul;
num_ulong = length / 4;
checksum = seed;
pb = data;
while (num_ulong-- > 0) {
ul = *pb++;
ul |= (((uint32_t)(*pb++)) << 8);
ul |= (((uint32_t)(*pb++)) << 16);
ul |= (((uint32_t)(*pb++)) << 24);
checksum ^= ul;
}
ul = 0;
switch (length % 4) {
case 3:
ul |= (((uint32_t)(*pb++)) << 16);
case 2:
ul |= (((uint32_t)(*pb++)) << 8);
case 1:
ul |= *pb++;
default:
break;
}
checksum ^= ul;
return checksum;
}
uint32_t ndr_cab_generate_checksum(const struct CFDATA *r)
{
uint32_t csumPartial;
csumPartial = ndr_cab_compute_checksum(&r->ab[0], r->cbData, 0);
return ndr_cab_compute_checksum((uint8_t *)discard_const(&r->cbData),
sizeof(r->cbData) + sizeof(r->cbUncomp),
csumPartial);
}
static bool ndr_size_cab_file(const struct cab_file *r, uint32_t *psize)
{
uint32_t size = 0;
int i;
/* header */
size += 36;
/* folder */
for (i = 0; i < r->cfheader.cFolders; i++) {
if (size + 8 < size) {
/* Integer wrap. */
return false;
}
size += 8;
}
/* files */
for (i = 0; i < r->cfheader.cFiles; i++) {
uint32_t cfsize = ndr_size_CFFILE(&r->cffiles[i], 0);
if (size + cfsize < size) {
/* Integer wrap. */
return false;
}
size += cfsize;
}
/* data */
for (i = 0; i < ndr_count_cfdata(r); i++) {
if (size + 8 < size) {
/* Integer wrap. */
return false;
}
size += 8;
if (size + r->cfdata[i].cbData < size) {
/* Integer wrap. */
return false;
}
size += r->cfdata[i].cbData;
}
*psize = size;
return true;
}
enum cf_compress_type ndr_cab_get_compression(const struct cab_file *r)
{
if (r->cfheader.cFolders == 0) {
return CF_COMPRESS_NONE;
}
return r->cffolders[0].typeCompress;
}
_PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags, const struct cab_file *r)
{
uint32_t cntr_cffolders_0;
uint32_t cntr_cffiles_0;
uint32_t cntr_cfdata_0;
uint32_t cab_size = 0;
{
uint32_t _flags_save_STRUCT = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
if (ndr_flags & NDR_SCALARS) {
uint32_t next_offset = 0;
NDR_CHECK(ndr_push_align(ndr, 4));
NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) {
NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
}
for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) {
uint32_t offset = ndr->offset + 4;
NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
if (cntr_cffiles_0 > 0) {
next_offset += r->cffiles[cntr_cffiles_0 - 1].cbFile;
}
SIVAL(ndr->data, offset, next_offset);
}
#if 0
NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r)));
#endif
for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (ndr_count_cfdata(r)); cntr_cfdata_0++) {
NDR_CHECK(ndr_push_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
}
NDR_CHECK(ndr_push_trailer_align(ndr, 4));
}
if (ndr_flags & NDR_BUFFERS) {
}
ndr->flags = _flags_save_STRUCT;
}
if (ndr_size_cab_file(r, &cab_size) == false) {
return NDR_ERR_VALIDATE;
}
SIVAL(ndr->data, 8, cab_size);
return NDR_ERR_SUCCESS;
}
_PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, int ndr_flags, struct cab_file *r)
{
uint32_t size_cffolders_0 = 0;
uint32_t cntr_cffolders_0;
TALLOC_CTX *_mem_save_cffolders_0 = NULL;
uint32_t size_cffiles_0 = 0;
uint32_t cntr_cffiles_0;
TALLOC_CTX *_mem_save_cffiles_0 = NULL;
uint32_t size_cfdata_0 = 0;
uint32_t cntr_cfdata_0;
TALLOC_CTX *_mem_save_cfdata_0 = NULL;
{
uint32_t _flags_save_STRUCT = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_pull_align(ndr, 4));
NDR_CHECK(ndr_pull_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
size_cffolders_0 = r->cfheader.cFolders;
NDR_PULL_ALLOC_N(ndr, r->cffolders, size_cffolders_0);
_mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX(ndr);
NDR_PULL_SET_MEM_CTX(ndr, r->cffolders, 0);
for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
NDR_CHECK(ndr_pull_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
}
NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffolders_0, 0);
size_cffiles_0 = r->cfheader.cFiles;
NDR_PULL_ALLOC_N(ndr, r->cffiles, size_cffiles_0);
_mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX(ndr);
NDR_PULL_SET_MEM_CTX(ndr, r->cffiles, 0);
for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (size_cffiles_0); cntr_cffiles_0++) {
NDR_CHECK(ndr_pull_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
}
NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffiles_0, 0);
#if 0
NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cfdata_count));
#else
r->cfdata_count = ndr_count_cfdata(r);
#endif
size_cfdata_0 = r->cfdata_count;
NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0);
_mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr);
NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0);
for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (size_cfdata_0); cntr_cfdata_0++) {
NDR_CHECK(ndr_pull_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
}
NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0);
NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
}
if (ndr_flags & NDR_BUFFERS) {
}
ndr->flags = _flags_save_STRUCT;
}
return NDR_ERR_SUCCESS;
}