NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pgpkey.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <stdbool.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <unistd.h>
38#include "private.h"
39#include "mutt/lib.h"
40#include "address/lib.h"
41#include "config/lib.h"
42#include "email/lib.h"
43#include "core/lib.h"
44#include "mutt.h"
45#include "pgpkey.h"
46#include "lib.h"
47#include "editor/lib.h"
48#include "history/lib.h"
49#include "send/lib.h"
50#include "crypt.h"
51#include "globals.h" // IWYU pragma: keep
52#include "gnupgparse.h"
53#include "mutt_logging.h"
54#include "pgpinvoke.h"
55#ifdef CRYPT_BACKEND_CLASSIC_PGP
56#include "pgp.h"
57#include "pgplib.h"
58#endif
59
64{
65 char *what;
66 char *dflt;
67 struct PgpCache *next;
68};
69
71static struct PgpCache *IdDefaults = NULL;
72
73// clang-format off
74typedef uint8_t PgpKeyValidFlags;
75#define PGP_KV_NO_FLAGS 0
76#define PGP_KV_VALID (1 << 0)
77#define PGP_KV_ADDR (1 << 1)
78#define PGP_KV_STRING (1 << 2)
79#define PGP_KV_STRONGID (1 << 3)
80// clang-format on
81
82#define PGP_KV_MATCH (PGP_KV_ADDR | PGP_KV_STRING)
83
90{
91 if (key->flags & KEYFLAG_SUBKEY && key->parent)
92 return key->parent;
93 return key;
94}
95
102{
103 struct PgpKeyInfo *pk = pgp_principal_key(k);
104 if (k->flags & KEYFLAG_CANTUSE)
105 return false;
106 if (pk->flags & KEYFLAG_CANTUSE)
107 return false;
108
109 return true;
110}
111
117bool pgp_id_is_strong(struct PgpUid *uid)
118{
119 if ((uid->trust & 3) < 3)
120 return false;
121 /* else */
122 return true;
123}
124
130bool pgp_id_is_valid(struct PgpUid *uid)
131{
132 if (!pgp_key_is_valid(uid->parent))
133 return false;
134 if (uid->flags & KEYFLAG_CANTUSE)
135 return false;
136 /* else */
137 return true;
138}
139
148 struct Address *u_addr, struct PgpUid *uid)
149{
151
152 if (pgp_id_is_valid(uid))
154
155 if (pgp_id_is_strong(uid))
157
158 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
159 {
161 }
162
163 if (addr->personal && u_addr->personal &&
164 buf_istr_equal(addr->personal, u_addr->personal))
165 {
167 }
168
169 return flags;
170}
171
180struct PgpKeyInfo *pgp_ask_for_key(char *tag, const char *whatfor,
181 KeyFlags abilities, enum PgpRing keyring)
182{
183 struct PgpKeyInfo *key = NULL;
184 struct PgpCache *l = NULL;
185 struct Buffer *resp = buf_pool_get();
186
188
189 if (whatfor)
190 {
191 for (l = IdDefaults; l; l = l->next)
192 {
193 if (mutt_istr_equal(whatfor, l->what))
194 {
195 buf_strcpy(resp, l->dflt);
196 break;
197 }
198 }
199 }
200
201 while (true)
202 {
203 buf_reset(resp);
204 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
205 {
206 goto done;
207 }
208
209 if (whatfor)
210 {
211 if (l)
212 {
213 mutt_str_replace(&l->dflt, buf_string(resp));
214 }
215 else
216 {
217 l = mutt_mem_malloc(sizeof(struct PgpCache));
218 l->next = IdDefaults;
219 IdDefaults = l;
220 l->what = mutt_str_dup(whatfor);
221 l->dflt = buf_strdup(resp);
222 }
223 }
224
225 key = pgp_getkeybystr(buf_string(resp), abilities, keyring);
226 if (key)
227 goto done;
228
229 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
230 }
231
232done:
233 buf_pool_release(&resp);
234 return key;
235}
236
241{
242 struct Body *att = NULL;
243 char buf[1024] = { 0 };
244 char tmp[256] = { 0 };
245 struct stat st = { 0 };
246 pid_t pid;
247 OptPgpCheckTrust = false;
248 struct Buffer *tempf = NULL;
249
250 struct PgpKeyInfo *key = pgp_ask_for_key(_("Please enter the key ID: "), NULL,
252
253 if (!key)
254 return NULL;
255
256 snprintf(tmp, sizeof(tmp), "0x%s", pgp_fpr_or_lkeyid(pgp_principal_key(key)));
257 pgp_key_free(&key);
258
259 tempf = buf_pool_get();
260 buf_mktemp(tempf);
261 FILE *fp_tmp = mutt_file_fopen(buf_string(tempf), "w");
262 if (!fp_tmp)
263 {
264 mutt_perror(_("Can't create temporary file"));
265 goto cleanup;
266 }
267
268 FILE *fp_null = fopen("/dev/null", "w");
269 if (!fp_null)
270 {
271 mutt_perror(_("Can't open /dev/null"));
272 mutt_file_fclose(&fp_tmp);
273 unlink(buf_string(tempf));
274 goto cleanup;
275 }
276
277 mutt_message(_("Invoking PGP..."));
278
279 pid = pgp_invoke_export(NULL, NULL, NULL, -1, fileno(fp_tmp), fileno(fp_null), tmp);
280 if (pid == -1)
281 {
282 mutt_perror(_("Can't create filter"));
283 unlink(buf_string(tempf));
284 mutt_file_fclose(&fp_tmp);
285 mutt_file_fclose(&fp_null);
286 goto cleanup;
287 }
288
289 filter_wait(pid);
290
291 mutt_file_fclose(&fp_tmp);
292 mutt_file_fclose(&fp_null);
293
294 att = mutt_body_new();
295 att->filename = buf_strdup(tempf);
296 att->unlink = true;
297 att->use_disp = false;
298 att->type = TYPE_APPLICATION;
299 att->subtype = mutt_str_dup("pgp-keys");
300 snprintf(buf, sizeof(buf), _("PGP Key %s"), tmp);
301 att->description = mutt_str_dup(buf);
303
304 stat(buf_string(tempf), &st);
305 att->length = st.st_size;
306
307cleanup:
308 buf_pool_release(&tempf);
309 return att;
310}
311
320static void pgp_add_string_to_hints(const char *str, struct ListHead *hints)
321{
322 char *scratch = mutt_str_dup(str);
323 if (!scratch)
324 return;
325
326 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
327 {
328 if (strlen(t) > 3)
330 }
331
332 FREE(&scratch);
333}
334
340static struct PgpKeyInfo **pgp_get_lastp(struct PgpKeyInfo *p)
341{
342 for (; p; p = p->next)
343 if (!p->next)
344 return &p->next;
345
346 return NULL;
347}
348
357struct PgpKeyInfo *pgp_getkeybyaddr(struct Address *a, KeyFlags abilities,
358 enum PgpRing keyring, bool oppenc_mode)
359{
360 if (!a)
361 return NULL;
362
363 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
364
365 bool multi = false;
366
367 struct PgpKeyInfo *keys = NULL, *k = NULL, *kn = NULL;
368 struct PgpKeyInfo *the_strong_valid_key = NULL;
369 struct PgpKeyInfo *a_valid_addrmatch_key = NULL;
370 struct PgpKeyInfo *matches = NULL;
371 struct PgpKeyInfo **last = &matches;
372 struct PgpUid *q = NULL;
373
374 if (a->mailbox)
376 if (a->personal)
378
379 if (!oppenc_mode)
380 mutt_message(_("Looking for keys matching \"%s\"..."), buf_string(a->mailbox));
381 keys = pgp_get_candidates(keyring, &hints);
382
383 mutt_list_free(&hints);
384
385 if (!keys)
386 return NULL;
387
388 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", buf_string(a->personal),
389 buf_string(a->mailbox));
390
391 for (k = keys; k; k = kn)
392 {
393 kn = k->next;
394
395 mutt_debug(LL_DEBUG5, " looking at key: %s\n", pgp_keyid(k));
396
397 if (abilities && !(k->flags & abilities))
398 {
399 mutt_debug(LL_DEBUG3, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
400 continue;
401 }
402
403 bool match = false; /* any match */
404
405 for (q = k->address; q; q = q->next)
406 {
407 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
409 struct Address *qa = NULL;
410 TAILQ_FOREACH(qa, &al, entries)
411 {
412 PgpKeyValidFlags validity = pgp_id_matches_addr(a, qa, q);
413
414 if (validity & PGP_KV_MATCH) /* something matches */
415 match = true;
416
417 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_ADDR))
418 {
419 if (validity & PGP_KV_STRONGID)
420 {
421 if (the_strong_valid_key && (the_strong_valid_key != k))
422 multi = true;
423 the_strong_valid_key = k;
424 }
425 else
426 {
427 a_valid_addrmatch_key = k;
428 }
429 }
430 }
431
433 }
434
435 if (match)
436 {
437 *last = pgp_principal_key(k);
438 kn = pgp_remove_key(&keys, *last);
439 last = pgp_get_lastp(k);
440 }
441 }
442
443 pgp_key_free(&keys);
444
445 if (matches)
446 {
447 if (oppenc_mode)
448 {
449 const bool c_crypt_opportunistic_encrypt_strong_keys =
450 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
451 if (the_strong_valid_key)
452 {
453 pgp_remove_key(&matches, the_strong_valid_key);
454 k = the_strong_valid_key;
455 }
456 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
457 {
458 pgp_remove_key(&matches, a_valid_addrmatch_key);
459 k = a_valid_addrmatch_key;
460 }
461 else
462 {
463 k = NULL;
464 }
465 }
466 else if (the_strong_valid_key && !multi)
467 {
468 /* There was precisely one strong match on a valid ID.
469 * Proceed without asking the user. */
470 pgp_remove_key(&matches, the_strong_valid_key);
471 k = the_strong_valid_key;
472 }
473 else
474 {
475 /* Else: Ask the user. */
476 k = dlg_pgp(matches, a, NULL);
477 if (k)
478 pgp_remove_key(&matches, k);
479 }
480
481 pgp_key_free(&matches);
482
483 return k;
484 }
485
486 return NULL;
487}
488
496struct PgpKeyInfo *pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
497{
498 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
499 struct PgpKeyInfo *keys = NULL;
500 struct PgpKeyInfo *matches = NULL;
501 struct PgpKeyInfo **last = &matches;
502 struct PgpKeyInfo *k = NULL, *kn = NULL;
503 struct PgpUid *a = NULL;
504 size_t l;
505 const char *ps = NULL, *pl = NULL, *pfcopy = NULL, *phint = NULL;
506
507 char *p = strdup(cp); // mutt_str_dup converts "" into NULL, see #1809
508 l = mutt_str_len(p);
509 if ((l > 0) && (p[l - 1] == '!'))
510 p[l - 1] = 0;
511
512 mutt_message(_("Looking for keys matching \"%s\"..."), p);
513
514 pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
515 pgp_add_string_to_hints(phint, &hints);
516 keys = pgp_get_candidates(keyring, &hints);
517 mutt_list_free(&hints);
518
519 for (k = keys; k; k = kn)
520 {
521 kn = k->next;
522 if (abilities && !(k->flags & abilities))
523 continue;
524
525 /* This shouldn't happen, but keys without any addresses aren't selectable
526 * in dlg_pgp(). */
527 if (!k->address)
528 continue;
529
530 bool match = false;
531
532 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s:\n", p, pgp_long_keyid(k));
533
534 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, k->fingerprint)) ||
535 (pl && mutt_istr_equal(pl, pgp_long_keyid(k))) ||
536 (ps && mutt_istr_equal(ps, pgp_short_keyid(k))))
537 {
538 mutt_debug(LL_DEBUG5, " match #1\n");
539 match = true;
540 }
541 else
542 {
543 for (a = k->address; a; a = a->next)
544 {
545 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\":\n", p,
546 pgp_long_keyid(k), NONULL(a->addr));
547 if (mutt_istr_find(a->addr, p))
548 {
549 mutt_debug(LL_DEBUG5, " match #2\n");
550 match = true;
551 break;
552 }
553 }
554 }
555
556 if (match)
557 {
558 *last = pgp_principal_key(k);
559 kn = pgp_remove_key(&keys, *last);
560 last = pgp_get_lastp(k);
561 }
562 }
563
564 pgp_key_free(&keys);
565
566 if (matches)
567 {
568 k = dlg_pgp(matches, NULL, p);
569 if (k)
570 pgp_remove_key(&matches, k);
571 pgp_key_free(&matches);
572 }
573 else
574 {
575 k = NULL;
576 }
577
578 FREE(&pfcopy);
579 FREE(&p);
580 return k;
581}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
Email Address Handling.
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:665
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1277
Signing/encryption multiplexor.
Enter a string.
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Structs that make up an email.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:80
struct PgpKeyInfo * pgp_get_candidates(enum PgpRing keyring, struct ListHead *hints)
Find PGP keys matching a list of hints.
Definition: gnupgparse.c:417
Parse the output of CLI PGP programinclude "pgpkey.h".
struct Body * pgp_class_make_key_attachment(void)
Implements CryptModuleSpecs::pgp_make_key_attachment() -.
Definition: pgpkey.c:240
struct PgpKeyInfo * dlg_pgp(struct PgpKeyInfo *keys, struct Address *p, const char *s)
Let the user select a key to use -.
Definition: dlg_pgp.c:540
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:275
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:54
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:45
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:593
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
NeoMutt Logging.
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:126
#define KEYFLAG_SUBKEY
Key is a subkey.
Definition: lib.h:135
#define KEYFLAG_CANTUSE
Definition: lib.h:140
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:127
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition: pgp.c:166
char * pgp_keyid(struct PgpKeyInfo *k)
Get the ID of the main (parent) key.
Definition: pgp.c:205
char * pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
Get the fingerprint or long keyid.
Definition: pgp.c:235
char * pgp_short_keyid(struct PgpKeyInfo *k)
Get a key's short id.
Definition: pgp.c:178
PGP sign, encrypt, check routines.
pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
Use PGP to export a key from the user's keyring.
Definition: pgpinvoke.c:506
Wrapper around calls to external PGP program.
bool pgp_id_is_valid(struct PgpUid *uid)
Is a PGP key valid.
Definition: pgpkey.c:130
#define PGP_KV_NO_FLAGS
No flags are set.
Definition: pgpkey.c:75
#define PGP_KV_STRONGID
PGP Key is strong.
Definition: pgpkey.c:79
static void pgp_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: pgpkey.c:320
#define PGP_KV_MATCH
Definition: pgpkey.c:82
static PgpKeyValidFlags pgp_id_matches_addr(struct Address *addr, struct Address *u_addr, struct PgpUid *uid)
Does the key ID match the address.
Definition: pgpkey.c:147
struct PgpKeyInfo * pgp_ask_for_key(char *tag, const char *whatfor, KeyFlags abilities, enum PgpRing keyring)
Ask the user for a PGP key.
Definition: pgpkey.c:180
#define PGP_KV_VALID
PGP Key ID is valid.
Definition: pgpkey.c:76
#define PGP_KV_STRING
PGP Key name string is valid.
Definition: pgpkey.c:78
#define PGP_KV_ADDR
PGP Key address is valid.
Definition: pgpkey.c:77
static struct PgpKeyInfo ** pgp_get_lastp(struct PgpKeyInfo *p)
Get the last PGP key in a list.
Definition: pgpkey.c:340
static struct PgpCache * IdDefaults
Cache of GPGME keys.
Definition: pgpkey.c:71
bool pgp_id_is_strong(struct PgpUid *uid)
Is a PGP key strong?
Definition: pgpkey.c:117
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition: pgpkey.c:357
bool pgp_key_is_valid(struct PgpKeyInfo *k)
Is a PGP key valid?
Definition: pgpkey.c:101
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition: pgpkey.c:496
uint8_t PgpKeyValidFlags
Flags for valid Pgp Key fields, e.g. PGP_KV_VALID.
Definition: pgpkey.c:74
struct PgpKeyInfo * pgp_principal_key(struct PgpKeyInfo *key)
Get the main (parent) PGP key.
Definition: pgpkey.c:89
PGP key management routines.
PgpRing
PGP ring type.
Definition: pgpkey.h:38
@ PGP_PUBRING
Public keys.
Definition: pgpkey.h:39
void pgp_key_free(struct PgpKeyInfo **kpp)
Free a PGP key info.
Definition: pgplib.c:200
struct PgpKeyInfo * pgp_remove_key(struct PgpKeyInfo **klist, struct PgpKeyInfo *key)
Remove a PGP key from a list.
Definition: pgplib.c:168
Misc PGP helper routines.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:420
GUI display the mailboxes in a side panel.
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
The body of an email.
Definition: body.h:36
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
char * description
content-description
Definition: body.h:55
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
List of cached PGP keys.
Definition: pgpkey.c:64
char * dflt
Definition: pgpkey.c:66
struct PgpCache * next
Linked list.
Definition: pgpkey.c:67
char * what
Definition: pgpkey.c:65
Information about a PGP key.
Definition: pgplib.h:47
KeyFlags flags
Definition: pgplib.h:51
struct PgpKeyInfo * next
Definition: pgplib.h:57
struct PgpUid * address
Definition: pgplib.h:50
char * fingerprint
Definition: pgplib.h:49
struct PgpKeyInfo * parent
Definition: pgplib.h:56
PGP User ID.
Definition: pgplib.h:35
short trust
Definition: pgplib.h:37
struct PgpKeyInfo * parent
Parent key.
Definition: pgplib.h:39
int flags
Definition: pgplib.h:38
char * addr
Definition: pgplib.h:36
struct PgpUid * next
Linked list.
Definition: pgplib.h:40
#define buf_mktemp(buf)
Definition: tmp.h:33