]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2001, Robert Collins. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by Robert Collins <rbtcollins@hotmail.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* this is the parent class for all package source (not source code - installation | |
17 | * source as in http/ftp/disk file) operations. | |
18 | */ | |
19 | ||
20 | #include "package_source.h" | |
21 | #include "sha2.h" | |
22 | #include "csu_util/MD5Sum.h" | |
23 | #include "LogFile.h" | |
24 | #include "threebar.h" | |
25 | #include "Exception.h" | |
26 | #include "filemanip.h" | |
27 | #include "io_stream.h" | |
28 | #include "resource.h" | |
29 | ||
30 | extern ThreeBarProgressPage Progress; | |
31 | ||
32 | site::site (const std::string& newkey) : key(newkey) | |
33 | { | |
34 | } | |
35 | ||
36 | void | |
37 | packagesource::set_canonical (char const *fn) | |
38 | { | |
39 | canonical = fn; | |
40 | size_t found = canonical.find_last_of ("/"); | |
41 | shortname = canonical.substr (found + 1); | |
42 | } | |
43 | ||
44 | void | |
45 | packagesource::set_cached (const std::string& fp) | |
46 | { | |
47 | cached = fp; | |
48 | } | |
49 | ||
50 | void | |
51 | packagesource::check_size_and_cache (const std::string fullname) | |
52 | { | |
53 | DWORD fnsize = get_file_size (fullname); | |
54 | if (fnsize != size) | |
55 | { | |
56 | Log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname | |
57 | << " - Size mismatch: Ini-file: " << size | |
58 | << " != On-disk: " << fnsize << endLog; | |
59 | throw new Exception (TOSTRING(__LINE__) " " __FILE__, | |
60 | "Size mismatch for " + fullname, | |
61 | APPERR_CORRUPT_PACKAGE); | |
62 | } | |
63 | cached = fullname; | |
64 | validated = false; | |
65 | } | |
66 | ||
67 | void | |
68 | packagesource::check_hash () | |
69 | { | |
70 | if (validated || cached.empty ()) | |
71 | return; | |
72 | ||
73 | if (sha512_isSet) | |
74 | { | |
75 | check_sha512 (cached); | |
76 | validated = true; | |
77 | } | |
78 | else if (md5.isSet()) | |
79 | { | |
80 | check_md5 (cached); | |
81 | validated = true; | |
82 | } | |
83 | else | |
84 | Log (LOG_BABBLE) << "No checksum recorded for " << cached | |
85 | << ", cannot determine integrity of package!" | |
86 | << endLog; | |
87 | } | |
88 | ||
89 | static char * | |
90 | sha512_str (const unsigned char *in, char *buf) | |
91 | { | |
92 | char *bp = buf; | |
93 | for (int i = 0; i < SHA512_DIGEST_LENGTH; ++i) | |
94 | bp += sprintf (bp, "%02x", in[i]); | |
95 | *bp = '\0'; | |
96 | return buf; | |
97 | } | |
98 | ||
99 | void | |
100 | packagesource::check_sha512 (const std::string fullname) const | |
101 | { | |
102 | io_stream *thefile = io_stream::open (fullname, "rb", 0); | |
103 | if (!thefile) | |
104 | throw new Exception (TOSTRING (__LINE__) " " __FILE__, | |
105 | std::string ("IO Error opening ") + fullname, | |
106 | APPERR_IO_ERROR); | |
107 | SHA2_CTX ctx; | |
108 | unsigned char sha512result[SHA512_DIGEST_LENGTH]; | |
109 | char ini_sum[SHA512_DIGEST_STRING_LENGTH], | |
110 | disk_sum[SHA512_DIGEST_STRING_LENGTH]; | |
111 | ||
112 | SHA512Init (&ctx); | |
113 | ||
114 | Log (LOG_BABBLE) << "Checking SHA512 for " << fullname << endLog; | |
115 | ||
116 | std::wstring fmt = LoadStringW(IDS_PROGRESS_CHECKING_HASH); | |
117 | std::wstring s = format(fmt, "SHA512", shortname.c_str()); | |
118 | Progress.SetText1 (s.c_str()); | |
119 | Progress.SetText4 (IDS_PROGRESS_PROGRESS); | |
120 | Progress.SetBar1 (0); | |
121 | ||
122 | unsigned char buffer[64 * 1024]; | |
123 | ssize_t count; | |
124 | while ((count = thefile->read (buffer, sizeof (buffer))) > 0) | |
125 | { | |
126 | SHA512Update (&ctx, buffer, count); | |
127 | Progress.SetBar1 (thefile->tell (), thefile->get_size ()); | |
128 | } | |
129 | delete thefile; | |
130 | if (count < 0) | |
131 | throw new Exception (TOSTRING(__LINE__) " " __FILE__, | |
132 | "IO Error reading " + fullname, | |
133 | APPERR_IO_ERROR); | |
134 | ||
135 | SHA512Final (sha512result, &ctx); | |
136 | ||
137 | if (memcmp (sha512sum, sha512result, sizeof sha512result)) | |
138 | { | |
139 | Log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname | |
140 | << " - SHA512 mismatch: Ini-file: " | |
141 | << sha512_str (sha512sum, ini_sum) | |
142 | << " != On-disk: " | |
143 | << sha512_str (sha512result, disk_sum) | |
144 | << endLog; | |
145 | throw new Exception (TOSTRING(__LINE__) " " __FILE__, | |
146 | "SHA512 failure for " + fullname, | |
147 | APPERR_CORRUPT_PACKAGE); | |
148 | } | |
149 | ||
150 | Log (LOG_BABBLE) << "SHA512 verified OK: " << fullname << " " | |
151 | << sha512_str (sha512sum, ini_sum) << endLog; | |
152 | } | |
153 | ||
154 | void | |
155 | packagesource::check_md5 (const std::string fullname) const | |
156 | { | |
157 | io_stream *thefile = io_stream::open (fullname, "rb", 0); | |
158 | if (!thefile) | |
159 | throw new Exception (TOSTRING (__LINE__) " " __FILE__, | |
160 | std::string ("IO Error opening ") + fullname, | |
161 | APPERR_IO_ERROR); | |
162 | MD5Sum tempMD5; | |
163 | tempMD5.begin (); | |
164 | ||
165 | Log (LOG_BABBLE) << "Checking MD5 for " << fullname << endLog; | |
166 | ||
167 | std::wstring fmt = LoadStringW(IDS_PROGRESS_CHECKING_HASH); | |
168 | std::wstring s = format(fmt, "MD5", shortname); | |
169 | Progress.SetText1 (s.c_str()); | |
170 | Progress.SetText4 (IDS_PROGRESS_PROGRESS); | |
171 | Progress.SetBar1 (0); | |
172 | ||
173 | unsigned char buffer[64 * 1024]; | |
174 | ssize_t count; | |
175 | while ((count = thefile->read (buffer, sizeof (buffer))) > 0) | |
176 | { | |
177 | tempMD5.append (buffer, count); | |
178 | Progress.SetBar1 (thefile->tell (), thefile->get_size ()); | |
179 | } | |
180 | delete thefile; | |
181 | if (count < 0) | |
182 | throw new Exception (TOSTRING(__LINE__) " " __FILE__, | |
183 | "IO Error reading " + fullname, | |
184 | APPERR_IO_ERROR); | |
185 | ||
186 | tempMD5.finish (); | |
187 | ||
188 | if (md5 != tempMD5) | |
189 | { | |
190 | Log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname | |
191 | << " - MD5 mismatch: Ini-file: " << md5.str() | |
192 | << " != On-disk: " << tempMD5.str() << endLog; | |
193 | throw new Exception (TOSTRING(__LINE__) " " __FILE__, | |
194 | "MD5 failure for " + fullname, | |
195 | APPERR_CORRUPT_PACKAGE); | |
196 | } | |
197 | ||
198 | Log (LOG_BABBLE) << "MD5 verified OK: " << fullname << " " | |
199 | << md5.str() << endLog; | |
200 | } |