1 /*
2  * Copyright (c) 2009 - 2013 Thomas Schmitt
3  *
4  * This file is part of the libisofs project; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License version 2
6  * or later as published by the Free Software Foundation.
7  * See COPYING file for details.
8  */
9 
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 #ifdef HAVE_STDINT_H
16 #include <stdint.h>
17 #else
18 #ifdef HAVE_INTTYPES_H
19 #include <inttypes.h>
20 #endif
21 #endif
22 
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 
27 #include "writer.h"
28 #include "messages.h"
29 #include "ecma119.h"
30 #include "image.h"
31 #include "util.h"
32 
33 #include "md5.h"
34 
35 
36 /* This code is derived from RFC 1321 and implements computation of the
37     "RSA Data Security, Inc. MD5 Message-Digest Algorithm" */
38 
39 #define Libisofs_md5_S11 7
40 #define Libisofs_md5_S12 12
41 #define Libisofs_md5_S13 17
42 #define Libisofs_md5_S14 22
43 #define Libisofs_md5_S21 5
44 #define Libisofs_md5_S22 9
45 #define Libisofs_md5_S23 14
46 #define Libisofs_md5_S24 20
47 #define Libisofs_md5_S31 4
48 #define Libisofs_md5_S32 11
49 #define Libisofs_md5_S33 16
50 #define Libisofs_md5_S34 23
51 #define Libisofs_md5_S41 6
52 #define Libisofs_md5_S42 10
53 #define Libisofs_md5_S43 15
54 #define Libisofs_md5_S44 21
55 
56 
57 /* F, G, H and I are basic MD5 functions.
58  */
59 #define Libisofs_md5_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
60 #define Libisofs_md5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
61 #define Libisofs_md5_H(x, y, z) ((x) ^ (y) ^ (z))
62 #define Libisofs_md5_I(x, y, z) ((y) ^ ((x) | (~z)))
63 
64 /* ROTATE_LEFT rotates x left n bits.
65  */
66 #define Libisofs_md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
67 
68 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
69 Rotation is separate from addition to prevent recomputation.
70  */
71 #define Libisofs_md5_FF(a, b, c, d, x, s, ac) { \
72  (a) += Libisofs_md5_F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
73  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
74  (a) += (b); \
75   }
76 #define Libisofs_md5_GG(a, b, c, d, x, s, ac) { \
77  (a) += Libisofs_md5_G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
78  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
79  (a) += (b); \
80   }
81 #define Libisofs_md5_HH(a, b, c, d, x, s, ac) { \
82  (a) += Libisofs_md5_H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
83  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
84  (a) += (b); \
85   }
86 #define Libisofs_md5_II(a, b, c, d, x, s, ac) { \
87  (a) += Libisofs_md5_I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
88  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
89  (a) += (b); \
90   }
91 
92 
93 /* MD5 context. */
94 struct _libisofs_md5_ctx {
95   uint32_t state[4];                                   /* state (ABCD) */
96   uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */
97   unsigned char buffer[64];                         /* input buffer */
98 };
99 
100 typedef struct _libisofs_md5_ctx libisofs_md5_ctx;
101 
102 
103 /* MD5 basic transformation. Transforms state based on block.
104  */
md5__transform(uint32_t state[4],unsigned char block[64])105 static int md5__transform (uint32_t state[4], unsigned char block[64])
106 {
107  uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
108  unsigned int i, j;
109 
110  for (i = 0, j = 0; j < 64; i++, j += 4)
111    x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j+1]) << 8) |
112     (((uint32_t)block[j+2]) << 16) | (((uint32_t)block[j+3]) << 24);
113 
114   /* Round 1 */
115   Libisofs_md5_FF (a, b, c, d, x[ 0], Libisofs_md5_S11, 0xd76aa478); /* 1 */
116   Libisofs_md5_FF (d, a, b, c, x[ 1], Libisofs_md5_S12, 0xe8c7b756); /* 2 */
117   Libisofs_md5_FF (c, d, a, b, x[ 2], Libisofs_md5_S13, 0x242070db); /* 3 */
118   Libisofs_md5_FF (b, c, d, a, x[ 3], Libisofs_md5_S14, 0xc1bdceee); /* 4 */
119   Libisofs_md5_FF (a, b, c, d, x[ 4], Libisofs_md5_S11, 0xf57c0faf); /* 5 */
120   Libisofs_md5_FF (d, a, b, c, x[ 5], Libisofs_md5_S12, 0x4787c62a); /* 6 */
121   Libisofs_md5_FF (c, d, a, b, x[ 6], Libisofs_md5_S13, 0xa8304613); /* 7 */
122   Libisofs_md5_FF (b, c, d, a, x[ 7], Libisofs_md5_S14, 0xfd469501); /* 8 */
123   Libisofs_md5_FF (a, b, c, d, x[ 8], Libisofs_md5_S11, 0x698098d8); /* 9 */
124   Libisofs_md5_FF (d, a, b, c, x[ 9], Libisofs_md5_S12, 0x8b44f7af); /* 10 */
125   Libisofs_md5_FF (c, d, a, b, x[10], Libisofs_md5_S13, 0xffff5bb1); /* 11 */
126   Libisofs_md5_FF (b, c, d, a, x[11], Libisofs_md5_S14, 0x895cd7be); /* 12 */
127   Libisofs_md5_FF (a, b, c, d, x[12], Libisofs_md5_S11, 0x6b901122); /* 13 */
128   Libisofs_md5_FF (d, a, b, c, x[13], Libisofs_md5_S12, 0xfd987193); /* 14 */
129   Libisofs_md5_FF (c, d, a, b, x[14], Libisofs_md5_S13, 0xa679438e); /* 15 */
130   Libisofs_md5_FF (b, c, d, a, x[15], Libisofs_md5_S14, 0x49b40821); /* 16 */
131 
132   /* Round 2 */
133   Libisofs_md5_GG (a, b, c, d, x[ 1], Libisofs_md5_S21, 0xf61e2562); /* 17 */
134   Libisofs_md5_GG (d, a, b, c, x[ 6], Libisofs_md5_S22, 0xc040b340); /* 18 */
135   Libisofs_md5_GG (c, d, a, b, x[11], Libisofs_md5_S23, 0x265e5a51); /* 19 */
136   Libisofs_md5_GG (b, c, d, a, x[ 0], Libisofs_md5_S24, 0xe9b6c7aa); /* 20 */
137   Libisofs_md5_GG (a, b, c, d, x[ 5], Libisofs_md5_S21, 0xd62f105d); /* 21 */
138   Libisofs_md5_GG (d, a, b, c, x[10], Libisofs_md5_S22,  0x2441453); /* 22 */
139   Libisofs_md5_GG (c, d, a, b, x[15], Libisofs_md5_S23, 0xd8a1e681); /* 23 */
140   Libisofs_md5_GG (b, c, d, a, x[ 4], Libisofs_md5_S24, 0xe7d3fbc8); /* 24 */
141   Libisofs_md5_GG (a, b, c, d, x[ 9], Libisofs_md5_S21, 0x21e1cde6); /* 25 */
142   Libisofs_md5_GG (d, a, b, c, x[14], Libisofs_md5_S22, 0xc33707d6); /* 26 */
143   Libisofs_md5_GG (c, d, a, b, x[ 3], Libisofs_md5_S23, 0xf4d50d87); /* 27 */
144   Libisofs_md5_GG (b, c, d, a, x[ 8], Libisofs_md5_S24, 0x455a14ed); /* 28 */
145   Libisofs_md5_GG (a, b, c, d, x[13], Libisofs_md5_S21, 0xa9e3e905); /* 29 */
146   Libisofs_md5_GG (d, a, b, c, x[ 2], Libisofs_md5_S22, 0xfcefa3f8); /* 30 */
147   Libisofs_md5_GG (c, d, a, b, x[ 7], Libisofs_md5_S23, 0x676f02d9); /* 31 */
148   Libisofs_md5_GG (b, c, d, a, x[12], Libisofs_md5_S24, 0x8d2a4c8a); /* 32 */
149 
150   /* Round 3 */
151   Libisofs_md5_HH (a, b, c, d, x[ 5], Libisofs_md5_S31, 0xfffa3942); /* 33 */
152   Libisofs_md5_HH (d, a, b, c, x[ 8], Libisofs_md5_S32, 0x8771f681); /* 34 */
153   Libisofs_md5_HH (c, d, a, b, x[11], Libisofs_md5_S33, 0x6d9d6122); /* 35 */
154   Libisofs_md5_HH (b, c, d, a, x[14], Libisofs_md5_S34, 0xfde5380c); /* 36 */
155   Libisofs_md5_HH (a, b, c, d, x[ 1], Libisofs_md5_S31, 0xa4beea44); /* 37 */
156   Libisofs_md5_HH (d, a, b, c, x[ 4], Libisofs_md5_S32, 0x4bdecfa9); /* 38 */
157   Libisofs_md5_HH (c, d, a, b, x[ 7], Libisofs_md5_S33, 0xf6bb4b60); /* 39 */
158   Libisofs_md5_HH (b, c, d, a, x[10], Libisofs_md5_S34, 0xbebfbc70); /* 40 */
159   Libisofs_md5_HH (a, b, c, d, x[13], Libisofs_md5_S31, 0x289b7ec6); /* 41 */
160   Libisofs_md5_HH (d, a, b, c, x[ 0], Libisofs_md5_S32, 0xeaa127fa); /* 42 */
161   Libisofs_md5_HH (c, d, a, b, x[ 3], Libisofs_md5_S33, 0xd4ef3085); /* 43 */
162   Libisofs_md5_HH (b, c, d, a, x[ 6], Libisofs_md5_S34,  0x4881d05); /* 44 */
163   Libisofs_md5_HH (a, b, c, d, x[ 9], Libisofs_md5_S31, 0xd9d4d039); /* 45 */
164   Libisofs_md5_HH (d, a, b, c, x[12], Libisofs_md5_S32, 0xe6db99e5); /* 46 */
165   Libisofs_md5_HH (c, d, a, b, x[15], Libisofs_md5_S33, 0x1fa27cf8); /* 47 */
166   Libisofs_md5_HH (b, c, d, a, x[ 2], Libisofs_md5_S34, 0xc4ac5665); /* 48 */
167 
168   /* Round 4 */
169   Libisofs_md5_II (a, b, c, d, x[ 0], Libisofs_md5_S41, 0xf4292244); /* 49 */
170   Libisofs_md5_II (d, a, b, c, x[ 7], Libisofs_md5_S42, 0x432aff97); /* 50 */
171   Libisofs_md5_II (c, d, a, b, x[14], Libisofs_md5_S43, 0xab9423a7); /* 51 */
172   Libisofs_md5_II (b, c, d, a, x[ 5], Libisofs_md5_S44, 0xfc93a039); /* 52 */
173   Libisofs_md5_II (a, b, c, d, x[12], Libisofs_md5_S41, 0x655b59c3); /* 53 */
174   Libisofs_md5_II (d, a, b, c, x[ 3], Libisofs_md5_S42, 0x8f0ccc92); /* 54 */
175   Libisofs_md5_II (c, d, a, b, x[10], Libisofs_md5_S43, 0xffeff47d); /* 55 */
176   Libisofs_md5_II (b, c, d, a, x[ 1], Libisofs_md5_S44, 0x85845dd1); /* 56 */
177   Libisofs_md5_II (a, b, c, d, x[ 8], Libisofs_md5_S41, 0x6fa87e4f); /* 57 */
178   Libisofs_md5_II (d, a, b, c, x[15], Libisofs_md5_S42, 0xfe2ce6e0); /* 58 */
179   Libisofs_md5_II (c, d, a, b, x[ 6], Libisofs_md5_S43, 0xa3014314); /* 59 */
180   Libisofs_md5_II (b, c, d, a, x[13], Libisofs_md5_S44, 0x4e0811a1); /* 60 */
181   Libisofs_md5_II (a, b, c, d, x[ 4], Libisofs_md5_S41, 0xf7537e82); /* 61 */
182   Libisofs_md5_II (d, a, b, c, x[11], Libisofs_md5_S42, 0xbd3af235); /* 62 */
183   Libisofs_md5_II (c, d, a, b, x[ 2], Libisofs_md5_S43, 0x2ad7d2bb); /* 63 */
184   Libisofs_md5_II (b, c, d, a, x[ 9], Libisofs_md5_S44, 0xeb86d391); /* 64 */
185 
186   state[0] += a;
187   state[1] += b;
188   state[2] += c;
189   state[3] += d;
190 
191   /* Zeroize sensitive information. */
192   memset ((char *) x, 0, sizeof (x));
193   return(1);
194 }
195 
196 
md5__encode(unsigned char * output,uint32_t * input,unsigned int len)197 static int md5__encode(unsigned char *output, uint32_t *input,
198                        unsigned int len)
199 {
200   unsigned int i, j;
201 
202   for (i = 0, j = 0; j < len; i++, j += 4) {
203     output[j] = (unsigned char)(input[i] & 0xff);
204     output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
205     output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
206     output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
207   }
208   return(1);
209 }
210 
211 
212 
md5_init(libisofs_md5_ctx * ctx,int flag)213 static int md5_init(libisofs_md5_ctx *ctx, int flag)
214 {
215  ctx->count[0] = ctx->count[1] = 0;
216  /* Load magic initialization constants. */
217  ctx->state[0] = 0x67452301;
218  ctx->state[1] = 0xefcdab89;
219  ctx->state[2] = 0x98badcfe;
220  ctx->state[3] = 0x10325476;
221  return(1);
222 }
223 
224 
225 /* MD5 block update operation. Continues an MD5 message-digest
226   operation, processing another message block, and updating the
227   context.
228  */
md5_update(libisofs_md5_ctx * ctx,unsigned char * data,int datalen,int flag)229 static int md5_update(libisofs_md5_ctx *ctx, unsigned char *data,
230                       int datalen, int flag)
231 {
232  int i, index, partlen;
233 
234  /* Compute number of bytes mod 64 */
235  index = ((ctx->count[0] >> 3) & 0x3F);
236  /* Update number of bits */
237  if ((ctx->count[0] += ((uint32_t) datalen << 3)) <
238      ((uint32_t) datalen << 3))
239    ctx->count[1]++;
240  ctx->count[1] += ((uint32_t) datalen >> 29);
241  partlen = 64 - index;
242 
243  /* Transform as many times as possible. */
244  if (datalen >= partlen) {
245    memcpy((char *) &ctx->buffer[index], (char *) data, partlen);
246    md5__transform(ctx->state, ctx->buffer);
247    for (i = partlen; i + 63 < datalen; i += 64)
248      md5__transform(ctx->state, &data[i]);
249    index = 0;
250  } else
251    i = 0;
252 
253  /* Buffer remaining data */
254  memcpy((char *) &ctx->buffer[index], (char *) &data[i],datalen-i);
255 
256  return(1);
257 }
258 
259 
md5_final(libisofs_md5_ctx * ctx,char result[16],int flag)260 static int md5_final(libisofs_md5_ctx *ctx, char result[16], int flag)
261 {
262  unsigned char bits[8], *respt;
263  unsigned int index, padlen;
264  static unsigned char PADDING[64] = {
265    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
268  };
269 
270  /* Save number of bits */
271  md5__encode(bits, ctx->count, 8);
272  /* Pad out to 56 mod 64.  */
273  index = (unsigned int)((ctx->count[0] >> 3) & 0x3f);
274  padlen = (index < 56) ? (56 - index) : (120 - index);
275  md5_update(ctx, PADDING, padlen,0);
276  /* Append length (before padding) */
277  md5_update(ctx, bits, 8,0);
278  /* Store state in result */
279  respt= (unsigned char *) result;
280  md5__encode(respt, ctx->state, 16);
281  /* Zeroize sensitive information.  */
282  memset ((char *) ctx, 0, sizeof (*ctx));
283  return(1);
284 }
285 
286 /** Compute a MD5 checksum from one or more calls of this function.
287     The first call has to be made with flag bit0 == 1. It may already submit
288     processing payload in data and datalen.
289     The last call has to be made with bit15 set. Normally bit1 will be set
290     too in order to receive the checksum before it gets disposed.
291     bit1 may only be set in the last call or together with bit2.
292     The combination of bit1 and bit2 may be used to get an intermediate
293     result without hampering an ongoing checksum computation.
294 
295     @param ctx      the checksum context which stores the state between calls.
296                     It gets created with flag bit0 and disposed with bit15.
297                     With flag bit0, *ctx has to be NULL or point to freeable
298                     memory.
299     @param data     the bytes to be checksummed
300     @param datalen  the number of bytes in data
301     @param result   returns the 16 bytes of checksum if called with bit1 set
302     @param flag     bit0= allocate and init *ctx
303                     bit1= transfer ctx to result
304                     bit2= with bit 0 : clone new *ctx from data
305                     bit15= free *ctx
306 */
307 static
libisofs_md5(void ** ctx_in,char * data,int datalen,char result[16],int flag)308 int libisofs_md5(void **ctx_in, char *data, int datalen,
309                  char result[16], int flag)
310 /* *ctx has to be NULL or point to freeable memory */
311 /*
312  bit0= allocate and init *ctx
313  bit1= transfer ctx to result
314  bit2= with bit 0 : clone new *ctx from data
315  bit15= free *ctx
316 */
317 {
318  unsigned char *datapt;
319  libisofs_md5_ctx **ctx;
320 
321  ctx= (libisofs_md5_ctx **) ctx_in;
322  if(flag&1) {
323    if(*ctx!=NULL)
324      free((char *) *ctx);
325    *ctx= calloc(1, sizeof(libisofs_md5_ctx));
326    if(*ctx==NULL)
327      return(-1);
328    md5_init(*ctx,0);
329    if(flag&4)
330      memcpy((char *) *ctx,data,sizeof(libisofs_md5_ctx));
331  }
332  if(*ctx==NULL)
333    return(0);
334  if(datalen>0) {
335    datapt= (unsigned char *) data;
336    md5_update(*ctx, datapt, datalen, 0);
337  }
338  if(flag&2)
339    md5_final(*ctx, result, 0);
340  if(flag&(1<<15)) {
341    free((char *) *ctx);
342    *ctx= NULL;
343  }
344  return(1);
345 }
346 
347 
348 /* ----------------------------------------------------------------------- */
349 
350 /* Public MD5 computing facility */
351 
352 /* API */
iso_md5_start(void ** md5_context)353 int iso_md5_start(void **md5_context)
354 {
355     int ret;
356 
357     ret = libisofs_md5(md5_context, NULL, 0, NULL, 1);
358     if (ret <= 0)
359         return ISO_OUT_OF_MEM;
360     return 1;
361 }
362 
363 
364 /* API */
iso_md5_compute(void * md5_context,char * data,int datalen)365 int iso_md5_compute(void *md5_context, char *data, int datalen)
366 {
367     int ret;
368 
369     ret = libisofs_md5(&md5_context, data, datalen, NULL, 0);
370     if (ret <= 0)
371         return ISO_NULL_POINTER;
372     return 1;
373 }
374 
375 
376 /* API */
iso_md5_clone(void * old_md5_context,void ** new_md5_context)377 int iso_md5_clone(void *old_md5_context, void **new_md5_context)
378 {
379     int ret;
380 
381     ret = libisofs_md5(new_md5_context, old_md5_context, 0, NULL, 1 | 4);
382     if (ret < 0)
383         return ISO_OUT_OF_MEM;
384     if (ret == 0)
385         return ISO_NULL_POINTER;
386     return 1;
387 }
388 
389 
390 /* API */
iso_md5_end(void ** md5_context,char result[16])391 int iso_md5_end(void **md5_context, char result[16])
392 {
393     int ret;
394 
395     ret = libisofs_md5(md5_context, NULL, 0, result, 2 | (1 << 15));
396     if (ret <= 0)
397         return ISO_NULL_POINTER;
398     return 1;
399 }
400 
401 
402 /* API */
iso_md5_match(char first_md5[16],char second_md5[16])403 int iso_md5_match(char first_md5[16], char second_md5[16])
404 {
405     int i;
406 
407     for (i= 0; i < 16; i++)
408         if (first_md5[i] != second_md5[i])
409             return 0;
410     return 1;
411 }
412 
413 
414 /* ----------------------------------------------------------------------- */
415 
416 
417 /* Function to identify and manage md5sum indice of the old image.
418  * data is supposed to be a 4 byte integer, bit 31 shall be 0,
419  * value 0 of this integer means that it is not a valid index.
420  */
checksum_cx_xinfo_func(void * data,int flag)421 int checksum_cx_xinfo_func(void *data, int flag)
422 {
423     /* data is an int disguised as pointer. It does not point to memory. */
424     return 1;
425 }
426 
427 /* The iso_node_xinfo_cloner function which gets associated to
428  * checksum_cx_xinfo_func by iso_init() resp. iso_init_with_flag() via
429  * iso_node_xinfo_make_clonable()
430  */
checksum_cx_xinfo_cloner(void * old_data,void ** new_data,int flag)431 int checksum_cx_xinfo_cloner(void *old_data, void **new_data, int flag)
432 {
433     *new_data = NULL;
434     if (flag)
435         return ISO_XINFO_NO_CLONE;
436     if (old_data == NULL)
437         return 0;
438     /* data is an int disguised as pointer. It does not point to memory. */
439     *new_data = old_data;
440     return 0;
441 }
442 
443 
444 /* Function to identify and manage md5 sums of unspecified providence stored
445  * directly in this xinfo.
446  */
checksum_md5_xinfo_func(void * data,int flag)447 int checksum_md5_xinfo_func(void *data, int flag)
448 {
449     if (data == NULL)
450         return 1;
451     free(data);
452     return 1;
453 }
454 
455 /* The iso_node_xinfo_cloner function which gets associated to
456  * checksum_md5_xinfo_func by iso_init() resp. iso_init_with_flag() via
457  * iso_node_xinfo_make_clonable()
458  */
checksum_md5_xinfo_cloner(void * old_data,void ** new_data,int flag)459 int checksum_md5_xinfo_cloner(void *old_data, void **new_data, int flag)
460 {
461     *new_data = NULL;
462     if (flag)
463         return ISO_XINFO_NO_CLONE;
464     if (old_data == NULL)
465         return 0;
466     *new_data = calloc(1, 16);
467     if (*new_data == NULL)
468         return ISO_OUT_OF_MEM;
469     memcpy(*new_data, old_data, 16);
470     return 16;
471 }
472 
473 
474 /* ----------------------------------------------------------------------- */
475 
476 /* MD5 checksum image writer */
477 
478 /*
479   @flag bit0= recursion
480         bit1= session will be appended to an existing image
481 */
482 static
checksum_copy_old_nodes(Ecma119Image * target,IsoNode * node,int flag)483 int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag)
484 {
485     IsoNode *pos;
486     IsoFile *file;
487     IsoImage *img;
488     int ret, i;
489     size_t value_length;
490     unsigned int idx = 0, old_idx = 0;
491     char *value = NULL, *md5_pt = NULL;
492     void *xipt;
493 
494     img = target->image;
495     if (target->checksum_buffer == NULL)
496         return 0;
497 
498     if (node->type == LIBISO_FILE) {
499         file = (IsoFile *) node;
500         if (file->from_old_session && target->opts->appendable) {
501             /* Look for checksums at various places */
502 
503             /* Try checksum directly stored with node */
504             if (md5_pt == NULL) {
505                 ret = iso_node_get_xinfo(node, checksum_md5_xinfo_func, &xipt);
506                 if (ret < 0)
507                     return ret;
508                 if (ret == 1)
509                     md5_pt = (char *) xipt;
510             }
511 
512             /* Try checksum index to image checksum buffer */
513             if (md5_pt == NULL && img->checksum_array != NULL) {
514                 ret = iso_node_get_xinfo(node, checksum_cx_xinfo_func, &xipt);
515                 if (ret <= 0)
516                     return ret;
517                 /* xipt is an int disguised as void pointer */
518                 old_idx = 0;
519                 for (i = 0; i < 4; i++)
520                     old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i];
521 
522                 if (old_idx == 0 || old_idx > img->checksum_idx_count - 1)
523                     return 0;
524                 md5_pt = img->checksum_array + 16 * old_idx;
525             }
526 
527             if (md5_pt == NULL)
528                 return 0;
529 
530             if (!target->opts->will_cancel) {
531                 ret = iso_node_lookup_attr(node, "isofs.cx", &value_length,
532                                            &value, 0);
533                 if (ret == 1 && value_length == 4) {
534                     for (i = 0; i < 4; i++)
535                         idx = (idx << 8) | ((unsigned char *) value)[i];
536                     if (idx > 0 && idx <= target->checksum_idx_counter) {
537                         memcpy(target->checksum_buffer + 16 * idx, md5_pt, 16);
538                     }
539                 }
540                 if (value != NULL)
541                     free(value);
542 
543                 /* >>> ts B30114 : It is unclear why these are removed here.
544                                    At least with the opts->will_cancel runs,
545                                    this is not appropriate.
546                 */
547                 iso_node_remove_xinfo(node, checksum_md5_xinfo_func);
548             }
549         }
550     } else if (node->type == LIBISO_DIR) {
551         for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
552             ret = checksum_copy_old_nodes(target, pos, 1);
553             if (ret < 0)
554                 return ret;
555         }
556     }
557     return ISO_SUCCESS;
558 }
559 
560 
561 static
checksum_writer_compute_data_blocks(IsoImageWriter * writer)562 int checksum_writer_compute_data_blocks(IsoImageWriter *writer)
563 {
564     size_t size;
565     Ecma119Image *t;
566     int ret;
567 
568     if (writer == NULL) {
569         return ISO_ASSERT_FAILURE;
570     }
571     t = writer->target;
572 
573     t->checksum_array_pos = t->curblock;
574                          /* (t->curblock already contains t->opts->ms_block) */
575     t->checksum_range_start = t->opts->ms_block;
576     size = (t->checksum_idx_counter + 2) / 128;
577     if (size * 128 < t->checksum_idx_counter + 2)
578         size++;
579     t->curblock += size;
580     t->checksum_range_size = t->checksum_array_pos + size
581                              - t->checksum_range_start;
582 
583     /* Extra block for stream detectable checksum tag */
584     t->checksum_tag_pos =  t->curblock;
585     t->curblock++;
586 
587     /* Allocate array of MD5 sums */
588     t->checksum_buffer = calloc(size, 2048);
589     if (t->checksum_buffer == NULL)
590         return ISO_OUT_OF_MEM;
591 
592     /* Copy MD5 from nodes of old image into writer->data */
593     ret = checksum_copy_old_nodes(t, (IsoNode *) t->image->root, 0);
594     if (ret < 0)
595         return ret;
596 
597     /* Record lba,count,size,cecksum_type in "isofs.ca" of root node */
598     ret = iso_root_set_isofsca((IsoNode *) t->image->root,
599                                t->checksum_range_start,
600                                t->checksum_array_pos,
601                                t->checksum_idx_counter + 2, 16, "MD5", 0);
602     if (ret < 0)
603         return ret;
604     return ISO_SUCCESS;
605 }
606 
607 
608 static
checksum_writer_write_vol_desc(IsoImageWriter * writer)609 int checksum_writer_write_vol_desc(IsoImageWriter *writer)
610 {
611 
612     /* The superblock checksum tag has to be written after
613        the Volume Descriptor Set Terminator and thus may not be
614        written by this function. (It would have been neat, though).
615     */
616 
617     return ISO_SUCCESS;
618 }
619 
620 
621 static
checksum_writer_write_data(IsoImageWriter * writer)622 int checksum_writer_write_data(IsoImageWriter *writer)
623 {
624     int wres, res;
625     size_t i, size;
626     Ecma119Image *t;
627     void *ctx = NULL;
628     char md5[16];
629 
630     if (writer == NULL) {
631         return ISO_ASSERT_FAILURE;
632     }
633 
634     t = writer->target;
635     iso_msg_debug(t->image->id, "Writing Checksums...");
636 
637     /* Write image checksum to index 0 */
638     if (t->checksum_ctx != NULL) {
639         res = iso_md5_clone(t->checksum_ctx, &ctx);
640         if (res > 0) {
641             res = iso_md5_end(&ctx, t->image_md5);
642             if (res > 0)
643                 memcpy(t->checksum_buffer + 0 * 16, t->image_md5, 16);
644         }
645     }
646 
647     size = (t->checksum_idx_counter + 2) / 128;
648     if (size * 128 < t->checksum_idx_counter + 2)
649         size++;
650 
651     /* Write checksum of checksum array as index t->checksum_idx_counter + 1 */
652     res = iso_md5_start(&ctx);
653     if (res > 0) {
654         for (i = 0; i < t->checksum_idx_counter + 1; i++)
655             iso_md5_compute(ctx,
656                           t->checksum_buffer + ((size_t) i) * (size_t) 16, 16);
657         res = iso_md5_end(&ctx, md5);
658         if (res > 0)
659            memcpy(t->checksum_buffer + (t->checksum_idx_counter + 1) * 16,
660                   md5, 16);
661     }
662 
663     for (i = 0; i < size; i++) {
664         wres = iso_write(t, t->checksum_buffer + ((size_t) 2048) * i, 2048);
665         if (wres < 0) {
666             res = wres;
667             goto ex;
668         }
669     }
670     if (t->checksum_ctx == NULL) {
671         res = ISO_SUCCESS;
672         goto ex;
673     }
674 
675     /* Write stream detectable checksum tag to extra block */;
676     res = iso_md5_write_tag(t, 1);
677     if (res < 0)
678         goto ex;
679 
680     res = ISO_SUCCESS;
681 ex:;
682     if (ctx != NULL)
683         iso_md5_end(&ctx, md5);
684     return(res);
685 }
686 
687 
688 static
checksum_writer_free_data(IsoImageWriter * writer)689 int checksum_writer_free_data(IsoImageWriter *writer)
690 {
691     /* nothing was allocated at writer->data */
692     return ISO_SUCCESS;
693 }
694 
695 
checksum_writer_create(Ecma119Image * target)696 int checksum_writer_create(Ecma119Image *target)
697 {
698     IsoImageWriter *writer;
699 
700     writer = malloc(sizeof(IsoImageWriter));
701     if (writer == NULL) {
702         return ISO_OUT_OF_MEM;
703     }
704 
705     writer->compute_data_blocks = checksum_writer_compute_data_blocks;
706     writer->write_vol_desc = checksum_writer_write_vol_desc;
707     writer->write_data = checksum_writer_write_data;
708     writer->free_data = checksum_writer_free_data;
709     writer->data = NULL;
710     writer->target = target;
711 
712     /* add this writer to image */
713     target->writers[target->nwriters++] = writer;
714     /* Account for superblock checksum tag */
715     if (target->opts->md5_session_checksum) {
716         target->checksum_sb_tag_pos = target->curblock;
717         target->curblock++;
718     }
719     return ISO_SUCCESS;
720 }
721 
722 
723 static
iso_md5_write_scdbackup_tag(Ecma119Image * t,char * tag_block,int flag)724 int iso_md5_write_scdbackup_tag(Ecma119Image *t, char *tag_block, int flag)
725 {
726     void *ctx = NULL;
727     off_t pos = 0, line_start;
728     int record_len, block_len, ret, i;
729     char postext[40], md5[16], *record = NULL;
730 
731     LIBISO_ALLOC_MEM(record, char, 160);
732     line_start = strlen(tag_block);
733     iso_md5_compute(t->checksum_ctx, tag_block, line_start);
734     ret = iso_md5_clone(t->checksum_ctx, &ctx);
735     if (ret < 0)
736         goto ex;
737     ret = iso_md5_end(&ctx, md5);
738 
739     pos = (off_t) t->checksum_tag_pos * (off_t) 2048 + line_start;
740     if(pos >= 1000000000)
741         sprintf(postext, "%u%9.9u", (unsigned int) (pos / 1000000000),
742                                     (unsigned int) (pos % 1000000000));
743     else
744         sprintf(postext, "%u", (unsigned int) pos);
745     sprintf(record, "%s %s ", t->opts->scdbackup_tag_parm, postext);
746     record_len = strlen(record);
747     for (i = 0; i < 16; i++)
748          sprintf(record + record_len + 2 * i,
749                  "%2.2x", ((unsigned char *) md5)[i]);
750     record_len += 32;
751 
752     ret = iso_md5_start(&ctx);
753     if (ret < 0)
754         goto ex;
755     iso_md5_compute(ctx, record, record_len);
756     iso_md5_end(&ctx, md5);
757 
758     sprintf(tag_block + line_start, "scdbackup_checksum_tag_v0.1 %s %d %s ",
759             postext, record_len, record);
760     block_len = strlen(tag_block);
761     for (i = 0; i < 16; i++)
762         sprintf(tag_block + block_len + 2 * i,
763                 "%2.2x", ((unsigned char *) md5)[i]);
764     block_len+= 32;
765     tag_block[block_len++]= '\n';
766 
767     if (t->opts->scdbackup_tag_written != NULL)
768     	strncpy(t->opts->scdbackup_tag_written, tag_block + line_start,
769                 block_len - line_start);
770     ret = ISO_SUCCESS;
771 ex:;
772     if (ctx != NULL)
773         iso_md5_end(&ctx, md5);
774     LIBISO_FREE_MEM(record);
775     return ret;
776 }
777 
778 
779 /* Write stream detectable checksum tag to extra block.
780  * @flag bit0-7= tag type
781  *               1= session tag (End checksumming.)
782  *               2= superblock tag (System Area and Volume Descriptors)
783  *               3= tree tag (ECMA-119 and Rock Ridge tree)
784  *               4= relocated superblock tag (at LBA 0 of overwritable media)
785  *                  Write to target->opts_overwrite rather than to iso_write().
786  */
iso_md5_write_tag(Ecma119Image * t,int flag)787 int iso_md5_write_tag(Ecma119Image *t, int flag)
788 {
789     int ret, mode, l, i, wres, tag_id_len;
790     void *ctx = NULL;
791     char md5[16], *tag_block = NULL, *tag_id;
792     uint32_t size = 0, pos = 0, start;
793 
794     LIBISO_ALLOC_MEM(tag_block, char, 2048);
795     start = t->checksum_range_start;
796     mode = flag & 255;
797     if (mode < 1 || mode > 4)
798         {ret = ISO_WRONG_ARG_VALUE; goto ex;}
799     ret = iso_md5_clone(t->checksum_ctx, &ctx);
800     if (ret < 0)
801         goto ex;
802     ret = iso_md5_end(&ctx, md5);
803     if (mode == 1) {
804         size = t->checksum_range_size;
805         pos = t->checksum_tag_pos;
806     } else {
807         if (mode == 2) {
808             pos = t->checksum_sb_tag_pos;
809         } else if (mode == 3) {
810             pos = t->checksum_tree_tag_pos;
811         } else if (mode == 4) {
812             pos = t->checksum_rlsb_tag_pos;
813             start = pos - (pos % 32);
814         }
815         size = pos - start;
816     }
817     if (ret < 0)
818         goto ex;
819 
820     iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0);
821     sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u",
822             tag_id, pos, start, size);
823 
824     l = strlen(tag_block);
825     if (mode == 2) {
826         sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos);
827     } else if (mode == 3) {
828         sprintf(tag_block + l, " next=%u", t->checksum_tag_pos);
829     } else if (mode == 4) {
830         sprintf(tag_block + l, " session_start=%u", t->opts->ms_block);
831     }
832     strcat(tag_block + l, " md5=");
833     l = strlen(tag_block);
834     for (i = 0; i < 16; i++)
835         sprintf(tag_block + l + 2 * i, "%2.2x",
836                 ((unsigned char *) md5)[i]);
837     l+= 32;
838 
839     ret = iso_md5_start(&ctx);
840     if (ret > 0) {
841         iso_md5_compute(ctx, tag_block, l);
842         iso_md5_end(&ctx, md5);
843         strcpy(tag_block + l, " self=");
844         l += 6;
845         for (i = 0; i < 16; i++)
846             sprintf(tag_block + l + 2 * i, "%2.2x",
847                     ((unsigned char *) md5)[i]);
848     }
849     tag_block[l + 32] = '\n';
850 
851     if (mode == 1 && t->opts->scdbackup_tag_parm[0]) {
852         if (t->opts->ms_block > 0) {
853             iso_msg_submit(t->image->id, ISO_SCDBACKUP_TAG_NOT_0, 0, NULL);
854         } else {
855             ret = iso_md5_write_scdbackup_tag(t, tag_block, 0);
856             if (ret < 0)
857                 goto ex;
858         }
859     }
860 
861     if (mode == 4) {
862         if (t->opts_overwrite != NULL)
863             memcpy(t->opts_overwrite + pos * 2048, tag_block, 2048);
864     } else {
865         wres = iso_write(t, tag_block, 2048);
866         if (wres < 0) {
867             ret = wres;
868             goto ex;
869         }
870     }
871 
872     ret = ISO_SUCCESS;
873 ex:;
874     if (ctx != NULL)
875         iso_md5_end(&ctx, md5);
876     LIBISO_FREE_MEM(tag_block);
877     return ret;
878 }
879 
880 
881