]> git.saurik.com Git - apt.git/blame - methods/gpgv.cc
test if TMPDIR is accessible before using
[apt.git] / methods / gpgv.cc
CommitLineData
ea542140
DK
1#include <config.h>
2
b3d44315 3#include <apt-pkg/acquire-method.h>
472ff00e 4#include <apt-pkg/configuration.h>
453b82a3 5#include <apt-pkg/error.h>
2f5b6151 6#include <apt-pkg/gpgv.h>
453b82a3 7#include <apt-pkg/strutl.h>
3927c6da 8#include <apt-pkg/fileutl.h>
b3d44315 9
453b82a3 10#include <ctype.h>
b3d44315 11#include <errno.h>
453b82a3
DK
12#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
b3d44315 16#include <sys/wait.h>
453b82a3 17#include <unistd.h>
b3d44315 18#include <iostream>
453b82a3 19#include <string>
f5a3d009
DK
20#include <vector>
21
ea542140
DK
22#include <apti18n.h>
23
8f3ba4e8
DK
24using std::string;
25using std::vector;
26
b3d44315
MV
27#define GNUPGPREFIX "[GNUPG:]"
28#define GNUPGBADSIG "[GNUPG:] BADSIG"
29#define GNUPGNOPUBKEY "[GNUPG:] NO_PUBKEY"
30#define GNUPGVALIDSIG "[GNUPG:] VALIDSIG"
c5d8878d
MV
31#define GNUPGGOODSIG "[GNUPG:] GOODSIG"
32#define GNUPGKEYEXPIRED "[GNUPG:] KEYEXPIRED"
33#define GNUPGREVKEYSIG "[GNUPG:] REVKEYSIG"
2abb68b7 34#define GNUPGNODATA "[GNUPG:] NODATA"
b3d44315
MV
35
36class GPGVMethod : public pkgAcqMethod
37{
38 private:
da9ed163 39 string VerifyGetSigners(const char *file, const char *outfile,
c5d8878d
MV
40 vector<string> &GoodSigners,
41 vector<string> &BadSigners,
42 vector<string> &WorthlessSigners,
b3d44315
MV
43 vector<string> &NoPubKeySigners);
44
45 protected:
46 virtual bool Fetch(FetchItem *Itm);
9983999d 47 virtual bool Configuration(string Message);
b3d44315
MV
48 public:
49
50 GPGVMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {};
51};
52
9983999d
MV
53bool GPGVMethod::Configuration(string Message)
54{
55 if (pkgAcqMethod::Configuration(Message) == false)
56 return false;
57
58 DropPrivsOrDie();
59
60 return true;
61}
62
da9ed163 63string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
b3d44315
MV
64 vector<string> &GoodSigners,
65 vector<string> &BadSigners,
c5d8878d 66 vector<string> &WorthlessSigners,
b3d44315
MV
67 vector<string> &NoPubKeySigners)
68{
46e39c8e 69 bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
da9ed163 70
46e39c8e
MV
71 if (Debug == true)
72 std::clog << "inside VerifyGetSigners" << std::endl;
73
b3d44315 74 int fd[2];
46e39c8e 75
b3d44315 76 if (pipe(fd) < 0)
b3d44315 77 return "Couldn't create pipe";
b3d44315 78
cf440fac 79 pid_t pid = fork();
b3d44315 80 if (pid < 0)
da9ed163 81 return string("Couldn't spawn new process") + strerror(errno);
b3d44315 82 else if (pid == 0)
99ed26d3 83 ExecGPGV(outfile, file, 3, fd);
b3d44315
MV
84 close(fd[1]);
85
cf440fac
DK
86 FILE *pipein = fdopen(fd[0], "r");
87
b39bb552 88 // Loop over the output of apt-key (which really is gnupg), and check the signatures.
b3d44315
MV
89 size_t buffersize = 64;
90 char *buffer = (char *) malloc(buffersize);
91 size_t bufferoff = 0;
92 while (1)
93 {
94 int c;
95
96 // Read a line. Sigh.
97 while ((c = getc(pipein)) != EOF && c != '\n')
98 {
aaab1007
DK
99 if (bufferoff == buffersize)
100 {
101 char* newBuffer = (char *) realloc(buffer, buffersize *= 2);
102 if (newBuffer == NULL)
103 {
104 free(buffer);
105 return "Couldn't allocate a buffer big enough for reading";
106 }
107 buffer = newBuffer;
108 }
b3d44315
MV
109 *(buffer+bufferoff) = c;
110 bufferoff++;
111 }
112 if (bufferoff == 0 && c == EOF)
113 break;
114 *(buffer+bufferoff) = '\0';
115 bufferoff = 0;
46e39c8e
MV
116 if (Debug == true)
117 std::clog << "Read: " << buffer << std::endl;
b3d44315
MV
118
119 // Push the data into three separate vectors, which
120 // we later concatenate. They're kept separate so
121 // if we improve the apt method communication stuff later
122 // it will be better.
123 if (strncmp(buffer, GNUPGBADSIG, sizeof(GNUPGBADSIG)-1) == 0)
124 {
46e39c8e
MV
125 if (Debug == true)
126 std::clog << "Got BADSIG! " << std::endl;
b3d44315
MV
127 BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
128 }
129
130 if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0)
131 {
46e39c8e
MV
132 if (Debug == true)
133 std::clog << "Got NO_PUBKEY " << std::endl;
b3d44315
MV
134 NoPubKeySigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
135 }
2abb68b7
MV
136 if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0)
137 {
46e39c8e
MV
138 if (Debug == true)
139 std::clog << "Got NODATA! " << std::endl;
2abb68b7
MV
140 BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
141 }
c5d8878d
MV
142 if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0)
143 {
46e39c8e
MV
144 if (Debug == true)
145 std::clog << "Got KEYEXPIRED! " << std::endl;
c5d8878d
MV
146 WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
147 }
148 if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0)
149 {
46e39c8e
MV
150 if (Debug == true)
151 std::clog << "Got REVKEYSIG! " << std::endl;
c5d8878d
MV
152 WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX)));
153 }
154 if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0)
b3d44315
MV
155 {
156 char *sig = buffer + sizeof(GNUPGPREFIX);
c5d8878d 157 char *p = sig + sizeof("GOODSIG");
b3d44315
MV
158 while (*p && isxdigit(*p))
159 p++;
160 *p = 0;
46e39c8e
MV
161 if (Debug == true)
162 std::clog << "Got GOODSIG, key ID:" << sig << std::endl;
b3d44315
MV
163 GoodSigners.push_back(string(sig));
164 }
165 }
166 fclose(pipein);
1b7bf822 167 free(buffer);
b3d44315 168
cf440fac 169 int status;
b3d44315 170 waitpid(pid, &status, 0);
46e39c8e 171 if (Debug == true)
b3d44315 172 {
2737f28a 173 ioprintf(std::clog, "gpgv exited with status %i\n", WEXITSTATUS(status));
b3d44315
MV
174 }
175
176 if (WEXITSTATUS(status) == 0)
177 {
178 if (GoodSigners.empty())
339690e4 179 return _("Internal error: Good signature, but could not determine key fingerprint?!");
da9ed163 180 return "";
b3d44315
MV
181 }
182 else if (WEXITSTATUS(status) == 1)
339690e4 183 return _("At least one invalid signature was encountered.");
b3d44315 184 else if (WEXITSTATUS(status) == 111)
b39bb552 185 return _("Could not execute 'apt-key' to verify signature (is gnupg installed?)");
ae99ce2e 186 else if (WEXITSTATUS(status) == 112)
b3d44315 187 {
ae99ce2e
DK
188 // acquire system checks for "NODATA" to generate GPG errors (the others are only warnings)
189 std::string errmsg;
190 //TRANSLATORS: %s is a single techy word like 'NODATA'
191 strprintf(errmsg, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NODATA");
192 return errmsg;
b3d44315
MV
193 }
194 else
b39bb552 195 return _("Unknown error executing apt-key");
b3d44315
MV
196}
197
198bool GPGVMethod::Fetch(FetchItem *Itm)
199{
200 URI Get = Itm->Uri;
201 string Path = Get.Host + Get.Path; // To account for relative paths
202 string keyID;
203 vector<string> GoodSigners;
204 vector<string> BadSigners;
c5d8878d
MV
205 // a worthless signature is a expired or revoked one
206 vector<string> WorthlessSigners;
b3d44315
MV
207 vector<string> NoPubKeySigners;
208
209 FetchResult Res;
210 Res.Filename = Itm->DestFile;
211 URIStart(Res);
212
b39bb552 213 // Run apt-key on file, extract contents and get the key ID of the signer
da9ed163 214 string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(),
c5d8878d
MV
215 GoodSigners, BadSigners, WorthlessSigners,
216 NoPubKeySigners);
b3d44315
MV
217 if (GoodSigners.empty() || !BadSigners.empty() || !NoPubKeySigners.empty())
218 {
219 string errmsg;
220 // In this case, something bad probably happened, so we just go
221 // with what the other method gave us for an error message.
c5d8878d 222 if (BadSigners.empty() && WorthlessSigners.empty() && NoPubKeySigners.empty())
b3d44315
MV
223 errmsg = msg;
224 else
225 {
226 if (!BadSigners.empty())
227 {
339690e4 228 errmsg += _("The following signatures were invalid:\n");
b3d44315 229 for (vector<string>::iterator I = BadSigners.begin();
f7f0d6c7 230 I != BadSigners.end(); ++I)
b3d44315
MV
231 errmsg += (*I + "\n");
232 }
c5d8878d
MV
233 if (!WorthlessSigners.empty())
234 {
235 errmsg += _("The following signatures were invalid:\n");
236 for (vector<string>::iterator I = WorthlessSigners.begin();
f7f0d6c7 237 I != WorthlessSigners.end(); ++I)
c5d8878d
MV
238 errmsg += (*I + "\n");
239 }
b3d44315
MV
240 if (!NoPubKeySigners.empty())
241 {
339690e4 242 errmsg += _("The following signatures couldn't be verified because the public key is not available:\n");
b3d44315 243 for (vector<string>::iterator I = NoPubKeySigners.begin();
f7f0d6c7 244 I != NoPubKeySigners.end(); ++I)
b3d44315
MV
245 errmsg += (*I + "\n");
246 }
247 }
ce424cd4
MV
248 // this is only fatal if we have no good sigs or if we have at
249 // least one bad signature. good signatures and NoPubKey signatures
250 // happen easily when a file is signed with multiple signatures
251 if(GoodSigners.empty() or !BadSigners.empty())
f23153d0 252 return _error->Error("%s", errmsg.c_str());
b3d44315
MV
253 }
254
b3d44315
MV
255 // Just pass the raw output up, because passing it as a real data
256 // structure is too difficult with the method stuff. We keep it
257 // as three separate vectors for future extensibility.
258 Res.GPGVOutput = GoodSigners;
259 Res.GPGVOutput.insert(Res.GPGVOutput.end(),BadSigners.begin(),BadSigners.end());
260 Res.GPGVOutput.insert(Res.GPGVOutput.end(),NoPubKeySigners.begin(),NoPubKeySigners.end());
261 URIDone(Res);
262
263 if (_config->FindB("Debug::Acquire::gpgv", false))
264 {
b39bb552 265 std::clog << "apt-key succeeded\n";
b3d44315
MV
266 }
267
268 return true;
269}
270
271
272int main()
273{
339690e4 274 setlocale(LC_ALL, "");
3927c6da 275
b3d44315
MV
276 GPGVMethod Mth;
277
278 return Mth.Run();
279}