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