diff --git a/agent/ChangeLog b/agent/ChangeLog index 18f02f77b..9a398f576 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,11 @@ +2002-02-18 Werner Koch + + * command.c (cmd_marktrusted): Implemented. + * trustlist.c (agent_marktrusted): New. + (open_list): Add APPEND arg. + + * query.c (agent_get_confirmation): New. + 2002-02-06 Werner Koch * cache.c (housekeeping): Fixed linking in the remove case. diff --git a/agent/agent.h b/agent/agent.h index 9236ef07a..a4cf8629d 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -110,6 +110,7 @@ int agent_askpin (const char *desc_text, const char *err_text, int agent_get_passphrase (char **retpass, const char *desc, const char *prompt, const char *errtext); +int agent_get_confirmation (const char *desc, const char *prompt); /*-- cache.c --*/ int agent_put_cache (const char *key, const char *data, int ttl); @@ -139,7 +140,7 @@ int agent_private_key_type (const unsigned char *privatekey); /*-- trustlist.c --*/ int agent_istrusted (const char *fpr); int agent_listtrusted (void *assuan_context); - +int agent_marktrusted (const char *name, const char *fpr, int flag); #endif /*AGENT_H*/ diff --git a/agent/command.c b/agent/command.c index bbcab8e7d..0a329627f 100644 --- a/agent/command.c +++ b/agent/command.c @@ -108,13 +108,42 @@ cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line) } -/* MARKTRUSTED +/* MARKTRUSTED Store a new key in into the trustlist*/ static int cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line) { - return ASSUAN_Not_Implemented; + int rc, n, i; + char *p; + char fpr[41]; + int flag; + + /* parse the fingerprint value */ + for (p=line,n=0; hexdigitp (p); p++, n++) + ; + if (!spacep (p) || !(n == 40 || n == 32)) + return set_error (Parameter_Error, "invalid fingerprint"); + i = 0; + if (n==32) + { + strcpy (fpr, "00000000"); + i += 8; + } + for (p=line; i < 40; p++, i++) + fpr[i] = *p >= 'a'? (*p & 0xdf): *p; + fpr[i] = 0; + + while (spacep (p)) + p++; + flag = *p++; + if ( (flag != 'S' && flag != 'P') || !spacep (p) ) + return set_error (Parameter_Error, "invalid flag - must be P or S"); + while (spacep (p)) + p++; + + rc = agent_marktrusted (p, fpr, flag); + return map_to_assuan_status (rc); } @@ -476,7 +505,7 @@ register_commands (ASSUAN_CONTEXT ctx) } -/* Startup the server. If LISTEN_FD is given as -1, this is simple +/* Startup the server. If LISTEN_FD is given as -1, this is a simple piper server, otherwise it is a regular server */ void start_command_handler (int listen_fd) diff --git a/agent/query.c b/agent/query.c index 3b8cd08df..1abfefcd9 100644 --- a/agent/query.c +++ b/agent/query.c @@ -297,6 +297,42 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt, } + +/* Pop up the PIN-entry, display the text and the prompt and ask the + user to confirm this. We return 0 for success, ie. the used + confirmed it, GNUPG_Not_Confirmed for what the text says or an + other error. */ +int +agent_get_confirmation (const char *desc, const char *prompt) +{ + int rc; + char line[ASSUAN_LINELENGTH]; + + rc = start_pinentry (); + if (rc) + return rc; + + if (desc) + snprintf (line, DIM(line)-1, "SETDESC %s", desc); + else + snprintf (line, DIM(line)-1, "RESET"); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + if (rc) + return map_assuan_err (rc); + + if (prompt) + { + snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); + if (rc) + return map_assuan_err (rc); + } + + rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL); + return map_assuan_err (rc); +} diff --git a/agent/trustlist.c b/agent/trustlist.c index 222d2dc9e..15208cedf 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -40,7 +40,7 @@ static const char headerblurb[] = "# length limit but this is not serious limitation as the format of the\n" "# entries is fixed and checked by gpg-agent: A non-comment line starts\n" "# with optional white spaces, followed by exactly 40 hex character,\n" -"# optioanlly followed by a flag charcter which my either be 'P', 'S'\n" +"# optioanlly followed by a flag character which my either be 'P', 'S'\n" "# or '*'. Additional data delimited with by a white space is ignored.\n" "\n"; @@ -49,12 +49,12 @@ static FILE *trustfp; static int -open_list (void) +open_list (int append) { char *fname; fname = make_filename (opt.homedir, "trustlist.txt", NULL); - trustfp = fopen (fname, "r"); + trustfp = fopen (fname, append? "a+":"r"); if (!trustfp && errno == ENOENT) { trustfp = fopen (fname, "wx"); @@ -66,7 +66,7 @@ open_list (void) } fputs (headerblurb, trustfp); fclose (trustfp); - trustfp = fopen (fname, "r"); + trustfp = fopen (fname, append? "a+":"r"); } if (!trustfp) @@ -98,7 +98,7 @@ read_list (char *key, int *keyflag) if (!trustfp) { - rc = open_list (); + rc = open_list (0); if (rc) return rc; } @@ -162,7 +162,7 @@ read_list (char *key, int *keyflag) return 0; } -/* check whether the given fr is in our trustdb. We expect FPR to be +/* check whether the given fpr is in our trustdb. We expect FPR to be an all uppercase hexstring of 40 characters. */ int agent_istrusted (const char *fpr) @@ -220,8 +220,85 @@ agent_listtrusted (void *assuan_context) } +/* Insert the given fpr into our trustdb. We expect FPR to be an all + uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'. + This function does first check whether that key has alreay ben put + into the trustdb and returns success in this case. Before a FPR + actually gets inserted, the user is asked by means of the pin-entry + whether this is actual wants he want to do. +*/ +int +agent_marktrusted (const char *name, const char *fpr, int flag) +{ + int rc; + static char key[41]; + int keyflag; + char *desc; + if (trustfp) + rewind (trustfp); + while (!(rc=read_list (key, &keyflag))) + { + if (!strcmp (key, fpr)) + return 0; + } + fclose (trustfp); + trustfp = NULL; + if (rc != -1) + return rc; /* error in the trustdb */ + /* insert a new one */ + if (asprintf (&desc, + "Please verify that the certificate identified as:%%0A" + " \"%s\"%%0A" + "has the fingerprint:%%0A" + " %s", name, fpr) < 0 ) + return GNUPG_Out_Of_Core; + rc = agent_get_confirmation (desc, "Correct|No"); + free (desc); + if (rc) + return rc; + if (asprintf (&desc, + "Do you ultimately trust%%0A" + " \"%s\"%%0A" + "to correctly certify user certificates?", + name) < 0 ) + return GNUPG_Out_Of_Core; + rc = agent_get_confirmation (desc, "Yes|No"); + free (desc); + if (rc) + return rc; + /* now check again to avoid duplicates. Also open in append mode now */ + rc = open_list (1); + if (rc) + return rc; + rewind (trustfp); + while (!(rc=read_list (key, &keyflag))) + { + if (!strcmp (key, fpr)) + return 0; + } + if (rc != -1) + { + fclose (trustfp); + trustfp = NULL; + return rc; /* error in the trustdb */ + } + rc = 0; + /* append the key */ + fflush (trustfp); + fputs ("\n# ", trustfp); + print_sanitized_string (trustfp, name, 0); + fprintf (trustfp, "\n%s %c\n", fpr, flag); + if (ferror (trustfp)) + rc = GNUPG_Write_Error; + + /* close because we are in append mode */ + if (fclose (trustfp)) + rc = GNUPG_File_Error; + trustfp = NULL; + return rc; +}