1 /* librepo - A library providing (libcURL like) API to downloading repository
2  * Copyright (C) 2012  Tomas Mlcoch
3  *
4  * Licensed under the GNU Lesser General Public License Version 2.1
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #define _POSIX_C_SOURCE 200809L
22 #define _BSD_SOURCE
23 
24 #include <glib.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <curl/curl.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 
36 
37 #include "handle_internal.h"
38 #include "handle.h"
39 #include "result_internal.h"
40 #include "repomd.h"
41 #include "rcodes.h"
42 #include "util.h"
43 #include "yum.h"
44 #include "version.h"
45 #include "yum_internal.h"
46 #include "url_substitution.h"
47 #include "downloader.h"
48 #include "fastestmirror_internal.h"
49 #include "cleanup.h"
50 
51 CURL *
lr_get_curl_handle()52 lr_get_curl_handle()
53 {
54     CURL *h;
55 
56     lr_global_init();
57 
58     h = curl_easy_init();
59     if (!h)
60         return NULL;
61 
62     if (curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK)
63         goto err;
64     if (curl_easy_setopt(h, CURLOPT_MAXREDIRS, 6) != CURLE_OK)
65         goto err;
66     if (curl_easy_setopt(h, CURLOPT_CONNECTTIMEOUT, LRO_CONNECTTIMEOUT_DEFAULT) != CURLE_OK)
67         goto err;
68     if (curl_easy_setopt(h, CURLOPT_LOW_SPEED_TIME, LRO_LOWSPEEDTIME_DEFAULT) != CURLE_OK)
69         goto err;
70     if (curl_easy_setopt(h, CURLOPT_LOW_SPEED_LIMIT, LRO_LOWSPEEDLIMIT_DEFAULT) != CURLE_OK)
71         goto err;
72     if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 2) != CURLE_OK)
73         goto err;
74     if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK)
75         goto err;
76     if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYSTATUS, 0) != CURLE_OK)
77         goto err;
78     if (curl_easy_setopt(h, CURLOPT_FTP_USE_EPSV, LRO_FTPUSEEPSV_DEFAULT) != CURLE_OK)
79         goto err;
80     if (curl_easy_setopt(h, CURLOPT_FILETIME, 0) != CURLE_OK)
81         goto err;
82 
83     return h;
84 
85 err:
86     curl_easy_cleanup(h);
87     return NULL;
88 }
89 
90 void
lr_handle_free_list(char *** list)91 lr_handle_free_list(char ***list)
92 {
93     if (!list || *list == NULL)
94         return;
95     for (int x=0; (*list)[x]; x++)
96         lr_free((*list)[x]);
97     lr_free(*list);
98     *list = NULL;
99 }
100 
101 LrHandle *
lr_handle_init(void)102 lr_handle_init(void)
103 {
104     LrHandle *handle;
105     CURL *curl = lr_get_curl_handle();
106 
107     if (!curl)
108         return NULL;
109 
110     handle = lr_malloc0(sizeof(LrHandle));
111     handle->curl_handle = curl;
112     handle->fastestmirrormaxage = LRO_FASTESTMIRRORMAXAGE_DEFAULT;
113     handle->mirrorlist_fd = -1;
114     handle->metalink_fd = -1;
115     handle->onetimeflag_apply = FALSE;
116     handle->checks |= LR_CHECK_CHECKSUM;
117     handle->maxparalleldownloads = LRO_MAXPARALLELDOWNLOADS_DEFAULT;
118     handle->maxdownloadspermirror = LRO_MAXDOWNLOADSPERMIRROR_DEFAULT;
119     handle->lowspeedtime = LRO_LOWSPEEDTIME_DEFAULT;
120     handle->lowspeedlimit = LRO_LOWSPEEDLIMIT_DEFAULT;
121     handle->sslverifypeer = 1;
122     handle->sslverifyhost = 2;
123     handle->sslverifystatus = 0;
124     handle->proxy_sslverifypeer = 1;
125     handle->proxy_sslverifyhost = 2;
126     handle->ipresolve = LRO_IPRESOLVE_DEFAULT;
127     handle->allowed_mirror_failures = LRO_ALLOWEDMIRRORFAILURES_DEFAULT;
128     handle->adaptivemirrorsorting = LRO_ADAPTIVEMIRRORSORTING_DEFAULT;
129     handle->gnupghomedir = g_strdup(LRO_GNUPGHOMEDIR_DEFAULT);
130     handle->fastestmirrortimeout = LRO_FASTESTMIRRORTIMEOUT_DEFAULT;
131     handle->offline = LRO_OFFLINE_DEFAULT;
132     handle->httpauthmethods = LRO_HTTPAUTHMETHODS_DEFAULT;
133     handle->proxyauthmethods = LRO_PROXYAUTHMETHODS_DEFAULT;
134     handle->ftpuseepsv = LRO_FTPUSEEPSV_DEFAULT;
135     handle->cachedir = NULL;
136     handle->preservetime = 0;
137 
138     return handle;
139 }
140 
141 void
lr_handle_free(LrHandle * handle)142 lr_handle_free(LrHandle *handle)
143 {
144     if (!handle)
145         return;
146     if (handle->curl_handle)
147         curl_easy_cleanup(handle->curl_handle);
148     if (handle->mirrorlist_fd != -1)
149         close(handle->mirrorlist_fd);
150     if (handle->metalink_fd != -1)
151         close(handle->metalink_fd);
152     lr_handle_free_list(&handle->urls);
153     lr_free(handle->fastestmirrorcache);
154     lr_free(handle->mirrorlist);
155     lr_free(handle->mirrorlisturl);
156     lr_free(handle->metalinkurl);
157     lr_free(handle->onetimeflag);
158     lr_free(handle->used_mirror);
159     lr_free(handle->destdir);
160     lr_free(handle->useragent);
161     lr_free(handle->sslclientcert);
162     lr_free(handle->sslclientkey);
163     lr_free(handle->sslcacert);
164     lr_free(handle->proxy_sslclientcert);
165     lr_free(handle->proxy_sslclientkey);
166     lr_free(handle->proxy_sslcacert);
167     lr_lrmirrorlist_free(handle->internal_mirrorlist);
168     lr_lrmirrorlist_free(handle->urls_mirrors);
169     lr_lrmirrorlist_free(handle->mirrorlist_mirrors);
170     lr_lrmirrorlist_free(handle->metalink_mirrors);
171     lr_lrmirrorlist_free(handle->mirrors);
172     lr_metalink_free(handle->metalink);
173     lr_handle_free_list(&handle->yumdlist);
174     lr_urlvars_free(handle->yumslist);
175     lr_handle_free_list(&handle->yumblist);
176     lr_urlvars_free(handle->urlvars);
177     lr_free(handle->gnupghomedir);
178     lr_free(handle->cachedir);
179     lr_handle_free_list(&handle->httpheader);
180     lr_free(handle);
181 }
182 
183 typedef enum {
184     LR_REMOTESOURCE_URLS,
185     LR_REMOTESOURCE_MIRRORLIST,
186     LR_REMOTESOURCE_METALINK,
187     LR_REMOTESOURCE_LOCAL_OPT,
188     LR_REMOTESOURCE_OFFLINE_OPT,
189     LR_REMOTESOURCE_OTHER,
190 } LrChangedRemoteSource;
191 
curlauth_bitmask(LrAuth mask)192 static unsigned long curlauth_bitmask(LrAuth mask)
193 {
194     unsigned long out_mask = 0UL;
195 
196     if (mask == LR_AUTH_NONE)
197         return (unsigned long) CURLAUTH_NONE;
198 
199     if (mask & LR_AUTH_BASIC)
200         out_mask |= CURLAUTH_BASIC;
201     if (mask & LR_AUTH_DIGEST)
202         out_mask |= CURLAUTH_DIGEST;
203     if (mask & LR_AUTH_NEGOTIATE)
204 #ifdef CURLAUTH_NEGOTIATE
205         out_mask |= CURLAUTH_NEGOTIATE;
206 #else
207         out_mask |= CURLAUTH_GSSNEGOTIATE;
208 #endif
209     if (mask & LR_AUTH_NTLM)
210         out_mask |= CURLAUTH_NTLM;
211     if (mask & LR_AUTH_DIGEST_IE)
212         out_mask |= CURLAUTH_DIGEST_IE;
213     if (mask & LR_AUTH_NTLM_WB)
214         out_mask |= CURLAUTH_NTLM_WB;
215     if (mask & LR_AUTH_ONLY)
216         out_mask |= CURLAUTH_ONLY;
217     if (mask == LR_AUTH_ANY)
218         out_mask |= CURLAUTH_ANY;
219 
220     return out_mask;
221 }
222 
223 static void
lr_handle_remote_sources_changed(LrHandle * handle,LrChangedRemoteSource type)224 lr_handle_remote_sources_changed(LrHandle *handle, LrChangedRemoteSource type)
225 {
226     // Called when options like:
227     // LRO_URLS
228     // LRO_MIRRORLIST
229     // LRO_MIRRORLISTURL
230     // LRO_METALINKURL
231     // LRO_LOCAL
232     // LRO_OFFLINE
233     // are changed
234 
235     // Internal mirrorlist is no more valid
236     lr_lrmirrorlist_free(handle->internal_mirrorlist);
237     handle->internal_mirrorlist = NULL;
238 
239     // Mirrors reported via mirrors are no more valid too
240     lr_lrmirrorlist_free(handle->mirrors);
241     handle->mirrors = NULL;
242 
243     if (type == LR_REMOTESOURCE_URLS) {
244         lr_lrmirrorlist_free(handle->urls_mirrors);
245         handle->urls_mirrors = NULL;
246     }
247 
248     if (type == LR_REMOTESOURCE_MIRRORLIST) {
249         lr_lrmirrorlist_free(handle->mirrorlist_mirrors);
250         handle->mirrorlist_mirrors = NULL;
251         if (handle->mirrorlist_fd != -1)
252             close(handle->mirrorlist_fd);
253         handle->mirrorlist_fd = -1;
254     }
255 
256     if (type == LR_REMOTESOURCE_METALINK) {
257         lr_lrmirrorlist_free(handle->metalink_mirrors);
258         handle->metalink_mirrors = NULL;
259         if (handle->metalink_fd != -1)
260             close(handle->metalink_fd);
261         handle->metalink_fd = -1;
262         lr_metalink_free(handle->metalink);
263         handle->metalink = NULL;
264     }
265 }
266 
267 gboolean
lr_handle_setopt(LrHandle * handle,GError ** err,LrHandleOption option,...)268 lr_handle_setopt(LrHandle *handle,
269                  GError **err,
270                  LrHandleOption option,
271                  ...)
272 {
273     gboolean ret = TRUE;
274     va_list arg;
275     CURLcode c_rc = CURLE_OK;
276     CURL *c_h;
277 
278     assert(!err || *err == NULL);
279 
280     // Variables for values from va_arg
281     long val_long;
282     gint64 val_gint64;
283 
284     if (!handle) {
285         g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
286                     "No handle specified");
287         return FALSE;
288     }
289 
290     c_h = handle->curl_handle;
291 
292     va_start(arg, option);
293 
294     switch (option) {
295     case LRO_UPDATE:
296         handle->update = va_arg(arg, long) ? 1 : 0;
297         break;
298 
299     case LRO_MIRRORLIST:
300         // DEPRECATED!
301         g_warning("WARNING! Deprecated LRO_MIRRORLIST used");
302         if (handle->mirrorlist) lr_free(handle->mirrorlist);
303         handle->mirrorlist = g_strdup(va_arg(arg, char *));
304 
305         if (handle->mirrorlisturl)
306             lr_free(handle->mirrorlisturl);
307         handle->mirrorlisturl = NULL;
308         if (handle->metalinkurl)
309             lr_free(handle->metalinkurl);
310         handle->metalinkurl = NULL;
311         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_MIRRORLIST);
312         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_METALINK);
313 
314         if (!handle->mirrorlist)
315             break;
316 
317         if (strstr(handle->mirrorlist, "metalink"))
318             handle->metalinkurl = g_strdup(handle->mirrorlist);
319         else
320             handle->mirrorlisturl = g_strdup(handle->mirrorlist);
321         break;
322 
323     case LRO_MIRRORLISTURL:
324         if (handle->mirrorlisturl)
325             lr_free(handle->mirrorlisturl);
326         handle->mirrorlisturl = g_strdup(va_arg(arg, char *));
327         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_MIRRORLIST);
328         break;
329 
330     case LRO_METALINKURL:
331         if (handle->metalinkurl)
332             lr_free(handle->metalinkurl);
333         handle->metalinkurl = g_strdup(va_arg(arg, char *));
334         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_METALINK);
335         break;
336 
337     case LRO_ONETIMEFLAG:
338         if (handle->onetimeflag)
339             lr_free(handle->onetimeflag);
340         handle->onetimeflag = g_strdup(va_arg(arg, char *));
341         break;
342 
343     case LRO_LOCAL:
344         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_LOCAL_OPT);
345         handle->local = va_arg(arg, long) ? 1 : 0;
346         break;
347 
348     case LRO_HTTPAUTH:
349         if (va_arg(arg, long) ==  0) {
350             c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
351             handle->httpauthmethods = LR_AUTH_BASIC;
352         } else {
353             c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
354             handle->httpauthmethods = LR_AUTH_ANY;
355         }
356         break;
357 
358     case LRO_USERPWD:
359         c_rc = curl_easy_setopt(c_h, CURLOPT_USERPWD, va_arg(arg, char *));
360         break;
361 
362     case LRO_PROXY:
363         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY, va_arg(arg, char *));
364         break;
365 
366     case LRO_PROXYPORT: {
367         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYPORT,va_arg(arg, long));
368         break;
369     }
370 
371     case LRO_PROXYTYPE: {
372         long curl_proxy = -1;
373         switch (va_arg(arg, long)) {
374             case LR_PROXY_HTTP:     curl_proxy = CURLPROXY_HTTP;    break;
375             case LR_PROXY_HTTP_1_0: curl_proxy = CURLPROXY_HTTP_1_0;break;
376             case LR_PROXY_SOCKS4:   curl_proxy = CURLPROXY_SOCKS4;  break;
377             case LR_PROXY_SOCKS5:   curl_proxy = CURLPROXY_SOCKS5;  break;
378             case LR_PROXY_SOCKS4A:  curl_proxy = CURLPROXY_SOCKS4A; break;
379             case LR_PROXY_SOCKS5_HOSTNAME: curl_proxy = CURLPROXY_SOCKS5_HOSTNAME; break;
380             default: break;
381         }
382         if (curl_proxy == -1) {
383             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
384                     "Bad LRO_PROXYTYPE value");
385             ret = FALSE;
386         } else {
387             c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYTYPE, curl_proxy);
388         }
389         break;
390     }
391 
392     case LRO_PROXYAUTH:
393         if (va_arg(arg, long) == 0) {
394             c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
395             handle->proxyauthmethods = LR_AUTH_BASIC;
396         } else {
397             c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
398             handle->proxyauthmethods = LR_AUTH_ANY;
399         }
400         break;
401 
402     case LRO_PROXYUSERPWD:
403         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYUSERPWD, va_arg(arg, char *));
404         break;
405 
406     case LRO_PROGRESSCB:
407         handle->user_cb = va_arg(arg, LrProgressCb);
408         break;
409 
410     case LRO_PROGRESSDATA:
411         handle->user_data = va_arg(arg, void *);
412         break;
413 
414     case LRO_MAXSPEED:
415         val_gint64 = va_arg(arg, gint64);
416         if (val_gint64 < 0) {
417             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
418                         "Bad value of LRO_MAXSPEED");
419             ret = FALSE;
420             break;
421         } else if (val_gint64 != 0 && val_gint64 < handle->lowspeedlimit) {
422             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
423                         "LRO_MAXSPEED (%"G_GINT64_FORMAT") is lower than "
424                         "LRO_LOWSPEEDLIMIT (%ld)", val_gint64,
425                         handle->lowspeedlimit);
426             ret = FALSE;
427             break;
428         }
429         handle->maxspeed = val_gint64;
430         break;
431 
432     case LRO_DESTDIR:
433         if (handle->destdir) lr_free(handle->destdir);
434         handle->destdir = g_strdup(va_arg(arg, char *));
435         break;
436 
437     case LRO_REPOTYPE:
438         handle->repotype = va_arg(arg, LrRepotype);
439         if (handle->repotype != LR_YUMREPO) {
440             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
441                         "Bad value of LRO_REPOTYPE");
442             ret = FALSE;
443         }
444         break;
445 
446     case LRO_CONNECTTIMEOUT:
447         c_rc = curl_easy_setopt(c_h, CURLOPT_CONNECTTIMEOUT, va_arg(arg, long));
448         break;
449 
450     case LRO_IGNOREMISSING:
451         handle->ignoremissing = va_arg(arg, long) ? 1 : 0;
452         break;
453 
454     case LRO_INTERRUPTIBLE:
455         handle->interruptible = va_arg(arg, long) ? 1 : 0;
456         break;
457 
458     case LRO_USERAGENT: {
459         char *useragent = va_arg(arg, char *);
460         if (handle->useragent) lr_free(handle->useragent);
461         handle->useragent = g_strdup(useragent);
462         c_rc = curl_easy_setopt(c_h, CURLOPT_USERAGENT, useragent);
463         break;
464     }
465 
466     case LRO_GPGCHECK:
467         if (va_arg(arg, long))
468             handle->checks |= LR_CHECK_GPG;
469         else
470             handle->checks &= ~LR_CHECK_GPG;
471         break;
472 
473     case LRO_CHECKSUM:
474         if (va_arg(arg, long))
475             handle->checks |= LR_CHECK_CHECKSUM;
476         else
477             handle->checks &= ~LR_CHECK_CHECKSUM;
478         break;
479 
480     case LRO_URLS:
481     case LRO_YUMDLIST:
482     case LRO_YUMBLIST:
483     {
484         int size = 0;
485         char **list = va_arg(arg, char **);
486         char ***handle_list = NULL;
487 
488         if (option == LRO_URLS) {
489             handle_list = &handle->urls;
490             lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_URLS);
491         } else if (option == LRO_YUMDLIST) {
492             handle_list = &handle->yumdlist;
493         } else if (option == LRO_YUMBLIST) {
494             handle_list = &handle->yumblist;
495         }
496 
497         lr_handle_free_list(handle_list);
498         if (!list)
499             break;
500 
501         // Get list length
502         while (list[size])
503             size++;
504         size++;
505 
506         if (size == 1 && option == LRO_URLS) {
507             // Only NULL present in list of URLs, keep handle->urls = NULL
508             break;
509         }
510 
511         // Copy the list
512         *handle_list = lr_strv_dup(list);
513         break;
514     }
515 
516     case LRO_HTTPHEADER:
517     {
518         char **list = va_arg(arg, char **);
519         lr_handle_free_list(&handle->httpheader);
520         handle->httpheader = lr_strv_dup(list);
521         break;
522     }
523 
524     case LRO_FETCHMIRRORS:
525         handle->fetchmirrors = va_arg(arg, long) ? 1 : 0;
526         break;
527 
528     case LRO_MAXMIRRORTRIES:
529         val_long = va_arg(arg, long);
530 
531         if (handle->maxmirrortries < LRO_MAXMIRRORTRIES_MIN) {
532             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
533                     "Value of LRO_MAXMIRRORTRIES is too low (use value > %ld)",
534                     LRO_MAXMIRRORTRIES_MIN);
535             ret = FALSE;
536         } else {
537             handle->maxmirrortries = val_long;
538         }
539 
540         break;
541 
542     case LRO_MAXPARALLELDOWNLOADS:
543         val_long = va_arg(arg, long);
544 
545         if (val_long < LRO_MAXPARALLELDOWNLOADS_MIN ||
546             val_long > LRO_MAXPARALLELDOWNLOADS_MAX) {
547             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
548                         "Bad value of LRO_MAXPARALLELDOWNLOADS.");
549             ret = FALSE;
550         } else {
551             handle->maxparalleldownloads = val_long;
552         }
553 
554         break;
555 
556     case LRO_MAXDOWNLOADSPERMIRROR:
557         val_long = va_arg(arg, long);
558 
559         if (val_long < LRO_MAXDOWNLOADSPERMIRROR_MIN) {
560             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
561                         "Value of LRO_MAXDOWNLOADSPERMIRROR is too low.");
562             ret = FALSE;
563         } else {
564             handle->maxdownloadspermirror = val_long;
565         }
566 
567         break;
568 
569     case LRO_YUMSLIST: {
570         LrUrlVars *vars = va_arg(arg, LrUrlVars *);
571         lr_urlvars_free(handle->yumslist);
572         handle->yumslist = vars;
573         break;
574     }
575 
576     case LRO_VARSUB: {
577         LrUrlVars *vars = va_arg(arg, LrUrlVars *);
578         lr_urlvars_free(handle->urlvars);
579         handle->urlvars = vars;
580 
581         /* Do not do copy
582         for (LrUrlVars *elem = vars; elem; elem = lr_list_next(elem)) {
583             LrVar *var = elem->data;
584             handle->urlvars = lr_urlvars_set(handle->urlvars, var->var, var->val);
585         }
586         */
587 
588         break;
589     }
590 
591     case LRO_FASTESTMIRROR:
592         handle->fastestmirror = va_arg(arg, long) ? 1 : 0;
593         break;
594 
595     case LRO_FASTESTMIRRORCACHE: {
596         char *fastestmirrorcache = va_arg(arg, char *);
597         if (handle->fastestmirrorcache) lr_free(handle->fastestmirrorcache);
598         handle->fastestmirrorcache = g_strdup(fastestmirrorcache);
599         break;
600     }
601 
602     case LRO_FASTESTMIRRORMAXAGE:
603         val_long = va_arg(arg, long);
604 
605         if (val_long < LRO_FASTESTMIRRORMAXAGE_MIN) {
606             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
607                         "Value of LRO_FASTESTMIRRORMAXAGE is too low.");
608             ret = FALSE;
609         } else {
610             handle->fastestmirrormaxage = val_long;
611         }
612 
613         break;
614 
615     case LRO_FASTESTMIRRORCB:
616         handle->fastestmirrorcb = va_arg(arg, LrFastestMirrorCb);
617         break;
618 
619     case LRO_FASTESTMIRRORDATA:
620         handle->fastestmirrordata = va_arg(arg, void *);
621         break;
622 
623     case LRO_LOWSPEEDTIME:
624         val_long = va_arg(arg, long);
625 
626         if (val_long < LRO_LOWSPEEDTIME_MIN) {
627             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
628                         "Value of LRO_LOWSPEEDTIME is too low.");
629             ret = FALSE;
630         } else {
631             c_rc = curl_easy_setopt(c_h, CURLOPT_LOW_SPEED_TIME, val_long);
632             handle->lowspeedtime = val_long;
633         }
634 
635         break;
636 
637     case LRO_LOWSPEEDLIMIT:
638         val_long = va_arg(arg, long);
639 
640         if (val_long < LRO_LOWSPEEDLIMIT_MIN) {
641             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
642                         "Value of LRO_LOWSPEEDLIMIT is too low.");
643             ret = FALSE;
644         } else if (handle->maxspeed != 0 && handle->maxspeed < val_long) {
645             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
646                         "Value of LRO_LOWSPEEDLIMIT (%ld) is higher than "
647                         "LRO_MAXSPEED (%"G_GINT64_FORMAT")",
648                         val_long, handle->maxspeed);
649             ret = FALSE;
650         } else {
651             c_rc = curl_easy_setopt(c_h, CURLOPT_LOW_SPEED_LIMIT, val_long);
652             handle->lowspeedlimit = val_long;
653         }
654 
655         break;
656 
657     case LRO_HMFCB:
658         handle->hmfcb = va_arg(arg, LrHandleMirrorFailureCb);
659         break;
660 
661     case LRO_SSLVERIFYPEER:
662         handle->sslverifypeer = va_arg(arg, long) ? 1 : 0;
663         c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYPEER, handle->sslverifypeer);
664         break;
665 
666     case LRO_SSLVERIFYSTATUS:
667         handle->sslverifystatus = va_arg(arg, long) ? 1 : 0;
668         c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYSTATUS, handle->sslverifystatus);
669         break;
670 
671     case LRO_SSLVERIFYHOST:
672         handle->sslverifyhost = va_arg(arg, long) ? 2 : 0;
673         c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYHOST, handle->sslverifyhost);
674         break;
675 
676     case LRO_SSLCLIENTCERT:
677         if (handle->sslclientcert)
678             lr_free(handle->sslclientcert);
679         handle->sslclientcert = g_strdup(va_arg(arg, char *));
680         c_rc = curl_easy_setopt(c_h, CURLOPT_SSLCERT, handle->sslclientcert);
681         if (c_rc == CURLE_OK && handle->sslclientcert && !strncasecmp(handle->sslclientcert, "pkcs11:", 7)) {
682             c_rc = curl_easy_setopt(c_h, CURLOPT_SSLCERTTYPE, "ENG");
683         }
684         break;
685 
686     case LRO_SSLCLIENTKEY:
687         if (handle->sslclientkey)
688             lr_free(handle->sslclientkey);
689         handle->sslclientkey = g_strdup(va_arg(arg, char *));
690         c_rc = curl_easy_setopt(c_h, CURLOPT_SSLKEY, handle->sslclientkey);
691         if (c_rc == CURLE_OK && handle->sslclientkey && !strncasecmp(handle->sslclientkey, "pkcs11:", 7)) {
692             c_rc = curl_easy_setopt(c_h, CURLOPT_SSLKEYTYPE, "ENG");
693         }
694         break;
695 
696     case LRO_SSLCACERT:
697         if (handle->sslcacert)
698             lr_free(handle->sslcacert);
699         handle->sslcacert = g_strdup(va_arg(arg, char *));
700         c_rc = curl_easy_setopt(c_h, CURLOPT_CAINFO, handle->sslcacert);
701         break;
702 
703     case LRO_PROXY_SSLVERIFYPEER:
704         handle->proxy_sslverifypeer = va_arg(arg, long) ? 1 : 0;
705         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSL_VERIFYPEER, handle->proxy_sslverifypeer);
706         break;
707 
708     case LRO_PROXY_SSLVERIFYHOST:
709         handle->proxy_sslverifyhost = va_arg(arg, long) ? 2 : 0;
710         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSL_VERIFYHOST, handle->proxy_sslverifyhost);
711         break;
712 
713     case LRO_PROXY_SSLCLIENTCERT:
714         if (handle->proxy_sslclientcert)
715             lr_free(handle->proxy_sslclientcert);
716         handle->proxy_sslclientcert = g_strdup(va_arg(arg, char *));
717         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLCERT, handle->proxy_sslclientcert);
718         if (c_rc == CURLE_OK && handle->proxy_sslclientcert && !strncasecmp(handle->proxy_sslclientcert, "pkcs11:", 7)) {
719             c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLCERTTYPE, "ENG");
720         }
721         break;
722 
723     case LRO_PROXY_SSLCLIENTKEY:
724         if (handle->proxy_sslclientkey)
725             lr_free(handle->proxy_sslclientkey);
726         handle->proxy_sslclientkey = g_strdup(va_arg(arg, char *));
727         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLKEY, handle->proxy_sslclientkey);
728         if (c_rc == CURLE_OK && handle->proxy_sslclientkey && !strncasecmp(handle->proxy_sslclientkey, "pkcs11:", 7)) {
729             c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLKEYTYPE, "ENG");
730         }
731         break;
732 
733     case LRO_PROXY_SSLCACERT:
734         if (handle->proxy_sslcacert)
735             lr_free(handle->proxy_sslcacert);
736         handle->proxy_sslcacert = g_strdup(va_arg(arg, char *));
737         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_CAINFO, handle->proxy_sslcacert);
738         break;
739 
740     case LRO_IPRESOLVE: {
741         long type = -1;
742         long lr_type = va_arg(arg, LrIpResolveType);
743         switch (lr_type) {
744             case LR_IPRESOLVE_WHATEVER: type = CURL_IPRESOLVE_WHATEVER; break;
745             case LR_IPRESOLVE_V4:       type = CURL_IPRESOLVE_V4;       break;
746             case LR_IPRESOLVE_V6:       type = CURL_IPRESOLVE_V6;       break;
747             default: break;
748         }
749         if (type == -1) {
750             g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
751                     "Bad LRO_IPRESOLVE value");
752             ret = FALSE;
753         } else {
754             handle->ipresolve = lr_type;
755             c_rc = curl_easy_setopt(c_h, CURLOPT_IPRESOLVE, type);
756         }
757         break;
758     }
759 
760     case LRO_ALLOWEDMIRRORFAILURES:
761         handle->allowed_mirror_failures = va_arg(arg, long);
762         break;
763 
764     case LRO_ADAPTIVEMIRRORSORTING:
765         handle->adaptivemirrorsorting = va_arg(arg, long);
766         break;
767 
768     case LRO_GNUPGHOMEDIR: {
769         char *gnupghomedir = va_arg(arg, char *);
770         lr_free(handle->gnupghomedir);
771         handle->gnupghomedir = g_strdup(gnupghomedir);
772         break;
773     }
774 
775     case LRO_FASTESTMIRRORTIMEOUT:
776         handle->fastestmirrortimeout = va_arg(arg, double);
777         break;
778 
779     case LRO_OFFLINE:
780         lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_OFFLINE_OPT);
781         handle->offline = va_arg(arg, long) ? 1 : 0;
782         break;
783 
784     case LRO_HTTPAUTHMETHODS: {
785         LrAuth in_bitmask = va_arg(arg, LrAuth);
786         long bitmask = curlauth_bitmask(in_bitmask);
787         handle->httpauthmethods = in_bitmask;
788         c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, bitmask);
789         break;
790     }
791 
792     case LRO_PROXYAUTHMETHODS: {
793         LrAuth in_bitmask = va_arg(arg, LrAuth);
794         long bitmask = curlauth_bitmask(in_bitmask);
795         handle->proxyauthmethods = in_bitmask;
796         c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, bitmask);
797         break;
798     }
799 
800     case LRO_FTPUSEEPSV:
801         handle->ftpuseepsv = va_arg(arg, long) ? 1 : 0;
802         c_rc = curl_easy_setopt(c_h, CURLOPT_FTP_USE_EPSV, handle->ftpuseepsv);
803         break;
804 
805     case LRO_CACHEDIR:
806         if (handle->cachedir) lr_free(handle->cachedir);
807         handle->cachedir = g_strdup(va_arg(arg, char *));
808         break;
809 
810     case LRO_PRESERVETIME:
811         handle->preservetime = va_arg(arg, long) ? 1 : 0;
812         c_rc = curl_easy_setopt(c_h, CURLOPT_FILETIME, handle->preservetime);
813         break;
814 
815     default:
816         g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
817                     "Unknown option");
818         ret = FALSE;
819         break;
820 
821     };
822 
823     /* Handle CURL error return code */
824     if (ret == TRUE && c_rc != CURLE_OK) {
825         ret = FALSE;
826         switch (c_rc) {
827         case CURLE_FAILED_INIT:
828             g_set_error(err, LR_HANDLE_ERROR, LRE_CURLSETOPT,
829                         "curl_easy_setopt error: %s",
830                         curl_easy_strerror(c_rc));
831             break;
832         default:
833             g_set_error(err, LR_HANDLE_ERROR, LRE_CURL,
834                         "curl error: %s",
835                         curl_easy_strerror(c_rc));
836             break;
837         };
838     }
839 
840     va_end(arg);
841     return ret;
842 }
843 
844 static gboolean
lr_handle_prepare_urls(LrHandle * handle,GError ** err)845 lr_handle_prepare_urls(LrHandle *handle, GError **err)
846 {
847     assert(!handle->urls_mirrors);
848 
849     for (int x=0; handle->urls[x]; x++) {
850         gchar *url = handle->urls[x];
851         _cleanup_free_ gchar *final_url = NULL;
852 
853         // Make sure that url has protocol specified
854         final_url = lr_prepend_url_protocol(url);
855         if (!final_url) {
856             g_set_error(err, LR_HANDLE_ERROR, LRE_BADURL,
857                         "Cannot resolve path for: \"%s\"", url);
858             return FALSE;
859         }
860 
861         // Append the url into internal list of urls specified by LRO_URLS
862         handle->urls_mirrors = lr_lrmirrorlist_append_url(
863                                             handle->urls_mirrors,
864                                             final_url,
865                                             handle->urlvars);
866     }
867 
868     return TRUE;
869 }
870 
871 static gboolean
lr_yum_download_url_retry(int attempts,LrHandle * lr_handle,const char * url,int fd,gboolean no_cache,gboolean is_zchunk,GError ** err)872 lr_yum_download_url_retry(int attempts, LrHandle *lr_handle, const char *url,
873                           int fd, gboolean no_cache, gboolean is_zchunk,
874                           GError **err)
875 {
876     gboolean ret = FALSE;
877 
878     for (int i = 1;; i++) {
879         ret = lr_yum_download_url(lr_handle, url, fd, no_cache, is_zchunk, err);
880         if (ret)
881             return ret;
882 
883         if (i >= attempts)
884             return ret; // Caller to handle the last err
885 
886         g_debug("%s: Attempt #%d to download %s failed: %s",
887                 __func__, i, url, (*err)->message);
888 
889         if (ftruncate(fd, 0) < 0) {
890             g_set_error(err, LR_DOWNLOADER_ERROR, LRE_IO,
891                         "ftruncate() failed: %s", g_strerror(errno));
892             return FALSE;
893         }
894 
895         g_clear_error (err);
896     }
897 }
898 
899 static gboolean
lr_handle_prepare_mirrorlist(LrHandle * handle,gchar * localpath,GError ** err)900 lr_handle_prepare_mirrorlist(LrHandle *handle, gchar *localpath, GError **err)
901 {
902     assert(handle->mirrorlist_fd == -1);
903     assert(!handle->mirrorlist_mirrors);
904 
905     int fd = -1;
906 
907     // Get file descriptor with content
908 
909     if (!localpath && !handle->mirrorlisturl) {
910         // Nothing to do
911         return TRUE;
912     } else if (localpath && !handle->mirrorlisturl) {
913         // Just try to use mirrorlist of the local repository
914         _cleanup_free_ gchar *path = lr_pathconcat(localpath, "mirrorlist", NULL);
915 
916         if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
917             g_debug("%s: Local mirrorlist found at %s", __func__, path);
918             fd = open(path, O_RDONLY);
919             if (fd < 0) {
920                 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
921                             "Cannot open %s: %s",
922                             path, g_strerror(errno));
923                 return FALSE;
924             }
925         } else {
926             // No local mirrorlist
927             return TRUE;
928         }
929     } else if (!handle->mirrorlisturl) {
930         // Nothing to do
931         return TRUE;
932     } else if (handle->offline && !lr_is_local_path(handle->mirrorlisturl)) {
933         // We should work offline, ignore remote mirrorlist
934         g_debug("%s: LRO_OFFLINE used, remote mirrorlist ignored: %s",
935                 __func__, handle->mirrorlisturl);
936         return TRUE;
937     } else if (handle->local && !lr_is_local_path(handle->mirrorlisturl)) {
938         // We should work only locally, ignore remote mirrorlist
939         g_debug("%s: LRO_LOCAL used, remote mirrorlist ignored: %s",
940                 __func__, handle->mirrorlisturl);
941         return TRUE;
942     } else if (handle->mirrorlisturl) {
943         // Download remote mirrorlist
944         _cleanup_free_ gchar *url = NULL;
945 
946         fd = lr_gettmpfile();
947         if (fd < 0) {
948             g_debug("%s: Cannot create a temporary file", __func__);
949             g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
950                         "Cannot create a temporary file");
951             return FALSE;
952         }
953 
954         url = lr_prepend_url_protocol(handle->mirrorlisturl);
955         handle->onetimeflag_apply = TRUE;
956         if (!lr_yum_download_url_retry(3, handle, url, fd, TRUE, FALSE, err)) {
957             close(fd);
958             return FALSE;
959         }
960 
961         if (lseek(fd, 0, SEEK_SET) != 0) {
962             g_debug("%s: Seek error: %s", __func__, g_strerror(errno));
963             g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
964                         "lseek(%d, 0, SEEK_SET) error: %s",
965                         fd, g_strerror(errno));
966             close(fd);
967             return FALSE;
968         }
969     }
970 
971     assert(fd >= 0);
972 
973     // Parse the file descriptor content
974 
975     g_debug("%s: Parsing mirrorlist", __func__);
976 
977     LrMirrorlist *ml = lr_mirrorlist_init();
978     gboolean ret = lr_mirrorlist_parse_file(ml, fd, err);
979     if (!ret) {
980         g_debug("%s: Error while parsing mirrorlist", __func__);
981         close(fd);
982         lr_mirrorlist_free(ml);
983         return FALSE;
984     }
985 
986     if (!ml->urls) {
987         g_debug("%s: No URLs in mirrorlist", __func__);
988         g_set_error(err, LR_HANDLE_ERROR, LRE_MLBAD, "No URLs in mirrorlist");
989         close(fd);
990         lr_mirrorlist_free(ml);
991         return FALSE;
992     }
993 
994     // List parsed mirrors
995     g_debug("%s: Mirrors from mirrorlist:", __func__);
996     for (GSList *elem = ml->urls; elem; elem = g_slist_next(elem))
997         g_debug("  %s", (gchar *) elem->data);
998 
999     // Convert mirrorlist to internal mirrorlist format
1000 
1001     handle->mirrorlist_mirrors = lr_lrmirrorlist_append_mirrorlist(
1002                                             NULL,
1003                                             ml,
1004                                             handle->urlvars);
1005     handle->mirrorlist_fd = fd;
1006 
1007     lr_mirrorlist_free(ml);
1008 
1009     g_debug("%s: Mirrorlist parsed", __func__);
1010     return TRUE;
1011 }
1012 
1013 static gboolean
lr_handle_prepare_metalink(LrHandle * handle,gchar * localpath,GError ** err)1014 lr_handle_prepare_metalink(LrHandle *handle, gchar *localpath, GError **err)
1015 {
1016     assert(handle->metalink_fd == -1);
1017     assert(!handle->metalink_mirrors);
1018     assert(!handle->metalink);
1019 
1020     int fd = -1;
1021 
1022     // Get file descriptor with content
1023 
1024     if (!localpath && !handle->metalinkurl) {
1025         // Nothing to do
1026         return TRUE;
1027     } else if (localpath && !handle->metalinkurl) {
1028         // Just try to use metalink of the local repository
1029         _cleanup_free_ gchar *path = lr_pathconcat(localpath, "metalink.xml", NULL);
1030 
1031         if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
1032             g_debug("%s: Local metalink.xml found at %s", __func__, path);
1033             fd = open(path, O_RDONLY);
1034             if (fd < 0) {
1035                 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1036                             "Cannot open %s: %s",
1037                             path, g_strerror(errno));
1038                 return FALSE;
1039             }
1040         } else {
1041             // No local metalink
1042             return TRUE;
1043         }
1044     } else if (!handle->metalinkurl) {
1045         // Nothing to do
1046         return TRUE;
1047     } else if (handle->offline && !lr_is_local_path(handle->metalinkurl)) {
1048         // We should work offline, ignore remote mirrorlist
1049         g_debug("%s: LRO_OFFLINE used, remote metalink ignored: %s",
1050                 __func__, handle->metalinkurl);
1051         return TRUE;
1052     } else if (handle->local && !lr_is_local_path(handle->metalinkurl)) {
1053         // We should work only locally, ignore remote mirrorlist
1054         g_debug("%s: LRO_LOCAL used, remote metalink ignored: %s",
1055                 __func__, handle->metalinkurl);
1056         return TRUE;
1057     } else if (handle->metalinkurl) {
1058         // Download remote metalink
1059         _cleanup_free_ gchar *url = NULL;
1060 
1061         fd = lr_gettmpfile();
1062         if (fd < 0) {
1063             g_debug("%s: Cannot create a temporary file", __func__);
1064             g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1065                         "Cannot create a temporary file");
1066             return FALSE;
1067         }
1068 
1069         url = lr_prepend_url_protocol(handle->metalinkurl);
1070         handle->onetimeflag_apply = TRUE;
1071         if (!lr_yum_download_url_retry(3, handle, url, fd, TRUE, FALSE, err)) {
1072             close(fd);
1073             return FALSE;
1074         }
1075 
1076         if (lseek(fd, 0, SEEK_SET) != 0) {
1077             g_debug("%s: Seek error: %s", __func__, g_strerror(errno));
1078             g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1079                         "lseek(%d, 0, SEEK_SET) error: %s",
1080                         fd, g_strerror(errno));
1081             close(fd);
1082             return FALSE;
1083         }
1084     }
1085 
1086     assert(fd >= 0);
1087 
1088     // Parse the file descriptor content
1089 
1090     g_debug("%s: Parsing metalink.xml", __func__);
1091 
1092     gchar *metalink_file = "";
1093     gchar *metalink_suffix = NULL;
1094     if (handle->repotype == LR_YUMREPO) {
1095         metalink_file = "repomd.xml";
1096         metalink_suffix = "repodata/repomd.xml";
1097     }
1098 
1099     LrMetalink *ml = lr_metalink_init();
1100     gboolean ret = lr_metalink_parse_file(ml,
1101                                           fd,
1102                                           metalink_file,
1103                                           lr_xml_parser_warning_logger,
1104                                           "Metalink xml parser",
1105                                           err);
1106     if (!ret) {
1107         g_warning("Error while parsing metalink");
1108         close(fd);
1109         lr_metalink_free(ml);
1110         return FALSE;
1111     }
1112 
1113     if (!ml->urls) {
1114         g_debug("%s: No URLs in metalink", __func__);
1115         g_set_error(err, LR_HANDLE_ERROR, LRE_MLBAD, "No URLs in metalink");
1116         close(fd);
1117         lr_metalink_free(ml);
1118         return FALSE;
1119     }
1120 
1121     // List parsed mirrors
1122     g_debug("%s: Mirrors from metalink:", __func__);
1123     for (GSList *elem = ml->urls; elem; elem = g_slist_next(elem))
1124         g_debug("  %s", ((LrMetalinkUrl *) elem->data)->url);
1125 
1126     // Convert metalink to internal mirrorlist format
1127 
1128     handle->metalink_mirrors = lr_lrmirrorlist_append_metalink(
1129                                             NULL,
1130                                             ml,
1131                                             metalink_suffix,
1132                                             handle->urlvars);
1133     handle->metalink_fd = fd;
1134     handle->metalink = ml;
1135 
1136     g_debug("%s: Metalink parsed", __func__);
1137     return TRUE;
1138 }
1139 
1140 gboolean
lr_handle_prepare_internal_mirrorlist(LrHandle * handle,gboolean usefastestmirror,GError ** err)1141 lr_handle_prepare_internal_mirrorlist(LrHandle *handle,
1142                                       gboolean usefastestmirror,
1143                                       GError **err)
1144 {
1145     assert(!err || *err == NULL);
1146 
1147     if (handle->internal_mirrorlist)
1148         return TRUE;  // Internal mirrorlist already exists
1149 
1150     // Create internal mirrorlist
1151 
1152     g_debug("%s: Preparing internal mirrorlist", __func__);
1153 
1154     // Get local path in case of local repository
1155     gchar *local_path = NULL;
1156     if (handle->urls && handle->urls[0]) {
1157         // If first base URL is local path, get that path
1158         // (without file: or file:// prefix if specified)
1159         gchar *url = handle->urls[0];
1160         if (g_str_has_prefix(url, "file://"))
1161             local_path = url + 7;
1162         else if (g_str_has_prefix(url, "file:"))  // RFC 3986
1163             local_path = url + 5;
1164         else if (!strstr(url, "://"))
1165             local_path = url;
1166     }
1167 
1168     // Since urls, mirrorlists and metalinks are not exclusive its
1169     // sufficient for at least on of the three to succeed in order to
1170     // continue. In the case where all of present ones fail we propagate
1171     // only the last error, because GError cannot handle multiple
1172     // errors at the same time.
1173 
1174     gboolean ret_urls = FALSE;
1175     gboolean ret_mirrorlist = FALSE;
1176     gboolean ret_metalink = FALSE;
1177     gboolean at_least_one_present = FALSE;
1178     GError *tmp_err = NULL;
1179 
1180     // LRO_URLS
1181     if (!handle->urls_mirrors && handle->urls) {
1182         at_least_one_present = TRUE;
1183         ret_urls = lr_handle_prepare_urls(handle, &tmp_err);
1184         if (!ret_urls) {
1185             assert(tmp_err);
1186             g_warning("LRO_URLS processing failed: %s", tmp_err->message);
1187         }
1188     }
1189 
1190     // LRO_MIRRORLISTURL
1191     if (!handle->mirrorlist_mirrors && (handle->mirrorlisturl || local_path)) {
1192         g_clear_error(&tmp_err);
1193         at_least_one_present = TRUE;
1194         ret_mirrorlist = lr_handle_prepare_mirrorlist(handle, local_path, &tmp_err);
1195         if (!ret_mirrorlist) {
1196             assert(tmp_err);
1197             g_warning("LRO_MIRRORLISTURL processing failed: %s", tmp_err->message);
1198         }
1199     }
1200 
1201     // LRO_METALINKURL
1202     if (!handle->metalink_mirrors && (handle->metalinkurl || local_path)) {
1203         g_clear_error(&tmp_err);
1204         at_least_one_present = TRUE;
1205         ret_metalink = lr_handle_prepare_metalink(handle, local_path, &tmp_err);
1206         if (!ret_metalink) {
1207             assert(tmp_err);
1208             g_warning("LRO_METALINKURL processing failed: %s", tmp_err->message);
1209         }
1210     }
1211 
1212     if (!ret_urls && !ret_mirrorlist && !ret_metalink && at_least_one_present) {
1213         g_propagate_error(err, tmp_err);
1214         return FALSE;
1215     }
1216 
1217     // Append all the mirrorlist to the single internal mirrorlist
1218     // This internal mirrorlist is used for downloading
1219     // Note: LRO_MIRRORLISTURL and LRO_METALINKURL lists are included
1220     // to this list only if they are explicitly specified (lists
1221     // implicitly loaded from a local repository are not included)
1222 
1223     g_debug("%s: Finalizing internal mirrorlist", __func__);
1224 
1225     // Mirrorlist from the LRO_MIRRORLISTURL
1226     if (handle->mirrorlisturl)
1227         handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1228                                                 handle->internal_mirrorlist,
1229                                                 handle->mirrorlist_mirrors);
1230 
1231     // Mirrorlist from the LRO_METALINKURL
1232     if (handle->metalinkurl)
1233         handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1234                                                 handle->internal_mirrorlist,
1235                                                 handle->metalink_mirrors);
1236 
1237     // Mirrorlist from the LRO_URLS
1238     handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1239                                             handle->internal_mirrorlist,
1240                                             handle->urls_mirrors);
1241 
1242     // If enabled, sort internal mirrorlist by the connection
1243     // speed (the LRO_FASTESTMIRROR option)
1244     if (usefastestmirror) {
1245         g_debug("%s: Sorting internal mirrorlist by connection speed",
1246                 __func__);
1247         gboolean ret = lr_fastestmirror_sort_internalmirrorlist(handle, err);
1248         if (!ret)
1249             return FALSE;
1250     }
1251 
1252     // Prepare mirrors (the list that is reported via LRI_MIRRORS)
1253     // This list contains mirrors from mirrorlist and/or metalink
1254     // even if they are not explicitly specified, but are available
1255     // in a local repo (that is specified at the first url of LRO_URLS)
1256 
1257     g_debug("%s: Finalizing mirrors reported via LRI_MIRRORS", __func__);
1258 
1259     handle->mirrors = lr_lrmirrorlist_append_lrmirrorlist(
1260                                             handle->mirrors,
1261                                             handle->mirrorlist_mirrors);
1262     handle->mirrors = lr_lrmirrorlist_append_lrmirrorlist(
1263                                             handle->mirrors,
1264                                             handle->metalink_mirrors);
1265 
1266     return TRUE;
1267 }
1268 
1269 gboolean
lr_handle_perform(LrHandle * handle,LrResult * result,GError ** err)1270 lr_handle_perform(LrHandle *handle, LrResult *result, GError **err)
1271 {
1272     int ret = TRUE;
1273     GError *tmp_err = NULL;
1274 
1275     assert(handle);
1276     assert(!err || *err == NULL);
1277 
1278     if (!result) {
1279         g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1280                     "No result argument passed");
1281         return FALSE;
1282     }
1283 
1284     if (!handle->urls && !handle->mirrorlisturl && !handle->metalinkurl) {
1285         g_set_error(err, LR_HANDLE_ERROR, LRE_NOURL,
1286                 "No LRO_URLS, LRO_MIRRORLISTURL nor LRO_METALINKURL specified");
1287         return FALSE;
1288     }
1289 
1290     if (handle->repotype != LR_YUMREPO) {
1291         g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1292                     "Bad LRO_REPOTYPE specified");
1293         return FALSE;
1294     }
1295 
1296     /* Setup destination directory */
1297     if (handle->update) {
1298         if (!result->destdir) {
1299             g_set_error(err, LR_HANDLE_ERROR, LRE_INCOMPLETERESULT,
1300                         "Incomplete result object, destdir is missing");
1301             return FALSE;
1302         }
1303         lr_free(handle->destdir);
1304         handle->destdir = g_strdup(result->destdir);
1305     } else if (!handle->destdir && !handle->local) {
1306         handle->destdir = g_strdup(TMP_DIR_TEMPLATE);
1307         if (!mkdtemp(handle->destdir)) {
1308             g_set_error(err, LR_HANDLE_ERROR, LRE_CANNOTCREATETMP,
1309                         "Cannot create tmpdir: %s", g_strerror(errno));
1310             return FALSE;
1311         }
1312     }
1313 
1314     g_debug("%s: Using dir: %s", __func__, handle->destdir);
1315 
1316     struct sigaction old_sigact;
1317     if (handle->interruptible) {
1318         /* Setup sighandler */
1319         struct sigaction sigact;
1320         g_debug("%s: Using own SIGINT handler", __func__);
1321         memset(&sigact, 0, sizeof(old_sigact));
1322         memset(&sigact, 0, sizeof(sigact));
1323         sigemptyset(&sigact.sa_mask);
1324         sigact.sa_handler = lr_sigint_handler;
1325         sigaddset(&sigact.sa_mask, SIGINT);
1326         sigact.sa_flags = 0;
1327         if (sigaction(SIGINT, &sigact, &old_sigact) == -1) {
1328             g_set_error(err, LR_HANDLE_ERROR, LRE_SIGACTION,
1329                         "sigaction(SIGINT,,) error");
1330             return FALSE;
1331         }
1332     }
1333 
1334     ret = lr_handle_prepare_internal_mirrorlist(handle,
1335                                                 handle->fastestmirror,
1336                                                 &tmp_err);
1337     if (!ret) {
1338         g_debug("Cannot prepare internal mirrorlist: %s", tmp_err->message);
1339         g_propagate_prefixed_error(err, tmp_err,
1340                                    "Cannot prepare internal mirrorlist: ");
1341         return FALSE;
1342     }
1343 
1344     if (handle->fetchmirrors) {
1345         /* Only download and parse mirrorlist */
1346         g_debug("%s: Only fetching mirrorlist/metalink", __func__);
1347     } else {
1348         /* Do the other stuff */
1349         switch (handle->repotype) {
1350         case LR_YUMREPO:
1351             g_debug("%s: Downloading/Locating yum repo", __func__);
1352             ret = lr_yum_perform(handle, result, &tmp_err);
1353             break;
1354         default:
1355             g_debug("%s: Bad repo type", __func__);
1356             assert(0);
1357             ret = FALSE;
1358             g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1359                         "Bad repo type: %d", handle->repotype);
1360             break;
1361         }
1362     }
1363 
1364     if (handle->interruptible) {
1365         /* Restore signal handler */
1366         g_debug("%s: Restoring an old SIGINT handler", __func__);
1367         sigaction(SIGINT, &old_sigact, NULL);
1368 
1369         if (lr_interrupt) {
1370             g_set_error(err, LR_HANDLE_ERROR, LRE_INTERRUPTED,
1371                         "Librepo was interrupted by a signal");
1372             if (tmp_err)
1373                 g_error_free(tmp_err);
1374             return FALSE;
1375         }
1376     }
1377 
1378     assert((ret && !tmp_err) || (!ret && tmp_err));
1379 
1380     if (tmp_err)
1381         g_propagate_error(err, tmp_err);
1382 
1383     return ret;
1384 }
1385 
1386 gboolean
lr_handle_getinfo(LrHandle * handle,GError ** err,LrHandleInfoOption option,...)1387 lr_handle_getinfo(LrHandle *handle,
1388                   GError **err,
1389                   LrHandleInfoOption option,
1390                   ...)
1391 {
1392     gboolean rc = TRUE;
1393     va_list arg;
1394     char **str;
1395     long *lnum;
1396     double *dnum;
1397 
1398     assert(!err || *err == NULL);
1399 
1400     if (!handle) {
1401         g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1402                     "No handle specified");
1403         return FALSE;
1404     }
1405 
1406     va_start(arg, option);
1407 
1408     switch (option) {
1409 
1410     case LRI_UPDATE:
1411         lnum = va_arg(arg, long *);
1412         *lnum = (long) handle->update;
1413         break;
1414 
1415     case LRI_MIRRORLIST:
1416         str = va_arg(arg, char **);
1417         *str = handle->mirrorlist;
1418         break;
1419 
1420     case LRI_MIRRORLISTURL:
1421         str = va_arg(arg, char **);
1422         *str = handle->mirrorlisturl;
1423         break;
1424 
1425     case LRI_METALINKURL:
1426         str = va_arg(arg, char **);
1427         *str = handle->metalinkurl;
1428         break;
1429 
1430     case LRI_LOCAL:
1431         lnum = va_arg(arg, long *);
1432         *lnum = (long) handle->local;
1433         break;
1434 
1435     case LRI_PROGRESSCB: {
1436         LrProgressCb *cb= va_arg(arg, LrProgressCb *);
1437         *cb = handle->user_cb;
1438         break;
1439     }
1440 
1441     case LRI_PROGRESSDATA: {
1442         void **data = va_arg(arg, void **);
1443         *data = handle->user_data;
1444         break;
1445     }
1446 
1447     case LRI_DESTDIR:
1448         str = va_arg(arg, char **);
1449         *str = handle->destdir;
1450         break;
1451 
1452     case LRI_REPOTYPE:
1453         lnum = va_arg(arg, long *);
1454         *lnum = (long) handle->repotype;
1455         break;
1456 
1457     case LRI_USERAGENT:
1458         str = va_arg(arg, char **);
1459         *str = handle->useragent;
1460         break;
1461 
1462     case LRI_URLS:
1463     case LRI_YUMDLIST:
1464     case LRI_YUMBLIST:
1465     case LRI_HTTPHEADER: {
1466         char **source_list = NULL;
1467         char ***strlist = va_arg(arg, char ***);
1468 
1469         if (option == LRI_URLS)
1470             source_list = handle->urls;
1471         else if (option == LRI_YUMDLIST)
1472             source_list = handle->yumdlist;
1473         else if (option == LRI_YUMBLIST)
1474             source_list = handle->yumblist;
1475         else if (option == LRI_HTTPHEADER)
1476             source_list = handle->httpheader;
1477 
1478         if (!source_list) {
1479             *strlist = NULL;
1480             break;
1481         }
1482 
1483         *strlist = lr_strv_dup(source_list);
1484         break;
1485     }
1486 
1487     case LRI_FETCHMIRRORS:
1488         lnum = va_arg(arg, long *);
1489         *lnum = (long) handle->fetchmirrors;
1490         break;
1491 
1492     case LRI_MAXMIRRORTRIES:
1493         lnum = va_arg(arg, long *);
1494         *lnum = (long) handle->maxmirrortries;
1495         break;
1496 
1497     case LRI_YUMSLIST: {
1498         LrUrlVars **slist = va_arg(arg, LrUrlVars **);
1499         *slist = handle->yumslist;
1500         break;
1501     }
1502 
1503     case LRI_VARSUB: {
1504         LrUrlVars **vars = va_arg(arg, LrUrlVars **);
1505         *vars = handle->urlvars;
1506         break;
1507     }
1508 
1509     case LRI_MIRRORS: {
1510         int x;
1511         char ***list = va_arg(arg, char ***);
1512         *list = NULL;
1513         LrInternalMirrorlist *ml = handle->mirrors;
1514 
1515         if (!ml)
1516             // lr_handle_perform() or lr_download_package() was not called yet
1517             break;
1518 
1519         /* Make list of urls from internal mirrorlist */
1520         x = 0;
1521         *list = lr_malloc((g_slist_length(ml) + 1) * sizeof(char *));
1522         for (LrInternalMirrorlist *elem = ml; elem; elem = g_slist_next(elem)) {
1523             LrInternalMirror *mirror = elem->data;
1524             (*list)[x] = g_strdup(mirror->url);
1525             x++;
1526         }
1527         (*list)[x] = NULL;
1528         break;
1529     }
1530 
1531     case LRI_METALINK: {
1532         LrMetalink **metalink = va_arg(arg, LrMetalink **);
1533         *metalink = handle->metalink;
1534         break;
1535     }
1536 
1537     case LRI_FASTESTMIRROR:
1538         lnum = va_arg(arg, long *);
1539         *lnum = (long) handle->fastestmirror;
1540         break;
1541 
1542     case LRI_FASTESTMIRRORCACHE:
1543         str = va_arg(arg, char **);
1544         *str = handle->fastestmirrorcache;
1545         break;
1546 
1547     case LRI_FASTESTMIRRORMAXAGE:
1548         lnum = va_arg(arg, long *);
1549         *lnum = (long) handle->fastestmirrormaxage;
1550         break;
1551 
1552     case LRI_HMFCB: {
1553         LrHandleMirrorFailureCb *cb= va_arg(arg, LrHandleMirrorFailureCb *);
1554         *cb = handle->hmfcb;
1555         break;
1556     }
1557 
1558     case LRI_SSLVERIFYPEER:
1559         lnum = va_arg(arg, long *);
1560         *lnum = (long) handle->sslverifypeer;
1561         break;
1562 
1563     case LRI_SSLVERIFYSTATUS:
1564         lnum = va_arg(arg, long *);
1565         *lnum = (long) handle->sslverifystatus;
1566         break;
1567 
1568 
1569     case LRI_SSLVERIFYHOST:
1570         lnum = va_arg(arg, long *);
1571         *lnum = (long) (handle->sslverifyhost ? 1 : 0);
1572         break;
1573 
1574     case LRI_SSLCLIENTCERT:
1575         str = va_arg(arg, char **);
1576         *str = handle->sslclientcert;
1577         break;
1578 
1579     case LRI_SSLCLIENTKEY:
1580         str = va_arg(arg, char **);
1581         *str = handle->sslclientkey;
1582         break;
1583 
1584     case LRI_SSLCACERT:
1585         str = va_arg(arg, char **);
1586         *str = handle->sslcacert;
1587         break;
1588 
1589     case LRI_PROXY_SSLVERIFYPEER:
1590         lnum = va_arg(arg, long *);
1591         *lnum = (long) handle->proxy_sslverifypeer;
1592         break;
1593 
1594     case LRI_PROXY_SSLVERIFYHOST:
1595         lnum = va_arg(arg, long *);
1596         *lnum = (long) (handle->proxy_sslverifyhost ? 1 : 0);
1597         break;
1598 
1599     case LRI_PROXY_SSLCLIENTCERT:
1600         str = va_arg(arg, char **);
1601         *str = handle->proxy_sslclientcert;
1602         break;
1603 
1604     case LRI_PROXY_SSLCLIENTKEY:
1605         str = va_arg(arg, char **);
1606         *str = handle->proxy_sslclientkey;
1607         break;
1608 
1609     case LRI_PROXY_SSLCACERT:
1610         str = va_arg(arg, char **);
1611         *str = handle->proxy_sslcacert;
1612         break;
1613 
1614     case LRI_IPRESOLVE: {
1615         LrIpResolveType *type = va_arg(arg, LrIpResolveType *);
1616         *type = (LrIpResolveType) (handle->ipresolve);
1617         break;
1618     }
1619 
1620     case LRI_ALLOWEDMIRRORFAILURES:
1621         lnum = va_arg(arg, long *);
1622         *lnum = (long) (handle->allowed_mirror_failures);
1623         break;
1624 
1625     case LRI_ADAPTIVEMIRRORSORTING:
1626         lnum = va_arg(arg, long *);
1627         *lnum = (long) (handle->adaptivemirrorsorting);
1628         break;
1629 
1630     case LRI_GNUPGHOMEDIR:
1631         str = va_arg(arg, char **);
1632         *str = handle->gnupghomedir;
1633         break;
1634 
1635     case LRI_FASTESTMIRRORTIMEOUT:
1636         dnum = va_arg(arg, double *);
1637         *dnum = (double) handle->fastestmirrortimeout;
1638         break;
1639 
1640     case LRI_OFFLINE:
1641         lnum = va_arg(arg, long *);
1642         *lnum = (long) handle->offline;
1643         break;
1644 
1645     case LRI_LOWSPEEDTIME:
1646         lnum = va_arg(arg, long *);
1647         *lnum = (long) (handle->lowspeedtime);
1648         break;
1649 
1650     case LRI_LOWSPEEDLIMIT:
1651         lnum = va_arg(arg, long *);
1652         *lnum = (long) (handle->lowspeedlimit);
1653         break;
1654 
1655     case LRI_HTTPAUTHMETHODS: {
1656         LrAuth *auth = va_arg(arg, LrAuth *);
1657         *auth = handle->httpauthmethods;
1658         break;
1659     }
1660 
1661     case LRI_PROXYAUTHMETHODS: {
1662         LrAuth *auth = va_arg(arg, LrAuth *);
1663         *auth = handle->proxyauthmethods;
1664         break;
1665     }
1666 
1667     case LRI_FTPUSEEPSV:
1668         lnum = va_arg(arg, long *);
1669         *lnum = (long) handle->ftpuseepsv;
1670         break;
1671 
1672     case LRI_CACHEDIR:
1673         str = va_arg(arg, char **);
1674         *str = handle->cachedir;
1675         break;
1676 
1677     default:
1678         rc = FALSE;
1679         g_set_error(err, LR_HANDLE_ERROR, LRE_UNKNOWNOPT,
1680                     "Unknown option");
1681         break;
1682     }
1683 
1684     va_end(arg);
1685     return rc;
1686 }
1687