Rizin
unix-like reverse engineering framework and cli tools
oabd.c
Go to the documentation of this file.
1 /* This file is part of libmspack.
2  * © 2013 Intel Corporation
3  *
4  * libmspack is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6  *
7  * For further details, see the file COPYING.LIB distributed with libmspack
8  */
9 
10 /* The Exchange Online Addressbook (OAB or sometimes OAL) is distributed
11  * as a .LZX file in one of two forms. Either a "full download" containing
12  * the entire address list, or an incremental binary patch which should be
13  * applied to a previous version of the full decompressed data.
14  *
15  * The contents and format of the decompressed OAB are not handled here.
16  *
17  * For a complete description of the format, see the MSDN site:
18  *
19  * http://msdn.microsoft.com/en-us/library/cc463914 - [MS-OXOAB].pdf
20  * http://msdn.microsoft.com/en-us/library/cc483133 - [MS-PATCH].pdf
21  */
22 
23 /* OAB decompression implementation */
24 
25 #include <system.h>
26 #include <oab.h>
27 #include <lzx.h>
28 #include <crc32.h>
29 
30 /* prototypes */
31 static int oabd_decompress(struct msoab_decompressor *self, const char *input,
32  const char *output);
33 static int oabd_decompress_incremental(struct msoab_decompressor *self,
34  const char *input, const char *base,
35  const char *output);
36 static int oabd_param(struct msoab_decompressor *base, int param, int value);
37 static int copy_fh(struct mspack_system *sys, struct mspack_file *infh,
38  struct mspack_file *outfh, size_t bytes_to_copy,
39  unsigned char *buf, int buf_size);
40 
41 
42 struct msoab_decompressor *
44 {
45  struct msoab_decompressor_p *self = NULL;
46 
47  if (!sys) sys = mspack_default_system;
48  if (!mspack_valid_system(sys)) return NULL;
49 
50  if ((self = (struct msoab_decompressor_p *) sys->alloc(sys, sizeof(struct msoab_decompressor_p)))) {
51  self->base.decompress = &oabd_decompress;
52  self->base.decompress_incremental = &oabd_decompress_incremental;
53  self->base.set_param = &oabd_param;
54  self->system = sys;
55  self->buf_size = 4096;
56  }
57  return (struct msoab_decompressor *) self;
58 }
59 
61  struct msoab_decompressor_p *self = (struct msoab_decompressor_p *)base;
62  if (self) {
63  struct mspack_system *sys = self->system;
64  sys->free(self);
65  }
66 }
67 
68 struct oabd_file {
71  unsigned int crc;
72  size_t available;
73 };
74 
75 
76 static int oabd_sys_read (struct mspack_file *base_file, void *buf, int size)
77 {
78  struct oabd_file *file = (struct oabd_file *)base_file;
79  int bytes_read;
80 
81  if ((size_t)size > file->available)
82  size = file->available;
83 
84  bytes_read = file->orig_sys->read(file->orig_file, buf, size);
85  if (bytes_read < 0)
86  return bytes_read;
87 
88  file->available -= bytes_read;
89  return bytes_read;
90 }
91 
92 static int oabd_sys_write (struct mspack_file *base_file, void *buf, int size)
93 {
94  struct oabd_file *file = (struct oabd_file *)base_file;
95  int bytes_written = file->orig_sys->write(file->orig_file, buf, size);
96 
97  if (bytes_written > 0)
98  file->crc = crc32(file->crc, buf, bytes_written);
99 
100  return bytes_written;
101 }
102 
103 static int oabd_decompress(struct msoab_decompressor *_self, const char *input,
104  const char *output)
105 {
106  struct msoab_decompressor_p *self = (struct msoab_decompressor_p *) _self;
107  struct mspack_system *sys;
108  struct mspack_file *infh = NULL;
109  struct mspack_file *outfh = NULL;
110  unsigned char *buf = NULL;
111  unsigned char hdrbuf[oabhead_SIZEOF];
112  unsigned int block_max, target_size;
113  struct lzxd_stream *lzx = NULL;
114  struct mspack_system oabd_sys;
115  struct oabd_file in_ofh, out_ofh;
116  unsigned int window_bits;
117  int ret = MSPACK_ERR_OK;
118 
119  if (!self) return MSPACK_ERR_ARGS;
120  sys = self->system;
121 
122  infh = sys->open(sys, input, MSPACK_SYS_OPEN_READ);
123  if (!infh) {
124  ret = MSPACK_ERR_OPEN;
125  goto out;
126  }
127 
128  if (sys->read(infh, hdrbuf, oabhead_SIZEOF) != oabhead_SIZEOF) {
129  ret = MSPACK_ERR_READ;
130  goto out;
131  }
132 
133  if (EndGetI32(&hdrbuf[oabhead_VersionHi]) != 3 ||
134  EndGetI32(&hdrbuf[oabhead_VersionLo]) != 1) {
135  ret = MSPACK_ERR_SIGNATURE;
136  goto out;
137  }
138 
139  block_max = EndGetI32(&hdrbuf[oabhead_BlockMax]);
140  target_size = EndGetI32(&hdrbuf[oabhead_TargetSize]);
141 
142  outfh = sys->open(sys, output, MSPACK_SYS_OPEN_WRITE);
143  if (!outfh) {
144  ret = MSPACK_ERR_OPEN;
145  goto out;
146  }
147 
148  buf = sys->alloc(sys, self->buf_size);
149  if (!buf) {
150  ret = MSPACK_ERR_NOMEMORY;
151  goto out;
152  }
153 
154  oabd_sys = *sys;
155  oabd_sys.read = oabd_sys_read;
156  oabd_sys.write = oabd_sys_write;
157 
158  in_ofh.orig_sys = sys;
159  in_ofh.orig_file = infh;
160 
161  out_ofh.orig_sys = sys;
162  out_ofh.orig_file = outfh;
163 
164  while (target_size) {
165  unsigned int blk_csize, blk_dsize, blk_crc, blk_flags;
166 
167  if (sys->read(infh, buf, oabblk_SIZEOF) != oabblk_SIZEOF) {
168  ret = MSPACK_ERR_READ;
169  goto out;
170  }
171  blk_flags = EndGetI32(&buf[oabblk_Flags]);
172  blk_csize = EndGetI32(&buf[oabblk_CompSize]);
173  blk_dsize = EndGetI32(&buf[oabblk_UncompSize]);
174  blk_crc = EndGetI32(&buf[oabblk_CRC]);
175 
176  if (blk_dsize > block_max || blk_dsize > target_size || blk_flags > 1) {
177  ret = MSPACK_ERR_DATAFORMAT;
178  goto out;
179  }
180 
181  if (!blk_flags) {
182  /* Uncompressed block */
183  if (blk_dsize != blk_csize) {
184  ret = MSPACK_ERR_DATAFORMAT;
185  goto out;
186  }
187  ret = copy_fh(sys, infh, outfh, blk_dsize, buf, self->buf_size);
188  if (ret) goto out;
189  } else {
190  /* LZX compressed block */
191  window_bits = 17;
192 
193  while (window_bits < 25 && (1U << window_bits) < blk_dsize)
194  window_bits++;
195 
196  in_ofh.available = blk_csize;
197  out_ofh.crc = 0xffffffff;
198 
199  lzx = lzxd_init(&oabd_sys, (void *)&in_ofh, (void *)&out_ofh, window_bits,
200  0, self->buf_size, blk_dsize, 1);
201  if (!lzx) {
202  ret = MSPACK_ERR_NOMEMORY;
203  goto out;
204  }
205 
206  ret = lzxd_decompress(lzx, blk_dsize);
207  if (ret != MSPACK_ERR_OK)
208  goto out;
209 
210  lzxd_free(lzx);
211  lzx = NULL;
212 
213  /* Consume any trailing padding bytes before the next block */
214  ret = copy_fh(sys, infh, NULL, in_ofh.available, buf, self->buf_size);
215  if (ret) goto out;
216 
217  if (out_ofh.crc != blk_crc) {
218  ret = MSPACK_ERR_CHECKSUM;
219  goto out;
220  }
221  }
222  target_size -= blk_dsize;
223  }
224 
225  out:
226  if (lzx) lzxd_free(lzx);
227  if (outfh) sys->close(outfh);
228  if (infh) sys->close(infh);
229  sys->free(buf);
230 
231  return ret;
232 }
233 
235  const char *input, const char *base,
236  const char *output)
237 {
238  struct msoab_decompressor_p *self = (struct msoab_decompressor_p *) _self;
239  struct mspack_system *sys;
240  struct mspack_file *infh = NULL;
241  struct mspack_file *basefh = NULL;
242  struct mspack_file *outfh = NULL;
243  unsigned char *buf = NULL;
244  unsigned char hdrbuf[patchhead_SIZEOF];
245  unsigned int block_max, target_size;
246  struct lzxd_stream *lzx = NULL;
247  struct mspack_system oabd_sys;
248  struct oabd_file in_ofh, out_ofh;
249  unsigned int window_bits, window_size;
250  int ret = MSPACK_ERR_OK;
251 
252  if (!self) return MSPACK_ERR_ARGS;
253  sys = self->system;
254 
255  infh = sys->open(sys, input, MSPACK_SYS_OPEN_READ);
256  if (!infh) {
257  ret = MSPACK_ERR_OPEN;
258  goto out;
259  }
260 
261  if (sys->read(infh, hdrbuf, patchhead_SIZEOF) != patchhead_SIZEOF) {
262  ret = MSPACK_ERR_READ;
263  goto out;
264  }
265 
266  if (EndGetI32(&hdrbuf[patchhead_VersionHi]) != 3 ||
267  EndGetI32(&hdrbuf[patchhead_VersionLo]) != 2) {
268  ret = MSPACK_ERR_SIGNATURE;
269  goto out;
270  }
271 
272  block_max = EndGetI32(&hdrbuf[patchhead_BlockMax]);
273  target_size = EndGetI32(&hdrbuf[patchhead_TargetSize]);
274 
275  /* We use it for reading block headers too */
276  if (block_max < patchblk_SIZEOF)
277  block_max = patchblk_SIZEOF;
278 
279  basefh = sys->open(sys, base, MSPACK_SYS_OPEN_READ);
280  if (!basefh) {
281  ret = MSPACK_ERR_OPEN;
282  goto out;
283  }
284 
285  outfh = sys->open(sys, output, MSPACK_SYS_OPEN_WRITE);
286  if (!outfh) {
287  ret = MSPACK_ERR_OPEN;
288  goto out;
289  }
290 
291  buf = sys->alloc(sys, self->buf_size);
292  if (!buf) {
293  ret = MSPACK_ERR_NOMEMORY;
294  goto out;
295  }
296 
297  oabd_sys = *sys;
298  oabd_sys.read = oabd_sys_read;
299  oabd_sys.write = oabd_sys_write;
300 
301  in_ofh.orig_sys = sys;
302  in_ofh.orig_file = infh;
303 
304  out_ofh.orig_sys = sys;
305  out_ofh.orig_file = outfh;
306 
307  while (target_size) {
308  unsigned int blk_csize, blk_dsize, blk_ssize, blk_crc;
309 
310  if (sys->read(infh, buf, patchblk_SIZEOF) != patchblk_SIZEOF) {
311  ret = MSPACK_ERR_READ;
312  goto out;
313  }
314  blk_csize = EndGetI32(&buf[patchblk_PatchSize]);
315  blk_dsize = EndGetI32(&buf[patchblk_TargetSize]);
316  blk_ssize = EndGetI32(&buf[patchblk_SourceSize]);
317  blk_crc = EndGetI32(&buf[patchblk_CRC]);
318 
319  if (blk_dsize > block_max || blk_dsize > target_size ||
320  blk_ssize > block_max) {
321  ret = MSPACK_ERR_DATAFORMAT;
322  goto out;
323  }
324 
325 
326  window_size = (blk_ssize + 32767) & ~32767;
327  window_size += blk_dsize;
328  window_bits = 17;
329 
330  while (window_bits < 25 && (1U << window_bits) < window_size)
331  window_bits++;
332 
333  in_ofh.available = blk_csize;
334  out_ofh.crc = 0xffffffff;
335 
336  lzx = lzxd_init(&oabd_sys, (void *)&in_ofh, (void *)&out_ofh, window_bits,
337  0, 4096, blk_dsize, 1);
338  if (!lzx) {
339  ret = MSPACK_ERR_NOMEMORY;
340  goto out;
341  }
342  ret = lzxd_set_reference_data(lzx, sys, basefh, blk_ssize);
343  if (ret != MSPACK_ERR_OK)
344  goto out;
345 
346  ret = lzxd_decompress(lzx, blk_dsize);
347  if (ret != MSPACK_ERR_OK)
348  goto out;
349 
350  lzxd_free(lzx);
351  lzx = NULL;
352 
353  /* Consume any trailing padding bytes before the next block */
354  ret = copy_fh(sys, infh, NULL, in_ofh.available, buf, self->buf_size);
355  if (ret) goto out;
356 
357  if (out_ofh.crc != blk_crc) {
358  ret = MSPACK_ERR_CHECKSUM;
359  goto out;
360  }
361 
362  target_size -= blk_dsize;
363  }
364 
365  out:
366  if (lzx) lzxd_free(lzx);
367  if (outfh) sys->close(outfh);
368  if (basefh) sys->close(basefh);
369  if (infh) sys->close(infh);
370  sys->free(buf);
371 
372  return ret;
373 }
374 
375 static int copy_fh(struct mspack_system *sys, struct mspack_file *infh,
376  struct mspack_file *outfh, size_t bytes_to_copy,
377  unsigned char *buf, int buf_size)
378 {
379  while (bytes_to_copy) {
380  int run = buf_size;
381  if ((size_t) run > bytes_to_copy) {
382  run = (int) bytes_to_copy;
383  }
384  if (sys->read(infh, buf, run) != run) {
385  return MSPACK_ERR_READ;
386  }
387  if (outfh && sys->write(outfh, buf, run) != run) {
388  return MSPACK_ERR_WRITE;
389  }
390  bytes_to_copy -= run;
391  }
392  return MSPACK_ERR_OK;
393 }
394 
395 static int oabd_param(struct msoab_decompressor *base, int param, int value) {
396  struct msoab_decompressor_p *self = (struct msoab_decompressor_p *) base;
397  if (self && param == MSOABD_PARAM_DECOMPBUF && value >= 16) {
398  /* must be at least 16 bytes (patchblk_SIZEOF, oabblk_SIZEOF) */
399  self->buf_size = value;
400  return MSPACK_ERR_OK;
401  }
402  return MSPACK_ERR_ARGS;
403 }
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
int lzxd_set_reference_data(struct lzxd_stream *lzx, struct mspack_system *system, struct mspack_file *input, unsigned int length)
Definition: lzxd.c:353
struct lzxd_stream * lzxd_init(struct mspack_system *system, struct mspack_file *input, struct mspack_file *output, int window_bits, int reset_interval, int input_buffer_size, off_t output_length, char is_delta)
Definition: lzxd.c:279
void lzxd_free(struct lzxd_stream *lzx)
Definition: lzxd.c:800
int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes)
Definition: lzxd.c:393
#define MSPACK_ERR_OK
Definition: mspack.h:485
#define MSPACK_ERR_OPEN
Definition: mspack.h:489
#define MSPACK_ERR_WRITE
Definition: mspack.h:493
#define MSPACK_SYS_OPEN_WRITE
Definition: mspack.h:460
#define MSPACK_SYS_OPEN_READ
Definition: mspack.h:458
#define MSPACK_ERR_CHECKSUM
Definition: mspack.h:503
#define MSPACK_ERR_SIGNATURE
Definition: mspack.h:499
#define MSPACK_ERR_ARGS
Definition: mspack.h:487
#define MSOABD_PARAM_DECOMPBUF
Definition: mspack.h:2379
#define MSPACK_ERR_DATAFORMAT
Definition: mspack.h:501
#define MSPACK_ERR_READ
Definition: mspack.h:491
#define MSPACK_ERR_NOMEMORY
Definition: mspack.h:497
struct mspack_system * mspack_default_system
Definition: system.c:238
int mspack_valid_system(struct mspack_system *sys)
Definition: system.c:58
static int value
Definition: cmd_api.c:93
#define NULL
Definition: cris-opc.c:27
static int buf_size
Definition: debug_qnx.c:35
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
#define EndGetI32(a)
Definition: macros.h:37
#define patchhead_VersionHi
Definition: oab.h:46
#define oabhead_TargetSize
Definition: oab.h:37
#define patchblk_CRC
Definition: oab.h:58
#define oabhead_VersionHi
Definition: oab.h:34
#define patchblk_SIZEOF
Definition: oab.h:59
#define oabhead_VersionLo
Definition: oab.h:35
#define oabhead_BlockMax
Definition: oab.h:36
#define oabblk_CRC
Definition: oab.h:43
#define patchhead_TargetSize
Definition: oab.h:50
#define patchblk_SourceSize
Definition: oab.h:57
#define patchblk_PatchSize
Definition: oab.h:55
#define oabblk_SIZEOF
Definition: oab.h:44
#define oabhead_SIZEOF
Definition: oab.h:38
#define oabblk_Flags
Definition: oab.h:40
#define patchhead_SIZEOF
Definition: oab.h:53
#define patchblk_TargetSize
Definition: oab.h:56
#define patchhead_BlockMax
Definition: oab.h:48
#define oabblk_CompSize
Definition: oab.h:41
#define oabblk_UncompSize
Definition: oab.h:42
#define patchhead_VersionLo
Definition: oab.h:47
struct msoab_decompressor * mspack_create_oab_decompressor(struct mspack_system *sys)
Definition: oabd.c:43
static int oabd_decompress_incremental(struct msoab_decompressor *self, const char *input, const char *base, const char *output)
Definition: oabd.c:234
static int oabd_sys_write(struct mspack_file *base_file, void *buf, int size)
Definition: oabd.c:92
static int oabd_decompress(struct msoab_decompressor *self, const char *input, const char *output)
Definition: oabd.c:103
static int oabd_param(struct msoab_decompressor *base, int param, int value)
Definition: oabd.c:395
static int oabd_sys_read(struct mspack_file *base_file, void *buf, int size)
Definition: oabd.c:76
static int copy_fh(struct mspack_system *sys, struct mspack_file *infh, struct mspack_file *outfh, size_t bytes_to_copy, unsigned char *buf, int buf_size)
Definition: oabd.c:375
void mspack_destroy_oab_decompressor(struct msoab_decompressor *base)
Definition: oabd.c:60
static int run(int i, const char *arg)
Definition: rz-bb.c:19
static int
Definition: sfsocketcall.h:114
Definition: gzappend.c:170
struct msoab_decompressor base
Definition: oab.h:28
void(* close)(struct mspack_file *file)
Definition: mspack.h:321
struct mspack_file *(* open)(struct mspack_system *self, const char *filename, int mode)
Definition: mspack.h:310
void(* free)(void *ptr)
Definition: mspack.h:430
int(* read)(struct mspack_file *file, void *buffer, int bytes)
Definition: mspack.h:336
int(* write)(struct mspack_file *file, void *buffer, int bytes)
Definition: mspack.h:353
void *(* alloc)(struct mspack_system *self, size_t bytes)
Definition: mspack.h:421
Definition: oabd.c:68
struct mspack_system * orig_sys
Definition: oabd.c:69
size_t available
Definition: oabd.c:72
unsigned int crc
Definition: oabd.c:71
struct mspack_file * orig_file
Definition: oabd.c:70
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
diff_output_t output
Definition: zipcmp.c:237
unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, uInt len)
Definition: crc32.c:1063