File: | sign/rpmgensig.c |
Warning: | line 268, column 6 Value stored to 'rc' is never read |
1 | /** \ingroup rpmcli |
2 | * \file lib/rpmchecksig.c |
3 | * Verify the signature of a package. |
4 | */ |
5 | |
6 | #include "system.h" |
7 | |
8 | #include <errno(*__errno_location ()).h> |
9 | #include <sys/wait.h> |
10 | #include <popt.h> |
11 | #include <libgen.h> |
12 | |
13 | #include <rpm/rpmlib.h> /* RPMSIGTAG & related */ |
14 | #include <rpm/rpmmacro.h> |
15 | #include <rpm/rpmpgp.h> |
16 | #include <rpm/rpmsign.h> |
17 | #include <rpm/rpmfileutil.h> /* rpmMkTemp() */ |
18 | #include <rpm/rpmlog.h> |
19 | #include <rpm/rpmstring.h> |
20 | #include <rpmio/rpmio_internal.h> |
21 | |
22 | #include "lib/rpmlead.h" |
23 | #include "lib/signature.h" |
24 | #include "sign/rpmsignfiles.h" |
25 | |
26 | #include "debug.h" |
27 | |
28 | typedef struct sigTarget_s { |
29 | FD_t fd; |
30 | const char *fileName; |
31 | off_t start; |
32 | rpm_loff_t size; |
33 | } *sigTarget; |
34 | |
35 | /* |
36 | * There is no function for creating unique temporary fifos so create |
37 | * unique temporary directory and then create fifo in it. |
38 | */ |
39 | static char *mkTempFifo(void) |
40 | { |
41 | char *tmppath = NULL((void*)0), *tmpdir = NULL((void*)0), *fifofn = NULL((void*)0); |
42 | mode_t mode; |
43 | |
44 | tmppath = rpmExpand("%{_tmppath}", NULL((void*)0)); |
45 | if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1)) |
46 | goto exit; |
47 | |
48 | |
49 | tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL((void*)0)); |
50 | mode = umask(0077); |
51 | tmpdir = mkdtemp(tmpdir); |
52 | umask(mode); |
53 | if (tmpdir == NULL((void*)0)) { |
54 | rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n")dcgettext ("rpm", "error creating temp directory %s: %m\n", 5 ), |
55 | tmpdir); |
56 | tmpdir = _free(tmpdir)rfree((tmpdir)); |
57 | goto exit; |
58 | } |
59 | |
60 | fifofn = rpmGetPath(tmpdir, "/fifo", NULL((void*)0)); |
61 | if (mkfifo(fifofn, 0600) == -1) { |
62 | rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n")dcgettext ("rpm", "error creating fifo %s: %m\n", 5), fifofn); |
63 | fifofn = _free(fifofn)rfree((fifofn)); |
64 | } |
65 | |
66 | exit: |
67 | if (fifofn == NULL((void*)0) && tmpdir != NULL((void*)0)) |
68 | unlink(tmpdir); |
69 | |
70 | free(tmppath); |
71 | free(tmpdir); |
72 | |
73 | return fifofn; |
74 | } |
75 | |
76 | /* Delete fifo and then temporary directory in which it was located */ |
77 | static int rpmRmTempFifo(const char *fn) |
78 | { |
79 | int rc = 0; |
80 | char *dfn = NULL((void*)0), *dir = NULL((void*)0); |
81 | |
82 | if ((rc = unlink(fn)) != 0) { |
83 | rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n")dcgettext ("rpm", "error delete fifo %s: %m\n", 5), fn); |
84 | return rc; |
85 | } |
86 | |
87 | dfn = xstrdup(fn)rstrdup((fn)); |
88 | dir = dirname(dfn); |
89 | |
90 | if ((rc = rmdir(dir)) != 0) |
91 | rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n")dcgettext ("rpm", "error delete directory %s: %m\n", 5), dir); |
92 | free(dfn); |
93 | |
94 | return rc; |
95 | } |
96 | |
97 | static int closeFile(FD_t *fdp) |
98 | { |
99 | if (fdp == NULL((void*)0) || *fdp == NULL((void*)0)) |
100 | return 1; |
101 | |
102 | /* close and reset *fdp to NULL */ |
103 | (void) Fclose(*fdp); |
104 | *fdp = NULL((void*)0); |
105 | return 0; |
106 | } |
107 | |
108 | /** |
109 | */ |
110 | static int manageFile(FD_t *fdp, const char *fn, int flags) |
111 | { |
112 | FD_t fd; |
113 | const char *fmode; |
114 | |
115 | if (fdp == NULL((void*)0) || fn == NULL((void*)0)) /* programmer error */ |
116 | return 1; |
117 | |
118 | /* open a file and set *fdp */ |
119 | if (*fdp == NULL((void*)0) && fn != NULL((void*)0)) { |
120 | switch (flags & O_ACCMODE0003) { |
121 | case O_WRONLY01: |
122 | fmode = "w.ufdio"; |
123 | break; |
124 | case O_RDONLY00: |
125 | fmode = "r.ufdio"; |
126 | break; |
127 | default: |
128 | case O_RDWR02: |
129 | fmode = "r+.ufdio"; |
130 | break; |
131 | } |
132 | fd = Fopen(fn, fmode); |
133 | if (fd == NULL((void*)0) || Ferror(fd)) { |
134 | rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n")dcgettext ("rpm", "%s: open failed: %s\n", 5), fn, |
135 | Fstrerror(fd)); |
136 | return 1; |
137 | } |
138 | *fdp = fd; |
139 | return 0; |
140 | } |
141 | |
142 | /* no operation */ |
143 | if (*fdp != NULL((void*)0) && fn != NULL((void*)0)) |
144 | return 0; |
145 | |
146 | /* XXX never reached */ |
147 | return 1; |
148 | } |
149 | |
150 | /** |
151 | * Copy header+payload, calculating digest(s) on the fly. |
152 | * @param sfdp source file |
153 | * @param sfnp source path |
154 | * @param tfdp destination file |
155 | * @param tfnp destination path |
156 | */ |
157 | static int copyFile(FD_t *sfdp, const char *sfnp, |
158 | FD_t *tfdp, const char *tfnp) |
159 | { |
160 | unsigned char buf[BUFSIZ8192]; |
161 | ssize_t count; |
162 | int rc = 1; |
163 | |
164 | while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0) |
165 | { |
166 | if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) { |
167 | rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n")dcgettext ("rpm", "%s: Fwrite failed: %s\n", 5), tfnp, |
168 | Fstrerror(*tfdp)); |
169 | goto exit; |
170 | } |
171 | } |
172 | if (count < 0) { |
173 | rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n")dcgettext ("rpm", "%s: Fread failed: %s\n", 5), sfnp, Fstrerror(*sfdp)); |
174 | goto exit; |
175 | } |
176 | if (Fflush(*tfdp) != 0) { |
177 | rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n")dcgettext ("rpm", "%s: Fflush failed: %s\n", 5), tfnp, |
178 | Fstrerror(*tfdp)); |
179 | } |
180 | |
181 | rc = 0; |
182 | |
183 | exit: |
184 | return rc; |
185 | } |
186 | |
187 | /* |
188 | * Validate generated signature and insert to header if it looks sane. |
189 | * NSS doesn't support everything GPG does. Basic tests to see if the |
190 | * generated signature is something we can use. |
191 | * Return generated signature tag data on success, NULL on failure. |
192 | */ |
193 | static rpmtd makeSigTag(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen) |
194 | { |
195 | pgpDigParams sigp = NULL((void*)0); |
196 | rpmTagVal sigtag; |
197 | rpmtd sigtd = NULL((void*)0); |
198 | unsigned int hash_algo; |
199 | unsigned int pubkey_algo; |
200 | |
201 | if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) { |
202 | rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n")dcgettext ("rpm", "Unsupported PGP signature\n", 5)); |
203 | goto exit; |
204 | } |
205 | |
206 | hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); |
207 | if (rpmDigestLength(hash_algo) == 0) { |
208 | rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n")dcgettext ("rpm", "Unsupported PGP hash algorithm %u\n", 5), hash_algo); |
209 | goto exit; |
210 | } |
211 | |
212 | pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); |
213 | switch (pubkey_algo) { |
214 | case PGPPUBKEYALGO_DSA: |
215 | sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG; |
216 | break; |
217 | case PGPPUBKEYALGO_RSA: |
218 | sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP; |
219 | break; |
220 | default: |
221 | rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n")dcgettext ("rpm", "Unsupported PGP pubkey algorithm %u\n", 5), |
222 | pubkey_algo); |
223 | goto exit; |
224 | break; |
225 | } |
226 | |
227 | /* Looks sane, create the tag data */ |
228 | sigtd = rpmtdNew(); |
229 | sigtd->count = pktlen; |
230 | sigtd->data = memcpy(xmalloc(pktlen)rmalloc((pktlen)), pkt, pktlen);; |
231 | sigtd->type = RPM_BIN_TYPE; |
232 | sigtd->tag = sigtag; |
233 | sigtd->flags |= RPMTD_ALLOCED; |
234 | |
235 | exit: |
236 | pgpDigParamsFree(sigp); |
237 | return sigtd; |
238 | } |
239 | |
240 | static int runGPG(sigTarget sigt, const char *sigfile) |
241 | { |
242 | int pid = 0, status; |
243 | FD_t fnamedPipe = NULL((void*)0); |
244 | char *namedPipeName = NULL((void*)0); |
245 | unsigned char buf[BUFSIZ8192]; |
246 | ssize_t count; |
247 | ssize_t wantCount; |
248 | rpm_loff_t size; |
249 | int rc = 1; /* assume failure */ |
250 | |
251 | namedPipeName = mkTempFifo(); |
252 | |
253 | rpmPushMacro(NULL((void*)0), "__plaintext_filename", NULL((void*)0), namedPipeName, -1); |
254 | rpmPushMacro(NULL((void*)0), "__signature_filename", NULL((void*)0), sigfile, -1); |
255 | |
256 | if (!(pid = fork())) { |
257 | char *const *av; |
258 | char *cmd = NULL((void*)0); |
259 | const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL((void*)0)); |
260 | |
261 | if (gpg_path && *gpg_path != '\0') |
262 | (void) setenv("GNUPGHOME", gpg_path, 1); |
263 | |
264 | unsetenv("MALLOC_CHECK_"); |
265 | cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL((void*)0)); |
266 | rc = poptParseArgvString(cmd, NULL((void*)0), (const char ***)&av); |
267 | if (!rc) |
268 | rc = execve(av[0], av+1, environ); |
Value stored to 'rc' is never read | |
269 | |
270 | rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n")dcgettext ("rpm", "Could not exec %s: %s\n", 5), "gpg", |
271 | strerror(errno(*__errno_location ()))); |
272 | _exit(EXIT_FAILURE1); |
273 | } |
274 | |
275 | rpmPopMacro(NULL((void*)0), "__plaintext_filename"); |
276 | rpmPopMacro(NULL((void*)0), "__signature_filename"); |
277 | |
278 | fnamedPipe = Fopen(namedPipeName, "w"); |
279 | if (!fnamedPipe) { |
280 | rpmlog(RPMLOG_ERR, _("Fopen failed\n")dcgettext ("rpm", "Fopen failed\n", 5)); |
281 | goto exit; |
282 | } |
283 | |
284 | if (Fseek(sigt->fd, sigt->start, SEEK_SET0) < 0) { |
285 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
286 | sigt->fileName, Fstrerror(sigt->fd)); |
287 | goto exit; |
288 | } |
289 | |
290 | size = sigt->size; |
291 | wantCount = size < sizeof(buf) ? size : sizeof(buf); |
292 | while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) { |
293 | Fwrite(buf, sizeof(buf[0]), count, fnamedPipe); |
294 | if (Ferror(fnamedPipe)) { |
295 | rpmlog(RPMLOG_ERR, _("Could not write to pipe\n")dcgettext ("rpm", "Could not write to pipe\n", 5)); |
296 | goto exit; |
297 | } |
298 | size -= count; |
299 | wantCount = size < sizeof(buf) ? size : sizeof(buf); |
300 | } |
301 | if (count < 0) { |
302 | rpmlog(RPMLOG_ERR, _("Could not read from file %s: %s\n")dcgettext ("rpm", "Could not read from file %s: %s\n", 5), |
303 | sigt->fileName, Fstrerror(sigt->fd)); |
304 | goto exit; |
305 | } |
306 | Fclose(fnamedPipe); |
307 | fnamedPipe = NULL((void*)0); |
308 | |
309 | (void) waitpid(pid, &status, 0); |
310 | pid = 0; |
311 | if (!WIFEXITED(status)(((status) & 0x7f) == 0) || WEXITSTATUS(status)(((status) & 0xff00) >> 8)) { |
312 | rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n")dcgettext ("rpm", "gpg exec failed (%d)\n", 5), WEXITSTATUS(status)(((status) & 0xff00) >> 8)); |
313 | } else { |
314 | rc = 0; |
315 | } |
316 | |
317 | exit: |
318 | |
319 | if (fnamedPipe) |
320 | Fclose(fnamedPipe); |
321 | |
322 | if (pid) |
323 | waitpid(pid, &status, 0); |
324 | |
325 | if (namedPipeName) { |
326 | rpmRmTempFifo(namedPipeName); |
327 | free(namedPipeName); |
328 | } |
329 | |
330 | return rc; |
331 | } |
332 | |
333 | /** |
334 | * Generate GPG signature(s) for a header+payload file. |
335 | * @param sigh signature header |
336 | * @param ishdr header-only signature? |
337 | * @param sigt signature target |
338 | * @param passPhrase private key pass phrase |
339 | * @return generated sigtag on success, 0 on failure |
340 | */ |
341 | static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt) |
342 | { |
343 | char * sigfile = rstrscat(NULL((void*)0), sigt->fileName, ".sig", NULL((void*)0)); |
344 | struct stat st; |
345 | uint8_t * pkt = NULL((void*)0); |
346 | size_t pktlen = 0; |
347 | rpmtd sigtd = NULL((void*)0); |
348 | |
349 | if (runGPG(sigt, sigfile)) |
350 | goto exit; |
351 | |
352 | if (stat(sigfile, &st)) { |
353 | /* GPG failed to write signature */ |
354 | rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n")dcgettext ("rpm", "gpg failed to write signature\n", 5)); |
355 | goto exit; |
356 | } |
357 | |
358 | pktlen = st.st_size; |
359 | rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", pktlen); |
360 | pkt = xmalloc(pktlen)rmalloc((pktlen)); |
361 | |
362 | { FD_t fd; |
363 | |
364 | int rc = 0; |
365 | fd = Fopen(sigfile, "r.ufdio"); |
366 | if (fd != NULL((void*)0) && !Ferror(fd)) { |
367 | rc = Fread(pkt, sizeof(*pkt), pktlen, fd); |
368 | (void) Fclose(fd); |
369 | } |
370 | if (rc != pktlen) { |
371 | rpmlog(RPMLOG_ERR, _("unable to read the signature\n")dcgettext ("rpm", "unable to read the signature\n", 5)); |
372 | goto exit; |
373 | } |
374 | } |
375 | |
376 | rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", pktlen); |
377 | |
378 | /* Parse the signature, change signature tag as appropriate. */ |
379 | sigtd = makeSigTag(sigh, ishdr, pkt, pktlen); |
380 | exit: |
381 | (void) unlink(sigfile); |
382 | free(sigfile); |
383 | free(pkt); |
384 | |
385 | return sigtd; |
386 | } |
387 | |
388 | static void deleteSigs(Header sigh) |
389 | { |
390 | headerDel(sigh, RPMSIGTAG_GPG); |
391 | headerDel(sigh, RPMSIGTAG_PGP); |
392 | headerDel(sigh, RPMSIGTAG_DSA); |
393 | headerDel(sigh, RPMSIGTAG_RSA); |
394 | headerDel(sigh, RPMSIGTAG_PGP5); |
395 | } |
396 | |
397 | static int haveSignature(rpmtd sigtd, Header h) |
398 | { |
399 | pgpDigParams sig1 = NULL((void*)0); |
400 | pgpDigParams sig2 = NULL((void*)0); |
401 | struct rpmtd_s oldtd; |
402 | int rc = 0; /* assume no */ |
403 | |
404 | if (!headerGet(h, rpmtdTag(sigtd), &oldtd, HEADERGET_DEFAULT)) |
405 | return rc; |
406 | |
407 | pgpPrtParams(sigtd->data, sigtd->count, PGPTAG_SIGNATURE, &sig1); |
408 | while (rpmtdNext(&oldtd) >= 0 && rc == 0) { |
409 | pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2); |
410 | if (pgpDigParamsCmp(sig1, sig2) == 0) |
411 | rc = 1; |
412 | pgpDigParamsFree(sig2); |
413 | } |
414 | pgpDigParamsFree(sig1); |
415 | rpmtdFreeData(&oldtd); |
416 | |
417 | return rc; |
418 | } |
419 | |
420 | static int replaceSignature(Header sigh, sigTarget sigt_v3, sigTarget sigt_v4) |
421 | { |
422 | int rc = -1; |
423 | rpmtd sigtd = NULL((void*)0); |
424 | |
425 | /* Make the cheaper v4 signature first */ |
426 | if ((sigtd = makeGPGSignature(sigh, 1, sigt_v4)) == NULL((void*)0)) |
427 | goto exit; |
428 | |
429 | /* See if we already have a signature by the same key and parameters */ |
430 | if (haveSignature(sigtd, sigh)) { |
431 | rc = 1; |
432 | goto exit; |
433 | } |
434 | /* Nuke all signature tags */ |
435 | deleteSigs(sigh); |
436 | |
437 | if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0) |
438 | goto exit; |
439 | rpmtdFree(sigtd); |
440 | |
441 | /* Assume the same signature test holds for v3 signature too */ |
442 | if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL((void*)0)) |
443 | goto exit; |
444 | |
445 | if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0) |
446 | goto exit; |
447 | |
448 | rc = 0; |
449 | exit: |
450 | rpmtdFree(sigtd); |
451 | return rc; |
452 | } |
453 | |
454 | static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag) |
455 | { |
456 | struct rpmtd_s td; |
457 | rpmtd utd = &td; |
458 | Header nh; |
459 | Header oh; |
460 | |
461 | if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) { |
462 | oh = headerCopyLoad(utd->data); |
463 | nh = headerCopy(oh); |
464 | headerFree(oh); |
465 | rpmtdFreeData(utd); |
466 | headerFree(*hdrp); |
467 | *hdrp = headerLink(nh); |
468 | headerFree(nh); |
469 | } |
470 | } |
471 | |
472 | #ifdef WITH_IMAEVM |
473 | static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp, |
474 | off_t sigStart, off_t sigTargetSize, |
475 | char *SHA256, char *SHA1, uint8_t *MD5) |
476 | { |
477 | off_t archiveSize; |
478 | rpmRC rc = RPMRC_OK; |
479 | |
480 | if (Fseek(fd, sigStart, SEEK_SET0) < 0) { |
481 | rc = RPMRC_FAIL; |
482 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
483 | rpm, Fstrerror(fd)); |
484 | goto exit; |
485 | } |
486 | |
487 | /* Get payload size from signature tag */ |
488 | archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE); |
489 | if (!archiveSize) { |
490 | archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE); |
491 | } |
492 | |
493 | /* Set reserved space to 0 */ |
494 | rpmPushMacro(NULL((void*)0), "__gpg_reserved_space", NULL((void*)0), 0, RMIL_GLOBAL0); |
495 | |
496 | /* Replace old digests in sigh */ |
497 | rc = rpmGenerateSignature(SHA256, SHA1, MD5, sigTargetSize, archiveSize, fd); |
498 | if (rc != RPMRC_OK) { |
499 | rpmlog(RPMLOG_ERR, _("generateSignature failed\n")dcgettext ("rpm", "generateSignature failed\n", 5)); |
500 | goto exit; |
501 | } |
502 | |
503 | if (Fseek(fd, sigStart, SEEK_SET0) < 0) { |
504 | rc = RPMRC_FAIL; |
505 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
506 | rpm, Fstrerror(fd)); |
507 | goto exit; |
508 | } |
509 | |
510 | headerFree(*sigp); |
511 | rc = rpmReadSignature(fd, sigp, NULL((void*)0)); |
512 | if (rc != RPMRC_OK) { |
513 | rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n")dcgettext ("rpm", "rpmReadSignature failed\n", 5)); |
514 | goto exit; |
515 | } |
516 | |
517 | exit: |
518 | return rc; |
519 | } |
520 | #endif |
521 | |
522 | static rpmRC includeFileSignatures(FD_t fd, const char *rpm, |
523 | Header *sigp, Header *hdrp, |
524 | off_t sigStart, off_t headerStart) |
525 | { |
526 | #ifdef WITH_IMAEVM |
527 | FD_t ofd = NULL((void*)0); |
528 | char *trpm = NULL((void*)0); |
529 | char *key; |
530 | char *keypass; |
531 | char *SHA1 = NULL((void*)0); |
532 | char *SHA256 = NULL((void*)0); |
533 | uint8_t *MD5 = NULL((void*)0); |
534 | off_t sigTargetSize; |
535 | rpmRC rc = RPMRC_OK; |
536 | struct rpmtd_s osigtd; |
537 | char *o_sha1 = NULL((void*)0); |
538 | |
539 | unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE); |
540 | |
541 | key = rpmExpand("%{?_file_signing_key}", NULL((void*)0)); |
542 | |
543 | keypass = rpmExpand("%{?_file_signing_key_password}", NULL((void*)0)); |
544 | if (rstreq(keypass, "")) { |
545 | free(keypass); |
546 | keypass = NULL((void*)0); |
547 | } |
548 | |
549 | rc = rpmSignFiles(*hdrp, key, keypass); |
550 | if (rc != RPMRC_OK) { |
551 | goto exit; |
552 | } |
553 | |
554 | *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE); |
555 | if (*hdrp == NULL((void*)0)) { |
556 | rc = RPMRC_FAIL; |
557 | rpmlog(RPMLOG_ERR, _("headerReload failed\n")dcgettext ("rpm", "headerReload failed\n", 5)); |
558 | goto exit; |
559 | } |
560 | |
561 | ofd = rpmMkTempFile(NULL((void*)0), &trpm); |
562 | if (ofd == NULL((void*)0) || Ferror(ofd)) { |
563 | rc = RPMRC_FAIL; |
564 | rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n")dcgettext ("rpm", "rpmMkTemp failed\n", 5)); |
565 | goto exit; |
566 | } |
567 | |
568 | /* Copy archive to temp file */ |
569 | if (copyFile(&fd, rpm, &ofd, trpm)) { |
570 | rc = RPMRC_FAIL; |
571 | rpmlog(RPMLOG_ERR, _("copyFile failed\n")dcgettext ("rpm", "copyFile failed\n", 5)); |
572 | goto exit; |
573 | } |
574 | |
575 | if (Fseek(fd, headerStart, SEEK_SET0) < 0) { |
576 | rc = RPMRC_FAIL; |
577 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
578 | rpm, Fstrerror(fd)); |
579 | goto exit; |
580 | } |
581 | |
582 | /* Start MD5 calculation */ |
583 | fdInitDigestID(fd, PGPHASHALGO_MD5, RPMSIGTAG_MD5, 0); |
584 | |
585 | /* Write header to rpm and recalculate digests */ |
586 | fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMSIGTAG_SHA1, 0); |
587 | fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMSIGTAG_SHA256, 0); |
588 | rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES); |
589 | if (rc != RPMRC_OK) { |
590 | rpmlog(RPMLOG_ERR, _("headerWrite failed\n")dcgettext ("rpm", "headerWrite failed\n", 5)); |
591 | goto exit; |
592 | } |
593 | fdFiniDigest(fd, RPMSIGTAG_SHA1, (void **)&SHA1, NULL((void*)0), 1); |
594 | /* Only add SHA256 if it was there to begin with */ |
595 | if (headerIsEntry(*sigp, RPMSIGTAG_SHA256)) |
596 | fdFiniDigest(fd, RPMSIGTAG_SHA256, (void **)&SHA256, NULL((void*)0), 1); |
597 | |
598 | /* Copy archive from temp file */ |
599 | if (Fseek(ofd, 0, SEEK_SET0) < 0) { |
600 | rc = RPMRC_FAIL; |
601 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
602 | rpm, Fstrerror(fd)); |
603 | goto exit; |
604 | } |
605 | if (copyFile(&ofd, trpm, &fd, rpm)) { |
606 | rc = RPMRC_FAIL; |
607 | rpmlog(RPMLOG_ERR, _("copyFile failed\n")dcgettext ("rpm", "copyFile failed\n", 5)); |
608 | goto exit; |
609 | } |
610 | unlink(trpm); |
611 | |
612 | sigTargetSize = Ftell(fd) - headerStart; |
613 | fdFiniDigest(fd, RPMSIGTAG_MD5, (void **)&MD5, NULL((void*)0), 0); |
614 | |
615 | if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) { |
616 | o_sha1 = xstrdup(osigtd.data)rstrdup((osigtd.data)); |
617 | rpmtdFreeData(&osigtd); |
618 | } |
619 | |
620 | if (strcmp(SHA1, o_sha1) == 0) |
621 | rpmlog(RPMLOG_WARNING, |
622 | _("%s already contains identical file signatures\n")dcgettext ("rpm", "%s already contains identical file signatures\n" , 5), |
623 | rpm); |
624 | else |
625 | replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA256, SHA1, MD5); |
626 | |
627 | exit: |
628 | free(trpm); |
629 | free(MD5); |
630 | free(SHA1); |
631 | free(SHA256); |
632 | free(o_sha1); |
633 | free(keypass); |
634 | free(key); |
635 | if (ofd) |
636 | (void) closeFile(&ofd); |
637 | return rc; |
638 | #else |
639 | rpmlog(RPMLOG_ERR, _("file signing support not built in\n")dcgettext ("rpm", "file signing support not built in\n", 5)); |
640 | return RPMRC_FAIL; |
641 | #endif |
642 | } |
643 | |
644 | /** \ingroup rpmcli |
645 | * Create/modify elements in signature header. |
646 | * @param rpm path to package |
647 | * @param deleting adding or deleting signature? |
648 | * @param signfiles sign files if non-zero |
649 | * @return 0 on success, -1 on error |
650 | */ |
651 | static int rpmSign(const char *rpm, int deleting, int signfiles) |
652 | { |
653 | FD_t fd = NULL((void*)0); |
654 | FD_t ofd = NULL((void*)0); |
655 | char *trpm = NULL((void*)0); |
656 | Header sigh = NULL((void*)0); |
657 | Header h = NULL((void*)0); |
658 | char *msg = NULL((void*)0); |
659 | int res = -1; /* assume failure */ |
660 | rpmRC rc; |
661 | struct rpmtd_s utd; |
662 | off_t headerStart; |
663 | off_t sigStart; |
664 | struct sigTarget_s sigt_v3; |
665 | struct sigTarget_s sigt_v4; |
666 | unsigned int origSigSize; |
667 | int insSig = 0; |
668 | |
669 | fprintf(stdoutstdout, "%s:\n", rpm); |
670 | |
671 | if (manageFile(&fd, rpm, O_RDWR02)) |
672 | goto exit; |
673 | |
674 | if ((rc = rpmLeadRead(fd, NULL((void*)0), &msg)) != RPMRC_OK) { |
675 | rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg); |
676 | goto exit; |
677 | } |
678 | |
679 | sigStart = Ftell(fd); |
680 | rc = rpmReadSignature(fd, &sigh, &msg); |
681 | if (rc != RPMRC_OK) { |
682 | rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s")dcgettext ("rpm", "%s: rpmReadSignature failed: %s", 5), rpm, |
683 | (msg && *msg ? msg : "\n")); |
684 | goto exit; |
685 | } |
686 | |
687 | headerStart = Ftell(fd); |
688 | if (rpmReadHeader(NULL((void*)0), fd, &h, &msg) != RPMRC_OK) { |
689 | rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n")dcgettext ("rpm", "%s: headerRead failed: %s\n", 5), rpm, msg); |
690 | goto exit; |
691 | } |
692 | |
693 | if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { |
694 | rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n")dcgettext ("rpm", "Cannot sign RPM v3 packages\n", 5)); |
695 | goto exit; |
696 | } |
697 | |
698 | if (signfiles) { |
699 | includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart); |
700 | } |
701 | |
702 | unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES); |
703 | origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES); |
704 | |
705 | if (deleting) { /* Nuke all the signature tags. */ |
706 | deleteSigs(sigh); |
707 | } else { |
708 | /* Signature target containing header + payload */ |
709 | sigt_v3.fd = fd; |
710 | sigt_v3.start = headerStart; |
711 | sigt_v3.fileName = rpm; |
712 | sigt_v3.size = fdSize(fd) - headerStart; |
713 | |
714 | /* Signature target containing only header */ |
715 | sigt_v4 = sigt_v3; |
716 | sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES); |
717 | |
718 | res = replaceSignature(sigh, &sigt_v3, &sigt_v4); |
719 | if (res != 0) { |
720 | if (res == 1) { |
721 | rpmlog(RPMLOG_WARNING, |
722 | _("%s already contains identical signature, skipping\n")dcgettext ("rpm", "%s already contains identical signature, skipping\n" , 5), |
723 | rpm); |
724 | /* Identical signature is not an error */ |
725 | res = 0; |
726 | } |
727 | goto exit; |
728 | } |
729 | res = -1; |
730 | } |
731 | |
732 | /* Try to make new signature smaller to have size of original signature */ |
733 | rpmtdReset(&utd); |
734 | if (headerGet(sigh, RPMSIGTAG_RESERVEDSPACE, &utd, HEADERGET_MINMEM)) { |
735 | int diff; |
736 | int count; |
737 | char *reservedSpace = NULL((void*)0); |
738 | |
739 | count = utd.count; |
740 | diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize; |
741 | |
742 | if (diff < count) { |
743 | reservedSpace = xcalloc(count - diff, sizeof(char))rcalloc((count - diff), (sizeof(char))); |
744 | headerDel(sigh, RPMSIGTAG_RESERVEDSPACE); |
745 | rpmtdReset(&utd); |
746 | utd.tag = RPMSIGTAG_RESERVEDSPACE; |
747 | utd.count = count - diff; |
748 | utd.type = RPM_BIN_TYPE; |
749 | utd.data = reservedSpace; |
750 | headerPut(sigh, &utd, HEADERPUT_DEFAULT); |
751 | free(reservedSpace); |
752 | insSig = 1; |
753 | } |
754 | } |
755 | |
756 | /* Reallocate the signature into one contiguous region. */ |
757 | sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES); |
758 | if (sigh == NULL((void*)0)) /* XXX can't happen */ |
759 | goto exit; |
760 | |
761 | if (insSig) { |
762 | /* Insert new signature into original rpm */ |
763 | if (Fseek(fd, sigStart, SEEK_SET0) < 0) { |
764 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
765 | rpm, Fstrerror(fd)); |
766 | goto exit; |
767 | } |
768 | |
769 | if (rpmWriteSignature(fd, sigh)) { |
770 | rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n")dcgettext ("rpm", "%s: rpmWriteSignature failed: %s\n", 5), rpm, |
771 | Fstrerror(fd)); |
772 | goto exit; |
773 | } |
774 | res = 0; |
775 | } else { |
776 | /* Replace orignal rpm with new rpm containing new signature */ |
777 | rasprintf(&trpm, "%s.XXXXXX", rpm); |
778 | ofd = rpmMkTemp(trpm); |
779 | if (ofd == NULL((void*)0) || Ferror(ofd)) { |
780 | rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n")dcgettext ("rpm", "rpmMkTemp failed\n", 5)); |
781 | goto exit; |
782 | } |
783 | |
784 | /* Write the lead/signature of the output rpm */ |
785 | rc = rpmLeadWrite(ofd, h); |
786 | if (rc != RPMRC_OK) { |
787 | rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n")dcgettext ("rpm", "%s: writeLead failed: %s\n", 5), trpm, |
788 | Fstrerror(ofd)); |
789 | goto exit; |
790 | } |
791 | |
792 | if (rpmWriteSignature(ofd, sigh)) { |
793 | rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n")dcgettext ("rpm", "%s: rpmWriteSignature failed: %s\n", 5), trpm, |
794 | Fstrerror(ofd)); |
795 | goto exit; |
796 | } |
797 | |
798 | if (Fseek(fd, headerStart, SEEK_SET0) < 0) { |
799 | rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n")dcgettext ("rpm", "Could not seek in file %s: %s\n", 5), |
800 | rpm, Fstrerror(fd)); |
801 | goto exit; |
802 | } |
803 | /* Append the header and archive from the temp file */ |
804 | if (copyFile(&fd, rpm, &ofd, trpm) == 0) { |
805 | struct stat st; |
806 | |
807 | /* Move final target into place, restore file permissions. */ |
808 | if (stat(rpm, &st) == 0 && unlink(rpm) == 0 && |
809 | rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) { |
810 | res = 0; |
811 | } else { |
812 | rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n")dcgettext ("rpm", "replacing %s failed: %s\n", 5), |
813 | rpm, strerror(errno(*__errno_location ()))); |
814 | } |
815 | } |
816 | } |
817 | |
818 | exit: |
819 | if (fd) (void) closeFile(&fd); |
820 | if (ofd) (void) closeFile(&ofd); |
821 | |
822 | headerFree(sigh); |
823 | headerFree(h); |
824 | free(msg); |
825 | |
826 | /* Clean up intermediate target */ |
827 | if (trpm) { |
828 | (void) unlink(trpm); |
829 | free(trpm); |
830 | } |
831 | |
832 | return res; |
833 | } |
834 | |
835 | int rpmPkgSign(const char *path, const struct rpmSignArgs * args) |
836 | { |
837 | int rc; |
838 | |
839 | if (args) { |
840 | if (args->hashalgo) { |
841 | char *algo = NULL((void*)0); |
842 | rasprintf(&algo, "%d", args->hashalgo); |
843 | rpmPushMacro(NULL((void*)0), "_gpg_digest_algo", NULL((void*)0), algo, RMIL_GLOBAL0); |
844 | free(algo); |
845 | } |
846 | if (args->keyid) { |
847 | rpmPushMacro(NULL((void*)0), "_gpg_name", NULL((void*)0), args->keyid, RMIL_GLOBAL0); |
848 | } |
849 | } |
850 | |
851 | rc = rpmSign(path, 0, args ? args->signfiles : 0); |
852 | |
853 | if (args) { |
854 | if (args->hashalgo) { |
855 | rpmPopMacro(NULL((void*)0), "_gpg_digest_algo"); |
856 | } |
857 | if (args->keyid) { |
858 | rpmPopMacro(NULL((void*)0), "_gpg_name"); |
859 | } |
860 | } |
861 | |
862 | return rc; |
863 | } |
864 | |
865 | int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args) |
866 | { |
867 | return rpmSign(path, 1, 0); |
868 | } |