1 /*
2 * Copyright (c) 2005 Michael Schroeder (mls@suse.de)
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <fcntl.h>
14
15 #include <bzlib.h>
16 #include <zlib.h>
17 #include <lzma.h>
18 #include <sys/stat.h>
19
20 #include "util.h"
21 #include "md5.h"
22 #include "rpmhead.h"
23 #include "cfile.h"
24 #include "deltarpm.h"
25
26 /*****************************************************************
27 * fileblock handling, maintain everything we want to know about the
28 * filelist
29 *
30 */
31
32 int
headtofb(struct rpmhead * h,struct fileblock * fb)33 headtofb(struct rpmhead *h, struct fileblock *fb)
34 {
35 unsigned int *digestalgoarray;
36 fb->h = h;
37 fb->filelinktos = fb->filemd5s = 0;
38 fb->filemodes = fb->filesizes = 0;
39 fb->filenames = headexpandfilelist(h, &fb->cnt);
40 if (!fb->filenames)
41 {
42 fb->cnt = 0;
43 return 0;
44 }
45 fb->filemodes = headint16(h, TAG_FILEMODES, (int *)0);
46 fb->filesizes = headint32(h, TAG_FILESIZES, (int *)0);
47 fb->filerdevs = headint16(h, TAG_FILERDEVS, (int *)0);
48 fb->filelinktos = headstringarray(h, TAG_FILELINKTOS, (int *)0);
49 fb->filemd5s = headstringarray(h, TAG_FILEMD5S, (int *)0);
50 fb->digestalgo = 1;
51 if ((digestalgoarray = headint32(h, TAG_FILEDIGESTALGO, (int *)0)))
52 {
53 fb->digestalgo = digestalgoarray[0];
54 free(digestalgoarray);
55 }
56 if (fb->digestalgo != 1 && fb->digestalgo != 8)
57 {
58 fprintf(stderr, "Unknown digest type: %d\n", fb->digestalgo);
59 exit(1);
60 }
61 return 0;
62 }
63
64 /*****************************************************************
65 * sequence handling, uncompress the sequence string, check if
66 * it matches the installed rpm header, check files if requested.
67 */
68
69 struct seqdescr *
expandseq(unsigned char * seq,int seql,int * nump,struct fileblock * fb,int (* checkfunc)(char *,int,unsigned char *,unsigned int))70 expandseq(unsigned char *seq, int seql, int *nump, struct fileblock *fb, int (*checkfunc)(char *, int, unsigned char *, unsigned int))
71 {
72 unsigned char *s;
73 char *fn;
74 int *res;
75 int i, n, n2, num, nib, shi, tog, jump, pos;
76 unsigned int rdev, lsize;
77 MD5_CTX seqmd5;
78 unsigned char seqmd5res[16];
79 struct seqdescr *sd;
80 drpmuint off;
81 unsigned char fmd5[32];
82 int error = 0;
83
84 n = num = nib = shi = jump = pos = 0;
85 tog = 1;
86
87 res = xmalloc2(fb->cnt, sizeof(unsigned int));
88 seql -= 16;
89 for (i = 0, s = seq + 16; i < seql; )
90 {
91 if (!nib)
92 n2 = (*s >> 4);
93 else
94 {
95 n2 = (*s & 0x0f);
96 s++;
97 i++;
98 }
99 nib ^= 1;
100 if (n2 & 8)
101 {
102 n2 ^= 8;
103 if (shi)
104 n2 <<= shi;
105 n |= n2;
106 shi += 3;
107 continue;
108 }
109 if (shi)
110 n2 <<= shi;
111 shi = 0;
112 n2 |= n;
113 n = 0;
114 if (jump)
115 {
116 jump = 0;
117 pos = n2;
118 tog = 1;
119 continue;
120 }
121 if (n2 == 0)
122 {
123 jump = 1;
124 continue;
125 }
126 if (!tog)
127 {
128 pos += n2;
129 tog = 1;
130 continue;
131 }
132 for (; n2 > 0; n2--)
133 {
134 if (num >= fb->cnt || pos >= fb->cnt)
135 {
136 fprintf(stderr, "corrupt delta: bad sequence\n");
137 exit(1);
138 }
139 res[num++] = pos++;
140 }
141 tog = 0;
142 }
143 if (shi)
144 {
145 fprintf(stderr, "corrupt delta: bad sequence\n");
146 exit(1);
147 }
148 res = xrealloc2(res, num, sizeof(unsigned int));
149 sd = xmalloc2(num + 1, sizeof(*sd));
150 if (nump)
151 *nump = num + 1;
152 rpmMD5Init(&seqmd5);
153 off = 0;
154 for (n = 0; n < num; n++)
155 {
156 i = sd[n].i = res[n];
157 lsize = rdev = 0;
158 if (S_ISREG(fb->filemodes[i]))
159 lsize = fb->filesizes[i];
160 else if (S_ISLNK(fb->filemodes[i]))
161 lsize = strlen(fb->filelinktos[i]);
162 if (S_ISBLK(fb->filemodes[i]) || S_ISCHR(fb->filemodes[i]))
163 rdev = fb->filerdevs[i];
164 fn = fb->filenames[i];
165 if (*fn == '/')
166 fn++;
167 rpmMD5Update(&seqmd5, (unsigned char *)fn, strlen(fn) + 1);
168 rpmMD5Update32(&seqmd5, fb->filemodes[i]);
169 rpmMD5Update32(&seqmd5, lsize);
170 rpmMD5Update32(&seqmd5, rdev);
171 sd[n].cpiolen = 110 + 2 + strlen(fn) + 1;
172 if (sd[n].cpiolen & 3)
173 sd[n].cpiolen += 4 - (sd[n].cpiolen & 3);
174 sd[n].datalen = lsize;
175 if (sd[n].datalen & 3)
176 sd[n].datalen += 4 - (sd[n].datalen & 3);
177 if (S_ISLNK(fb->filemodes[i]))
178 rpmMD5Update(&seqmd5, (unsigned char *)fb->filelinktos[i], strlen(fb->filelinktos[i]) + 1);
179 else if (S_ISREG(fb->filemodes[i]) && lsize)
180 {
181 if (fb->digestalgo == 1)
182 parsemd5(fb->filemd5s[i], fmd5);
183 else
184 parsesha256(fb->filemd5s[i], fmd5);
185 if (checkfunc && checkfunc(fb->filenames[i], fb->digestalgo, fmd5, lsize))
186 error = 1;
187 if (fb->digestalgo == 1)
188 rpmMD5Update(&seqmd5, fmd5, 16);
189 else
190 rpmMD5Update(&seqmd5, fmd5, 32);
191 }
192 sd[n].off = off;
193 off += sd[n].cpiolen + sd[n].datalen;
194 sd[n].f = 0;
195 }
196 sd[n].i = -1;
197 sd[n].cpiolen = 124;
198 sd[n].datalen = 0;
199 sd[n].off = off;
200 sd[n].f = 0;
201 rpmMD5Final(seqmd5res, &seqmd5);
202 free(res);
203 if (memcmp(seqmd5res, seq, 16) || error)
204 {
205 fprintf(stderr, "delta does not match installed data\n");
206 exit(1);
207 }
208 return sd;
209 }
210
bzread4(struct cfile * bfp)211 static unsigned int bzread4(struct cfile *bfp)
212 {
213 unsigned char d[4];
214 if (bfp->read(bfp, d, 4) != 4)
215 {
216 perror("bzread4 error");
217 exit(1);
218 }
219 return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
220 }
221
222 void
readdeltarpm(char * n,struct deltarpm * d,struct cfile ** cfp)223 readdeltarpm(char *n, struct deltarpm *d, struct cfile **cfp)
224 {
225 int dfd;
226 struct cfile *bfp;
227 unsigned int nevrl;
228 drpmuint off;
229 int i;
230
231 memset((char *)d, 0, sizeof(*d));
232 d->name = n;
233 if (!strcmp(n, "-"))
234 dfd = 0;
235 else if ((dfd = open(n, O_RDONLY)) < 0)
236 {
237 perror(n);
238 exit(1);
239 }
240 if (xread(dfd, d->rpmlead, 12) != 12)
241 {
242 fprintf(stderr, "%s: not a delta rpm\n", n);
243 exit(1);
244 }
245 if (d->rpmlead[0] == 'd' && d->rpmlead[1] == 'r' && d->rpmlead[2] == 'p' && d->rpmlead[3] == 'm')
246 {
247 unsigned char *p;
248 d->version = (d->rpmlead[4] << 24) | (d->rpmlead[5] << 16) | (d->rpmlead[6] << 8) | d->rpmlead[7];
249 if ((d->version & 0xffffff00) != 0x444c5400)
250 {
251 fprintf(stderr, "%s: not a delta rpm\n", n);
252 exit(1);
253 }
254 if (d->version != 0x444c5431 && d->version != 0x444c5432 && d->version != 0x444c5433)
255 {
256 fprintf(stderr, "%s: unsupported version: %c\n", n, (d->version & 255));
257 exit(1);
258 }
259 nevrl = (d->rpmlead[8] << 24) | (d->rpmlead[9] << 16) | (d->rpmlead[10] << 8) | d->rpmlead[11];
260 d->targetnevr = xmalloc(nevrl + 4); /* also room for 4 bytes addblklen */
261 if (xread(dfd, d->targetnevr, nevrl + 4) != nevrl + 4)
262 {
263 fprintf(stderr, "%s: read error add data\n", n);
264 exit(1);
265 }
266 p = (unsigned char *)d->targetnevr + nevrl;
267 d->addblklen = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
268 d->targetnevr[nevrl] = 0;
269 if (d->addblklen)
270 {
271 d->addblk = xmalloc(d->addblklen);
272 if (xread(dfd, d->addblk, d->addblklen) != d->addblklen)
273 {
274 fprintf(stderr, "%s: read error add data\n", n);
275 exit(1);
276 }
277 }
278 d->h = 0;
279 if ((bfp = cfile_open(CFILE_OPEN_RD, dfd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
280 {
281 fprintf(stderr, "%s: payload open failed\n", n);
282 exit(1);
283 }
284 }
285 else
286 {
287 if (d->rpmlead[0] != 0xed || d->rpmlead[1] != 0xab || d->rpmlead[2] != 0xee || d->rpmlead[3] != 0xdb)
288 {
289 fprintf(stderr, "%s: not a delta rpm\n", n);
290 exit(1);
291 }
292 if (xread(dfd, d->rpmlead + 12, 96 - 12) != 96 - 12)
293 {
294 fprintf(stderr, "%s: not a delta rpm\n", n);
295 exit(1);
296 }
297 if (d->rpmlead[4] != 0x03 || d->rpmlead[0x4e] != 0 || d->rpmlead[0x4f] != 5)
298 {
299 fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", n);
300 exit(1);
301 }
302 d->h = readhead(dfd, 1);
303 if (!d->h)
304 {
305 fprintf(stderr, "%s: could not read signature header\n", n);
306 exit(1);
307
308 }
309 free(d->h);
310 d->h = readhead(dfd, 0);
311 if (!d->h)
312 {
313 fprintf(stderr, "%s: could not read header\n", n);
314 exit(1);
315 }
316 d->targetnevr = headtonevr(d->h);
317 if ((bfp = cfile_open(CFILE_OPEN_RD, dfd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
318 {
319 fprintf(stderr, "%s: payload open failed\n", n);
320 exit(1);
321 }
322 d->addblklen = 0;
323 }
324 d->deltacomp = bfp->comp;
325 d->version = bzread4(bfp);
326 if ((d->version & 0xffffff00) != 0x444c5400)
327 {
328 fprintf(stderr, "%s: not a delta rpm\n", n);
329 exit(1);
330 }
331 if (d->version != 0x444c5431 && d->version != 0x444c5432 && d->version != 0x444c5433)
332 {
333 fprintf(stderr, "%s: unsupported version: %c\n", n, (d->version & 255));
334 exit(1);
335 }
336 if (!d->h && d->version < 0x444c5433)
337 {
338 fprintf(stderr, "%s: rpm only deltarpm with old version\n", n);
339 exit(1);
340 }
341 nevrl = bzread4(bfp);
342 d->nevr = xmalloc(nevrl + 1);
343 d->nevr[nevrl] = 0;
344 if (bfp->read(bfp, d->nevr, nevrl) != nevrl)
345 {
346 fprintf(stderr, "%s: read error nevr\n", n);
347 exit(1);
348 }
349 d->seql = bzread4(bfp);
350 if (d->seql < 16)
351 {
352 fprintf(stderr, "%s: corrupt delta\n", n);
353 exit(1);
354 }
355 d->seq = xmalloc(d->seql);
356 if (bfp->read(bfp, d->seq, d->seql) != d->seql)
357 {
358 fprintf(stderr, "%s: read error seq\n", n);
359 exit(1);
360 }
361 if (bfp->read(bfp, d->targetmd5, 16) != 16)
362 {
363 fprintf(stderr, "%s: read error md5\n", n);
364 exit(1);
365 }
366 d->targetcomppara = 0;
367 d->offadjn = 0;
368 d->offadjs = 0;
369 if (d->version != 0x444c5431)
370 {
371 d->targetsize = bzread4(bfp);
372 d->targetcomp = bzread4(bfp);
373 d->targetcompparalen = bzread4(bfp);
374 if (d->targetcompparalen)
375 {
376 d->targetcomppara = xmalloc(d->targetcompparalen);
377 if (bfp->read(bfp, d->targetcomppara, d->targetcompparalen) != d->targetcompparalen)
378 {
379 fprintf(stderr, "%s: read error comppara\n", n);
380 exit(1);
381 }
382 }
383 if (d->version != 0x444c5432)
384 {
385 d->compheadlen = bzread4(bfp);
386 d->offadjn = bzread4(bfp);
387 d->offadjs = 0;
388 if (d->offadjn)
389 {
390 d->offadjs = xmalloc2(d->offadjn, 2 * sizeof(unsigned int));
391 for (i = 0; i < d->offadjn; i++)
392 d->offadjs[2 * i] = bzread4(bfp);
393 for (i = 0; i < d->offadjn; i++)
394 {
395 unsigned int a = bzread4(bfp);
396 if ((a & 0x80000000) != 0)
397 a = (unsigned int)(-(int)(a ^ 0x80000000));
398 d->offadjs[2 * i + 1] = a;
399 }
400 }
401 }
402 }
403 else
404 {
405 char *compressor = headstring(d->h, TAG_PAYLOADCOMPRESSOR);
406 if (compressor && !strcmp(compressor, "lzma"))
407 d->targetcomp = CFILE_COMP_LZMA;
408 else if (compressor && !strcmp(compressor, "bzip2"))
409 d->targetcomp = CFILE_COMP_BZ;
410 else
411 d->targetcomp = CFILE_COMP_GZ;
412 d->targetsize = 0;
413 d->targetcompparalen = 0;
414 }
415 d->leadl = bzread4(bfp);
416 if (d->leadl < 96 + 16)
417 {
418 fprintf(stderr, "%s: corrupt delta\n", n);
419 exit(1);
420 }
421 d->lead = xmalloc(d->leadl);
422 if (bfp->read(bfp, d->lead, d->leadl) != d->leadl)
423 {
424 fprintf(stderr, "%s: read error lead\n", n);
425 exit(1);
426 }
427 d->payformatoff = bzread4(bfp);
428 if (d->h && d->payformatoff > d->h->dcnt - 4)
429 {
430 fprintf(stderr, "%s: bad payformat offset\n", n);
431 exit(1);
432 }
433 d->inn = bzread4(bfp);
434 d->outn = bzread4(bfp);
435 d->in = xmalloc2(d->inn, 2 * sizeof(unsigned int));
436 d->out = xmalloc2(d->outn, 2 * sizeof(unsigned int));
437 d->paylen = 0;
438 for (i = 0; i < d->inn; i++)
439 d->in[2 * i] = bzread4(bfp);
440 for (i = 0; i < d->inn; i++)
441 {
442 d->in[2 * i + 1] = bzread4(bfp);
443 d->paylen += d->in[2 * i + 1];
444 }
445 for (i = 0; i < d->outn; i++)
446 d->out[2 * i] = bzread4(bfp);
447 for (i = 0; i < d->outn; i++)
448 {
449 d->out[2 * i + 1] = bzread4(bfp);
450 d->paylen += d->out[2 * i + 1];
451 }
452
453 d->outlen = 0;
454 if (d->version > 0x444c5432)
455 {
456 #ifdef DELTARPM_64BIT
457 d->outlen = (drpmuint)bzread4(bfp) << 32;
458 #else
459 if (bzread4(bfp) != 0)
460 {
461 fprintf(stderr, "%s: deltarpm needs support for archives > 4GB\n", n);
462 exit(1);
463 }
464 #endif
465 }
466 d->outlen |= bzread4(bfp);
467 if (d->addblklen)
468 {
469 if (bzread4(bfp))
470 {
471 fprintf(stderr, "%s: two add data blocks\n", n);
472 exit(1);
473 }
474 }
475 else
476 {
477 d->addblklen = bzread4(bfp);
478 if (d->addblklen)
479 {
480 d->addblk = xmalloc(d->addblklen);
481 if (bfp->read(bfp, d->addblk, d->addblklen) != d->addblklen)
482 {
483 fprintf(stderr, "%s: read error add data\n", n);
484 exit(1);
485 }
486 }
487 }
488 d->inlen = 0;
489 if (d->version > 0x444c5432)
490 {
491 #ifdef DELTARPM_64BIT
492 d->inlen = (drpmuint)bzread4(bfp) << 32;
493 #else
494 if (bzread4(bfp) != 0)
495 {
496 fprintf(stderr, "%s: deltarpm needs support for archives > 4GB\n", n);
497 exit(1);
498 }
499 #endif
500 }
501 d->inlen |= bzread4(bfp);
502 if (cfp)
503 *cfp = bfp;
504 else
505 {
506 d->indata = xmalloc(d->inlen);
507 if (bfp->read(bfp, d->indata, d->inlen) != d->inlen)
508 {
509 fprintf(stderr, "%s: read error deltarpm data\n", n);
510 exit(1);
511 }
512 bfp->close(bfp);
513 }
514 off = 0;
515 for (i = 0; i < d->inn; i++)
516 {
517 off += d->in[2 * i + 1];
518 if (off > d->inlen)
519 {
520 fprintf(stderr, "%s: corrupt delta instructions\n", n);
521 exit(1);
522 }
523 }
524 off = 0;
525 for (i = 0; i < d->outn; i++)
526 {
527 if (d->out[2 * i] & 0x80000000)
528 d->out[2 * i] = (unsigned int)(-(int)(d->out[2 * i] ^ 0x80000000));
529 off += (int)d->out[2 * i];
530 if (off > d->outlen)
531 {
532 fprintf(stderr, "corrupt delta instructions (outdata off %llu > %llu)\n", (unsigned long long)off, (unsigned long long)d->outlen);
533 exit(1);
534 }
535 off += d->out[2 * i + 1];
536 if (off < 1 || off > d->outlen)
537 {
538 fprintf(stderr, "corrupt delta instructions (outdata off + len %llu > %llu)\n", (unsigned long long)off, (unsigned long long)d->outlen);
539 exit(1);
540 }
541 }
542 d->sdesc = 0;
543 d->nsdesc = 0;
544 d->outptr = 0;
545 d->next = d->prev = 0;
546 if (!cfp && strcmp(d->name, "-") != 0)
547 close(dfd);
548 }
549