4 * Copyright (c) 2008-2011 Pacman Development Team <pacman-dev@archlinux.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <locale.h> /* setlocale() */
41 #define CHECK_ERR(void) do { \
42 if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { goto error; } \
46 * Return a statically allocated validity string based on the GPGME validity
47 * code. This is mainly for debug purposes and is not translated.
48 * @param validity a validity code returned by GPGME
49 * @return a string such as "marginal"
51 static const char *string_validity(gpgme_validity_t validity
)
54 case GPGME_VALIDITY_UNKNOWN
:
56 case GPGME_VALIDITY_UNDEFINED
:
58 case GPGME_VALIDITY_NEVER
:
60 case GPGME_VALIDITY_MARGINAL
:
62 case GPGME_VALIDITY_FULL
:
64 case GPGME_VALIDITY_ULTIMATE
:
70 static void sigsum_test_bit(gpgme_sigsum_t sigsum
, alpm_list_t
**summary
,
71 gpgme_sigsum_t bit
, const char *value
)
74 *summary
= alpm_list_add(*summary
, (void *)value
);
79 * Calculate a set of strings to represent the given GPGME signature summary
80 * value. This is a bitmask so you may get any number of strings back.
81 * @param sigsum a GPGME signature summary bitmask
82 * @return the list of signature summary strings
84 static alpm_list_t
*list_sigsum(gpgme_sigsum_t sigsum
)
86 alpm_list_t
*summary
= NULL
;
87 /* The docs say this can be a bitmask...not sure I believe it, but we'll code
88 * for it anyway and show all possible flags in the returned string. */
90 /* The signature is fully valid. */
91 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_VALID
, "valid");
92 /* The signature is good. */
93 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_GREEN
, "green");
94 /* The signature is bad. */
95 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_RED
, "red");
96 /* One key has been revoked. */
97 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_REVOKED
, "key revoked");
98 /* One key has expired. */
99 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_EXPIRED
, "key expired");
100 /* The signature has expired. */
101 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SIG_EXPIRED
, "sig expired");
102 /* Can't verify: key missing. */
103 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_KEY_MISSING
, "key missing");
104 /* CRL not available. */
105 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_MISSING
, "crl missing");
106 /* Available CRL is too old. */
107 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_CRL_TOO_OLD
, "crl too old");
108 /* A policy was not met. */
109 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_BAD_POLICY
, "bad policy");
110 /* A system error occured. */
111 sigsum_test_bit(sigsum
, &summary
, GPGME_SIGSUM_SYS_ERROR
, "sys error");
114 summary
= alpm_list_add(summary
, (void *)"(empty)");
120 * Initialize the GPGME library.
121 * This can be safely called multiple times; however it is not thread-safe.
122 * @param handle the context handle
123 * @return 0 on success, -1 on error
125 static int init_gpgme(alpm_handle_t
*handle
)
128 const char *version
, *sigdir
;
130 gpgme_engine_info_t enginfo
;
133 /* we already successfully initialized the library */
137 sigdir
= handle
->gpgdir
;
139 if(_alpm_access(handle
, sigdir
, "pubring.gpg", R_OK
)
140 || _alpm_access(handle
, sigdir
, "trustdb.gpg", R_OK
)) {
141 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
142 _alpm_log(handle
, ALPM_LOG_DEBUG
, "Signature verification will fail!\n");
143 _alpm_log(handle
, ALPM_LOG_WARNING
,
144 _("Public keyring not found; have you run '%s'?\n"),
145 "pacman-key --init");
148 /* calling gpgme_check_version() returns the current version and runs
149 * some internal library setup code */
150 version
= gpgme_check_version(NULL
);
151 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME version: %s\n", version
);
152 gpgme_set_locale(NULL
, LC_CTYPE
, setlocale(LC_CTYPE
, NULL
));
154 gpgme_set_locale(NULL
, LC_MESSAGES
, setlocale(LC_MESSAGES
, NULL
));
157 * The GPGME library installs a SIGPIPE signal handler automatically if
158 * the default signal hander is in use. The only time we set a handler
159 * for SIGPIPE is in dload.c, and we reset it when we are done. Given that
160 * we do this, we can let GPGME do its automagic. However, if we install
161 * a library-wide SIGPIPE handler, we will have to be careful.
164 /* check for OpenPGP support (should be a no-brainer, but be safe) */
165 err
= gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP
);
168 /* set and check engine information */
169 err
= gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP
, NULL
, sigdir
);
171 err
= gpgme_get_engine_info(&enginfo
);
173 _alpm_log(handle
, ALPM_LOG_DEBUG
, "GPGME engine info: file=%s, home=%s\n",
174 enginfo
->file_name
, enginfo
->home_dir
);
180 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
181 RET_ERR(handle
, ALPM_ERR_GPGME
, -1);
185 * Determine if we have a key is known in our local keyring.
186 * @param handle the context handle
187 * @param fpr the fingerprint key ID to look up
188 * @return 1 if key is known, 0 if key is unknown, -1 on error
190 static int key_in_keychain(alpm_handle_t
*handle
, const char *fpr
)
197 memset(&ctx
, 0, sizeof(ctx
));
198 err
= gpgme_new(&ctx
);
201 _alpm_log(handle
, ALPM_LOG_DEBUG
, "looking up key %s locally\n", fpr
);
203 err
= gpgme_get_key(ctx
, fpr
, &key
, 0);
204 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
205 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
207 } else if(gpg_err_code(err
) == GPG_ERR_NO_ERROR
) {
208 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup success, key exists\n");
211 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
215 gpgme_key_unref(key
);
221 * Search for a GPG key in a remote location.
222 * This requires GPGME to call the gpg binary and have a keyserver previously
223 * defined in a gpg.conf configuration file.
224 * @param handle the context handle
225 * @param fpr the fingerprint key ID to look up
226 * @param pgpkey storage location for the given key if found
227 * @return 1 on success, 0 on key not found, -1 on error
229 static int key_search(alpm_handle_t
*handle
, const char *fpr
,
230 alpm_pgpkey_t
*pgpkey
)
234 gpgme_keylist_mode_t mode
;
238 memset(&ctx
, 0, sizeof(ctx
));
239 err
= gpgme_new(&ctx
);
242 mode
= gpgme_get_keylist_mode(ctx
);
243 /* using LOCAL and EXTERN together doesn't work for GPG 1.X. Ugh. */
244 mode
&= ~GPGME_KEYLIST_MODE_LOCAL
;
245 mode
|= GPGME_KEYLIST_MODE_EXTERN
;
246 err
= gpgme_set_keylist_mode(ctx
, mode
);
249 _alpm_log(handle
, ALPM_LOG_DEBUG
, "looking up key %s remotely\n", fpr
);
251 err
= gpgme_get_key(ctx
, fpr
, &key
, 0);
252 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
253 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
256 } else if(gpg_err_code(err
) != GPG_ERR_NO_ERROR
) {
257 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
261 /* should only get here if key actually exists */
263 if(key
->subkeys
->fpr
) {
264 pgpkey
->fingerprint
= key
->subkeys
->fpr
;
265 } else if(key
->subkeys
->keyid
) {
266 pgpkey
->fingerprint
= key
->subkeys
->keyid
;
268 pgpkey
->uid
= key
->uids
->uid
;
269 pgpkey
->name
= key
->uids
->name
;
270 pgpkey
->email
= key
->uids
->email
;
271 pgpkey
->created
= key
->subkeys
->timestamp
;
272 pgpkey
->expires
= key
->subkeys
->expires
;
273 pgpkey
->length
= key
->subkeys
->length
;
274 pgpkey
->revoked
= key
->subkeys
->revoked
;
276 switch (key
->subkeys
->pubkey_algo
) {
280 pgpkey
->pubkey_algo
= 'R';
284 pgpkey
->pubkey_algo
= 'D';
291 pgpkey
->pubkey_algo
= 'E';
303 * Import a key into the local keyring.
304 * @param handle the context handle
305 * @param key the key to import, likely retrieved from #key_search
306 * @return 0 on success, -1 on error
308 static int key_import(alpm_handle_t
*handle
, alpm_pgpkey_t
*key
)
313 gpgme_import_result_t result
;
316 if(_alpm_access(handle
, handle
->gpgdir
, "pubring.gpg", W_OK
)) {
317 /* no chance of import succeeding if pubring isn't writable */
318 _alpm_log(handle
, ALPM_LOG_ERROR
, _("keyring is not writable\n"));
322 memset(&ctx
, 0, sizeof(ctx
));
323 err
= gpgme_new(&ctx
);
326 _alpm_log(handle
, ALPM_LOG_DEBUG
, "importing key\n");
330 err
= gpgme_op_import_keys(ctx
, keys
);
332 result
= gpgme_op_import_result(ctx
);
334 /* we know we tried to import exactly one key, so check for this */
335 if(result
->considered
!= 1 || !result
->imports
) {
336 _alpm_log(handle
, ALPM_LOG_DEBUG
, "could not import key, 0 results\n");
338 } else if(result
->imports
->result
!= GPG_ERR_NO_ERROR
) {
339 _alpm_log(handle
, ALPM_LOG_DEBUG
, "gpg error: %s\n", gpgme_strerror(err
));
351 * Decode a loaded signature in base64 form.
352 * @param base64_data the signature to attempt to decode
353 * @param data the decoded data; must be freed by the caller
354 * @param data_len the length of the returned data
355 * @return 0 on success, -1 on failure to properly decode
357 static int decode_signature(const char *base64_data
,
358 unsigned char **data
, size_t *data_len
) {
359 size_t len
= strlen(base64_data
);
360 unsigned char *usline
= (unsigned char *)base64_data
;
361 /* reasonable allocation of expected length is 3/4 of encoded length */
362 size_t destlen
= len
* 3 / 4;
363 MALLOC(*data
, destlen
, goto error
);
364 if(base64_decode(*data
, &destlen
, usline
, len
)) {
378 * Check the PGP signature for the given file path.
379 * If base64_sig is provided, it will be used as the signature data after
380 * decoding. If base64_sig is NULL, expect a signature file next to path
383 * The return value will be 0 if nothing abnormal happened during the signature
384 * check, and -1 if an error occurred while checking signatures or if a
385 * signature could not be found; pm_errno will be set. Note that "abnormal"
386 * does not include a failed signature; the value in siglist should be checked
387 * to determine if the signature(s) are good.
388 * @param handle the context handle
389 * @param path the full path to a file
390 * @param base64_sig optional PGP signature data in base64 encoding
391 * @param siglist a pointer to storage for signature results
392 * @return 0 in normal cases, -1 if the something failed in the check process
394 int _alpm_gpgme_checksig(alpm_handle_t
*handle
, const char *path
,
395 const char *base64_sig
, alpm_siglist_t
*siglist
)
397 int ret
= -1, sigcount
;
398 gpgme_error_t err
= 0;
400 gpgme_data_t filedata
, sigdata
;
401 gpgme_verify_result_t verify_result
;
402 gpgme_signature_t gpgsig
;
403 char *sigpath
= NULL
;
404 unsigned char *decoded_sigdata
= NULL
;
405 FILE *file
= NULL
, *sigfile
= NULL
;
407 if(!path
|| _alpm_access(handle
, NULL
, path
, R_OK
) != 0) {
408 RET_ERR(handle
, ALPM_ERR_NOT_A_FILE
, -1);
412 RET_ERR(handle
, ALPM_ERR_WRONG_ARGS
, -1);
417 sigpath
= _alpm_sigpath(handle
, path
);
418 /* this will just help debugging */
419 _alpm_access(handle
, NULL
, sigpath
, R_OK
);
422 /* does the file we are verifying exist? */
423 file
= fopen(path
, "rb");
425 handle
->pm_errno
= ALPM_ERR_NOT_A_FILE
;
429 /* does the sig file exist (if we didn't get the data directly)? */
431 sigfile
= fopen(sigpath
, "rb");
432 if(sigfile
== NULL
) {
433 _alpm_log(handle
, ALPM_LOG_DEBUG
, "sig path %s could not be opened\n",
435 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
440 if(init_gpgme(handle
)) {
441 /* pm_errno was set in gpgme_init() */
445 _alpm_log(handle
, ALPM_LOG_DEBUG
, "checking signature for %s\n", path
);
447 memset(&ctx
, 0, sizeof(ctx
));
448 memset(&sigdata
, 0, sizeof(sigdata
));
449 memset(&filedata
, 0, sizeof(filedata
));
451 err
= gpgme_new(&ctx
);
454 /* create our necessary data objects to verify the signature */
455 err
= gpgme_data_new_from_stream(&filedata
, file
);
458 /* next create data object for the signature */
460 /* memory-based, we loaded it from a sync DB */
462 int decode_ret
= decode_signature(base64_sig
,
463 &decoded_sigdata
, &data_len
);
465 handle
->pm_errno
= ALPM_ERR_SIG_INVALID
;
468 err
= gpgme_data_new_from_mem(&sigdata
,
469 (char *)decoded_sigdata
, data_len
, 0);
471 /* file-based, it is on disk */
472 err
= gpgme_data_new_from_stream(&sigdata
, sigfile
);
476 /* here's where the magic happens */
477 err
= gpgme_op_verify(ctx
, sigdata
, filedata
, NULL
);
479 verify_result
= gpgme_op_verify_result(ctx
);
481 if(!verify_result
|| !verify_result
->signatures
) {
482 _alpm_log(handle
, ALPM_LOG_DEBUG
, "no signatures returned\n");
483 handle
->pm_errno
= ALPM_ERR_SIG_MISSING
;
486 for(gpgsig
= verify_result
->signatures
, sigcount
= 0;
487 gpgsig
; gpgsig
= gpgsig
->next
, sigcount
++);
488 _alpm_log(handle
, ALPM_LOG_DEBUG
, "%d signatures returned\n", sigcount
);
490 CALLOC(siglist
->results
, sigcount
, sizeof(alpm_sigresult_t
),
491 handle
->pm_errno
= ALPM_ERR_MEMORY
; goto gpg_error
);
492 siglist
->count
= sigcount
;
494 for(gpgsig
= verify_result
->signatures
, sigcount
= 0; gpgsig
;
495 gpgsig
= gpgsig
->next
, sigcount
++) {
496 alpm_list_t
*summary_list
, *summary
;
497 alpm_sigstatus_t status
;
498 alpm_sigvalidity_t validity
;
500 alpm_sigresult_t
*result
;
502 _alpm_log(handle
, ALPM_LOG_DEBUG
, "fingerprint: %s\n", gpgsig
->fpr
);
503 summary_list
= list_sigsum(gpgsig
->summary
);
504 for(summary
= summary_list
; summary
; summary
= summary
->next
) {
505 _alpm_log(handle
, ALPM_LOG_DEBUG
, "summary: %s\n", (const char *)summary
->data
);
507 alpm_list_free(summary_list
);
508 _alpm_log(handle
, ALPM_LOG_DEBUG
, "status: %s\n", gpgme_strerror(gpgsig
->status
));
509 _alpm_log(handle
, ALPM_LOG_DEBUG
, "timestamp: %lu\n", gpgsig
->timestamp
);
510 _alpm_log(handle
, ALPM_LOG_DEBUG
, "exp_timestamp: %lu\n", gpgsig
->exp_timestamp
);
511 _alpm_log(handle
, ALPM_LOG_DEBUG
, "validity: %s; reason: %s\n",
512 string_validity(gpgsig
->validity
),
513 gpgme_strerror(gpgsig
->validity_reason
));
515 result
= siglist
->results
+ sigcount
;
516 err
= gpgme_get_key(ctx
, gpgsig
->fpr
, &key
, 0);
517 if(gpg_err_code(err
) == GPG_ERR_EOF
) {
518 _alpm_log(handle
, ALPM_LOG_DEBUG
, "key lookup failed, unknown key\n");
519 err
= GPG_ERR_NO_ERROR
;
520 /* we dupe the fpr in this case since we have no key to point at */
521 STRDUP(result
->key
.fingerprint
, gpgsig
->fpr
,
522 handle
->pm_errno
= ALPM_ERR_MEMORY
; goto gpg_error
);
526 result
->key
.data
= key
;
527 result
->key
.fingerprint
= key
->subkeys
->fpr
;
528 result
->key
.uid
= key
->uids
->uid
;
529 result
->key
.name
= key
->uids
->name
;
530 result
->key
.email
= key
->uids
->email
;
531 result
->key
.created
= key
->subkeys
->timestamp
;
532 result
->key
.expires
= key
->subkeys
->expires
;
533 _alpm_log(handle
, ALPM_LOG_DEBUG
,
534 "key: %s, %s, owner_trust %s, disabled %d\n",
535 key
->subkeys
->fpr
, key
->uids
->uid
,
536 string_validity(key
->owner_trust
), key
->disabled
);
540 switch(gpg_err_code(gpgsig
->status
)) {
542 case GPG_ERR_NO_ERROR
:
543 status
= ALPM_SIGSTATUS_VALID
;
545 case GPG_ERR_KEY_EXPIRED
:
546 status
= ALPM_SIGSTATUS_KEY_EXPIRED
;
549 case GPG_ERR_SIG_EXPIRED
:
550 status
= ALPM_SIGSTATUS_SIG_EXPIRED
;
552 case GPG_ERR_NO_PUBKEY
:
553 status
= ALPM_SIGSTATUS_KEY_UNKNOWN
;
555 case GPG_ERR_BAD_SIGNATURE
:
557 status
= ALPM_SIGSTATUS_INVALID
;
560 /* special case: key disabled is not returned in above status code */
561 if(result
->key
.data
&& key
->disabled
) {
562 status
= ALPM_SIGSTATUS_KEY_DISABLED
;
565 switch(gpgsig
->validity
) {
566 case GPGME_VALIDITY_ULTIMATE
:
567 case GPGME_VALIDITY_FULL
:
568 validity
= ALPM_SIGVALIDITY_FULL
;
570 case GPGME_VALIDITY_MARGINAL
:
571 validity
= ALPM_SIGVALIDITY_MARGINAL
;
573 case GPGME_VALIDITY_NEVER
:
574 validity
= ALPM_SIGVALIDITY_NEVER
;
576 case GPGME_VALIDITY_UNKNOWN
:
577 case GPGME_VALIDITY_UNDEFINED
:
579 validity
= ALPM_SIGVALIDITY_UNKNOWN
;
583 result
->status
= status
;
584 result
->validity
= validity
;
590 gpgme_data_release(sigdata
);
591 gpgme_data_release(filedata
);
602 FREE(decoded_sigdata
);
603 if(gpg_err_code(err
) != GPG_ERR_NO_ERROR
) {
604 _alpm_log(handle
, ALPM_LOG_ERROR
, _("GPGME error: %s\n"), gpgme_strerror(err
));
605 RET_ERR(handle
, ALPM_ERR_GPGME
, -1);
610 #else /* HAVE_LIBGPGME */
611 static int key_in_keychain(alpm_handle_t UNUSED
*handle
, const char UNUSED
*fpr
)
615 int _alpm_gpgme_checksig(alpm_handle_t UNUSED
*handle
, const char UNUSED
*path
,
616 const char UNUSED
*base64_sig
, alpm_siglist_t UNUSED
*siglist
)
620 #endif /* HAVE_LIBGPGME */
623 * Form a signature path given a file path.
624 * Caller must free the result.
625 * @param handle the context handle
626 * @param path the full path to a file
627 * @return the path with '.sig' appended, NULL on errors
629 char *_alpm_sigpath(alpm_handle_t
*handle
, const char *path
)
637 len
= strlen(path
) + 5;
638 CALLOC(sigpath
, len
, sizeof(char), RET_ERR(handle
, ALPM_ERR_MEMORY
, NULL
));
639 sprintf(sigpath
, "%s.sig", path
);
644 * Helper for checking the PGP signature for the given file path.
645 * This wraps #_alpm_gpgme_checksig in a slightly friendlier manner to simplify
646 * handling of optional signatures and marginal/unknown trust levels and
647 * handling the correct error code return values.
648 * @param handle the context handle
649 * @param path the full path to a file
650 * @param base64_sig optional PGP signature data in base64 encoding
651 * @param optional whether signatures are optional (e.g., missing OK)
652 * @param marginal whether signatures with marginal trust are acceptable
653 * @param unknown whether signatures with unknown trust are acceptable
654 * @param sigdata a pointer to storage for signature results
655 * @return 0 on success, -1 on error (consult pm_errno or sigdata)
657 int _alpm_check_pgp_helper(alpm_handle_t
*handle
, const char *path
,
658 const char *base64_sig
, int optional
, int marginal
, int unknown
,
659 alpm_siglist_t
**sigdata
)
661 alpm_siglist_t
*siglist
;
664 CALLOC(siglist
, 1, sizeof(alpm_siglist_t
),
665 RET_ERR(handle
, ALPM_ERR_MEMORY
, -1));
667 ret
= _alpm_gpgme_checksig(handle
, path
, base64_sig
, siglist
);
668 if(ret
&& handle
->pm_errno
== ALPM_ERR_SIG_MISSING
) {
670 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing optional signature\n");
671 handle
->pm_errno
= 0;
674 _alpm_log(handle
, ALPM_LOG_DEBUG
, "missing required signature\n");
675 /* ret will already be -1 */
678 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature check failed\n");
679 /* ret will already be -1 */
682 for(num
= 0; !ret
&& num
< siglist
->count
; num
++) {
683 switch(siglist
->results
[num
].status
) {
684 case ALPM_SIGSTATUS_VALID
:
685 case ALPM_SIGSTATUS_KEY_EXPIRED
:
686 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is valid\n");
687 switch(siglist
->results
[num
].validity
) {
688 case ALPM_SIGVALIDITY_FULL
:
689 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is fully trusted\n");
691 case ALPM_SIGVALIDITY_MARGINAL
:
692 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is marginal trust\n");
697 case ALPM_SIGVALIDITY_UNKNOWN
:
698 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is unknown trust\n");
703 case ALPM_SIGVALIDITY_NEVER
:
704 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature should never be trusted\n");
709 case ALPM_SIGSTATUS_SIG_EXPIRED
:
710 case ALPM_SIGSTATUS_KEY_UNKNOWN
:
711 case ALPM_SIGSTATUS_KEY_DISABLED
:
712 case ALPM_SIGSTATUS_INVALID
:
713 _alpm_log(handle
, ALPM_LOG_DEBUG
, "signature is not valid\n");
723 alpm_siglist_cleanup(siglist
);
731 * Examine a signature result list and take any appropriate or necessary
732 * actions. This may include asking the user to import a key or simply printing
733 * helpful failure messages so the user can take action out of band.
734 * @param handle the context handle
735 * @param identifier a friendly name for the signed resource; usually a
736 * database or package name
737 * @param siglist a pointer to storage for signature results
738 * @param optional whether signatures are optional (e.g., missing OK)
739 * @param marginal whether signatures with marginal trust are acceptable
740 * @param unknown whether signatures with unknown trust are acceptable
741 * @return 0 if all signatures are OK, -1 on errors, 1 if we should retry the
744 int _alpm_process_siglist(alpm_handle_t
*handle
, const char *identifier
,
745 alpm_siglist_t
*siglist
, int optional
, int marginal
, int unknown
)
750 if(!optional
&& siglist
->count
== 0) {
751 _alpm_log(handle
, ALPM_LOG_ERROR
,
752 _("%s: missing required signature\n"), identifier
);
755 for(i
= 0; i
< siglist
->count
; i
++) {
756 alpm_sigresult_t
*result
= siglist
->results
+ i
;
757 const char *name
= result
->key
.uid
? result
->key
.uid
: result
->key
.fingerprint
;
758 switch(result
->status
) {
759 case ALPM_SIGSTATUS_VALID
:
760 case ALPM_SIGSTATUS_KEY_EXPIRED
:
761 switch(result
->validity
) {
762 case ALPM_SIGVALIDITY_FULL
:
764 case ALPM_SIGVALIDITY_MARGINAL
:
766 _alpm_log(handle
, ALPM_LOG_ERROR
,
767 _("%s: signature from \"%s\" is marginal trust\n"),
769 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
772 case ALPM_SIGVALIDITY_UNKNOWN
:
774 _alpm_log(handle
, ALPM_LOG_ERROR
,
775 _("%s: signature from \"%s\" is unknown trust\n"),
777 /* QUESTION(handle, ALPM_QUESTION_EDIT_KEY_TRUST, &result->key, NULL, NULL, &answer); */
780 case ALPM_SIGVALIDITY_NEVER
:
781 _alpm_log(handle
, ALPM_LOG_ERROR
,
782 _("%s: signature from \"%s\" should never be trusted\n"),
787 case ALPM_SIGSTATUS_KEY_UNKNOWN
:
788 /* ensure this key is still actually unknown; we may have imported it
789 * on an earlier call to this function. */
790 if(key_in_keychain(handle
, result
->key
.fingerprint
) == 1) {
793 _alpm_log(handle
, ALPM_LOG_ERROR
,
794 _("%s: key \"%s\" is unknown\n"), identifier
, name
);
798 alpm_pgpkey_t fetch_key
;
799 memset(&fetch_key
, 0, sizeof(fetch_key
));
801 if(key_search(handle
, result
->key
.fingerprint
, &fetch_key
) == 1) {
802 _alpm_log(handle
, ALPM_LOG_DEBUG
,
803 "unknown key, found %s on keyserver\n", fetch_key
.uid
);
804 if(!_alpm_access(handle
, handle
->gpgdir
, "pubring.gpg", W_OK
)) {
805 QUESTION(handle
, ALPM_QUESTION_IMPORT_KEY
,
806 &fetch_key
, NULL
, NULL
, &answer
);
808 if(key_import(handle
, &fetch_key
) == 0) {
811 _alpm_log(handle
, ALPM_LOG_ERROR
,
812 _("key \"%s\" could not be imported\n"), fetch_key
.uid
);
816 /* keyring directory was not writable, so we don't even try */
817 _alpm_log(handle
, ALPM_LOG_WARNING
,
818 _("key %s, \"%s\" found on keyserver, keyring is not writable\n"),
819 fetch_key
.fingerprint
, fetch_key
.uid
);
822 _alpm_log(handle
, ALPM_LOG_ERROR
,
823 _("key \"%s\" could not be looked up remotely\n"), name
);
825 gpgme_key_unref(fetch_key
.data
);
829 case ALPM_SIGSTATUS_KEY_DISABLED
:
830 _alpm_log(handle
, ALPM_LOG_ERROR
,
831 _("%s: key \"%s\" is disabled\n"), identifier
, name
);
833 case ALPM_SIGSTATUS_SIG_EXPIRED
:
834 _alpm_log(handle
, ALPM_LOG_ERROR
,
835 _("%s: signature from \"%s\" is expired\n"), identifier
, name
);
837 case ALPM_SIGSTATUS_INVALID
:
838 _alpm_log(handle
, ALPM_LOG_ERROR
,
839 _("%s: signature from \"%s\" is invalid\n"),
849 * Check the PGP signature for the given package file.
850 * @param pkg the package to check
851 * @param siglist a pointer to storage for signature results
852 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
854 int SYMEXPORT
alpm_pkg_check_pgp_signature(alpm_pkg_t
*pkg
,
855 alpm_siglist_t
*siglist
)
857 ASSERT(pkg
!= NULL
, return -1);
858 ASSERT(siglist
!= NULL
, RET_ERR(pkg
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
859 pkg
->handle
->pm_errno
= 0;
861 return _alpm_gpgme_checksig(pkg
->handle
, pkg
->filename
,
862 pkg
->base64_sig
, siglist
);
866 * Check the PGP signature for the given database.
867 * @param db the database to check
868 * @param siglist a pointer to storage for signature results
869 * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred)
871 int SYMEXPORT
alpm_db_check_pgp_signature(alpm_db_t
*db
,
872 alpm_siglist_t
*siglist
)
874 ASSERT(db
!= NULL
, return -1);
875 ASSERT(siglist
!= NULL
, RET_ERR(db
->handle
, ALPM_ERR_WRONG_ARGS
, -1));
876 db
->handle
->pm_errno
= 0;
878 return _alpm_gpgme_checksig(db
->handle
, _alpm_db_path(db
), NULL
, siglist
);
882 * Clean up and free a signature result list.
883 * Note that this does not free the siglist object itself in case that
884 * was allocated on the stack; this is the responsibility of the caller.
885 * @param siglist a pointer to storage for signature results
886 * @return 0 on success, -1 on error
888 int SYMEXPORT
alpm_siglist_cleanup(alpm_siglist_t
*siglist
)
890 ASSERT(siglist
!= NULL
, return -1);
892 for(num
= 0; num
< siglist
->count
; num
++) {
893 alpm_sigresult_t
*result
= siglist
->results
+ num
;
894 if(result
->key
.data
) {
896 gpgme_key_unref(result
->key
.data
);
899 free(result
->key
.fingerprint
);
903 free(siglist
->results
);
905 siglist
->results
= NULL
;
910 /* vim: set ts=2 sw=2 noet: */