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