~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to libclamav/sis.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
3
 
 *
4
 
 *  Authors: Alberto Wu
 
2
 *  Copyright (C) 2005 - 2006 Tomasz Kojm <tkojm@clamav.net>
5
3
 *
6
4
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License version 2 as
8
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
9
8
 *
10
9
 *  This program is distributed in the hope that it will be useful,
11
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
21
#include "clamav-config.h"
23
22
#endif
24
23
 
 
24
#if HAVE_MMAP
 
25
 
25
26
#include <stdio.h>
26
 
#if HAVE_STDLIB_H
27
 
#include <stdlib.h>
28
 
#endif
29
 
#if HAVE_STRING_H
30
27
#include <string.h>
31
 
#endif
32
 
#if HAVE_SYS_TYPES_H
33
28
#include <sys/types.h>
34
 
#endif
35
 
#if HAVE_SYS_STAT_H
36
29
#include <sys/stat.h>
37
 
#endif
38
30
#include <fcntl.h>
 
31
#include <sys/stat.h>
 
32
#ifdef  HAVE_UNISTD_H
 
33
#include <unistd.h>
 
34
#endif
 
35
#include <time.h>
39
36
#include <zlib.h>
40
37
 
41
38
#include "others.h"
 
39
 
 
40
#if HAVE_SYS_MMAN_H
 
41
#include <sys/mman.h>
 
42
#else /* HAVE_SYS_MMAN_H */
 
43
#undef HAVE_MMAP
 
44
#endif
 
45
 
42
46
#include "clamav.h"
43
47
#include "scanners.h"
 
48
#include "cltypes.h"
44
49
#include "sis.h"
45
50
 
46
 
#define EC32(x) le32_to_host(x)
47
 
#define EC16(x) le16_to_host(x)
48
 
 
49
 
static int real_scansis(FILE *, cli_ctx *, const char *);
50
 
static int real_scansis9x(FILE *, cli_ctx *, const char *);
51
 
 
52
 
/*************************************************
53
 
       This is the wrapper to the old and new
54
 
            format handlers - see below.
55
 
 *************************************************/
56
 
 
57
 
int cli_scansis(int desc, cli_ctx *ctx) {
58
 
  FILE *f;
59
 
  int i;
60
 
  char *tmpd;
61
 
  uint32_t uid[4];
62
 
 
63
 
  cli_dbgmsg("in scansis()\n");
64
 
 
65
 
  if (!(tmpd = cli_gentemp(ctx->engine->tmpdir)))    
66
 
    return CL_ETMPDIR;
67
 
  if (mkdir(tmpd, 0700)) {
68
 
    cli_dbgmsg("SIS: Can't create temporary directory %s\n", tmpd);
69
 
    free(tmpd);
70
 
    return CL_ETMPDIR;
71
 
  }
72
 
  if (ctx->engine->keeptmp)
73
 
    cli_dbgmsg("SIS: Extracting files to %s\n", tmpd);
74
 
 
75
 
  if ((i=dup(desc))==-1) {
76
 
    cli_dbgmsg("SIS: dup() failed\n");
77
 
    cli_rmdirs(tmpd);
78
 
    free(tmpd);
79
 
    return CL_EDUP;
80
 
  }
81
 
  if (!(f=fdopen(i, "rb"))) {
82
 
    cli_dbgmsg("SIS: fdopen() failed\n");
83
 
    close(i);
84
 
    cli_rmdirs(tmpd);
85
 
    free(tmpd);
86
 
    return CL_EOPEN;
87
 
  }
88
 
  rewind(f);
89
 
  if (fread(uid, 16, 1, f)!=1) {
90
 
    cli_dbgmsg("SIS: unable to read UIDs\n");
91
 
    cli_rmdirs(tmpd);
92
 
    free(tmpd);
93
 
    fclose(f);
94
 
    return CL_EREAD;
95
 
  }
96
 
 
97
 
  cli_dbgmsg("SIS: UIDS %x %x %x - %x\n", EC32(uid[0]), EC32(uid[1]), EC32(uid[2]), EC32(uid[3]));
98
 
  if (uid[2]==EC32(0x10000419))
99
 
    i=real_scansis(f, ctx, tmpd);
100
 
  else if(uid[0]==EC32(0x10201a7a)) {
101
 
    i=real_scansis9x(f, ctx, tmpd);
102
 
  }
103
 
 
104
 
  if (!ctx->engine->keeptmp)
105
 
    cli_rmdirs(tmpd);
106
 
 
107
 
  free(tmpd);
108
 
  fclose(f);
109
 
  return i;
110
 
}
111
 
 
112
 
 
113
 
/*************************************************
114
 
     This is the handler for the old (pre 0.9)
115
 
                 SIS file format. 
116
 
 *************************************************/
117
 
 
118
 
enum {
119
 
  PKGfile,      /* I'm a real file */
120
 
  PKGlangfile,  /* Ich bin auch eine Datei */
121
 
  PKGoption,    /* options */
122
 
  PKGif,        /* #IF */
123
 
  PKGelsif,     /* #ELSIF */
124
 
  PKGelse,      /* #ELSE */
125
 
  PKGendif      /* #ENDIF */
126
 
};
127
 
 
128
 
enum {
129
 
  FTsimple = 0,
130
 
  FTtext,
131
 
  FTcomponent,
132
 
  FTrun,
133
 
  FTnull,
134
 
  FTmime,
135
 
  FTsubsis,
136
 
  FTcontsis,
137
 
  FTtextuninst,
138
 
  FTnotinst = 99
139
 
};
140
 
 
141
 
#define GETD(VAR) \
142
 
  if (sleft<4) { \
143
 
    memcpy(buff, buff+smax-sleft, sleft); \
144
 
    if ((smax=fread(buff+sleft,1,BUFSIZ-sleft,f)+sleft)<4) { \
145
 
      cli_dbgmsg("SIS: EOF\n"); \
146
 
      free(alangs); \
147
 
      return CL_CLEAN; \
148
 
    } \
149
 
    sleft=smax; \
150
 
  } \
151
 
  VAR = cli_readint32(&buff[smax-sleft]); \
152
 
  sleft-=4;
153
 
 
154
 
 
155
 
#define GETD2(VAR) {\
156
 
  if (sleft<4) { \
157
 
    memcpy(buff, buff+smax-sleft, sleft); \
158
 
    if ((smax=fread(buff+sleft,1,BUFSIZ-sleft,f)+sleft)<4) { \
159
 
      cli_dbgmsg("SIS: EOF\n"); \
160
 
      free(alangs); \
161
 
      free(ptrs); \
162
 
      return CL_CLEAN; \
163
 
    } \
164
 
    sleft=smax; \
165
 
  } \
166
 
  VAR = cli_readint32(&buff[smax-sleft]); \
167
 
  sleft-=4; \
168
 
}
169
 
 
170
 
#define SKIP(N) \
171
 
  if (sleft>=(N)) sleft-=(N); \
172
 
  else { \
173
 
    if ((N) < sleft) { \
174
 
      cli_dbgmsg("SIS: Refusing to seek back\n"); \
175
 
      free(alangs); \
176
 
      return CL_CLEAN; \
177
 
    } \
178
 
    fseek(f, (N)-sleft, SEEK_CUR); \
179
 
    sleft=smax=fread(buff,1,BUFSIZ,f); \
180
 
  }
181
 
 
182
 
const char *sislangs[] = {"UNKNOWN", "UK English","French", "German", "Spanish", "Italian", "Swedish", "Danish", "Norwegian", "Finnish", "American", "Swiss French", "Swiss German", "Portuguese", "Turkish", "Icelandic", "Russian", "Hungarian", "Dutch", "Belgian Flemish", "Australian English", "Belgian French", "Austrian German", "New Zealand English", "International French", "Czech", "Slovak", "Polish", "Slovenian", "Taiwanese Chinese", "Hong Kong Chinese", "PRC Chinese", "Japanese", "Thai", "Afrikaans", "Albanian", "Amharic", "Arabic", "Armenian", "Tagalog", "Belarussian", "Bengali", "Bulgarian", "Burmese", "Catalan", "Croation", "Canadian English", "International English", "South African English", "Estonian", "Farsi", "Canadian French", "Gaelic", "Georgian", "Greek", "Cyprus Greek", "Gujarati", "Hebrew", "Hindi", "Indonesian", "Irish", "Swiss Italian", "Kannada", "Kazakh", "Kmer", "Korean", "Lao", "Latvian", "Lithuanian", "Macedonian", "Malay", "Malayalam", "Marathi", "Moldovian", "Mongolian", "Norwegian Nynorsk", "Brazilian Portuguese", "Punjabi", "Romanian", "Serbian", "Sinhalese", "Somali", "International Spanish", "American Spanish", "Swahili", "Finland Swedish", "Reserved", "Tamil", "Telugu", "Tibetan", "Tigrinya", "Cyprus Turkish", "Turkmen", "Ukrainian", "Urdu", "Reserved", "Vietnamese", "Welsh", "Zulu", "Other"};
183
 
#define MAXLANG (sizeof(sislangs)/sizeof(sislangs[0]))
184
 
 
185
 
static char *getsistring(FILE *f, uint32_t ptr, uint32_t len) {
186
 
  char *name;
187
 
  uint32_t i;
188
 
 
189
 
  if (!len) return NULL;
190
 
  if (len>400) len=400;
191
 
  name = cli_malloc(len);
192
 
  if (!name) {
193
 
    cli_dbgmsg("SIS: OOM\n");
194
 
    return NULL;
195
 
  }
196
 
  fseek(f, ptr, SEEK_SET);
197
 
  if (fread(name, len, 1, f)!=1) {
198
 
    cli_dbgmsg("SIS: Unable to read string\n");
199
 
    free(name);
200
 
    return NULL;
201
 
  }
202
 
  for (i = 0 ; i < len; i+=2) name[i/2] = name[i];
203
 
  name[i/2]='\0';
204
 
  return name;
205
 
}
206
 
 
207
 
static int spamsisnames(FILE *f, uint16_t langs, const char **alangs) {
208
 
  uint32_t *lens, *ptrs;
209
 
  unsigned int j;
210
 
 
211
 
  if (!(lens = cli_malloc(sizeof(uint32_t) * langs * 2))) {
212
 
    cli_dbgmsg("SIS: OOM\n");
213
 
    return 0;
214
 
  }
215
 
  if (fread(lens, sizeof(uint32_t) * langs * 2, 1, f)!=1) {
216
 
    cli_dbgmsg("SIS: Unable to read lengths and pointers\n");
217
 
    free(lens);
218
 
    return 1;
219
 
  }
220
 
  ptrs=&lens[langs];
221
 
 
222
 
  for (j=0; j<langs; j++) {
223
 
    char *name = getsistring(f,EC32(ptrs[j]),EC32(lens[j]));
224
 
    if (name) {
225
 
      cli_dbgmsg("\t%s (%s - @%x, len %d)\n", name, alangs[j], EC32(ptrs[j]), EC32(lens[j]));
226
 
      free(name);
227
 
    }
228
 
  }
229
 
  free(lens);
230
 
  return 1;
231
 
}
232
 
 
233
 
static int real_scansis(FILE *f, cli_ctx *ctx, const char *tmpd) {
234
 
  struct {
235
 
    uint16_t filesum;
236
 
    uint16_t langs;
237
 
    uint16_t files;
238
 
    uint16_t deps;
239
 
    uint16_t ulangs;
240
 
    uint16_t instfiles;
241
 
    uint16_t drive;
242
 
    uint16_t caps;
243
 
    uint32_t version;
244
 
    uint16_t flags;
245
 
    uint16_t type;
246
 
    uint16_t verhi;
247
 
    uint16_t verlo;
248
 
    uint32_t versub;
249
 
    uint32_t plangs;
250
 
    uint32_t pfiles;
251
 
    uint32_t pdeps;
252
 
    uint32_t pcerts;
253
 
    uint32_t pnames;
254
 
    uint32_t psig;
255
 
    uint32_t pcaps;
256
 
    uint32_t uspace;
257
 
    uint32_t nspace;
258
 
  } sis;
259
 
  const char **alangs;
260
 
  uint16_t *llangs;
261
 
  unsigned int i, sleft=0, smax=0, umped=0;
262
 
  uint8_t compd, buff[BUFSIZ];
263
 
 
264
 
  if (fread(&sis,sizeof(sis),1,f)!=1) {
265
 
    cli_dbgmsg("SIS: Unable to read header\n");
266
 
    return CL_CLEAN;
267
 
  }
268
 
  /*  cli_dbgmsg("SIS HEADER INFO: \nFile checksum: %x\nLangs: %d\nFiles: %d\nDeps: %d\nUsed langs: %d\nInstalled files: %d\nDest drive: %d\nCapabilities: %d\nSIS Version: %d\nFlags: %x\nType: %d\nVersion: %d.%d.%d\nLangs@: %x\nFiles@: %x\nDeps@: %x\nCerts@: %x\nName@: %x\nSig@: %x\nCaps@: %x\nUspace: %d\nNspace: %d\n\n", sis.filesum, sis.langs, sis.files, sis.deps, sis.ulangs, sis.instfiles, sis.drive, sis.caps, sis.version, sis.flags, sis.type, sis.verhi, sis.verlo, sis.versub, sis.plangs, sis.pfiles, sis.pdeps, sis.pcerts, sis.pnames, sis.psig, sis.pcaps, sis.uspace, sis.nspace);
269
 
   */
270
 
 
271
 
#if WORDS_BIGENDIAN != 0
272
 
  sis.langs=EC16(sis.langs);
273
 
  sis.files=EC16(sis.files);
274
 
  sis.deps=EC16(sis.deps);
275
 
  sis.flags=EC16(sis.flags);
276
 
  sis.plangs=EC32(sis.plangs);
277
 
  sis.pfiles=EC32(sis.pfiles);
278
 
  sis.pdeps=EC32(sis.pdeps);
279
 
  sis.pnames=EC32(sis.pnames);
280
 
  sis.pcaps=EC32(sis.pcaps);
 
51
#define EC32(x) le32_to_host(x) /* Convert little endian to host */
 
52
#define EC16(x) le16_to_host(x) /* Convert little endian to host */
 
53
 
 
54
extern short cli_leavetemps_flag;
 
55
 
 
56
static const char *langcodes[] = {
 
57
    "",   "EN", "FR", "GE", "SP", "IT", "SW", "DA", "NO", "FI", "AM",
 
58
    "SF", "SG", "PO", "TU", "IC", "RU", "HU", "DU", "BL", "AU", "BG",
 
59
    "AS", "NZ", "IF", "CS", "SK", "PL", "SL", "TC", "HK", "ZH", "JA",
 
60
    "TH", "AF", "SQ", "AH", "AR", "HY", "TL", "BE", "BN", "BG", "MY",
 
61
    "CA", "HR", "CE", "IE", "SF", "ET", "FA", "CF", "GD", "KA", "EL",
 
62
    "CG", "GU", "HE", "HI", "IN", "GA", "SZ", "KN", "KK", "KM", "KO",
 
63
    "LO", "LV", "LT", "MK", "MS", "ML", "MR", "MO", "MN", "NN", "BP",
 
64
    "PA", "RO", "SR", "SI", "SO", "OS", "LS", "SH", "FS", "TA", "TE",
 
65
    "BO", "TI", "CT", "TK", "UK", "UR", "",   "VI", "CY", "ZU"
 
66
};
 
67
 
 
68
#ifndef O_BINARY
 
69
#define O_BINARY 0
281
70
#endif
282
71
 
283
 
  if (!sis.langs || sis.langs>=MAXLANG) {
284
 
    cli_dbgmsg("SIS: Too many or too few languages found\n");
285
 
    return CL_CLEAN;
286
 
  }
287
 
  fseek(f, sis.plangs, SEEK_SET);
288
 
  if (!(llangs=cli_malloc(sis.langs * sizeof(uint16_t)))) {
289
 
    cli_dbgmsg("SIS: OOM\n");
290
 
    return CL_CLEAN;
291
 
  }
292
 
  if (fread(llangs, sis.langs * sizeof(uint16_t), 1, f)!=1) {
293
 
    cli_dbgmsg("SIS: Unable to read languages\n");
294
 
    free(llangs);
295
 
    return CL_CLEAN;
296
 
  }
297
 
  if (!(alangs=cli_malloc(sis.langs * sizeof(char *)))) {
298
 
    cli_dbgmsg("SIS: OOM\n");
299
 
    free(llangs);
300
 
    return CL_CLEAN;
301
 
  }
302
 
  for (i = 0; i< sis.langs; i++)
303
 
    alangs[i]=EC32(llangs[i])<MAXLANG ? sislangs[EC32(llangs[i])] : sislangs[0];
304
 
  free(llangs);
305
 
 
306
 
  if (!sis.pnames) {
307
 
    cli_dbgmsg("SIS: Application without a name?\n");
308
 
  } else {
309
 
    fseek(f, sis.pnames, SEEK_SET);
310
 
    cli_dbgmsg("SIS: Application name:\n");
311
 
    if (!spamsisnames(f, sis.langs, alangs)) {
312
 
      free(alangs);
313
 
      return CL_EMEM;
314
 
    }
315
 
  }
316
 
 
317
 
  if (!sis.pcaps) {
318
 
    cli_dbgmsg("SIS: Application without capabilities?\n");
319
 
  } else {
320
 
    fseek(f, sis.pcaps, SEEK_SET);
321
 
    cli_dbgmsg("SIS: Provides:\n");
322
 
    if (!spamsisnames(f, sis.langs, alangs)) {
323
 
      free(alangs);
324
 
      return CL_EMEM;
325
 
    }
326
 
  }
327
 
 
328
 
  if (!sis.pdeps) {
329
 
    cli_dbgmsg("SIS: No dependencies set for this application\n");
330
 
  } else {
331
 
    cli_dbgmsg("SIS: Depends on:\n");
332
 
    for (i = 0; i< sis.deps; i++) {
333
 
      struct {
334
 
        uint32_t uid;
335
 
        uint16_t verhi;
336
 
        uint16_t verlo;
337
 
        uint32_t versub;
338
 
      } dep;
339
 
      
340
 
      fseek(f, sis.pdeps + i*(sizeof(dep) + sis.langs*2*sizeof(uint32_t)), SEEK_SET);
341
 
      if (fread(&dep, sizeof(dep), 1, f)!=1) {
342
 
        cli_dbgmsg("SIS: Unable to read dependencies\n");
343
 
      } else {
344
 
        cli_dbgmsg("\tUID: %x v. %d.%d.%d\n\taka:\n", EC32(dep.uid), EC16(dep.verhi), EC16(dep.verlo), EC32(dep.versub));
345
 
        if (!spamsisnames(f, sis.langs, alangs)) {
346
 
          free(alangs);
347
 
          return CL_EMEM;
348
 
        }
349
 
      }
350
 
    }
351
 
  }
352
 
 
353
 
  compd = !(sis.flags & 0x0008);
354
 
  cli_dbgmsg("SIS: Package is%s compressed\n", (compd)?"":" not");
355
 
 
356
 
  fseek(f, sis.pfiles, SEEK_SET);
357
 
  for (i=0; i<sis.files; i++) {
358
 
    uint32_t pkgtype, fcount=1;
359
 
    uint32_t j;
360
 
 
361
 
    GETD(pkgtype);
362
 
    cli_dbgmsg("SIS: Pkgtype: %d\n", pkgtype);
363
 
    switch(pkgtype) {
364
 
    case PKGlangfile:
365
 
      fcount=sis.langs;
366
 
    case PKGfile: {
367
 
      uint32_t ftype,options,ssname,psname,sdname,pdname;
368
 
      const char *sftype;
369
 
      uint32_t *ptrs, *lens, *olens;
370
 
      char *fn;
371
 
      long fpos;
372
 
 
373
 
      GETD(ftype);
374
 
      GETD(options);
375
 
      GETD(ssname);
376
 
      GETD(psname);
377
 
      GETD(sdname);
378
 
      GETD(pdname);
379
 
      switch(ftype) {
380
 
      case FTsimple:
381
 
        sftype = "simple";
382
 
        break;
383
 
      case FTtext:
384
 
        sftype = "text";
385
 
        break;
386
 
      case FTcomponent:
387
 
        sftype = "component";
388
 
        break;
389
 
      case FTrun:
390
 
        sftype = "run";
391
 
        break;
392
 
      case FTnull:
393
 
        sftype = "null";
394
 
        break;
395
 
      case FTmime:
396
 
        sftype = "mime";
397
 
        break;
398
 
      case FTsubsis:
399
 
        sftype = "sub sis";
400
 
        break;
401
 
      case FTcontsis:
402
 
        sftype = "conatiner sis";
403
 
        break;
404
 
      case FTtextuninst:
405
 
        sftype = "uninstall text";
406
 
        break;
407
 
      case FTnotinst:
408
 
        sftype = "not to be intalled";
409
 
        break;
410
 
      default:
411
 
        sftype = "unknown";
412
 
      }
413
 
      cli_dbgmsg("SIS: File details:\n\tOptions: %d\n\tType: %s\n", options, sftype);
414
 
      fpos = ftell(f);
415
 
      if ((fn=getsistring(f, psname, ssname))) {
416
 
        cli_dbgmsg("\tOriginal filename: %s\n", fn);
417
 
        free(fn);
418
 
      }
419
 
      if ((fn=getsistring(f, pdname, sdname))) {
420
 
        cli_dbgmsg("\tInstalled to: %s\n", fn);
421
 
        free(fn);
422
 
      }
423
 
      fseek(f,fpos,SEEK_SET);
424
 
 
425
 
      if (!(ptrs=cli_malloc(fcount*sizeof(uint32_t)*3))) {
426
 
        cli_dbgmsg("\tOOM\n");
427
 
        free(alangs);
428
 
        return CL_CLEAN;
429
 
      }
430
 
      lens=&ptrs[fcount];
431
 
      olens=&ptrs[fcount*2];
432
 
      for (j=0; j<fcount; j++)
433
 
        GETD2(lens[j]);
434
 
      for (j=0; j<fcount; j++)
435
 
        GETD2(ptrs[j]);
436
 
      for (j=0; j<fcount; j++)
437
 
        GETD2(olens[j]);
438
 
      
439
 
      if (ftype!=FTnull) {
440
 
        char ofn[1024];
441
 
        int fd;
442
 
 
443
 
        fpos = ftell(f);
444
 
 
445
 
        for (j=0; j<fcount; j++) {
446
 
          void *comp, *decomp;
447
 
          uLongf olen;
448
 
 
449
 
          if (!lens[j]) {
450
 
            cli_dbgmsg("\tSkipping empty file\n");
451
 
            continue;
452
 
          }
453
 
          if (cli_checklimits("sis", ctx,lens[j], 0, 0)!=CL_CLEAN) continue;
454
 
          cli_dbgmsg("\tUnpacking lang#%d - ptr:%x csize:%x osize:%x\n", j, ptrs[j], lens[j], olens[j]);
455
 
          if (!(comp=cli_malloc(lens[j]))) {
456
 
            cli_dbgmsg("\tOOM\n");
457
 
            free(ptrs);
458
 
            free(alangs);
459
 
            return CL_CLEAN;
460
 
          }
461
 
          fseek(f,ptrs[j],SEEK_SET);
462
 
          if (fread(comp, lens[j], 1, f)!=1) {
463
 
            cli_dbgmsg("\tSkipping ghost or otherwise out of archive file\n");
464
 
            free(comp);
465
 
            continue;
466
 
          }
467
 
          if (compd) {
468
 
            if (olens[j]<=lens[j]*3 && cli_checklimits("sis", ctx, lens[j]*3, 0, 0)==CL_CLEAN)
469
 
              olen=lens[j]*3;
470
 
            else if (cli_checklimits("sis", ctx, olens[j], 0, 0)==CL_CLEAN)
471
 
              olen=olens[j];
472
 
            else {
473
 
              free(comp);
474
 
              continue;
475
 
            }
476
 
              
477
 
            if (!(decomp=cli_malloc(olen))) {
478
 
              cli_dbgmsg("\tOOM\n");
479
 
              free(comp);
480
 
              free(ptrs);
481
 
              free(alangs);
482
 
              return CL_CLEAN;
483
 
            }
484
 
            if (uncompress(decomp, &olen, comp, lens[j])!=Z_OK) {
485
 
              cli_dbgmsg("\tUnpacking failure\n");
486
 
              free(comp);
487
 
              free(decomp);
488
 
              continue;
489
 
            }
490
 
            free(comp);
491
 
          } else {
492
 
            olen = lens[j];
493
 
            decomp = comp;
494
 
          }
495
 
          snprintf(ofn, 1024, "%s"PATHSEP"sis%02d", tmpd, umped);
496
 
          ofn[1023]='\0';
497
 
          if ((fd=open(ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) {
498
 
            cli_errmsg("SIS: unable to create output file %s - aborting.", ofn);
499
 
            free(decomp);
500
 
            free(ptrs);
501
 
            free(alangs);
502
 
            return CL_ECREAT;
503
 
          }
504
 
          if (cli_writen(fd, decomp, olen)!=(int)olen) {
505
 
            close(fd);
506
 
            free(decomp);
507
 
            free(ptrs);
508
 
            free(alangs);
509
 
            return CL_EWRITE;
510
 
          }
511
 
          free(decomp);
512
 
          if (cli_magic_scandesc(fd, ctx) == CL_VIRUS) {
513
 
            close(fd);
514
 
            free(ptrs);
515
 
            free(alangs);
 
72
#define SIS_MAX_NAME 512
 
73
#define SIS_MAX_SIZE 134217728
 
74
 
 
75
static char *sis_utf16_decode(const char *str, uint32_t length)
 
76
{
 
77
        char *decoded;
 
78
        uint32_t i, j;
 
79
 
 
80
 
 
81
    if(!length || length % 2) {
 
82
        cli_warnmsg("SIS: sis_utf16_decode: Broken filename (length == %d)\n", length);
 
83
        return NULL;
 
84
    }
 
85
 
 
86
    if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
 
87
        return NULL;
 
88
 
 
89
    for(i = 0, j = 0; i < length; i += 2, j++) {
 
90
       decoded[j] = str[i + 1] << 4;
 
91
       decoded[j] += str[i];
 
92
       if(decoded[j] == '%')
 
93
           decoded[j] = '_';
 
94
    }
 
95
 
 
96
    return decoded;
 
97
}
 
98
 
 
99
static int sis_extract_simple(int fd, char *mfile, uint32_t length, uint32_t offset, uint16_t nlangs, uint8_t compressed, uint8_t *ifile, const char *dir, cli_ctx *ctx)
 
100
{
 
101
        const char *typedir = NULL;
 
102
        char *sname = NULL, *dname = NULL, *subdir, *fname, *buff;
 
103
        int desc, i;
 
104
        uint8_t get_dname = 1;
 
105
        uint32_t namelen, nameoff, filelen, fileoff;
 
106
        struct stat sb;
 
107
        uLong osize = 0;
 
108
        uLongf csize = 0;
 
109
 
 
110
 
 
111
    if(offset + 24 + 8 * nlangs >= length) {
 
112
        cli_errmsg("SIS: sis_extract_simple: Broken file record\n");
 
113
        return CL_EFORMAT;
 
114
    }
 
115
 
 
116
    switch(cli_readint32(mfile + offset)) {
 
117
        case 0x00:
 
118
            cli_dbgmsg("SIS: File type: Standard file\n");
 
119
            typedir = "standard";
 
120
            break;
 
121
        case 0x01:
 
122
            cli_dbgmsg("SIS: File type: Text file\n");
 
123
            typedir = "text";
 
124
            get_dname = 0;
 
125
            break;
 
126
        case 0x02:
 
127
            cli_dbgmsg("SIS: File type: Component file\n");
 
128
            typedir = "component";
 
129
            get_dname = 0;
 
130
            break;
 
131
        case 0x03:
 
132
            cli_dbgmsg("SIS: File type: Run file\n");
 
133
            typedir = "run";
 
134
            switch(cli_readint32(mfile + offset + 4)) {
 
135
                case 0x0000:
 
136
                    cli_dbgmsg("SIS:    * During installation only\n");
 
137
                    break;
 
138
                case 0x0001:
 
139
                    cli_dbgmsg("SIS:    * During removal only\n");
 
140
                    break;
 
141
                case 0x0002:
 
142
                    cli_dbgmsg("SIS:    * During installation and removal\n");
 
143
                    break;
 
144
                case 0x0100:
 
145
                    cli_dbgmsg("SIS:    * Ends when installation finished\n");
 
146
                    break;
 
147
                case 0x0200:
 
148
                    cli_dbgmsg("SIS:    * Waits until closed before continuing\n");
 
149
                    break;
 
150
                default:
 
151
                    cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details\n");
 
152
            }
 
153
            break;
 
154
        case 0x04:
 
155
            cli_dbgmsg("SIS: File type: Null file\n");
 
156
            return CL_CLEAN;
 
157
        case 0x05:
 
158
            cli_dbgmsg("SIS: File type: MIME file\n");
 
159
            return CL_CLEAN;
 
160
        default:
 
161
            cli_warnmsg("SIS: Unknown file type in file record\n");
 
162
    }
 
163
 
 
164
    /* Source name */
 
165
    namelen = (uint32_t) cli_readint32(mfile + offset + 8);
 
166
    if(namelen > SIS_MAX_NAME) {
 
167
        cli_warnmsg("SIS: sis_extract_simple: Source name too long and will not be decoded\n");
 
168
    } else {
 
169
        nameoff = cli_readint32(mfile + offset + 12);
 
170
        if(nameoff >= length || nameoff + namelen >= length) {
 
171
            cli_errmsg("SIS: sis_extract_simple: Broken source name data\n");
 
172
            return CL_EFORMAT;
 
173
        }
 
174
 
 
175
        if((sname = sis_utf16_decode(mfile + nameoff, namelen)))
 
176
            cli_dbgmsg("SIS: Source name: %s\n", sname);
 
177
        else
 
178
            cli_warnmsg("SIS: Source name not decoded\n");
 
179
    }
 
180
 
 
181
    /* Destination name */
 
182
    if(get_dname) {
 
183
        namelen = (uint32_t) cli_readint32(mfile + offset + 16);
 
184
        if(namelen > SIS_MAX_NAME) {
 
185
            cli_warnmsg("SIS: sis_extract_simple: Destination name too long and will not be decoded\n");
 
186
        } else {
 
187
            nameoff = cli_readint32(mfile + offset + 20);
 
188
            if(nameoff >= length || nameoff + namelen >= length) {
 
189
                cli_errmsg("SIS: sis_extract_simple: Broken destination name data\n");
 
190
                if(sname)
 
191
                    free(sname);
 
192
                return CL_EFORMAT;
 
193
            }
 
194
 
 
195
            if((dname = sis_utf16_decode(mfile + nameoff, namelen)))
 
196
                cli_dbgmsg("SIS: Destination name: %s\n", dname);
 
197
            else
 
198
                cli_warnmsg("SIS: Destination name not decoded\n");
 
199
        }
 
200
    }
 
201
 
 
202
    if(!cli_leavetemps_flag) {
 
203
        if(sname)
 
204
            free(sname);
 
205
        if(dname)
 
206
            free(dname);
 
207
    }
 
208
 
 
209
    /* Files */
 
210
    if(typedir) {
 
211
        if(!(subdir = cli_malloc(strlen(dir) + strlen(typedir) + 2)))
 
212
            return CL_EMEM;
 
213
        sprintf(subdir, "%s/%s", dir, typedir);
 
214
    } else {
 
215
        if(!(subdir = cli_strdup(dir)))
 
216
            return CL_EMEM;
 
217
    }
 
218
 
 
219
    if(stat(subdir, &sb) == -1) {
 
220
        if(mkdir(subdir, 0700) == -1) {
 
221
            free(subdir);
 
222
            return CL_EIO;
 
223
        }
 
224
    }
 
225
 
 
226
    for(i = 0; i < nlangs; i++) {
 
227
        filelen = cli_readint32(mfile + offset + 24 + 4 * i);
 
228
        fileoff = cli_readint32(mfile + offset + 24 + 4 * i + 4 * nlangs);
 
229
 
 
230
        if(fileoff == length) {
 
231
            cli_dbgmsg("SIS: Null file (installation record)\n");
 
232
            *ifile = 1;
 
233
            continue;
 
234
        } else if (fileoff > length) {
 
235
            if(!*ifile) {
 
236
                cli_errmsg("SIS: sis_extract_simple: Broken file data (fileoff)\n");
 
237
                free(subdir);
 
238
                return CL_EFORMAT;
 
239
            } else {
 
240
                cli_dbgmsg("SIS: Null file (installation track)\n");
 
241
                continue;
 
242
            }
 
243
        }
 
244
 
 
245
        if(filelen >= length || filelen + fileoff > length) {
 
246
            cli_errmsg("SIS: sis_extract_simple: Broken file data (filelen, fileoff)\n");
 
247
            free(subdir);
 
248
            return CL_EFORMAT;
 
249
        }
 
250
 
 
251
        if(!(fname = cli_gentemp(subdir))) {
 
252
            free(subdir);
 
253
            return CL_EMEM;
 
254
        }
 
255
 
 
256
        if(compressed) {
 
257
            csize = (uLong) filelen;
 
258
            filelen = cli_readint32(mfile + offset + 24 + 4 * i + 8 * nlangs);
 
259
            osize = (uLongf) filelen;
 
260
 
 
261
            if(!osize) {
 
262
                cli_dbgmsg("SIS: Empty file, skipping\n");
 
263
                free(fname);
 
264
                continue;
 
265
            }
 
266
 
 
267
            cli_dbgmsg("SIS: Compressed size: %d\n", csize);
 
268
            cli_dbgmsg("SIS: Original size: %d\n", osize);
 
269
 
 
270
            if(ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize) {
 
271
                cli_dbgmsg("SIS: Size exceeded (%d, max: %ld)\n", osize, ctx->limits->maxfilesize);
 
272
                if(BLOCKMAX) {
 
273
                    *ctx->virname = "SIS.ExceededFileSize";
 
274
                    free(subdir);
 
275
                    free(fname);
 
276
                    return CL_VIRUS;
 
277
                }
 
278
                /* osize is not reliable so continue */
 
279
            }
 
280
 
 
281
            if((osize <= 3 * csize) || (ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize))
 
282
                osize = 3 * csize;
 
283
 
 
284
            if(!(buff = cli_malloc((size_t) osize))) {
 
285
                cli_errmsg("SIS: sis_extract_simple: Can't allocate decompression buffer\n");
 
286
                free(subdir);
 
287
                free(fname);
 
288
                return CL_EIO;
 
289
            } 
 
290
 
 
291
            if(uncompress((Bytef *) buff, &osize , (Bytef *) mfile + fileoff, csize) != Z_OK) {
 
292
                cli_errmsg("SIS: sis_extract_simple: File decompression failed\n");
 
293
                free(buff);
 
294
                free(subdir);
 
295
                free(fname);
 
296
                return CL_EIO;
 
297
            }
 
298
 
 
299
            if(osize != (uLongf) filelen) {
 
300
                cli_dbgmsg("SIS: WARNING: Real original size: %u\n", osize);
 
301
                filelen = (uint32_t) osize;
 
302
            }
 
303
 
 
304
        } else {
 
305
            buff = mfile + fileoff;
 
306
        }
 
307
 
 
308
        if((desc = open(fname, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) == -1) {
 
309
            cli_errmsg("SIS: sis_extract_simple: Can't create new file %s\n", fname);
 
310
            free(subdir);
 
311
            free(fname);
 
312
            if(compressed)
 
313
                free(buff);
 
314
            return CL_EIO;
 
315
        } 
 
316
 
 
317
        if((uint32_t) cli_writen(desc, buff, filelen) != filelen) {
 
318
            cli_errmsg("SIS: sis_extract_simple: Can't write %d bytes to %s\n", filelen, fname);
 
319
            free(subdir);
 
320
            free(fname);
 
321
            if(compressed)
 
322
                free(buff);
 
323
            return CL_EIO;
 
324
        } else {
 
325
            if(compressed)
 
326
                cli_dbgmsg("SIS: File decompressed into %s\n", fname);
 
327
            else
 
328
                cli_dbgmsg("SIS: File saved into %s\n", fname);
 
329
        }
 
330
 
 
331
        if(close(desc) == -1) {
 
332
            cli_errmsg("SIS: sis_extract_simple: Can't close descriptor %d\n", desc);
 
333
            free(subdir);
 
334
            free(fname);
 
335
            if(compressed)
 
336
                free(buff);
 
337
            return CL_EIO;
 
338
        } 
 
339
 
 
340
        free(fname);
 
341
 
 
342
        if(compressed)
 
343
            free(buff);
 
344
    }
 
345
 
 
346
    free(subdir);
 
347
    return CL_SUCCESS;
 
348
}
 
349
 
 
350
int cli_scansis(int desc, cli_ctx *ctx)
 
351
{
 
352
        struct sis_file_hdr file_hdr;
 
353
        struct sis_file_hdr6 file_hdr6;
 
354
        uint8_t release = 0, compressed, ifile = 0;
 
355
        uint16_t opts, nlangs, *langrecs, nfiles;
 
356
        uint32_t frecord, n;
 
357
        size_t length;
 
358
        char *mfile = NULL, *langs, *dir;
 
359
        struct stat sb;
 
360
        int i, ret;
 
361
 
 
362
 
 
363
    if(fstat(desc, &sb) == -1) {
 
364
        cli_errmsg("SIS: fstat() failed\n");
 
365
        return CL_EIO;
 
366
    }
 
367
 
 
368
    if(sb.st_size < sizeof(struct sis_file_hdr)) {
 
369
        cli_dbgmsg("SIS: Broken or not a SIS file (too small)\n");
 
370
        return CL_CLEAN;
 
371
    }
 
372
 
 
373
    length = sb.st_size;
 
374
 
 
375
    if(length <= SIS_MAX_SIZE) {
 
376
        mfile = (char *) mmap(NULL, length, PROT_READ, MAP_PRIVATE, desc, 0);
 
377
        if(mfile == MAP_FAILED) {
 
378
            cli_errmsg("SIS: mmap() failed\n");
 
379
            return CL_EMEM;
 
380
        } else {
 
381
            cli_dbgmsg("SIS: mmap'ed file\n");
 
382
            memcpy(&file_hdr, mfile, sizeof(struct sis_file_hdr));
 
383
        }
 
384
    } else {
 
385
        cli_warnmsg("SIS: File too large (> %d)\n", SIS_MAX_SIZE);
 
386
        return CL_CLEAN;
 
387
    }
 
388
 
 
389
    if(EC32(file_hdr.uid3) != 0x10000419) {
 
390
        cli_dbgmsg("SIS: Not a SIS file\n");
 
391
        munmap(mfile, length);
 
392
        return CL_CLEAN;
 
393
    }
 
394
 
 
395
    switch(EC32(file_hdr.uid2)) {
 
396
        case 0x1000006d:
 
397
            cli_dbgmsg("SIS: EPOC release 3, 4 or 5\n");
 
398
            release = 3;
 
399
            break;
 
400
        case 0x10003a12:
 
401
            cli_dbgmsg("SIS: EPOC release 6\n");
 
402
            release = 6;
 
403
            break;
 
404
        case 0x100039ce:
 
405
        case 0x10003a38:
 
406
            cli_dbgmsg("SIS: Application(?)\n");
 
407
            return CL_CLEAN;
 
408
        default:
 
409
            cli_warnmsg("SIS: Unknown value of UID 2 (EPOC release == 0x%x) -> not a real SIS file??\n", EC32(file_hdr.uid2));
 
410
            munmap(mfile, length);
 
411
            return CL_CLEAN;
 
412
    }
 
413
 
 
414
    /* TODO: Verify checksums (uid4 and checksum) */
 
415
 
 
416
    /* Languages */
 
417
    nlangs = EC16(file_hdr.nlangs);
 
418
    cli_dbgmsg("SIS: Number of languages: %d\n", nlangs);
 
419
 
 
420
    if(nlangs && nlangs < 100) {
 
421
 
 
422
        if(EC32(file_hdr.plangs) >= length || EC32(file_hdr.plangs) + nlangs * 2 >= sb.st_size) {
 
423
            cli_errmsg("SIS: Broken file structure (language records)\n");
 
424
            munmap(mfile, length);
 
425
            return CL_EFORMAT;
 
426
        }
 
427
 
 
428
        if(!(langrecs = (uint16_t *) cli_malloc(nlangs * 2))) {
 
429
            munmap(mfile, length);
 
430
            return CL_EMEM;
 
431
        }
 
432
 
 
433
        memcpy(langrecs, mfile + EC32(file_hdr.plangs), nlangs * 2);
 
434
 
 
435
        if(!(langs = (char *) cli_calloc(nlangs * 3 + 1, sizeof(char)))) {
 
436
            munmap(mfile, length);
 
437
            free(langrecs);
 
438
            return CL_EMEM;
 
439
        }
 
440
 
 
441
        for(i = 0; i < nlangs; i++) {
 
442
            strncat(langs, langcodes[EC16(langrecs[i]) % 98], 2);
 
443
            if(i != nlangs - 1)
 
444
                strncat(langs, " ", 1);
 
445
        }
 
446
        cli_dbgmsg("SIS: Supported languages: %s\n", langs);
 
447
        free(langrecs);
 
448
        free(langs);
 
449
 
 
450
    } else  {
 
451
        cli_errmsg("SIS: Incorrect number of languages (%d)\n", nlangs);
 
452
        munmap(mfile, length);
 
453
        return CL_EFORMAT;
 
454
    }
 
455
 
 
456
    cli_dbgmsg("SIS: Offset of languages records: %d\n", EC32(file_hdr.plangs));
 
457
 
 
458
    if(EC16(file_hdr.ilang))
 
459
        cli_dbgmsg("SIS: Installation language: %d\n", EC16(file_hdr.ilang));
 
460
 
 
461
    /* Requisites */
 
462
    cli_dbgmsg("SIS: Number of requisites: %d\n", EC16(file_hdr.nreqs));
 
463
    cli_dbgmsg("SIS: Offset of requisites records: %d\n", EC32(file_hdr.preqs));
 
464
 
 
465
    /* Options flags */
 
466
    opts = EC16(file_hdr.options);
 
467
    cli_dbgmsg("SIS: Options:\n");
 
468
    if(opts & 0x0001)
 
469
        cli_dbgmsg("SIS:    * File is in Unicode format\n");
 
470
    if(opts & 0x0002)
 
471
        cli_dbgmsg("SIS:    * File is distributable\n");
 
472
    if(opts & 0x0008) {
 
473
        cli_dbgmsg("SIS:    * Packed files are not compressed\n");
 
474
        compressed = 0;
 
475
    } else {
 
476
        cli_dbgmsg("SIS:    * Packed files are compressed\n");
 
477
        compressed = 1;
 
478
    }
 
479
    if(opts & 0x0010)
 
480
        cli_dbgmsg("SIS:    * File installation shuts down all applications\n");
 
481
 
 
482
    /* Type flags */
 
483
    switch(EC16(file_hdr.type)) {
 
484
        case 0x0000:
 
485
            cli_dbgmsg("SIS: Type: Contains an application\n");
 
486
            break;
 
487
        case 0x0001:
 
488
            cli_dbgmsg("SIS: Type: Contains a shared/system component\n");
 
489
            break;
 
490
        case 0x0002:
 
491
            cli_dbgmsg("SIS: Type: Contains an optional (selectable) component\n");
 
492
            break;
 
493
        case 0x0003:
 
494
            cli_dbgmsg("SIS: Type: Configures an existing application or service\n");
 
495
            break;
 
496
        case 0x0004:
 
497
            cli_dbgmsg("SIS: Type: Patches an existing component\n");
 
498
            break;
 
499
        case 0x0005:
 
500
            cli_dbgmsg("SIS: Type: Upgrades an existing component\n");
 
501
            break;
 
502
        default:
 
503
            cli_warnmsg("SIS: Unknown value of type\n");
 
504
    } 
 
505
 
 
506
    cli_dbgmsg("SIS: Major version: %d\n", EC16(file_hdr.majorver));
 
507
    cli_dbgmsg("SIS: Minor version: %d\n", EC16(file_hdr.minorver));
 
508
 
 
509
    if(release == 6) {
 
510
 
 
511
        if(sizeof(struct sis_file_hdr) + sizeof(struct sis_file_hdr6) >= length) {
 
512
            cli_errmsg("SIS: Broken file structure (language records)\n");
 
513
            munmap(mfile, length);
 
514
            return CL_EFORMAT;
 
515
        }
 
516
 
 
517
        memcpy(&file_hdr6, mfile + sizeof(struct sis_file_hdr), sizeof(struct sis_file_hdr6));
 
518
        cli_dbgmsg("SIS: Maximum space required: %d\n", EC32(file_hdr6.maxispace));
 
519
    }
 
520
 
 
521
    /* Files */
 
522
    nfiles = EC16(file_hdr.nfiles);
 
523
 
 
524
    if(ctx->limits && ctx->limits->maxfiles && nfiles > ctx->limits->maxfiles) {
 
525
        cli_dbgmsg("SIS: Files limit reached (max: %d)\n", ctx->limits->maxfiles);
 
526
        if(BLOCKMAX) {
 
527
            *ctx->virname = "SIS.ExceededFilesLimit";
 
528
            munmap(mfile, length);
516
529
            return CL_VIRUS;
517
 
          }
518
 
          close(fd);
519
 
          umped++;
520
 
        }
521
 
        fseek(f,fpos,SEEK_SET);
522
 
      }
523
 
      free(ptrs);
524
 
      fcount=2*sizeof(uint32_t);
525
 
      break;
526
 
    }
527
 
    case PKGoption:
528
 
      cli_dbgmsg("SIS: I'm an option\n");
529
 
      GETD(fcount);
530
 
      fcount*=sis.langs*2*sizeof(uint32_t);
531
 
      break;
532
 
    case PKGif:
533
 
      cli_dbgmsg("SIS: #if\n");
534
 
      GETD(fcount);
535
 
      break;
536
 
    case PKGelsif:
537
 
      cli_dbgmsg("SIS: #elsif\n");
538
 
      GETD(fcount);
539
 
      break;
540
 
    case PKGelse:
541
 
      cli_dbgmsg("SIS: #else\n");
542
 
      fcount=0;
543
 
      break;
544
 
    case PKGendif:
545
 
      cli_dbgmsg("SIS: #endif\n");
546
 
      fcount=0;
547
 
      break;
548
 
    default:
549
 
      cli_dbgmsg("SIS: Unknown PKGtype, expect troubles\n");
550
 
      fcount=0;
551
 
    }
552
 
    SKIP(fcount);
553
 
  }
554
 
 
555
 
  free(alangs);
556
 
  return CL_CLEAN;
557
 
}
558
 
 
559
 
 
560
 
/*************************************************                                              
561
 
     This is the handler for the new (post 9.x) 
562
 
                  SIS file format. 
563
 
 *************************************************/
564
 
 
565
 
enum { T_INVALID, T_STRING, T_ARRAY, T_COMPRESSED, T_VERSION, T_VERSIONRANGE, T_DATE, T_TIME, T_DATETIME, T_UID, T_UNUSED, T_LANGUAGE, T_CONTENTS, T_CONTROLLER, T_INFO, T_SUPPORTEDLANGUAGES, T_SUPPORTEDOPTIONS, T_PREREQUISITES, T_DEPENDENCY, T_PROPERTIES, T_PROPERTY, T_SIGNATURES, T_CERTIFICATECHAIN, T_LOGO, T_FILEDESCRIPTION, T_HASH, T_IF, T_ELSEIF, T_INSTALLBLOCK, T_EXPRESSION, T_DATA, T_DATAUNIT, T_FILEDATA, T_SUPPORTEDOPTION, T_CONTROLLERCHECKSUM, T_DATACHECKSUM, T_SIGNATURE, T_BLOB, T_SIGNATUREALGORITHM, T_SIGNATURECERTIFICATECHAIN, T_DATAINDEX, T_CAPABILITIES, T_MAXVALUE };
566
 
 
567
 
const char *sisfields[] = {"Invalid", "String", "Array", "Compressed", "Version", "VersionRange", "Date", "Time", "DateTime", "Uid", "Unused", "Language", "Contents", "Controller", "Info", "SupportedLanguages", "SupportedOptions", "Prerequisites", "Dependency", "Properties", "Property", "Signatures", "CertificateChain", "Logo", "FileDescription", "Hash", "If", "ElseIf", "InstallBlock", "Expression", "Data", "DataUnit", "FileData", "SupportedOption", "ControllerChecksum", "DataChecksum", "Signature", "Blob", "SignatureAlgorithm", "SignatureCertificateChain", "DataIndex", "Capabilities"};
568
 
 
569
 
#define ALIGN4(x) (((x)&~3) + ((((x)&1)|(((x)>>1)&1))<<2))
570
 
 
571
 
#define HERE printf("here\n"),abort();
572
 
 
573
 
struct SISTREAM {
574
 
  FILE *f;
575
 
  uint8_t buff[BUFSIZ];
576
 
  uint32_t smax;
577
 
  uint32_t sleft;
578
 
  long fnext[7];
579
 
  uint32_t fsize[7];
580
 
  unsigned int level;
581
 
};
582
 
 
583
 
static inline int getd(struct SISTREAM *s, uint32_t *v) {
584
 
  if (s->sleft<4) {
585
 
    memcpy(s->buff, s->buff + s->smax - s->sleft, s->sleft);
586
 
    if ((s->sleft=s->smax=fread(&s->buff[s->sleft], 1, BUFSIZ - s->sleft, s->f) + s->sleft)<4) {
587
 
      return 1;
588
 
    }
589
 
  }
590
 
  *v = cli_readint32(&s->buff[s->smax - s->sleft]);
591
 
  s->sleft-=4;
592
 
  return 0;
593
 
}
594
 
 
595
 
static inline int getsize(struct SISTREAM *s) {
596
 
  uint32_t *fsize = &s->fsize[s->level];
597
 
  if(getd(s, fsize) || !*fsize || (*fsize)>>31 || (s->level && *fsize > s->fsize[s->level-1] * 2)) return 1;
598
 
  /* To handle crafted archives we allow the content to overflow the container but only up to 2 times the container size */
599
 
  s->fnext[s->level] = ftell(s->f) - s->sleft + *fsize;
600
 
  return 0;
601
 
}
602
 
 
603
 
static inline int getfield(struct SISTREAM *s, uint32_t *field) {
604
 
  int ret;
605
 
  if(!(ret = getd(s, field)))
606
 
    ret = getsize(s);
607
 
  if(!ret) {
608
 
    if (*field<T_MAXVALUE)
609
 
      cli_dbgmsg("SIS: %d:Got %s(%x) field with size %x\n", s->level, sisfields[*field], *field, s->fsize[s->level]);
610
 
    else
611
 
      cli_dbgmsg("SIS: %d:Got invalid(%x) field with size %x\n", s->level, *field, s->fsize[s->level]);
612
 
  }
613
 
  return ret;
614
 
}
615
 
 
616
 
static inline int skip(struct SISTREAM *s, uint32_t size) {
617
 
  long seekto;
618
 
  cli_dbgmsg("SIS: skipping %x\n", size);
619
 
  if (s->sleft>=size) s->sleft-=size;
620
 
  else {
621
 
    seekto = size - s->sleft;
622
 
    if (seekto<0) /* in case sizeof(long)==sizeof(uint32_t) */
623
 
      return 1;
624
 
    fseek(s->f, seekto, SEEK_CUR);
625
 
    /*     s->sleft = s->smax = fread(s->buff,1,BUFSIZ,s->f); */
626
 
    s->sleft = s->smax = 0;
627
 
  }
628
 
  return 0;
629
 
}
630
 
 
631
 
static inline int skipthis(struct SISTREAM *s) {
632
 
  return skip(s, ALIGN4(s->fsize[s->level]));
633
 
}
634
 
 
635
 
static inline void seeknext(struct SISTREAM *s) {
636
 
  fseek(s->f, s->fnext[s->level], SEEK_SET);
637
 
  /*   s->sleft = s->smax = fread(s->buff,1,BUFSIZ,s->f); */
638
 
  s->sleft = s->smax = 0;
639
 
}
640
 
 
641
 
 
642
 
static int real_scansis9x(FILE *f, cli_ctx *ctx, const char *tmpd) {
643
 
  struct SISTREAM stream;
644
 
  struct SISTREAM *s = &stream;
645
 
  uint32_t field, optst[]={T_CONTROLLERCHECKSUM, T_DATACHECKSUM, T_COMPRESSED};
646
 
  unsigned int i;
647
 
 
648
 
  s->f = f;
649
 
  s->smax = 0;
650
 
  s->sleft = 0;
651
 
  s->level = 0;
652
 
 
653
 
  if (getfield(s, &field) || field!=T_CONTENTS)
 
530
        }
 
531
        return CL_CLEAN;
 
532
    }
 
533
 
 
534
    cli_dbgmsg("SIS: Number of files: %d\n", nfiles);
 
535
    cli_dbgmsg("SIS: Offset of files records: %d\n", EC32(file_hdr.pfiles));
 
536
 
 
537
    if(!(dir = cli_gentempdir(NULL))) {
 
538
        cli_errmsg("SIS: Can't generate temporary directory\n");
 
539
        munmap(mfile, length);
 
540
        return CL_ETMPDIR;
 
541
    }
 
542
 
 
543
    if((frecord = EC32(file_hdr.pfiles)) >= length) {
 
544
        cli_errmsg("SIS: Broken file structure (frecord)\n");
 
545
        munmap(mfile, length);
 
546
        free(dir);
 
547
        return CL_EFORMAT;
 
548
    }
 
549
 
 
550
    for(i = 0; i < nfiles; i++) {
 
551
 
 
552
        cli_dbgmsg("SIS: -----\n");
 
553
 
 
554
        if(frecord + 4 >= length) {
 
555
            cli_errmsg("SIS: Broken file structure (frecord)\n");
 
556
            munmap(mfile, length);
 
557
            if(!cli_leavetemps_flag)
 
558
                cli_rmdirs(dir);
 
559
            free(dir);
 
560
            return CL_EFORMAT;
 
561
        }
 
562
 
 
563
        switch(cli_readint32(mfile + frecord)) {
 
564
            case 0x00000000:
 
565
                cli_dbgmsg("SIS: Simple file record\n");
 
566
                if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, 1, compressed, &ifile, dir, ctx))) {
 
567
                    munmap(mfile, length);
 
568
                    if(!cli_leavetemps_flag)
 
569
                        cli_rmdirs(dir);
 
570
                    free(dir);
 
571
                    return ret;
 
572
                }
 
573
 
 
574
                if(release == 6)
 
575
                    frecord += 32 + 12 + 4;
 
576
                else
 
577
                    frecord += 28 + 4 + 4;
 
578
 
 
579
                break;
 
580
            case 0x00000001:
 
581
                cli_dbgmsg("SIS: Multiple languages file record\n");
 
582
                /* TODO: Pass language strings into sis_extract */
 
583
                if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, nlangs, compressed, &ifile, dir, ctx))) {
 
584
                    munmap(mfile, length);
 
585
                    if(!cli_leavetemps_flag)
 
586
                        cli_rmdirs(dir);
 
587
                    free(dir);
 
588
                    return ret;
 
589
                }
 
590
 
 
591
                if(release == 6)
 
592
                    frecord += 32 + 12 * nlangs + 4;
 
593
                else
 
594
                    frecord += 28 + 4 * nlangs + 4;
 
595
 
 
596
                break;
 
597
            case 0x00000002:
 
598
                cli_dbgmsg("SIS: Options record\n");
 
599
                if(frecord + 8 >= length) {
 
600
                    munmap(mfile, length);
 
601
                    if(!cli_leavetemps_flag)
 
602
                        cli_rmdirs(dir);
 
603
                    free(dir);
 
604
                    return CL_EFORMAT;
 
605
                }
 
606
 
 
607
                n = cli_readint32(mfile + frecord + 4);
 
608
                cli_dbgmsg("SIS: Number of options: %d\n", n);
 
609
 
 
610
                if(n > 128 || frecord + 8 * n * nlangs >= length) {
 
611
                    cli_errmsg("SIS: Incorrect number of options\n");
 
612
                    munmap(mfile, length);
 
613
                    if(!cli_leavetemps_flag)
 
614
                        cli_rmdirs(dir);
 
615
                    free(dir);
 
616
                    return CL_EFORMAT;
 
617
                }
 
618
 
 
619
                frecord += 8 + 8 * n * nlangs + 16;
 
620
 
 
621
                break;
 
622
            case 0x00000003:
 
623
            case 0x00000004:
 
624
                cli_dbgmsg("SIS: If/ElseIf record\n");
 
625
                if(frecord + 8 >= length) {
 
626
                    munmap(mfile, length);
 
627
                    if(!cli_leavetemps_flag)
 
628
                        cli_rmdirs(dir);
 
629
                    free(dir);
 
630
                    return CL_EFORMAT;
 
631
                }
 
632
 
 
633
                n = cli_readint32(mfile + frecord + 4);
 
634
                cli_dbgmsg("SIS: Size of conditional expression: %d\n", n);
 
635
 
 
636
                if(n >= length) {
 
637
                    cli_errmsg("SIS: Incorrect size of conditional expression\n");
 
638
                    munmap(mfile, length);
 
639
                    if(!cli_leavetemps_flag)
 
640
                        cli_rmdirs(dir);
 
641
                    free(dir);
 
642
                    return CL_EFORMAT;
 
643
                }
 
644
 
 
645
                frecord += 8 + n;
 
646
                break;
 
647
            case 0x00000005:
 
648
                cli_dbgmsg("SIS: Else record\n");
 
649
                frecord += 4;
 
650
                break;
 
651
            case 0x00000006:
 
652
                cli_dbgmsg("SIS: EndIf record\n");
 
653
                frecord += 4;
 
654
                break;
 
655
            default:
 
656
                cli_warnmsg("SIS: Unknown file record type\n");
 
657
        }
 
658
    }
 
659
 
 
660
    /* scan extracted files */
 
661
    cli_dbgmsg("SIS:  ****** Scanning extracted files ******\n");
 
662
    ret = cli_scandir(dir, ctx);
 
663
 
 
664
    if(!cli_leavetemps_flag)
 
665
        cli_rmdirs(dir);
 
666
 
 
667
    free(dir);
 
668
    munmap(mfile, length);
 
669
 
 
670
    return ret;
 
671
}
 
672
 
 
673
#else /* HAVE_MMAP */
 
674
 
 
675
#include "clamav.h"
 
676
#include "others.h"
 
677
#include "sis.h"
 
678
 
 
679
int cli_scansis(int desc, cli_ctx *ctx)
 
680
{
 
681
    cli_warnmsg("Support for SIS files not compiled in!\n");
654
682
    return CL_CLEAN;
655
 
  s->level++;
656
 
 
657
 
  for (i=0;i<3;) {
658
 
    if (getfield(s, &field)) return CL_CLEAN;
659
 
    for (;i<3;i++) {
660
 
      if (field==optst[i]) {
661
 
        if (skipthis(s)) return CL_CLEAN;
662
 
        i++;
663
 
        break;
664
 
      }
665
 
    }
666
 
  }
667
 
  if (field!=T_COMPRESSED) return CL_CLEAN;
668
 
 
669
 
  i=0;
670
 
  while (1) { /* 1DATA */
671
 
    if (getfield(s, &field) || field!=T_DATA) break;
672
 
 
673
 
    s->level++; 
674
 
    while(1) { /* DATA::ARRAY */
675
 
      uint32_t atype;
676
 
      if (getfield(s, &field) || field!=T_ARRAY || getd(s, &atype) || atype!=T_DATAUNIT || s->fsize[s->level]<4) break;
677
 
      s->fsize[s->level]-=4;
678
 
 
679
 
      s->level++;
680
 
      while (s->fsize[s->level-1] && !getsize(s)) { /* FOREACH DATA::ARRAY::DATAUNITs */
681
 
        cli_dbgmsg("SIS: %d:Got dataunit element with size %x\n", s->level, s->fsize[s->level]);
682
 
        if (ALIGN4(s->fsize[s->level]) < s->fsize[s->level-1]) 
683
 
          s->fsize[s->level-1]-=ALIGN4(s->fsize[s->level]);
684
 
        else
685
 
          s->fsize[s->level-1]=0;
686
 
 
687
 
        s->level++;
688
 
        while(1) { /* DATA::ARRAY::DATAUNIT[x]::ARRAY */
689
 
          if(getfield(s, &field) || field!=T_ARRAY || getd(s, &atype) || atype!=T_FILEDATA || s->fsize[s->level]<4) break;
690
 
          s->fsize[s->level]-=4;
691
 
 
692
 
          s->level++;
693
 
          while (s->fsize[s->level-1] && !getsize(s)) { /* FOREACH DATA::ARRAY::DATAUNIT[x]::ARRAY::FILEDATA */
694
 
            uint32_t usize, usizeh;
695
 
            void *src, *dst;
696
 
            char tempf[1024];
697
 
            uLongf uusize;
698
 
            int fd;
699
 
 
700
 
            cli_dbgmsg("SIS: %d:Got filedata element with size %x\n", s->level, s->fsize[s->level]);
701
 
            if (ALIGN4(s->fsize[s->level]) < s->fsize[s->level-1]) 
702
 
              s->fsize[s->level-1]-=ALIGN4(s->fsize[s->level]);
703
 
            else
704
 
              s->fsize[s->level-1]=0;
705
 
 
706
 
            s->level++;
707
 
            while(1) { /* DATA::ARRAY::DATAUNIT[x]::ARRAY::FILEDATA[x]::COMPRESSED */
708
 
              if(getfield(s, &field) || field!=T_COMPRESSED || getd(s, &field) || getd(s, &usize) || getd(s, &usizeh) || usizeh) break;
709
 
              s->fsize[s->level]-=12;
710
 
              cli_dbgmsg("SIS: File is%s compressed - size %x -> %x\n", (field)?"":" not", s->fsize[s->level], usize);
711
 
              snprintf(tempf, 1024, "%s"PATHSEP"sis9x%02d", tmpd, i++);
712
 
              tempf[1023]='\0';
713
 
              fseek(s->f, -(long)s->sleft, SEEK_CUR);
714
 
              s->sleft = s->smax = 0;
715
 
 
716
 
              if (cli_checklimits("sis", ctx,ALIGN4(s->fsize[s->level]), 0, 0)!=CL_CLEAN) break;
717
 
              if (!(src=cli_malloc(ALIGN4(s->fsize[s->level])))) break;
718
 
              if (fread(src, ALIGN4(s->fsize[s->level]),1,s->f) != 1) {
719
 
                free(src);
720
 
                break;
721
 
              }
722
 
 
723
 
              if(field) { /* compressed */
724
 
                int zresult;
725
 
 
726
 
                if (usize<=s->fsize[s->level]*3 && cli_checklimits("sis", ctx, s->fsize[s->level]*3, 0, 0)==CL_CLEAN)
727
 
                  uusize=s->fsize[s->level]*3;
728
 
                else if (cli_checklimits("sis", ctx, usize, 0, 0)==CL_CLEAN)
729
 
                  uusize=usize;
730
 
                else {
731
 
                  free(src);
732
 
                  break;
733
 
                }
734
 
 
735
 
                if (!(dst=cli_malloc(uusize))) {
736
 
                  free(src);
737
 
                  break;
738
 
                }
739
 
                zresult=uncompress(dst, &uusize, src, s->fsize[s->level]);
740
 
                free(src);
741
 
                if (zresult!=Z_OK) {
742
 
                  cli_dbgmsg("SIS: Inflate failure (%d)\n", zresult);
743
 
                  free(dst);
744
 
                  break;
745
 
                }
746
 
                if ((uLongf)usize != uusize)
747
 
                  cli_dbgmsg("SIS: Warning: expected size %lx but got %lx\n", (uLongf)usize, uusize);
748
 
                else
749
 
                  cli_dbgmsg("SIS: File successfully inflated\n");
750
 
              } else { /* not compressed */
751
 
                dst = src;
752
 
                uusize = s->fsize[s->level];
753
 
              }
754
 
              if ((fd=open(tempf, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) {
755
 
                cli_errmsg("SIS: unable to create output file %s - aborting.", tempf);
756
 
                free(dst);
757
 
                break;
758
 
              }
759
 
              if (cli_writen(fd, dst, uusize)!=(int)uusize) {
760
 
                free(dst);
761
 
                close(fd);
762
 
                break;
763
 
              }
764
 
              free(dst);
765
 
              if (cli_magic_scandesc(fd, ctx) == CL_VIRUS) {
766
 
                close(fd);
767
 
                return CL_VIRUS;
768
 
              }
769
 
              close(fd);
770
 
              break;
771
 
            } /* DATA::ARRAY::DATAUNIT[x]::ARRAY::FILEDATA[x]::COMPRESSED */
772
 
            s->level--;
773
 
            seeknext(s);
774
 
          } /* FOREACH DATA::ARRAY::DATAUNIT[x]::ARRAY::FILEDATAs */
775
 
          s->level--;
776
 
          break;
777
 
        } /* DATA::ARRAY::DATAUNIT[x]::ARRAY */
778
 
        s->level--;
779
 
        seeknext(s);
780
 
      } /* FOREACH DATA::ARRAY::DATAUNITs */
781
 
      s->level--;
782
 
      break;
783
 
    } /* DATA::ARRAY */
784
 
    s->level--;
785
 
    seeknext(s);
786
 
  }
787
 
  return CL_CLEAN;
788
683
}
789
684
 
790
 
/*************************************************
791
 
  An (incomplete) FSM approach to sis9x unpacking
792
 
    maybe needed if sisdataindex gets exploited
793
 
 *************************************************/
794
 
 
795
 
/* #include <stdio.h> */
796
 
/* #include <stdint.h> */
797
 
/* #include <stdlib.h> */
798
 
/* #include <string.h> */
799
 
/* #include <zlib.h> */
800
 
 
801
 
/*   /\* FIXME: RESEEK before spamming strings if not compressed *\/ */
802
 
/* #define SPAMSARRAY(WHO) \ */
803
 
/*   GETD(field); \ */
804
 
/*   fsz-=4; \ */
805
 
/*   if(field!=T_STRING) { \ */
806
 
/*     printf(WHO" - Unexpected array type, skipping\n"); \ */
807
 
/*     break; \ */
808
 
/*   } \ */
809
 
/*   while(fsz>4) { \ */
810
 
/*     GETD(field); \ */
811
 
/*     fsz-=4; \ */
812
 
/*     if(field && fsz<=sleft && field<=fsz) { \ */
813
 
/*       stringifycbuff(&cbuff[smax-sleft], field); \ */
814
 
/*       printf(WHO" - \"%s\"\n", &cbuff[smax-sleft]); \ */
815
 
/*     } else { \ */
816
 
/*       printf(WHO" - Name not decoded\n"); \ */
817
 
/*       break; \ */
818
 
/*     } \ */
819
 
/*     SKIP(ALIGN4(field)); \ */
820
 
/*     fsz-=(ALIGN4(field)); \ */
821
 
/*     if((int32_t)fsz<0) fsz=0; \ */
822
 
/*   } */
823
 
    
824
 
 
825
 
/* enum { T_INVALID, T_STRING, T_ARRAY, T_COMPRESSED, T_VERSION, T_VERSIONRANGE, T_DATE, T_TIME, T_DATETIME, T_UID, T_UNUSED, T_LANGUAGE, T_CONTENTS, T_CONTROLLER, T_INFO, T_SUPPORTEDLANGUAGES, T_SUPPORTEDOPTIONS, T_PREREQUISITES, T_DEPENDENCY, T_PROPERTIES, T_PROPERTY, T_SIGNATURES, T_CERTIFICATECHAIN, T_LOGO, T_FILEDESCRIPTION, T_HASH, T_IF, T_ELSEIF, T_INSTALLBLOCK, T_EXPRESSION, T_DATA, T_DATAUNIT, T_FILEDATA, T_SUPPORTEDOPTION, T_CONTROLLERCHECKSUM, T_DATACHECKSUM, T_SIGNATURE, T_BLOB, T_SIGNATUREALGORITHM, T_SIGNATURECERTIFICATECHAIN, T_DATAINDEX, T_CAPABILITIES, T_MAXVALUE, CUST_SKIP }; */
826
 
 
827
 
 
828
 
/* #define GETD(VAR) \ */
829
 
/*   if (cbuff) { \ */
830
 
/*     if (sleft<4) { \ */
831
 
/*       printf("Unespectedly reached end of compressed buffer\n"); \ */
832
 
/*       free(cbuff); \ */
833
 
/*       cbuff=NULL; \ */
834
 
/*       smax=sleft=0; \ */
835
 
/*     } else { \ */
836
 
/*       VAR = cli_readint32(&cbuff[smax-sleft]); \ */
837
 
/*       sleft-=4; \ */
838
 
/*     } \ */
839
 
/*   } else { \ */
840
 
/*     if (sleft<4) { \ */
841
 
/*       memcpy(buff, buff+smax-sleft, sleft); \ */
842
 
/*       if ((smax=fread(buff+sleft,1,BUFSIZ-sleft,f)+sleft)<4) { \ */
843
 
/*      printf("EOF\n"); \ */
844
 
/*      return -1; \ */
845
 
/*       } \ */
846
 
/*       sleft=smax; \ */
847
 
/*     } \ */
848
 
/*     VAR = cli_readint32(&buff[smax-sleft]); \ */
849
 
/*     sleft-=4; \ */
850
 
/*   } */
851
 
 
852
 
 
853
 
/* #define SKIP(N) \ */
854
 
/*   if (cbuff && sleft<=(N)) { \ */
855
 
/*     free(cbuff); \ */
856
 
/*     cbuff=NULL; \ */
857
 
/*     smax=sleft=0; \ */
858
 
/*   } \ */
859
 
/*   if (sleft>=(N)) sleft-=(N); \ */
860
 
/*   else { \ */
861
 
/*     if ((ssize_t)((N)-sleft)<0) { \ */
862
 
/*       printf("Refusing to seek back\n"); \ */
863
 
/*       return -1; \ */
864
 
/*     } \ */
865
 
/*     fseek(f, (N)-sleft, SEEK_CUR); \ */
866
 
/*     sleft=smax=fread(buff,1,BUFSIZ,f); \ */
867
 
/*   } */
868
 
 
869
 
/* #define RESEEK() \ */
870
 
/*   if (!cbuff) { \ */
871
 
/*     fseek(f, -(long)sleft, SEEK_CUR); \ */
872
 
/*     sleft=smax=fread(buff,1,BUFSIZ,f); \ */
873
 
/*   } */
874
 
 
875
 
 
876
 
/* #define GETSZ \ */
877
 
/*   GETD(fsz); \ */
878
 
/*   if(fsz>>31) { \ */
879
 
/*     printf("Size too big\n"); \ */
880
 
/*     return -1; \ */
881
 
/*   } */
882
 
 
883
 
/* #define GETSIZE(TREE) \ */
884
 
/*   GETD(fsz); \ */
885
 
/*   if(!fsz || (fsz>>31)) { \ */
886
 
/*     printf(TREE" - Wrong field size\n"); \ */
887
 
/*     goto SIS_ERROR; \ */
888
 
/*   } */
889
 
 
890
 
 
891
 
/* static void stringifycbuff(uint8_t *ptr, uint32_t len) { */
892
 
/*   uint32_t i; */
893
 
 
894
 
/*   if (len>400) len=400; */
895
 
/*   for(i = 0 ; i < len; i+=2) ptr[i/2] = ptr[i]; */
896
 
/*   ptr[i/2]='\0'; */
897
 
/*   return; */
898
 
/* } */
899
 
 
900
 
/* const char *sisfields[] = {"Invalid", "String", "Array", "Compressed", "Version", "VersionRange", "Date", "Time", "DateTime", "Uid", "Unused", "Language", "Contents", "Controller", "Info", "SupportedLanguages", "SupportedOptions", "Prerequisites", "Dependency", "Properties", "Property", "Signatures", "CertificateChain", "Logo", "FileDescription", "Hash", "If", "ElseIf", "InstallBlock", "Expression", "Data", "DataUnit", "FileData", "SupportedOption", "ControllerChecksum", "DataChecksum", "Signature", "Blob", "SignatureAlgorithm", "SignatureCertificateChain", "DataIndex", "Capabilities", "PLACEHOLDER"}; */
901
 
 
902
 
/* const char *sislangs[] = {"UNKNOWN", "UK English","French", "German", "Spanish", "Italian", "Swedish", "Danish", "Norwegian", "Finnish", "American", "Swiss French", "Swiss German", "Portuguese", "Turkish", "Icelandic", "Russian", "Hungarian", "Dutch", "Belgian Flemish", "Australian English", "Belgian French", "Austrian German", "New Zealand English", "International French", "Czech", "Slovak", "Polish", "Slovenian", "Taiwanese Chinese", "Hong Kong Chinese", "PRC Chinese", "Japanese", "Thai", "Afrikaans", "Albanian", "Amharic", "Arabic", "Armenian", "Tagalog", "Belarussian", "Bengali", "Bulgarian", "Burmese", "Catalan", "Croation", "Canadian English", "International English", "South African English", "Estonian", "Farsi", "Canadian French", "Gaelic", "Georgian", "Greek", "Cyprus Greek", "Gujarati", "Hebrew", "Hindi", "Indonesian", "Irish", "Swiss Italian", "Kannada", "Kazakh", "Kmer", "Korean", "Lao", "Latvian", "Lithuanian", "Macedonian", "Malay", "Malayalam", "Marathi", "Moldovian", "Mongolian", "Norwegian Nynorsk", "Brazilian Portuguese", "Punjabi", "Romanian", "Serbian", "Sinhalese", "Somali", "International Spanish", "American Spanish", "Swahili", "Finland Swedish", "Reserved", "Tamil", "Telugu", "Tibetan", "Tigrinya", "Cyprus Turkish", "Turkmen", "Ukrainian", "Urdu", "Reserved", "Vietnamese", "Welsh", "Zulu", "Other"}; */
903
 
/* #define MAXLANG (sizeof(sislangs)/sizeof(sislangs[0])) */
904
 
 
905
 
 
906
 
/* int main(int argc, char **argv) { */
907
 
/*   FILE *f = fopen(argv[1], "r"); */
908
 
/*   uint32_t uid[4]; */
909
 
/*   unsigned int i, sleft=0, smax=0, level=0; */
910
 
/*   uint8_t buff[BUFSIZ], *cbuff=NULL; */
911
 
/*   uint32_t field, fsz; */
912
 
/*   int ret = 0; */
913
 
 
914
 
/*   struct { */
915
 
/*     char tree[200]; */
916
 
/*     unsigned int next[200]; */
917
 
/*     unsigned int count; */
918
 
/*   } sstack; */
919
 
    
920
 
/*   const struct PIPPO { */
921
 
/*     uint32_t expect; */
922
 
/*     uint8_t optional; */
923
 
/*     uint8_t dir; */
924
 
/*     struct PIPPO *next; */
925
 
/*     char *what; */
926
 
/*   } s[] = { */
927
 
/*     { T_CONTENTS,                   0, 1, &s[1], ""}, */
928
 
/*     { T_CONTROLLERCHECKSUM,         1, 0, &s[2], ""}, */
929
 
/*     { T_DATACHECKSUM,               1, 0, &s[3], ""}, */
930
 
/*     { T_COMPRESSED,                 0, 1, &s[4], ""}, */
931
 
/*     { T_CONTROLLER,                 0, 1, &s[5], ""}, */
932
 
/*     { T_INFO,                       0, 1, &s[6], ""}, */
933
 
/*     { T_UID,                        0, 0, &s[7], "App UID"}, */
934
 
/*     { T_STRING,                     0, 0, &s[8], "Vendor name"}, */
935
 
/*     { T_ARRAY,                      0, 0, &s[9], "App names"}, */
936
 
/*     { T_ARRAY,                      0, 0, &s[10], "Vendor names"}, */
937
 
/*     { T_VERSION,                    0, 0, &s[11], "App Version"}, */
938
 
/*     { T_DATETIME,                   0, 0, &s[12], ""}, */
939
 
/*     { T_DATE,                       0, 0, &s[13], "Creation Date"}, */
940
 
/*     { T_TIME,                       0, 0, &s[14], "Creation Time"}, */
941
 
/*     { CUST_SKIP,                    4, 0, &s[15], ""}, */
942
 
/*     { T_SUPPORTEDOPTIONS,           0, 2, &s[16], ""}, */
943
 
/*     { T_SUPPORTEDLANGUAGES,         0, 1, &s[17], ""}, */
944
 
/*     { T_ARRAY,                      0, 0, &s[18], "Supported Languages"}, */
945
 
/*     { T_PREREQUISITES,              0, 2, &s[19], ""}, */
946
 
/*     { T_PROPERTIES,                 0, 0, &s[20], ""}, */
947
 
/*     { T_LOGO,                       1, 0, &s[21], ""}, */
948
 
/*     { T_INSTALLBLOCK,               0, 0, &s[22], ""}, */
949
 
/*     { T_SIGNATURECERTIFICATECHAIN,  1, 0, &s[23], ""}, */
950
 
/*     { T_DATAINDEX,                  0, 0, &s[24], ""}, */
951
 
/*     { T_DATA,                       0, 3, NULL, NULL} */
952
 
/*   }; */
953
 
/*   struct PIPPO *this; */
954
 
 
955
 
/*   struct { */
956
 
/*     struct PIPPO s; */
957
 
/*     uint32_t totalsize; */
958
 
/*     struct PIPPO *next; */
959
 
/*   } t_array; */
960
 
  
961
 
/*   GETD(uid[0]); */
962
 
/*   GETD(uid[1]); */
963
 
/*   GETD(uid[2]); */
964
 
/*   GETD(uid[3]); */
965
 
 
966
 
/*   printf("UIDS: %x %x %x - %x\n",uid[0],uid[1],uid[2],uid[3]); */
967
 
 
968
 
/*   sstack.next[0]=0; */
969
 
/*   sstack.count=0; */
970
 
 
971
 
/*   for (this=&s[0]; this; this=this->next) { */
972
 
/*     if(this->expect==CUST_SKIP) { */
973
 
/*       SKIP(this->optional); */
974
 
/*       continue; */
975
 
/*     } */
976
 
/*     if (this!=&t_array) { */
977
 
/*       GETD(field); */
978
 
/*       GETSIZE("FIXME"); */
979
 
/*     } else { */
980
 
/*       GETSIZE("FIXME"); */
981
 
/*       if (t_array.totalsize<=(ALIGN4(fsz)+4)) */
982
 
/*      this->next = t_array.next; */
983
 
/*       t_array.totalsize-=ALIGN4(fsz)+4; */
984
 
/*       field = this->expect; */
985
 
/*     } */
986
 
/*     if(field>=T_MAXVALUE) { */
987
 
/*       printf("Bogus field found\n"); */
988
 
/*       ret=-1; */
989
 
/*       break; */
990
 
/*     } */
991
 
/*     for( ; this && this->optional && this->expect!=field; this=this->next) */
992
 
/*       printf("Skipping optional state %s\n", sisfields[this->expect]); */
993
 
/*     if(!this) { */
994
 
/*       printf("Broken SIS file\n"); */
995
 
/*       break; */
996
 
/*     } */
997
 
/*     if(!this->optional && this->expect!=field) { */
998
 
/*       printf("Error: expecing %s but found %s\n", sisfields[this->expect], sisfields[field]); */
999
 
/*       goto SIS_ERROR; */
1000
 
/*     } */
1001
 
/*     printf("Got %s field (%d) with size %x(%u)\n", sisfields[field], field, fsz, fsz); */
1002
 
 
1003
 
/*     switch(this->dir) { */
1004
 
/*     case 1: /\* up *\/ */
1005
 
/*       strncpy(&sstack.tree[sstack.next[sstack.count]], sisfields[field], 200-sstack.next[sstack.count]); */
1006
 
/*       strncat(sstack.tree, ":", 200); */
1007
 
/*       sstack.count++; */
1008
 
/*       sstack.tree[199]='\0'; */
1009
 
/*       sstack.next[sstack.count]=strlen(sstack.tree); */
1010
 
/*       break; */
1011
 
/*     case 0: */
1012
 
/*       sstack.count--; */
1013
 
/*     default: */
1014
 
/*       sstack.count-=this->dir-1; */
1015
 
/*       strncpy(&sstack.tree[sstack.next[sstack.count]], sisfields[field], 200-sstack.next[sstack.count]); */
1016
 
/*       strncat(sstack.tree, ":", 200); */
1017
 
/*       sstack.tree[199]='\0'; */
1018
 
/*     } */
1019
 
 
1020
 
/*     printf("%s\n", sstack.tree); */
1021
 
 
1022
 
/*     switch(field) { */
1023
 
/*     case T_CONTENTS: */
1024
 
/*       continue; */
1025
 
/*     case T_CONTROLLERCHECKSUM: */
1026
 
/*       break; */
1027
 
/*     case T_DATACHECKSUM: */
1028
 
/*       break; */
1029
 
/*     case T_COMPRESSED: */
1030
 
/*       if(cbuff) { */
1031
 
/*      printf("Found nested compressed streams, aborting\n"); */
1032
 
/*      goto SIS_ERROR; */
1033
 
/*       } else { */
1034
 
/*      uint32_t method; */
1035
 
/*      uint32_t usize; */
1036
 
/*      uint32_t misc; */
1037
 
/*      int zresult; */
1038
 
/*      uint8_t *dbuff; */
1039
 
/*      uLongf uusize; */
1040
 
 
1041
 
/*      GETD(method); */
1042
 
/*      GETD(usize); */
1043
 
/*      GETD(misc); */
1044
 
/*      fsz-=12; */
1045
 
/*      if (misc) { */
1046
 
/*        printf("%s filesize too big\n", sstack.tree); */
1047
 
/*        goto SIS_ERROR; */
1048
 
/*      } */
1049
 
/*      printf("%s compression %d, size %d, usize %d\n", sstack.tree, method, fsz, usize); */
1050
 
/*      if(method) { */
1051
 
/*        fseek(f, -(long)sleft, SEEK_CUR); */
1052
 
/*        sleft=smax=0; */
1053
 
/*        uusize=usize; */
1054
 
/*        if(!(dbuff=malloc(ALIGN4(fsz)))) { */
1055
 
/*          printf("%s Out of memory\n", sstack.tree); */
1056
 
/*          goto SIS_ERROR; */
1057
 
/*        } */
1058
 
/*        if(!(cbuff=malloc(usize))) { */
1059
 
/*          free(dbuff); */
1060
 
/*          printf("%s Out of memory\n", sstack.tree); */
1061
 
/*          goto SIS_ERROR; */
1062
 
/*        } */
1063
 
/*        if (fread(dbuff,ALIGN4(fsz),1,f) != 1) { */
1064
 
/*          printf("%s Failed to read compressed data\n", sstack.tree); */
1065
 
/*          free(dbuff); */
1066
 
/*          goto SIS_ERROR; */
1067
 
/*        } */
1068
 
/*        zresult=uncompress(cbuff, &uusize, dbuff, fsz); */
1069
 
/*        free(dbuff); */
1070
 
/*        if (zresult!=Z_OK) { */
1071
 
/*          printf("%s Unpacking failure, skipping block\n", sstack.tree); */
1072
 
/*          goto SIS_ERROR; */
1073
 
/*        } */
1074
 
/*        if ((uLongf)usize != uusize) { */
1075
 
/*          printf("%s Expected size %lx but got %lx\n", sstack.tree, (uLongf)usize, uusize); */
1076
 
/*          goto SIS_ERROR; */
1077
 
/*        } */
1078
 
/*        smax=sleft=uusize; */
1079
 
/*        fwrite(cbuff, uusize, 1, fopen("/tmp/gunz", "w")); */
1080
 
/*      } */
1081
 
/*      continue; */
1082
 
/*       } */
1083
 
/*     case T_CONTROLLER: */
1084
 
/*       continue; */
1085
 
/*     case T_INFO: */
1086
 
/*       continue; */
1087
 
/*     case T_UID: */
1088
 
/*       GETD(field); */
1089
 
/*       fsz-=4; */
1090
 
/*       printf("%s %s = %x\n", sstack.tree, this->what, field); */
1091
 
/*       break; */
1092
 
/*     case T_STRING: */
1093
 
/*       RESEEK(); */
1094
 
/*       if(fsz && fsz<=sleft) { */
1095
 
/*      char *t=(cbuff)?&cbuff[smax-sleft]:&buff[smax-sleft]; */
1096
 
/*      stringifycbuff(t, fsz); */
1097
 
/*      printf("%s %s = \"%s\"\n", sstack.tree, this->what, t); */
1098
 
/*       } else printf("%s %s not decoded\n", sstack.tree, this->what); */
1099
 
/*       break; */
1100
 
/*     case T_ARRAY: */
1101
 
/*       GETD(field); */
1102
 
/*       fsz-=4; */
1103
 
/*       t_array.s.expect = field; */
1104
 
/*       t_array.s.optional = 0; */
1105
 
/*       t_array.s.dir = 0; */
1106
 
/*       t_array.s.next = &t_array; */
1107
 
/*       t_array.s.what = this->what; */
1108
 
/*       t_array.next = this->next; */
1109
 
/*       t_array.totalsize = ALIGN4(fsz); */
1110
 
/*       this = &t_array; */
1111
 
/*       continue; */
1112
 
/*     case T_VERSION: { */
1113
 
/*       uint32_t maj,min,bld; */
1114
 
/*       GETD(maj); */
1115
 
/*       GETD(min); */
1116
 
/*       GETD(bld); */
1117
 
/*       printf("%s %s = %u.%u.%u\n", sstack.tree, this->what, maj, min, bld); */
1118
 
/*       fsz-=12; */
1119
 
/*       break; */
1120
 
/*     } */
1121
 
/*     case T_DATETIME: */
1122
 
/*       continue; */
1123
 
/*     case T_DATE: */
1124
 
/*       GETD(field); */
1125
 
/*       fsz-=4; */
1126
 
/*       printf("%s %s = %u-%u-%u\n", sstack.tree, this->what, field&0xffff, (field>>16)&0xff, (field>>24)&0xff); */
1127
 
/*       break; */
1128
 
/*     case T_TIME: */
1129
 
/*       GETD(field); */
1130
 
/*       fsz-=4; /\* -1 aligns to 0 *\/ */
1131
 
/*       printf("%s %s = %u:%u:%u\n", sstack.tree, this->what, field&0xff, (field>>8)&0xff, (field>>16)&0xff); */
1132
 
/*       break; */
1133
 
/*     case T_SUPPORTEDOPTIONS: */
1134
 
/*       /\* FIXME: ANYTHING USEFUL HERE? *\/ */
1135
 
/*       break; */
1136
 
/*     case T_SUPPORTEDLANGUAGES: */
1137
 
/*       continue; */
1138
 
/*     case T_LANGUAGE: */
1139
 
/*       GETD(field); */
1140
 
/*       fsz-=4; */
1141
 
/*        printf("%s %s = \"%s\"\n", sstack.tree, this->what, field>=MAXLANG ? "Bad Language" : sislangs[field]); */
1142
 
/*        break; */
1143
 
/*     case T_PREREQUISITES: */
1144
 
/*       break; */
1145
 
/*     case T_PROPERTIES: */
1146
 
/*       break; */
1147
 
/*     case T_LOGO: */
1148
 
/*       break; */
1149
 
/*     case T_INSTALLBLOCK: */
1150
 
/*       break; */
1151
 
/*     case T_SIGNATURECERTIFICATECHAIN: */
1152
 
/*       t_array.s.expect = field; */
1153
 
/*       t_array.s.optional = 1; */
1154
 
/*       t_array.s.dir = 0; */
1155
 
/*       t_array.s.next = this; */
1156
 
/*       this = &t_array; */
1157
 
/*       break; */
1158
 
/*     case T_DATAINDEX: */
1159
 
/*       GETD(field); */
1160
 
/*       fsz-=4; */
1161
 
/*       printf("%s %s = %x\n", sstack.tree, this->what, field); */
1162
 
/*       if(cbuff) { */
1163
 
/*      if(ALIGN4(fsz) || sleft) */
1164
 
/*        printf("Trailing garbage found in compressed controller\n"); */
1165
 
/*      fsz=sleft=smax=0; */
1166
 
/*      free(cbuff); */
1167
 
/*      cbuff=NULL; */
1168
 
/*       } */
1169
 
/*       break; */
1170
 
/*     default: */
1171
 
/*       printf("Error: unhandled field %d\n", field); */
1172
 
/*       goto SIS_ERROR; */
1173
 
/*     } */
1174
 
/*     SKIP(ALIGN4(fsz)); */
1175
 
/*   } */
1176
 
/*   return 0; */
1177
 
 
1178
 
/*   SIS_ERROR: */
1179
 
/*   if(cbuff) free(cbuff); */
1180
 
/*   fclose(f); */
1181
 
/*   return 0; */
1182
 
/* } */
1183
 
 
 
685
#endif /* HAVE_MMAP */