deb_extractor.c (13041B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2002, 2003, 2004, 2012 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/deb_extractor.c 22 * @brief plugin to support Debian archives 23 * @author Christian Grothoff 24 * 25 * The .deb is an ar-chive file. It contains a tar.gz file 26 * named "control.tar.gz" which then contains a file 'control' 27 * that has the meta-data. And which variant of the various 28 * ar file formats is used is also not quite certain. Yuck. 29 * 30 * References: 31 * http://www.mkssoftware.com/docs/man4/tar.4.asp 32 * http://lists.debian.org/debian-policy/2003/12/msg00000.html 33 * http://www.opengroup.org/onlinepubs/009695399/utilities/ar.html 34 */ 35 #include "platform.h" 36 #include "extractor.h" 37 #include <zlib.h> 38 39 40 /** 41 * Maximum file size we allow for control.tar.gz files. 42 * This is a sanity check to avoid allocating huge amounts 43 * of memory. 44 */ 45 #define MAX_CONTROL_SIZE (1024 * 1024) 46 47 48 /** 49 * Re-implementation of 'strndup'. 50 * 51 * @param str string to duplicate 52 * @param n maximum number of bytes to copy 53 * @return NULL on error, otherwise 0-terminated copy of 'str' 54 * with at most n characters 55 */ 56 static char * 57 stndup (const char *str, size_t n) 58 { 59 char *tmp; 60 61 if (NULL == (tmp = malloc (n + 1))) 62 return NULL; 63 tmp[n] = '\0'; 64 memcpy (tmp, str, n); 65 return tmp; 66 } 67 68 69 /** 70 * Entry in the mapping from control data to LE types. 71 */ 72 struct Matches 73 { 74 /** 75 * Key in the Debian control file. 76 */ 77 const char *text; 78 79 /** 80 * Corresponding type in LE. 81 */ 82 enum EXTRACTOR_MetaType type; 83 }; 84 85 86 /** 87 * Map from deb-control entries to LE types. 88 * 89 * see also: "man 5 deb-control" 90 */ 91 static struct Matches tmap[] = { 92 {"Package: ", EXTRACTOR_METATYPE_PACKAGE_NAME}, 93 {"Version: ", EXTRACTOR_METATYPE_PACKAGE_VERSION}, 94 {"Section: ", EXTRACTOR_METATYPE_SECTION}, 95 {"Priority: ", EXTRACTOR_METATYPE_UPLOAD_PRIORITY}, 96 {"Architecture: ", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE}, 97 {"Depends: ", EXTRACTOR_METATYPE_PACKAGE_DEPENDENCY}, 98 {"Recommends: ", EXTRACTOR_METATYPE_PACKAGE_RECOMMENDS}, 99 {"Suggests: ", EXTRACTOR_METATYPE_PACKAGE_SUGGESTS}, 100 {"Installed-Size: ",EXTRACTOR_METATYPE_PACKAGE_INSTALLED_SIZE}, 101 {"Maintainer: ", EXTRACTOR_METATYPE_PACKAGE_MAINTAINER}, 102 {"Description: ", EXTRACTOR_METATYPE_DESCRIPTION}, 103 {"Source: ", EXTRACTOR_METATYPE_PACKAGE_SOURCE}, 104 {"Pre-Depends: ", EXTRACTOR_METATYPE_PACKAGE_PRE_DEPENDENCY}, 105 {"Conflicts: ", EXTRACTOR_METATYPE_PACKAGE_CONFLICTS}, 106 {"Replaces: ", EXTRACTOR_METATYPE_PACKAGE_REPLACES}, 107 {"Provides: ", EXTRACTOR_METATYPE_PACKAGE_PROVIDES}, 108 {"Essential: ", EXTRACTOR_METATYPE_PACKAGE_ESSENTIAL}, 109 {NULL, 0} 110 }; 111 112 113 /** 114 * Process the "control" file from the control.tar.gz 115 * 116 * @param data decompressed control data 117 * @param size number of bytes in data 118 * @param proc function to call with meta data 119 * @param proc_cls closure for 'proc' 120 * @return 0 to continue extracting, 1 if we are done 121 */ 122 static int 123 processControl (const char *data, 124 const size_t size, 125 EXTRACTOR_MetaDataProcessor proc, 126 void *proc_cls) 127 { 128 size_t pos; 129 char *key; 130 char *val; 131 size_t colon; 132 size_t eol; 133 unsigned int i; 134 135 pos = 0; 136 while (pos < size) 137 { 138 for (colon = pos; colon < size; colon++) 139 if ((':' == data[colon]) || ('\n' == data[colon])) 140 break; 141 if ((colon >= size) || (':' != data[colon])) 142 return 0; 143 colon++; 144 while ((colon < size) && (isspace ((unsigned char) data[colon]))) 145 colon++; 146 eol = colon; 147 while ((eol < size) && 148 (('\n' != data[eol]) || 149 ((eol + 1 < size) && (' ' == data[eol + 1])))) 150 eol++; 151 if ((eol == colon) || (eol > size)) 152 return 0; 153 if (NULL == (key = stndup (&data[pos], colon - pos))) 154 return 0; 155 for (i = 0; NULL != tmap[i].text; i++) 156 { 157 if (0 != strcmp (key, tmap[i].text)) 158 continue; 159 if (NULL == (val = stndup (&data[colon], eol - colon))) 160 { 161 free (key); 162 return 0; 163 } 164 if (0 != proc (proc_cls, 165 "deb", 166 tmap[i].type, 167 EXTRACTOR_METAFORMAT_UTF8, 168 "text/plain", 169 val, 170 strlen (val) + 1)) 171 { 172 free (val); 173 free (key); 174 return 1; 175 } 176 free (val); 177 break; 178 } 179 free (key); 180 pos = eol + 1; 181 } 182 return 0; 183 } 184 185 186 /** 187 * Header of an entry in a TAR file. 188 */ 189 struct TarHeader 190 { 191 /** 192 * Filename. 193 */ 194 char name[100]; 195 196 /** 197 * File access modes. 198 */ 199 char mode[8]; 200 201 /** 202 * Owner of the file. 203 */ 204 char userId[8]; 205 206 /** 207 * Group of the file. 208 */ 209 char groupId[8]; 210 211 /** 212 * Size of the file, in octal. 213 */ 214 char filesize[12]; 215 216 /** 217 * Last modification time. 218 */ 219 char lastModTime[12]; 220 221 /** 222 * Checksum of the file. 223 */ 224 char chksum[8]; 225 226 /** 227 * Is the file a link? 228 */ 229 char link; 230 231 /** 232 * Destination of the link. 233 */ 234 char linkName[100]; 235 }; 236 237 238 /** 239 * Extended TAR header for USTar format. 240 */ 241 struct USTarHeader 242 { 243 /** 244 * Original TAR header. 245 */ 246 struct TarHeader tar; 247 248 /** 249 * Additinal magic for USTar. 250 */ 251 char magic[6]; 252 253 /** 254 * Format version. 255 */ 256 char version[2]; 257 258 /** 259 * User name. 260 */ 261 char uname[32]; 262 263 /** 264 * Group name. 265 */ 266 char gname[32]; 267 268 /** 269 * Device major number. 270 */ 271 char devmajor[8]; 272 273 /** 274 * Device minor number. 275 */ 276 char devminor[8]; 277 278 /** 279 * Unknown (padding?). 280 */ 281 char prefix[155]; 282 }; 283 284 285 /** 286 * Process the control.tar file. 287 * 288 * @param data the deflated control.tar file data 289 * @param size number of bytes in data 290 * @param proc function to call with meta data 291 * @param proc_cls closure for 'proc' 292 * @return 0 to continue extracting, 1 if we are done 293 */ 294 static int 295 processControlTar (const char *data, 296 size_t size, 297 EXTRACTOR_MetaDataProcessor proc, 298 void *proc_cls) 299 { 300 struct TarHeader *tar; 301 struct USTarHeader *ustar; 302 size_t pos; 303 304 pos = 0; 305 while (pos + sizeof (struct TarHeader) < size) 306 { 307 unsigned long long fsize; 308 char buf[13]; 309 310 tar = (struct TarHeader *) &data[pos]; 311 if (pos + sizeof (struct USTarHeader) < size) 312 { 313 ustar = (struct USTarHeader *) &data[pos]; 314 if (0 == strncmp ("ustar", &ustar->magic[0], strlen ("ustar"))) 315 pos += 512; /* sizeof (struct USTarHeader); */ 316 else 317 pos += 257; /* sizeof (struct TarHeader); minus gcc alignment... */ 318 } 319 else 320 { 321 pos += 257; /* sizeof (struct TarHeader); minus gcc alignment... */ 322 } 323 324 memcpy (buf, &tar->filesize[0], 12); 325 buf[12] = '\0'; 326 if (1 != sscanf (buf, "%12llo", &fsize)) /* octal! Yuck yuck! */ 327 return 0; 328 if ((pos + fsize > size) || (fsize > size) || (pos + fsize < pos)) 329 return 0; 330 331 if (0 == strncmp (&tar->name[0], "./control", strlen ("./control"))) 332 { 333 /* found the 'control' file we were looking for */ 334 return processControl (&data[pos], fsize, proc, proc_cls); 335 } 336 if (0 != (fsize & 511)) 337 fsize = (fsize | 511) + 1; /* round up! */ 338 if (pos + fsize < pos) 339 return 0; 340 pos += fsize; 341 } 342 return 0; 343 } 344 345 346 /** 347 * Process the control.tar.gz file. 348 * 349 * @param ec extractor context with control.tar.gz at current read position 350 * @param size number of bytes in the control file 351 * @return 0 to continue extracting, 1 if we are done 352 */ 353 static int 354 processControlTGZ (struct EXTRACTOR_ExtractContext *ec, 355 unsigned long long size) 356 { 357 uint32_t bufSize; 358 char *buf; 359 void *data; 360 unsigned char *cdata; 361 z_stream strm; 362 int ret; 363 ssize_t sret; 364 unsigned long long off; 365 366 if (size > MAX_CONTROL_SIZE) 367 return 0; 368 if (0 == size) 369 return 0; 370 if (size < 4) 371 return 0; 372 if (NULL == (cdata = malloc (size))) 373 return 0; 374 off = 0; 375 while (off < size) 376 { 377 if (0 >= (sret = ec->read (ec->cls, 378 &data, 379 size - off))) 380 { 381 free (cdata); 382 return 0; 383 } 384 memcpy (&cdata[off], 385 data, 386 sret); 387 off += sret; 388 } 389 /* The top byte must be widened before it is shifted: `unsigned char' 390 promotes to `int', and 0x80 << 24 overflows a 32 bit int. */ 391 bufSize = ((uint32_t) cdata[size - 4]) 392 + (((uint32_t) cdata[size - 3]) << 8) 393 + (((uint32_t) cdata[size - 2]) << 16) 394 + (((uint32_t) cdata[size - 1]) << 24); 395 if (bufSize > MAX_CONTROL_SIZE) 396 { 397 free (cdata); 398 return 0; 399 } 400 if (NULL == (buf = malloc (bufSize))) 401 { 402 free (cdata); 403 return 0; 404 } 405 ret = 0; 406 memset (&strm, 407 0, 408 sizeof (z_stream)); 409 strm.next_in = (Bytef *) cdata; 410 strm.avail_in = size; 411 if (Z_OK == 412 inflateInit2 (&strm, 413 15 + 32)) 414 { 415 strm.next_out = (Bytef *) buf; 416 strm.avail_out = bufSize; 417 inflate (&strm, 418 Z_FINISH); 419 if (strm.total_out > 0) 420 ret = processControlTar (buf, 421 strm.total_out, 422 ec->proc, 423 ec->cls); 424 inflateEnd (&strm); 425 } 426 free (buf); 427 free (cdata); 428 return ret; 429 } 430 431 432 /** 433 * Header of an object in an "AR"chive file. 434 */ 435 struct ObjectHeader 436 { 437 /** 438 * Name of the file. 439 */ 440 char name[16]; 441 442 /** 443 * Last modification time for the file. 444 */ 445 char lastModTime[12]; 446 447 /** 448 * User ID of the owner. 449 */ 450 char userId[6]; 451 452 /** 453 * Group ID of the owner. 454 */ 455 char groupId[6]; 456 457 /** 458 * File access modes. 459 */ 460 char modeInOctal[8]; 461 462 /** 463 * Size of the file (as decimal string) 464 */ 465 char filesize[10]; 466 467 /** 468 * Tailer of the object header ("`\n") 469 */ 470 char trailer[2]; 471 }; 472 473 474 /** 475 * Main entry method for the DEB extraction plugin. 476 * 477 * @param ec extraction context provided to the plugin 478 */ 479 void 480 EXTRACTOR_deb_extract_method (struct EXTRACTOR_ExtractContext *ec); 481 482 void 483 EXTRACTOR_deb_extract_method (struct EXTRACTOR_ExtractContext *ec) 484 { 485 uint64_t pos; 486 int done = 0; 487 struct ObjectHeader hdrbuf; 488 const struct ObjectHeader *hdr; 489 uint64_t fsize; 490 unsigned long long csize; 491 char buf[11]; 492 void *data; 493 494 fsize = ec->get_size (ec->cls); 495 if (fsize < 128) 496 return; 497 if (8 != 498 ec->read (ec->cls, &data, 8)) 499 return; 500 if (0 != strncmp ("!<arch>\n", data, 8)) 501 return; 502 pos = 8; 503 while (pos + sizeof (struct ObjectHeader) < fsize) 504 { 505 if (pos != 506 ec->seek (ec->cls, pos, SEEK_SET)) 507 return; 508 if (sizeof (struct ObjectHeader) != 509 ec->read (ec->cls, &data, sizeof (struct ObjectHeader))) 510 return; 511 /* The pointer read() returns addresses the shared memory window and 512 is only valid until the next read() or seek() slides it. 513 processControlTGZ() below does both, so take a copy of the object 514 header now instead of dereferencing it again afterwards. */ 515 memcpy (&hdrbuf, data, sizeof (hdrbuf)); 516 hdr = &hdrbuf; 517 if (0 != strncmp (&hdr->trailer[0], "`\n", 2)) 518 return; 519 memcpy (buf, &hdr->filesize[0], 10); 520 buf[10] = '\0'; 521 if (1 != sscanf (buf, "%10llu", &csize)) 522 return; 523 pos += sizeof (struct ObjectHeader); 524 if ((pos + csize > fsize) || (csize > fsize) || (pos + csize < pos)) 525 return; 526 if (0 == strncmp (&hdr->name[0], 527 "control.tar.gz", 528 strlen ("control.tar.gz"))) 529 { 530 if (0 != processControlTGZ (ec, 531 csize)) 532 return; 533 done++; 534 } 535 if (0 == strncmp (&hdr->name[0], 536 "debian-binary", strlen ("debian-binary"))) 537 { 538 if (0 != ec->proc (ec->cls, 539 "deb", 540 EXTRACTOR_METATYPE_MIMETYPE, 541 EXTRACTOR_METAFORMAT_UTF8, 542 "text/plain", 543 "application/x-debian-package", 544 strlen ("application/x-debian-package") + 1)) 545 return; 546 done++; 547 } 548 pos += csize; 549 if (2 == done) 550 break; /* no need to process the rest of the archive */ 551 } 552 } 553 554 555 /* end of deb_extractor.c */