1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 #include "pool.h"
9 #include "repo.h"
10 #include "chksum.h"
11 #include "solv_xfopen.h"
12
13 #include "repoinfo.h"
14 #include "mirror.h"
15 #include "checksig.h"
16 #if defined(FEDORA) || defined(MAGEIA)
17 #include "repoinfo_config_yum.h"
18 #endif
19 #include "repoinfo_download.h"
20
21 static inline int
opentmpfile()22 opentmpfile()
23 {
24 char tmpl[100];
25 int fd;
26
27 strcpy(tmpl, "/var/tmp/solvXXXXXX");
28 fd = mkstemp(tmpl);
29 if (fd < 0)
30 {
31 perror("mkstemp");
32 exit(1);
33 }
34 unlink(tmpl);
35 return fd;
36 }
37
38 int
verify_checksum(int fd,const char * file,const unsigned char * chksum,Id chksumtype)39 verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype)
40 {
41 char buf[1024];
42 const unsigned char *sum;
43 Chksum *h;
44 int l;
45
46 h = solv_chksum_create(chksumtype);
47 if (!h)
48 {
49 printf("%s: unknown checksum type\n", file);
50 return 0;
51 }
52 while ((l = read(fd, buf, sizeof(buf))) > 0)
53 solv_chksum_add(h, buf, l);
54 lseek(fd, 0, SEEK_SET);
55 l = 0;
56 sum = solv_chksum_get(h, &l);
57 if (memcmp(sum, chksum, l))
58 {
59 printf("%s: checksum mismatch\n", file);
60 solv_chksum_free(h, 0);
61 return 0;
62 }
63 solv_chksum_free(h, 0);
64 return 1;
65 }
66
67 FILE *
curlfopen(struct repoinfo * cinfo,const char * file,int uncompress,const unsigned char * chksum,Id chksumtype,int markincomplete)68 curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete)
69 {
70 FILE *fp;
71 pid_t pid;
72 int fd;
73 int status;
74 char url[4096];
75 const char *baseurl = cinfo->baseurl;
76
77 if (!baseurl)
78 {
79 if (!cinfo->metalink && !cinfo->mirrorlist)
80 return 0;
81 if (file != cinfo->metalink && file != cinfo->mirrorlist)
82 {
83 unsigned char mlchksum[32];
84 Id mlchksumtype = 0;
85 fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0);
86 if (!fp)
87 return 0;
88 if (cinfo->metalink)
89 cinfo->baseurl = findmetalinkurl(fp, mlchksum, &mlchksumtype);
90 else
91 cinfo->baseurl = findmirrorlisturl(fp);
92 fclose(fp);
93 if (!cinfo->baseurl)
94 return 0;
95 #if defined(FEDORA) || defined(MAGEIA)
96 if (strchr(cinfo->baseurl, '$'))
97 {
98 char *b = yum_substitute(cinfo->repo->pool, cinfo->baseurl);
99 free(cinfo->baseurl);
100 cinfo->baseurl = strdup(b);
101 }
102 #endif
103 if (!chksumtype && mlchksumtype && !strcmp(file, "repodata/repomd.xml"))
104 {
105 chksumtype = mlchksumtype;
106 chksum = mlchksum;
107 }
108 return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete);
109 }
110 snprintf(url, sizeof(url), "%s", file);
111 }
112 else
113 {
114 const char *path = cinfo->path && strcmp(cinfo->path, "/") != 0 ? cinfo->path : "";
115 int l = strlen(baseurl);
116 int pl = strlen(path);
117 const char *sep = l && baseurl[l - 1] == '/' ? "" : "/";
118 const char *psep = pl && cinfo->path[pl - 1] == '/' ? "" : "/";
119 snprintf(url, sizeof(url), "%s%s%s%s%s", baseurl, sep, path, psep, file);
120 }
121 fd = opentmpfile();
122 // printf("url: %s\n", url);
123 if ((pid = fork()) == (pid_t)-1)
124 {
125 perror("fork");
126 exit(1);
127 }
128 if (pid == 0)
129 {
130 if (fd != 1)
131 {
132 dup2(fd, 1);
133 close(fd);
134 }
135 execlp("curl", "curl", "-f", "-s", "-L", url, (char *)0);
136 perror("curl");
137 _exit(0);
138 }
139 status = 0;
140 while (waitpid(pid, &status, 0) != pid)
141 ;
142 if (lseek(fd, 0, SEEK_END) == 0 && (!status || !chksumtype))
143 {
144 /* empty file */
145 close(fd);
146 return 0;
147 }
148 lseek(fd, 0, SEEK_SET);
149 if (status)
150 {
151 printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status);
152 if (markincomplete)
153 cinfo->incomplete = 1;
154 close(fd);
155 return 0;
156 }
157 if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype))
158 {
159 if (markincomplete)
160 cinfo->incomplete = 1;
161 close(fd);
162 return 0;
163 }
164 fcntl(fd, F_SETFD, FD_CLOEXEC);
165 if (uncompress)
166 {
167 if (solv_xfopen_iscompressed(file) < 0)
168 {
169 printf("%s: unsupported compression\n", file);
170 if (markincomplete)
171 cinfo->incomplete = 1;
172 close(fd);
173 return 0;
174 }
175 fp = solv_xfopen_fd(file, fd, "r");
176 }
177 else
178 fp = fdopen(fd, "r");
179 if (!fp)
180 close(fd);
181 return fp;
182 }
183
184 FILE *
downloadpackage(Solvable * s,const char * loc)185 downloadpackage(Solvable *s, const char *loc)
186 {
187 const unsigned char *chksum;
188 Id chksumtype;
189 struct repoinfo *cinfo = s->repo->appdata;
190
191 #ifdef ENABLE_SUSEREPO
192 if (cinfo->type == TYPE_SUSETAGS)
193 {
194 const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR);
195 loc = pool_tmpjoin(s->repo->pool, datadir ? datadir : "suse", "/", loc);
196 }
197 #endif
198 chksumtype = 0;
199 chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype);
200 return curlfopen(cinfo, loc, 0, chksum, chksumtype, 0);
201 }
202
203 int
downloadchecksig(struct repoinfo * cinfo,FILE * fp,const char * sigurl,Pool ** sigpool)204 downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool)
205 {
206 FILE *sigfp;
207 sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0);
208 if (!sigfp)
209 {
210 printf(" unsigned, skipped\n");
211 return 0;
212 }
213 if (!*sigpool)
214 *sigpool = read_sigs();
215 if (!checksig(*sigpool, fp, sigfp))
216 {
217 printf(" checksig failed, skipped\n");
218 fclose(sigfp);
219 return 0;
220 }
221 fclose(sigfp);
222 return 1;
223 }
224
225