1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. |
9 | * |
10 | * This software is licensed as described in the file COPYING, which |
11 | * you should have received as part of this distribution. The terms |
12 | * are also available at https://curl.haxx.se/docs/copyright.html. |
13 | * |
14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | * copies of the Software, and permit persons to whom the Software is |
16 | * furnished to do so, under the terms of the COPYING file. |
17 | * |
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | * KIND, either express or implied. |
20 | * |
21 | ***************************************************************************/ |
22 | #include "tool_setup.h" |
23 | |
24 | #ifdef USE_METALINK |
25 | |
26 | #include <sys/stat.h> |
27 | #include <stdlib.h> |
28 | |
29 | #ifdef HAVE_FCNTL_H |
30 | # include <fcntl.h> |
31 | #endif |
32 | |
33 | #undef HAVE_NSS_CONTEXT |
34 | |
35 | #ifdef USE_OPENSSL |
36 | # include <openssl/md5.h> |
37 | # include <openssl/sha.h> |
38 | #elif defined(USE_GNUTLS_NETTLE) |
39 | # include <nettle/md5.h> |
40 | # include <nettle/sha.h> |
41 | # define MD5_CTX struct md5_ctx |
42 | # define SHA_CTX struct sha1_ctx |
43 | # define SHA256_CTX struct sha256_ctx |
44 | #elif defined(USE_GNUTLS) |
45 | # include <gcrypt.h> |
46 | # define MD5_CTX gcry_md_hd_t |
47 | # define SHA_CTX gcry_md_hd_t |
48 | # define SHA256_CTX gcry_md_hd_t |
49 | #elif defined(USE_NSS) |
50 | # include <nss.h> |
51 | # include <pk11pub.h> |
52 | # define MD5_CTX void * |
53 | # define SHA_CTX void * |
54 | # define SHA256_CTX void * |
55 | # define HAVE_NSS_CONTEXT |
56 | static NSSInitContext *nss_context; |
57 | #elif defined(USE_POLARSSL) |
58 | # include <polarssl/md5.h> |
59 | # include <polarssl/sha1.h> |
60 | # include <polarssl/sha256.h> |
61 | # define MD5_CTX md5_context |
62 | # define SHA_CTX sha1_context |
63 | # define SHA256_CTX sha256_context |
64 | #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ |
65 | (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ |
66 | (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ |
67 | (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) |
68 | /* For Apple operating systems: CommonCrypto has the functions we need. |
69 | The library's headers are even backward-compatible with OpenSSL's |
70 | headers as long as we define COMMON_DIGEST_FOR_OPENSSL first. |
71 | |
72 | These functions are available on Tiger and later, as well as iOS 2.0 |
73 | and later. If you're building for an older cat, well, sorry. */ |
74 | # define COMMON_DIGEST_FOR_OPENSSL |
75 | # include <CommonCrypto/CommonDigest.h> |
76 | #elif defined(WIN32) |
77 | /* For Windows: If no other crypto library is provided, we fallback |
78 | to the hash functions provided within the Microsoft Windows CryptoAPI */ |
79 | # include <wincrypt.h> |
80 | /* Custom structure in order to store the required provider and hash handle */ |
81 | struct win32_crypto_hash { |
82 | HCRYPTPROV hCryptProv; |
83 | HCRYPTHASH hHash; |
84 | }; |
85 | /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */ |
86 | # ifndef ALG_SID_SHA_256 |
87 | # define ALG_SID_SHA_256 12 |
88 | # endif |
89 | # ifndef CALG_SHA_256 |
90 | # define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) |
91 | # endif |
92 | # define MD5_CTX struct win32_crypto_hash |
93 | # define SHA_CTX struct win32_crypto_hash |
94 | # define SHA256_CTX struct win32_crypto_hash |
95 | #else |
96 | # error "Can't compile METALINK support without a crypto library." |
97 | #endif |
98 | |
99 | #define ENABLE_CURLX_PRINTF |
100 | /* use our own printf() functions */ |
101 | #include "curlx.h" |
102 | |
103 | #include "tool_getparam.h" |
104 | #include "tool_paramhlp.h" |
105 | #include "tool_cfgable.h" |
106 | #include "tool_metalink.h" |
107 | #include "tool_operate.h" |
108 | #include "tool_msgs.h" |
109 | |
110 | #include "memdebug.h" /* keep this as LAST include */ |
111 | |
112 | /* Copied from tool_getparam.c */ |
113 | #define GetStr(str,val) do { \ |
114 | if(*(str)) { \ |
115 | free(*(str)); \ |
116 | *(str) = NULL; \ |
117 | } \ |
118 | if((val)) \ |
119 | *(str) = strdup((val)); \ |
120 | if(!(val)) \ |
121 | return PARAM_NO_MEM; \ |
122 | } WHILE_FALSE |
123 | |
124 | #if defined(USE_OPENSSL) |
125 | /* Functions are already defined */ |
126 | #elif defined(USE_GNUTLS_NETTLE) |
127 | |
128 | static int MD5_Init(MD5_CTX *ctx) |
129 | { |
130 | md5_init(ctx); |
131 | return 1; |
132 | } |
133 | |
134 | static void MD5_Update(MD5_CTX *ctx, |
135 | const unsigned char *input, |
136 | unsigned int inputLen) |
137 | { |
138 | md5_update(ctx, inputLen, input); |
139 | } |
140 | |
141 | static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) |
142 | { |
143 | md5_digest(ctx, 16, digest); |
144 | } |
145 | |
146 | static int SHA1_Init(SHA_CTX *ctx) |
147 | { |
148 | sha1_init(ctx); |
149 | return 1; |
150 | } |
151 | |
152 | static void SHA1_Update(SHA_CTX *ctx, |
153 | const unsigned char *input, |
154 | unsigned int inputLen) |
155 | { |
156 | sha1_update(ctx, inputLen, input); |
157 | } |
158 | |
159 | static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) |
160 | { |
161 | sha1_digest(ctx, 20, digest); |
162 | } |
163 | |
164 | static int SHA256_Init(SHA256_CTX *ctx) |
165 | { |
166 | sha256_init(ctx); |
167 | return 1; |
168 | } |
169 | |
170 | static void SHA256_Update(SHA256_CTX *ctx, |
171 | const unsigned char *input, |
172 | unsigned int inputLen) |
173 | { |
174 | sha256_update(ctx, inputLen, input); |
175 | } |
176 | |
177 | static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) |
178 | { |
179 | sha256_digest(ctx, 32, digest); |
180 | } |
181 | |
182 | #elif defined(USE_GNUTLS) |
183 | |
184 | static int MD5_Init(MD5_CTX *ctx) |
185 | { |
186 | gcry_md_open(ctx, GCRY_MD_MD5, 0); |
187 | return 1; |
188 | } |
189 | |
190 | static void MD5_Update(MD5_CTX *ctx, |
191 | const unsigned char *input, |
192 | unsigned int inputLen) |
193 | { |
194 | gcry_md_write(*ctx, input, inputLen); |
195 | } |
196 | |
197 | static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) |
198 | { |
199 | memcpy(digest, gcry_md_read(*ctx, 0), 16); |
200 | gcry_md_close(*ctx); |
201 | } |
202 | |
203 | static int SHA1_Init(SHA_CTX *ctx) |
204 | { |
205 | gcry_md_open(ctx, GCRY_MD_SHA1, 0); |
206 | return 1; |
207 | } |
208 | |
209 | static void SHA1_Update(SHA_CTX *ctx, |
210 | const unsigned char *input, |
211 | unsigned int inputLen) |
212 | { |
213 | gcry_md_write(*ctx, input, inputLen); |
214 | } |
215 | |
216 | static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) |
217 | { |
218 | memcpy(digest, gcry_md_read(*ctx, 0), 20); |
219 | gcry_md_close(*ctx); |
220 | } |
221 | |
222 | static int SHA256_Init(SHA256_CTX *ctx) |
223 | { |
224 | gcry_md_open(ctx, GCRY_MD_SHA256, 0); |
225 | return 1; |
226 | } |
227 | |
228 | static void SHA256_Update(SHA256_CTX *ctx, |
229 | const unsigned char *input, |
230 | unsigned int inputLen) |
231 | { |
232 | gcry_md_write(*ctx, input, inputLen); |
233 | } |
234 | |
235 | static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) |
236 | { |
237 | memcpy(digest, gcry_md_read(*ctx, 0), 32); |
238 | gcry_md_close(*ctx); |
239 | } |
240 | |
241 | #elif defined(USE_NSS) |
242 | |
243 | static int nss_hash_init(void **pctx, SECOidTag hash_alg) |
244 | { |
245 | PK11Context *ctx; |
246 | |
247 | /* we have to initialize NSS if not initialized already */ |
248 | if(!NSS_IsInitialized() && !nss_context) { |
249 | static NSSInitParameters params; |
250 | params.length = sizeof(params); |
251 | nss_context = NSS_InitContext("" , "" , "" , "" , ¶ms, NSS_INIT_READONLY |
252 | | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
253 | | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); |
254 | } |
255 | |
256 | ctx = PK11_CreateDigestContext(hash_alg); |
257 | if(!ctx) |
258 | return /* failure */ 0; |
259 | |
260 | if(PK11_DigestBegin(ctx) != SECSuccess) { |
261 | PK11_DestroyContext(ctx, PR_TRUE); |
262 | return /* failure */ 0; |
263 | } |
264 | |
265 | *pctx = ctx; |
266 | return /* success */ 1; |
267 | } |
268 | |
269 | static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len) |
270 | { |
271 | PK11Context *ctx = *pctx; |
272 | unsigned int outlen; |
273 | PK11_DigestFinal(ctx, out, &outlen, len); |
274 | PK11_DestroyContext(ctx, PR_TRUE); |
275 | } |
276 | |
277 | static int MD5_Init(MD5_CTX *pctx) |
278 | { |
279 | return nss_hash_init(pctx, SEC_OID_MD5); |
280 | } |
281 | |
282 | static void MD5_Update(MD5_CTX *pctx, |
283 | const unsigned char *input, |
284 | unsigned int input_len) |
285 | { |
286 | PK11_DigestOp(*pctx, input, input_len); |
287 | } |
288 | |
289 | static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx) |
290 | { |
291 | nss_hash_final(pctx, digest, 16); |
292 | } |
293 | |
294 | static int SHA1_Init(SHA_CTX *pctx) |
295 | { |
296 | return nss_hash_init(pctx, SEC_OID_SHA1); |
297 | } |
298 | |
299 | static void SHA1_Update(SHA_CTX *pctx, |
300 | const unsigned char *input, |
301 | unsigned int input_len) |
302 | { |
303 | PK11_DigestOp(*pctx, input, input_len); |
304 | } |
305 | |
306 | static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx) |
307 | { |
308 | nss_hash_final(pctx, digest, 20); |
309 | } |
310 | |
311 | static int SHA256_Init(SHA256_CTX *pctx) |
312 | { |
313 | return nss_hash_init(pctx, SEC_OID_SHA256); |
314 | } |
315 | |
316 | static void SHA256_Update(SHA256_CTX *pctx, |
317 | const unsigned char *input, |
318 | unsigned int input_len) |
319 | { |
320 | PK11_DigestOp(*pctx, input, input_len); |
321 | } |
322 | |
323 | static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx) |
324 | { |
325 | nss_hash_final(pctx, digest, 32); |
326 | } |
327 | |
328 | #elif defined(USE_POLARSSL) |
329 | |
330 | static int MD5_Init(MD5_CTX *ctx) |
331 | { |
332 | md5_starts(ctx); |
333 | return 1; |
334 | } |
335 | |
336 | static void MD5_Update(MD5_CTX *ctx, |
337 | const unsigned char *input, |
338 | unsigned int inputLen) |
339 | { |
340 | md5_update(ctx, input, inputLen); |
341 | } |
342 | |
343 | static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) |
344 | { |
345 | md5_finish(ctx, digest); |
346 | } |
347 | |
348 | static int SHA1_Init(SHA_CTX *ctx) |
349 | { |
350 | sha1_starts(ctx); |
351 | return 1; |
352 | } |
353 | |
354 | static void SHA1_Update(SHA_CTX *ctx, |
355 | const unsigned char *input, |
356 | unsigned int inputLen) |
357 | { |
358 | sha1_update(ctx, input, inputLen); |
359 | } |
360 | |
361 | static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) |
362 | { |
363 | sha1_finish(ctx, digest); |
364 | } |
365 | |
366 | static int SHA256_Init(SHA256_CTX *ctx) |
367 | { |
368 | sha256_starts(ctx, 0); /* 0 = sha256 */ |
369 | return 1; |
370 | } |
371 | |
372 | static void SHA256_Update(SHA256_CTX *ctx, |
373 | const unsigned char *input, |
374 | unsigned int inputLen) |
375 | { |
376 | sha256_update(ctx, input, inputLen); |
377 | } |
378 | |
379 | static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) |
380 | { |
381 | sha256_finish(ctx, digest); |
382 | } |
383 | |
384 | #elif defined(WIN32) |
385 | |
386 | static void win32_crypto_final(struct win32_crypto_hash *ctx, |
387 | unsigned char *digest, |
388 | unsigned int digestLen) |
389 | { |
390 | unsigned long length; |
391 | CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0); |
392 | if(length == digestLen) |
393 | CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0); |
394 | if(ctx->hHash) |
395 | CryptDestroyHash(ctx->hHash); |
396 | if(ctx->hCryptProv) |
397 | CryptReleaseContext(ctx->hCryptProv, 0); |
398 | } |
399 | |
400 | static int MD5_Init(MD5_CTX *ctx) |
401 | { |
402 | if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, |
403 | PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { |
404 | CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash); |
405 | } |
406 | return 1; |
407 | } |
408 | |
409 | static void MD5_Update(MD5_CTX *ctx, |
410 | const unsigned char *input, |
411 | unsigned int inputLen) |
412 | { |
413 | CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); |
414 | } |
415 | |
416 | static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) |
417 | { |
418 | win32_crypto_final(ctx, digest, 16); |
419 | } |
420 | |
421 | static int SHA1_Init(SHA_CTX *ctx) |
422 | { |
423 | if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, |
424 | PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { |
425 | CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash); |
426 | } |
427 | return 1; |
428 | } |
429 | |
430 | static void SHA1_Update(SHA_CTX *ctx, |
431 | const unsigned char *input, |
432 | unsigned int inputLen) |
433 | { |
434 | CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); |
435 | } |
436 | |
437 | static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx) |
438 | { |
439 | win32_crypto_final(ctx, digest, 20); |
440 | } |
441 | |
442 | static int SHA256_Init(SHA256_CTX *ctx) |
443 | { |
444 | if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, |
445 | PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { |
446 | CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash); |
447 | } |
448 | return 1; |
449 | } |
450 | |
451 | static void SHA256_Update(SHA256_CTX *ctx, |
452 | const unsigned char *input, |
453 | unsigned int inputLen) |
454 | { |
455 | CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0); |
456 | } |
457 | |
458 | static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx) |
459 | { |
460 | win32_crypto_final(ctx, digest, 32); |
461 | } |
462 | |
463 | #endif /* CRYPTO LIBS */ |
464 | |
465 | const digest_params MD5_DIGEST_PARAMS[] = { |
466 | { |
467 | CURLX_FUNCTION_CAST(Curl_digest_init_func, MD5_Init), |
468 | CURLX_FUNCTION_CAST(Curl_digest_update_func, MD5_Update), |
469 | CURLX_FUNCTION_CAST(Curl_digest_final_func, MD5_Final), |
470 | sizeof(MD5_CTX), |
471 | 16 |
472 | } |
473 | }; |
474 | |
475 | const digest_params SHA1_DIGEST_PARAMS[] = { |
476 | { |
477 | CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA1_Init), |
478 | CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA1_Update), |
479 | CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA1_Final), |
480 | sizeof(SHA_CTX), |
481 | 20 |
482 | } |
483 | }; |
484 | |
485 | const digest_params SHA256_DIGEST_PARAMS[] = { |
486 | { |
487 | CURLX_FUNCTION_CAST(Curl_digest_init_func, SHA256_Init), |
488 | CURLX_FUNCTION_CAST(Curl_digest_update_func, SHA256_Update), |
489 | CURLX_FUNCTION_CAST(Curl_digest_final_func, SHA256_Final), |
490 | sizeof(SHA256_CTX), |
491 | 32 |
492 | } |
493 | }; |
494 | |
495 | static const metalink_digest_def SHA256_DIGEST_DEF[] = { |
496 | {"sha-256" , SHA256_DIGEST_PARAMS} |
497 | }; |
498 | |
499 | static const metalink_digest_def SHA1_DIGEST_DEF[] = { |
500 | {"sha-1" , SHA1_DIGEST_PARAMS} |
501 | }; |
502 | |
503 | static const metalink_digest_def MD5_DIGEST_DEF[] = { |
504 | {"md5" , MD5_DIGEST_PARAMS} |
505 | }; |
506 | |
507 | /* |
508 | * The alias of supported hash functions in the order by preference |
509 | * (basically stronger hash comes first). We included "sha-256" and |
510 | * "sha256". The former is the name defined in the IANA registry named |
511 | * "Hash Function Textual Names". The latter is widely (and |
512 | * historically) used in Metalink version 3. |
513 | */ |
514 | static const metalink_digest_alias digest_aliases[] = { |
515 | {"sha-256" , SHA256_DIGEST_DEF}, |
516 | {"sha256" , SHA256_DIGEST_DEF}, |
517 | {"sha-1" , SHA1_DIGEST_DEF}, |
518 | {"sha1" , SHA1_DIGEST_DEF}, |
519 | {"md5" , MD5_DIGEST_DEF}, |
520 | {NULL, NULL} |
521 | }; |
522 | |
523 | digest_context *Curl_digest_init(const digest_params *dparams) |
524 | { |
525 | digest_context *ctxt; |
526 | |
527 | /* Create digest context */ |
528 | ctxt = malloc(sizeof(*ctxt)); |
529 | |
530 | if(!ctxt) |
531 | return ctxt; |
532 | |
533 | ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize); |
534 | |
535 | if(!ctxt->digest_hashctx) { |
536 | free(ctxt); |
537 | return NULL; |
538 | } |
539 | |
540 | ctxt->digest_hash = dparams; |
541 | |
542 | if(dparams->digest_init(ctxt->digest_hashctx) != 1) { |
543 | free(ctxt->digest_hashctx); |
544 | free(ctxt); |
545 | return NULL; |
546 | } |
547 | |
548 | return ctxt; |
549 | } |
550 | |
551 | int Curl_digest_update(digest_context *context, |
552 | const unsigned char *data, |
553 | unsigned int len) |
554 | { |
555 | (*context->digest_hash->digest_update)(context->digest_hashctx, data, len); |
556 | |
557 | return 0; |
558 | } |
559 | |
560 | int Curl_digest_final(digest_context *context, unsigned char *result) |
561 | { |
562 | if(result) |
563 | (*context->digest_hash->digest_final)(result, context->digest_hashctx); |
564 | |
565 | free(context->digest_hashctx); |
566 | free(context); |
567 | |
568 | return 0; |
569 | } |
570 | |
571 | static unsigned char hex_to_uint(const char *s) |
572 | { |
573 | char buf[3]; |
574 | unsigned long val; |
575 | buf[0] = s[0]; |
576 | buf[1] = s[1]; |
577 | buf[2] = 0; |
578 | val = strtoul(buf, NULL, 16); |
579 | return (unsigned char)(val&0xff); |
580 | } |
581 | |
582 | /* |
583 | * Check checksum of file denoted by filename. The expected hash value |
584 | * is given in hex_hash which is hex-encoded string. |
585 | * |
586 | * This function returns 1 if it succeeds or one of the following |
587 | * integers: |
588 | * |
589 | * 0: |
590 | * Checksum didn't match. |
591 | * -1: |
592 | * Could not open file; or could not read data from file. |
593 | * -2: |
594 | * Hash algorithm not available. |
595 | */ |
596 | static int check_hash(const char *filename, |
597 | const metalink_digest_def *digest_def, |
598 | const unsigned char *digest, FILE *error) |
599 | { |
600 | unsigned char *result; |
601 | digest_context *dctx; |
602 | int check_ok, flags, fd; |
603 | |
604 | flags = O_RDONLY; |
605 | #ifdef O_BINARY |
606 | /* O_BINARY is required in order to avoid binary EOF in text mode */ |
607 | flags |= O_BINARY; |
608 | #endif |
609 | |
610 | fd = open(filename, flags); |
611 | if(fd == -1) { |
612 | fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n" , filename, |
613 | digest_def->hash_name, strerror(errno)); |
614 | return -1; |
615 | } |
616 | |
617 | dctx = Curl_digest_init(digest_def->dparams); |
618 | if(!dctx) { |
619 | fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n" , filename, |
620 | digest_def->hash_name, "failed to initialize hash algorithm" ); |
621 | close(fd); |
622 | return -2; |
623 | } |
624 | |
625 | result = malloc(digest_def->dparams->digest_resultlen); |
626 | if(!result) { |
627 | close(fd); |
628 | Curl_digest_final(dctx, NULL); |
629 | return -1; |
630 | } |
631 | while(1) { |
632 | unsigned char buf[4096]; |
633 | ssize_t len = read(fd, buf, sizeof(buf)); |
634 | if(len == 0) { |
635 | break; |
636 | } |
637 | else if(len == -1) { |
638 | fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n" , filename, |
639 | digest_def->hash_name, strerror(errno)); |
640 | Curl_digest_final(dctx, result); |
641 | close(fd); |
642 | return -1; |
643 | } |
644 | Curl_digest_update(dctx, buf, (unsigned int)len); |
645 | } |
646 | Curl_digest_final(dctx, result); |
647 | check_ok = memcmp(result, digest, |
648 | digest_def->dparams->digest_resultlen) == 0; |
649 | /* sha*sum style verdict output */ |
650 | if(check_ok) |
651 | fprintf(error, "Metalink: validating (%s) [%s] OK\n" , filename, |
652 | digest_def->hash_name); |
653 | else |
654 | fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n" , |
655 | filename, digest_def->hash_name); |
656 | |
657 | free(result); |
658 | close(fd); |
659 | return check_ok; |
660 | } |
661 | |
662 | int metalink_check_hash(struct GlobalConfig *config, |
663 | metalinkfile *mlfile, |
664 | const char *filename) |
665 | { |
666 | int rv; |
667 | fprintf(config->errors, "Metalink: validating (%s)...\n" , filename); |
668 | if(mlfile->checksum == NULL) { |
669 | fprintf(config->errors, |
670 | "Metalink: validating (%s) FAILED (digest missing)\n" , filename); |
671 | return -2; |
672 | } |
673 | rv = check_hash(filename, mlfile->checksum->digest_def, |
674 | mlfile->checksum->digest, config->errors); |
675 | return rv; |
676 | } |
677 | |
678 | static metalink_checksum * |
679 | checksum_from_hex_digest(const metalink_digest_def *digest_def, |
680 | const char *hex_digest) |
681 | { |
682 | metalink_checksum *chksum; |
683 | unsigned char *digest; |
684 | size_t i; |
685 | size_t len = strlen(hex_digest); |
686 | digest = malloc(len/2); |
687 | if(!digest) |
688 | return 0; |
689 | |
690 | for(i = 0; i < len; i += 2) { |
691 | digest[i/2] = hex_to_uint(hex_digest + i); |
692 | } |
693 | chksum = malloc(sizeof(metalink_checksum)); |
694 | if(chksum) { |
695 | chksum->digest_def = digest_def; |
696 | chksum->digest = digest; |
697 | } |
698 | else |
699 | free(digest); |
700 | return chksum; |
701 | } |
702 | |
703 | static metalink_resource *new_metalink_resource(const char *url) |
704 | { |
705 | metalink_resource *res; |
706 | res = malloc(sizeof(metalink_resource)); |
707 | if(res) { |
708 | res->next = NULL; |
709 | res->url = strdup(url); |
710 | if(!res->url) { |
711 | free(res); |
712 | return NULL; |
713 | } |
714 | } |
715 | return res; |
716 | } |
717 | |
718 | /* Returns nonzero if hex_digest is properly formatted; that is each |
719 | letter is in [0-9A-Za-z] and the length of the string equals to the |
720 | result length of digest * 2. */ |
721 | static int check_hex_digest(const char *hex_digest, |
722 | const metalink_digest_def *digest_def) |
723 | { |
724 | size_t i; |
725 | for(i = 0; hex_digest[i]; ++i) { |
726 | char c = hex_digest[i]; |
727 | if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || |
728 | ('A' <= c && c <= 'Z'))) { |
729 | return 0; |
730 | } |
731 | } |
732 | return digest_def->dparams->digest_resultlen * 2 == i; |
733 | } |
734 | |
735 | static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo) |
736 | { |
737 | metalinkfile *f; |
738 | f = (metalinkfile*)malloc(sizeof(metalinkfile)); |
739 | if(!f) |
740 | return NULL; |
741 | |
742 | f->next = NULL; |
743 | f->filename = strdup(fileinfo->name); |
744 | if(!f->filename) { |
745 | free(f); |
746 | return NULL; |
747 | } |
748 | f->checksum = NULL; |
749 | f->resource = NULL; |
750 | if(fileinfo->checksums) { |
751 | const metalink_digest_alias *digest_alias; |
752 | for(digest_alias = digest_aliases; digest_alias->alias_name; |
753 | ++digest_alias) { |
754 | metalink_checksum_t **p; |
755 | for(p = fileinfo->checksums; *p; ++p) { |
756 | if(curl_strequal(digest_alias->alias_name, (*p)->type) && |
757 | check_hex_digest((*p)->hash, digest_alias->digest_def)) { |
758 | f->checksum = |
759 | checksum_from_hex_digest(digest_alias->digest_def, |
760 | (*p)->hash); |
761 | break; |
762 | } |
763 | } |
764 | if(f->checksum) { |
765 | break; |
766 | } |
767 | } |
768 | } |
769 | if(fileinfo->resources) { |
770 | metalink_resource_t **p; |
771 | metalink_resource root, *tail; |
772 | root.next = NULL; |
773 | tail = &root; |
774 | for(p = fileinfo->resources; *p; ++p) { |
775 | metalink_resource *res; |
776 | /* Filter by type if it is non-NULL. In Metalink v3, type |
777 | includes the type of the resource. In curl, we are only |
778 | interested in HTTP, HTTPS and FTP. In addition to them, |
779 | Metalink v3 file may contain bittorrent type URL, which |
780 | points to the BitTorrent metainfo file. We ignore it here. |
781 | In Metalink v4, type was deprecated and all |
782 | fileinfo->resources point to the target file. BitTorrent |
783 | metainfo file URL may be appeared in fileinfo->metaurls. |
784 | */ |
785 | if((*p)->type == NULL || |
786 | curl_strequal((*p)->type, "http" ) || |
787 | curl_strequal((*p)->type, "https" ) || |
788 | curl_strequal((*p)->type, "ftp" ) || |
789 | curl_strequal((*p)->type, "ftps" )) { |
790 | res = new_metalink_resource((*p)->url); |
791 | if(res) { |
792 | tail->next = res; |
793 | tail = res; |
794 | } |
795 | else { |
796 | tail = root.next; |
797 | |
798 | /* clean up the linked list */ |
799 | while(tail) { |
800 | res = tail->next; |
801 | free(tail->url); |
802 | free(tail); |
803 | tail = res; |
804 | } |
805 | free(f->filename); |
806 | free(f); |
807 | return NULL; |
808 | } |
809 | } |
810 | } |
811 | f->resource = root.next; |
812 | } |
813 | return f; |
814 | } |
815 | |
816 | int parse_metalink(struct OperationConfig *config, struct OutStruct *outs, |
817 | const char *metalink_url) |
818 | { |
819 | metalink_error_t r; |
820 | metalink_t* metalink; |
821 | metalink_file_t **files; |
822 | bool warnings = FALSE; |
823 | |
824 | /* metlaink_parse_final deletes outs->metalink_parser */ |
825 | r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink); |
826 | outs->metalink_parser = NULL; |
827 | if(r != 0) { |
828 | return -1; |
829 | } |
830 | if(metalink->files == NULL) { |
831 | fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " |
832 | "(missing or invalid file name)\n" , |
833 | metalink_url); |
834 | metalink_delete(metalink); |
835 | return -1; |
836 | } |
837 | for(files = metalink->files; *files; ++files) { |
838 | struct getout *url; |
839 | /* Skip an entry which has no resource. */ |
840 | if(!(*files)->resources) { |
841 | fprintf(config->global->errors, "Metalink: parsing (%s) WARNING " |
842 | "(missing or invalid resource)\n" , |
843 | metalink_url); |
844 | continue; |
845 | } |
846 | if(config->url_get || |
847 | ((config->url_get = config->url_list) != NULL)) { |
848 | /* there's a node here, if it already is filled-in continue to |
849 | find an "empty" node */ |
850 | while(config->url_get && (config->url_get->flags & GETOUT_URL)) |
851 | config->url_get = config->url_get->next; |
852 | } |
853 | |
854 | /* now there might or might not be an available node to fill in! */ |
855 | |
856 | if(config->url_get) |
857 | /* existing node */ |
858 | url = config->url_get; |
859 | else |
860 | /* there was no free node, create one! */ |
861 | url = new_getout(config); |
862 | |
863 | if(url) { |
864 | metalinkfile *mlfile = new_metalinkfile(*files); |
865 | if(!mlfile) |
866 | break; |
867 | |
868 | if(!mlfile->checksum) { |
869 | warnings = TRUE; |
870 | fprintf(config->global->errors, |
871 | "Metalink: parsing (%s) WARNING (digest missing)\n" , |
872 | metalink_url); |
873 | } |
874 | /* Set name as url */ |
875 | GetStr(&url->url, mlfile->filename); |
876 | |
877 | /* set flag metalink here */ |
878 | url->flags |= GETOUT_URL | GETOUT_METALINK; |
879 | |
880 | if(config->metalinkfile_list) { |
881 | config->metalinkfile_last->next = mlfile; |
882 | config->metalinkfile_last = mlfile; |
883 | } |
884 | else { |
885 | config->metalinkfile_list = config->metalinkfile_last = mlfile; |
886 | } |
887 | } |
888 | } |
889 | metalink_delete(metalink); |
890 | return (warnings) ? -2 : 0; |
891 | } |
892 | |
893 | size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb, |
894 | void *userdata) |
895 | { |
896 | struct per_transfer *per = userdata; |
897 | struct OutStruct *outs = &per->outs; |
898 | struct OperationConfig *config = outs->config; |
899 | int rv; |
900 | |
901 | /* |
902 | * Once that libcurl has called back tool_write_cb() the returned value |
903 | * is checked against the amount that was intended to be written, if |
904 | * it does not match then it fails with CURLE_WRITE_ERROR. So at this |
905 | * point returning a value different from sz*nmemb indicates failure. |
906 | */ |
907 | const size_t failure = (sz && nmemb) ? 0 : 1; |
908 | |
909 | if(!config) |
910 | return failure; |
911 | |
912 | rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb); |
913 | if(rv == 0) |
914 | return sz * nmemb; |
915 | else { |
916 | fprintf(config->global->errors, "Metalink: parsing FAILED\n" ); |
917 | return failure; |
918 | } |
919 | } |
920 | |
921 | /* |
922 | * Returns nonzero if content_type includes mediatype. |
923 | */ |
924 | static int check_content_type(const char *content_type, const char *media_type) |
925 | { |
926 | const char *ptr = content_type; |
927 | size_t media_type_len = strlen(media_type); |
928 | for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr); |
929 | if(!*ptr) { |
930 | return 0; |
931 | } |
932 | return curl_strnequal(ptr, media_type, media_type_len) && |
933 | (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' || |
934 | *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';'); |
935 | } |
936 | |
937 | int check_metalink_content_type(const char *content_type) |
938 | { |
939 | return check_content_type(content_type, "application/metalink+xml" ); |
940 | } |
941 | |
942 | int count_next_metalink_resource(metalinkfile *mlfile) |
943 | { |
944 | int count = 0; |
945 | metalink_resource *res; |
946 | for(res = mlfile->resource; res; res = res->next, ++count); |
947 | return count; |
948 | } |
949 | |
950 | static void delete_metalink_checksum(metalink_checksum *chksum) |
951 | { |
952 | if(chksum == NULL) { |
953 | return; |
954 | } |
955 | Curl_safefree(chksum->digest); |
956 | Curl_safefree(chksum); |
957 | } |
958 | |
959 | static void delete_metalink_resource(metalink_resource *res) |
960 | { |
961 | if(res == NULL) { |
962 | return; |
963 | } |
964 | Curl_safefree(res->url); |
965 | Curl_safefree(res); |
966 | } |
967 | |
968 | void delete_metalinkfile(metalinkfile *mlfile) |
969 | { |
970 | metalink_resource *res; |
971 | if(mlfile == NULL) { |
972 | return; |
973 | } |
974 | Curl_safefree(mlfile->filename); |
975 | delete_metalink_checksum(mlfile->checksum); |
976 | for(res = mlfile->resource; res;) { |
977 | metalink_resource *next; |
978 | next = res->next; |
979 | delete_metalink_resource(res); |
980 | res = next; |
981 | } |
982 | Curl_safefree(mlfile); |
983 | } |
984 | |
985 | void clean_metalink(struct OperationConfig *config) |
986 | { |
987 | if(config) { |
988 | while(config->metalinkfile_list) { |
989 | metalinkfile *mlfile = config->metalinkfile_list; |
990 | config->metalinkfile_list = config->metalinkfile_list->next; |
991 | delete_metalinkfile(mlfile); |
992 | } |
993 | config->metalinkfile_last = 0; |
994 | } |
995 | } |
996 | |
997 | void metalink_cleanup(void) |
998 | { |
999 | #ifdef HAVE_NSS_CONTEXT |
1000 | if(nss_context) { |
1001 | NSS_ShutdownContext(nss_context); |
1002 | nss_context = NULL; |
1003 | } |
1004 | #endif |
1005 | } |
1006 | |
1007 | #endif /* USE_METALINK */ |
1008 | |