33b6e7392d4e7395d3694f073c5d3eee32143da6
[oweals/opkg-lede.git] / libopkg / opkg_download.c
1 /* vi: set noexpandtab sw=4 sts=4: */
2 /* opkg_download.c - the opkg package management system
3
4    Carl D. Worth
5
6    Copyright (C) 2001 University of Southern California
7    Copyright (C) 2008 OpenMoko Inc
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18 */
19
20 #include <sys/wait.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <libgen.h>
24
25 #include "opkg_download.h"
26 #include "opkg_message.h"
27
28 #include "sprintf_alloc.h"
29 #include "xsystem.h"
30 #include "file_util.h"
31 #include "opkg_defines.h"
32 #include "libbb/libbb.h"
33
34 #ifdef HAVE_CURL
35 #include <curl/curl.h>
36 #endif
37
38 #if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL)
39 #include <openssl/conf.h>
40 #include <openssl/evp.h>
41 #include <openssl/err.h>
42 #include <openssl/ssl.h>
43 #endif
44
45 #if defined(HAVE_GPGME)
46 #include <gpgme.h>
47 #elif defined(HAVE_OPENSSL)
48 #include <openssl/bio.h>
49 #include <openssl/objects.h>
50 #include <openssl/x509.h>
51 #include <openssl/pem.h>
52 #include <openssl/hmac.h>
53 #endif
54
55 #ifdef HAVE_PATHFINDER
56 #include "opkg_pathfinder.h"
57 #endif
58
59 #if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL)
60 static void openssl_init(void);
61 #endif
62
63 #ifdef HAVE_OPENSSL
64 static X509_STORE *setup_verify(char *CAfile, char *CApath);
65 #endif
66
67 #ifdef HAVE_CURL
68 /*
69  * Make curl an instance variable so we don't have to instanciate it
70  * each time
71  */
72 static CURL *curl = NULL;
73 static CURL *opkg_curl_init(curl_progress_func cb, void *data);
74 #endif
75
76 static int str_starts_with(const char *str, const char *prefix)
77 {
78         return (strncmp(str, prefix, strlen(prefix)) == 0);
79 }
80
81 int
82 opkg_download(const char *src, const char *dest_file_name,
83               curl_progress_func cb, void *data, const short hide_error)
84 {
85         int err = 0;
86
87         char *src_basec = xstrdup(src);
88         char *src_base = basename(src_basec);
89         char *tmp_file_location;
90
91         opkg_msg(NOTICE, "Downloading %s\n", src);
92
93         if (str_starts_with(src, "file:")) {
94                 const char *file_src = src + 5;
95                 opkg_msg(INFO, "Copying %s to %s...", file_src, dest_file_name);
96                 err = file_copy(file_src, dest_file_name);
97                 opkg_msg(INFO, "Done.\n");
98                 free(src_basec);
99                 return err;
100         }
101
102         sprintf_alloc(&tmp_file_location, "%s/%s", conf->tmp_dir, src_base);
103         free(src_basec);
104         err = unlink(tmp_file_location);
105         if (err && errno != ENOENT) {
106                 opkg_perror(ERROR, "Failed to unlink %s", tmp_file_location);
107                 free(tmp_file_location);
108                 return -1;
109         }
110
111         if (conf->http_proxy) {
112                 opkg_msg(DEBUG,
113                          "Setting environment variable: http_proxy = %s.\n",
114                          conf->http_proxy);
115                 setenv("http_proxy", conf->http_proxy, 1);
116         }
117         if (conf->ftp_proxy) {
118                 opkg_msg(DEBUG,
119                          "Setting environment variable: ftp_proxy = %s.\n",
120                          conf->ftp_proxy);
121                 setenv("ftp_proxy", conf->ftp_proxy, 1);
122         }
123         if (conf->no_proxy) {
124                 opkg_msg(DEBUG,
125                          "Setting environment variable: no_proxy = %s.\n",
126                          conf->no_proxy);
127                 setenv("no_proxy", conf->no_proxy, 1);
128         }
129 #ifdef HAVE_CURL
130         CURLcode res;
131         FILE *file = fopen(tmp_file_location, "w");
132
133         curl = opkg_curl_init(cb, data);
134         if (curl) {
135                 curl_easy_setopt(curl, CURLOPT_URL, src);
136                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
137
138                 res = curl_easy_perform(curl);
139                 fclose(file);
140                 if (res) {
141                         long error_code;
142                         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE,
143                                           &error_code);
144                         opkg_msg(hide_error ? DEBUG2 : ERROR,
145                                  "Failed to download %s: %s.\n", src,
146                                  curl_easy_strerror(res));
147                         free(tmp_file_location);
148                         return -1;
149                 }
150
151         } else {
152                 free(tmp_file_location);
153                 return -1;
154         }
155 #else
156         {
157                 int res;
158                 const char *argv[8];
159                 int i = 0;
160
161                 argv[i++] = "wget";
162                 argv[i++] = "-q";
163                 if (conf->http_proxy || conf->ftp_proxy) {
164                         argv[i++] = "-Y";
165                         argv[i++] = "on";
166                 }
167                 argv[i++] = "-O";
168                 argv[i++] = tmp_file_location;
169                 argv[i++] = src;
170                 argv[i++] = NULL;
171                 res = xsystem(argv);
172
173                 if (res) {
174                         opkg_msg(ERROR,
175                                  "Failed to download %s, wget returned %d.\n",
176                                  src, res);
177                         if (res == 4)
178                                 opkg_msg(ERROR,
179                                          "Check your network settings and connectivity.\n\n");
180                         free(tmp_file_location);
181                         return -1;
182                 }
183         }
184 #endif
185
186         err = file_move(tmp_file_location, dest_file_name);
187
188         free(tmp_file_location);
189
190         return err;
191 }
192
193 static int
194 opkg_download_cache(const char *src, const char *dest_file_name,
195                     curl_progress_func cb, void *data)
196 {
197         char *cache_name = xstrdup(src);
198         char *cache_location, *p;
199         int err = 0;
200
201         if (!conf->cache || str_starts_with(src, "file:")) {
202                 err = opkg_download(src, dest_file_name, cb, data, 0);
203                 goto out1;
204         }
205
206         if (!file_is_dir(conf->cache)) {
207                 opkg_msg(ERROR, "%s is not a directory.\n", conf->cache);
208                 err = 1;
209                 goto out1;
210         }
211
212         for (p = cache_name; *p; p++)
213                 if (*p == '/')
214                         *p = ',';       /* looks nicer than | or # */
215
216         sprintf_alloc(&cache_location, "%s/%s", conf->cache, cache_name);
217         if (file_exists(cache_location))
218                 opkg_msg(NOTICE, "Copying %s.\n", cache_location);
219         else {
220                 /* cache file with funky name not found, try simple name */
221                 free(cache_name);
222                 char *filename = strrchr(dest_file_name, '/');
223                 if (filename)
224                         cache_name = xstrdup(filename + 1);     // strip leading '/'
225                 else
226                         cache_name = xstrdup(dest_file_name);
227                 free(cache_location);
228                 sprintf_alloc(&cache_location, "%s/%s", conf->cache,
229                               cache_name);
230                 if (file_exists(cache_location))
231                         opkg_msg(NOTICE, "Copying %s.\n", cache_location);
232                 else {
233                         err = opkg_download(src, cache_location, cb, data, 0);
234                         if (err) {
235                                 (void)unlink(cache_location);
236                                 goto out2;
237                         }
238                 }
239         }
240
241         err = file_copy(cache_location, dest_file_name);
242
243 out2:
244         free(cache_location);
245 out1:
246         free(cache_name);
247         return err;
248 }
249
250 int opkg_download_pkg(pkg_t * pkg, const char *dir)
251 {
252         int err;
253         char *url;
254         char *local_filename;
255         char *stripped_filename;
256         char *filename;
257
258         if (pkg->src == NULL) {
259                 opkg_msg(ERROR,
260                          "Package %s is not available from any configured src.\n",
261                          pkg->name);
262                 return -1;
263         }
264
265         filename = pkg_get_string(pkg, PKG_FILENAME);
266
267         if (filename == NULL) {
268                 opkg_msg(ERROR,
269                          "Package %s does not have a valid filename field.\n",
270                          pkg->name);
271                 return -1;
272         }
273
274         sprintf_alloc(&url, "%s/%s", pkg->src->value, filename);
275
276         /* The filename might be something like
277            "../../foo.opk". While this is correct, and exactly what we
278            want to use to construct url above, here we actually need to
279            use just the filename part, without any directory. */
280
281         stripped_filename = strrchr(filename, '/');
282         if (!stripped_filename)
283                 stripped_filename = filename;
284
285         sprintf_alloc(&local_filename, "%s/%s", dir, stripped_filename);
286         pkg_set_string(pkg, PKG_LOCAL_FILENAME, local_filename);
287
288         err = opkg_download_cache(url, local_filename, NULL, NULL);
289         free(url);
290
291         return err;
292 }
293
294 /*
295  * Downloads file from url, installs in package database, return package name.
296  */
297 int opkg_prepare_url_for_install(const char *url, char **namep)
298 {
299         int err = 0;
300         pkg_t *pkg;
301         abstract_pkg_t *ab_pkg;
302
303         pkg = pkg_new();
304
305         if (str_starts_with(url, "http://")
306             || str_starts_with(url, "ftp://")) {
307                 char *tmp_file;
308                 char *file_basec = xstrdup(url);
309                 char *file_base = basename(file_basec);
310
311                 sprintf_alloc(&tmp_file, "%s/%s", conf->tmp_dir, file_base);
312                 err = opkg_download(url, tmp_file, NULL, NULL, 0);
313                 if (err)
314                         return err;
315
316                 err = pkg_init_from_file(pkg, tmp_file);
317                 if (err)
318                         return err;
319
320                 free(tmp_file);
321                 free(file_basec);
322
323         } else if (strcmp(&url[strlen(url) - 4], OPKG_PKG_EXTENSION) == 0
324                    || strcmp(&url[strlen(url) - 4], IPKG_PKG_EXTENSION) == 0
325                    || strcmp(&url[strlen(url) - 4], DPKG_PKG_EXTENSION) == 0) {
326
327                 err = pkg_init_from_file(pkg, url);
328                 if (err)
329                         return err;
330                 opkg_msg(DEBUG2, "Package %s provided by hand (%s).\n",
331                          pkg->name, pkg_get_string(pkg, PKG_LOCAL_FILENAME));
332                 pkg->provided_by_hand = 1;
333
334         } else {
335                 ab_pkg = ensure_abstract_pkg_by_name(url);
336
337                 if (!(ab_pkg->state_flag & SF_NEED_DETAIL)) {
338                         opkg_msg(DEBUG, "applying abpkg flag to %s\n", ab_pkg->name);
339                         ab_pkg->state_flag |= SF_NEED_DETAIL;
340                 }
341
342                 pkg_deinit(pkg);
343                 free(pkg);
344                 return 0;
345         }
346
347         pkg->dest = conf->default_dest;
348         pkg->state_want = SW_INSTALL;
349         pkg->state_flag |= SF_PREFER;
350         hash_insert_pkg(pkg, 1);
351
352         if (namep) {
353                 *namep = xstrdup(pkg->name);
354         }
355         return 0;
356 }
357
358 int opkg_verify_file(char *text_file, char *sig_file)
359 {
360 #if defined HAVE_USIGN
361         int status = -1;
362         int pid;
363
364         if (conf->check_signature == 0)
365                 return 0;
366
367         pid = fork();
368         if (pid < 0)
369                 return -1;
370
371         if (!pid) {
372                 execl("/usr/sbin/opkg-key", "opkg-key", "verify", sig_file,
373                       text_file, NULL);
374                 exit(255);
375         }
376
377         waitpid(pid, &status, 0);
378         if (!WIFEXITED(status) || WEXITSTATUS(status))
379                 return -1;
380
381         return 0;
382 #elif defined HAVE_GPGME
383         if (conf->check_signature == 0)
384                 return 0;
385         int status = -1;
386         gpgme_ctx_t ctx;
387         gpgme_data_t sig, text, key;
388         gpgme_error_t err;
389         gpgme_verify_result_t result;
390         gpgme_signature_t s;
391         char *trusted_path = NULL;
392
393         gpgme_check_version(NULL);
394
395         err = gpgme_new(&ctx);
396
397         if (err)
398                 return -1;
399
400         sprintf_alloc(&trusted_path, "%s/%s", conf->offline_root,
401                       "/etc/opkg/trusted.gpg");
402         err = gpgme_data_new_from_file(&key, trusted_path, 1);
403         free(trusted_path);
404         if (err) {
405                 return -1;
406         }
407         err = gpgme_op_import(ctx, key);
408         if (err) {
409                 gpgme_data_release(key);
410                 return -1;
411         }
412         gpgme_data_release(key);
413
414         err = gpgme_data_new_from_file(&sig, sig_file, 1);
415         if (err) {
416                 gpgme_release(ctx);
417                 return -1;
418         }
419
420         err = gpgme_data_new_from_file(&text, text_file, 1);
421         if (err) {
422                 gpgme_data_release(sig);
423                 gpgme_release(ctx);
424                 return -1;
425         }
426
427         err = gpgme_op_verify(ctx, sig, text, NULL);
428
429         result = gpgme_op_verify_result(ctx);
430         if (!result)
431                 return -1;
432
433         /* see if any of the signitures matched */
434         s = result->signatures;
435         while (s) {
436                 status = gpg_err_code(s->status);
437                 if (status == GPG_ERR_NO_ERROR)
438                         break;
439                 s = s->next;
440         }
441
442         gpgme_data_release(sig);
443         gpgme_data_release(text);
444         gpgme_release(ctx);
445
446         return status;
447 #elif defined HAVE_OPENSSL
448         X509_STORE *store = NULL;
449         PKCS7 *p7 = NULL;
450         BIO *in = NULL, *indata = NULL;
451
452         // Sig check failed by default !
453         int status = -1;
454
455         openssl_init();
456
457         // Set-up the key store
458         if (!
459             (store =
460              setup_verify(conf->signature_ca_file, conf->signature_ca_path))) {
461                 opkg_msg(ERROR, "Can't open CA certificates.\n");
462                 goto verify_file_end;
463         }
464         // Open a BIO to read the sig file
465         if (!(in = BIO_new_file(sig_file, "rb"))) {
466                 opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file);
467                 goto verify_file_end;
468         }
469         // Read the PKCS7 block contained in the sig file
470         p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
471         if (!p7) {
472                 opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n",
473                          sig_file);
474                 goto verify_file_end;
475         }
476 #if defined(HAVE_PATHFINDER)
477         if (conf->check_x509_path) {
478                 if (!pkcs7_pathfinder_verify_signers(p7)) {
479                         opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: "
480                                  "Path verification failed.\n");
481                         goto verify_file_end;
482                 }
483         }
484 #endif
485
486         // Open the Package file to authenticate
487         if (!(indata = BIO_new_file(text_file, "rb"))) {
488                 opkg_msg(ERROR, "Can't open file %s.\n", text_file);
489                 goto verify_file_end;
490         }
491         // Let's verify the autenticity !
492         if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1) {
493                 // Get Off My Lawn!
494                 opkg_msg(ERROR, "Verification failure.\n");
495         } else {
496                 // Victory !
497                 status = 0;
498         }
499
500 verify_file_end:
501         BIO_free(in);
502         BIO_free(indata);
503         PKCS7_free(p7);
504         X509_STORE_free(store);
505
506         return status;
507 #else
508         /* mute `unused variable' warnings. */
509         (void)sig_file;
510         (void)text_file;
511         (void)conf;
512         return 0;
513 #endif
514 }
515
516 #if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL)
517 static void openssl_init(void)
518 {
519         static int init = 0;
520
521         if (!init) {
522                 OPENSSL_config(NULL);
523                 OpenSSL_add_all_algorithms();
524                 ERR_load_crypto_strings();
525                 init = 1;
526         }
527 }
528
529 #endif
530
531 #if defined HAVE_OPENSSL
532 static X509_STORE *setup_verify(char *CAfile, char *CApath)
533 {
534         X509_STORE *store = NULL;
535         X509_LOOKUP *lookup = NULL;
536
537         if (!(store = X509_STORE_new())) {
538                 // Something bad is happening...
539                 goto end;
540         }
541         // adds the X509 file lookup method
542         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
543         if (lookup == NULL) {
544                 goto end;
545         }
546         // Autenticating against one CA file
547         if (CAfile) {
548                 if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) {
549                         // Invalid CA => Bye bye
550                         opkg_msg(ERROR, "Error loading file %s.\n", CAfile);
551                         goto end;
552                 }
553         } else {
554                 X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
555         }
556
557         // Now look into CApath directory if supplied
558         lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
559         if (lookup == NULL) {
560                 goto end;
561         }
562
563         if (CApath) {
564                 if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) {
565                         opkg_msg(ERROR, "Error loading directory %s.\n",
566                                  CApath);
567                         goto end;
568                 }
569         } else {
570                 X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
571         }
572
573         // All right !
574         ERR_clear_error();
575         return store;
576
577 end:
578
579         X509_STORE_free(store);
580         return NULL;
581
582 }
583
584 #endif
585
586 #ifdef HAVE_CURL
587 void opkg_curl_cleanup(void)
588 {
589         if (curl != NULL) {
590                 curl_easy_cleanup(curl);
591                 curl = NULL;
592         }
593 }
594
595 static CURL *opkg_curl_init(curl_progress_func cb, void *data)
596 {
597
598         if (curl == NULL) {
599                 curl = curl_easy_init();
600
601 #ifdef HAVE_SSLCURL
602                 openssl_init();
603
604                 if (conf->ssl_engine) {
605
606                         /* use crypto engine */
607                         if (curl_easy_setopt
608                             (curl, CURLOPT_SSLENGINE,
609                              conf->ssl_engine) != CURLE_OK) {
610                                 opkg_msg(ERROR,
611                                          "Can't set crypto engine '%s'.\n",
612                                          conf->ssl_engine);
613
614                                 opkg_curl_cleanup();
615                                 return NULL;
616                         }
617                         /* set the crypto engine as default */
618                         if (curl_easy_setopt
619                             (curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK) {
620                                 opkg_msg(ERROR,
621                                          "Can't set crypto engine '%s' as default.\n",
622                                          conf->ssl_engine);
623
624                                 opkg_curl_cleanup();
625                                 return NULL;
626                         }
627                 }
628
629                 /* cert & key can only be in PEM case in the same file */
630                 if (conf->ssl_key_passwd) {
631                         if (curl_easy_setopt
632                             (curl, CURLOPT_SSLKEYPASSWD,
633                              conf->ssl_key_passwd) != CURLE_OK) {
634                                 opkg_msg(DEBUG,
635                                          "Failed to set key password.\n");
636                         }
637                 }
638
639                 /* sets the client certificate and its type */
640                 if (conf->ssl_cert_type) {
641                         if (curl_easy_setopt
642                             (curl, CURLOPT_SSLCERTTYPE,
643                              conf->ssl_cert_type) != CURLE_OK) {
644                                 opkg_msg(DEBUG,
645                                          "Failed to set certificate format.\n");
646                         }
647                 }
648                 /* SSL cert name isn't mandatory */
649                 if (conf->ssl_cert) {
650                         curl_easy_setopt(curl, CURLOPT_SSLCERT, conf->ssl_cert);
651                 }
652
653                 /* sets the client key and its type */
654                 if (conf->ssl_key_type) {
655                         if (curl_easy_setopt
656                             (curl, CURLOPT_SSLKEYTYPE,
657                              conf->ssl_key_type) != CURLE_OK) {
658                                 opkg_msg(DEBUG, "Failed to set key format.\n");
659                         }
660                 }
661                 if (conf->ssl_key) {
662                         if (curl_easy_setopt
663                             (curl, CURLOPT_SSLKEY, conf->ssl_key) != CURLE_OK) {
664                                 opkg_msg(DEBUG, "Failed to set key.\n");
665                         }
666                 }
667
668                 /* Should we verify the peer certificate ? */
669                 if (conf->ssl_dont_verify_peer) {
670                         /*
671                          * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10)
672                          */
673                         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
674                 } else {
675 #ifdef HAVE_PATHFINDER
676                         if (conf->check_x509_path) {
677                                 if (curl_easy_setopt
678                                     (curl, CURLOPT_SSL_CTX_FUNCTION,
679                                      curl_ssl_ctx_function) != CURLE_OK) {
680                                         opkg_msg(DEBUG,
681                                                  "Failed to set ssl path verification callback.\n");
682                                 } else {
683                                         curl_easy_setopt(curl,
684                                                          CURLOPT_SSL_CTX_DATA,
685                                                          NULL);
686                                 }
687                         }
688 #endif
689                 }
690
691                 /* certification authority file and/or path */
692                 if (conf->ssl_ca_file) {
693                         curl_easy_setopt(curl, CURLOPT_CAINFO,
694                                          conf->ssl_ca_file);
695                 }
696                 if (conf->ssl_ca_path) {
697                         curl_easy_setopt(curl, CURLOPT_CAPATH,
698                                          conf->ssl_ca_path);
699                 }
700 #endif
701
702                 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
703                 curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
704                 if (conf->http_proxy || conf->ftp_proxy) {
705                         char *userpwd;
706                         sprintf_alloc(&userpwd, "%s:%s", conf->proxy_user,
707                                       conf->proxy_passwd);
708                         curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd);
709                         free(userpwd);
710                 }
711         }
712
713         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, (cb == NULL));
714         if (cb) {
715                 curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, data);
716                 curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, cb);
717         }
718
719         return curl;
720
721 }
722 #endif