pinentry.c (31549B)
1 /* pinentry.c - The PIN entry support library 2 Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015 g10 Code GmbH 3 4 This file is part of PINENTRY. 5 6 PINENTRY is free software; you can redistribute it and/or modify it 7 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. 10 11 PINENTRY is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 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/>. 18 */ 19 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 #include <assert.h> 24 25 #include <assuan.h> 26 27 #include "memory.h" 28 #include "secmem-util.h" 29 #include "argparse.h" 30 #include "pinentry.h" 31 #include "password-cache.h" 32 33 /* Keep the name of our program here. */ 34 static char this_pgmname[50]; 35 36 struct pinentry pinentry; 37 38 static void 39 pinentry_reset (int use_defaults) 40 { 41 /* GPG Agent sets these options once when it starts the pinentry. 42 Don't reset them. */ 43 int grab = pinentry.grab; 44 char *ttyname = pinentry.ttyname; 45 char *ttytype = pinentry.ttytype; 46 char *lc_ctype = pinentry.lc_ctype; 47 char *lc_messages = pinentry.lc_messages; 48 int allow_external_password_cache = pinentry.allow_external_password_cache; 49 char *default_ok = pinentry.default_ok; 50 char *default_cancel = pinentry.default_cancel; 51 char *default_prompt = pinentry.default_prompt; 52 char *default_pwmngr = pinentry.default_pwmngr; 53 char *touch_file = pinentry.touch_file; 54 55 /* These options are set from the command line. Don't reset 56 them. */ 57 int debug = pinentry.debug; 58 char *display = pinentry.display; 59 int parent_wid = pinentry.parent_wid; 60 61 pinentry_color_t color_fg = pinentry.color_fg; 62 int color_fg_bright = pinentry.color_fg_bright; 63 pinentry_color_t color_bg = pinentry.color_bg; 64 pinentry_color_t color_so = pinentry.color_so; 65 int color_so_bright = pinentry.color_so_bright; 66 67 int timout = pinentry.timeout; 68 69 /* Free any allocated memory. */ 70 if (use_defaults) 71 { 72 free (pinentry.ttyname); 73 free (pinentry.ttytype); 74 free (pinentry.lc_ctype); 75 free (pinentry.lc_messages); 76 free (pinentry.default_ok); 77 free (pinentry.default_cancel); 78 free (pinentry.default_prompt); 79 free (pinentry.default_pwmngr); 80 free (pinentry.touch_file); 81 free (pinentry.display); 82 } 83 84 free (pinentry.title); 85 free (pinentry.description); 86 free (pinentry.error); 87 free (pinentry.prompt); 88 free (pinentry.ok); 89 free (pinentry.notok); 90 free (pinentry.cancel); 91 secmem_free (pinentry.pin); 92 free (pinentry.repeat_passphrase); 93 free (pinentry.repeat_error_string); 94 free (pinentry.quality_bar); 95 free (pinentry.quality_bar_tt); 96 free (pinentry.keyinfo); 97 98 /* Reset the pinentry structure. */ 99 memset (&pinentry, 0, sizeof (pinentry)); 100 101 if (use_defaults) 102 { 103 /* Pinentry timeout in seconds. */ 104 pinentry.timeout = 60; 105 106 /* Global grab. */ 107 pinentry.grab = 1; 108 109 pinentry.color_fg = PINENTRY_COLOR_DEFAULT; 110 pinentry.color_fg_bright = 0; 111 pinentry.color_bg = PINENTRY_COLOR_DEFAULT; 112 pinentry.color_so = PINENTRY_COLOR_DEFAULT; 113 pinentry.color_so_bright = 0; 114 } 115 else 116 /* Restore the options. */ 117 { 118 pinentry.grab = grab; 119 pinentry.ttyname = ttyname; 120 pinentry.ttytype = ttytype; 121 pinentry.lc_ctype = lc_ctype; 122 pinentry.lc_messages = lc_messages; 123 pinentry.allow_external_password_cache = allow_external_password_cache; 124 pinentry.default_ok = default_ok; 125 pinentry.default_cancel = default_cancel; 126 pinentry.default_prompt = default_prompt; 127 pinentry.default_pwmngr = default_pwmngr; 128 pinentry.touch_file = touch_file; 129 130 pinentry.debug = debug; 131 pinentry.display = display; 132 pinentry.parent_wid = parent_wid; 133 134 pinentry.color_fg = color_fg; 135 pinentry.color_fg_bright = color_fg_bright; 136 pinentry.color_bg = color_bg; 137 pinentry.color_so = color_so; 138 pinentry.color_so_bright = color_so_bright; 139 140 pinentry.timeout = timout; 141 } 142 } 143 144 static gpg_error_t 145 pinentry_assuan_reset_handler (assuan_context_t ctx, char *line) 146 { 147 (void)ctx; 148 (void)line; 149 150 pinentry_reset (0); 151 152 return 0; 153 } 154 155 156 157 static int lc_ctype_unknown_warning = 0; 158 159 /* Copy TEXT or TEXTLEN to BUFFER and escape as required. Return a 160 pointer to the end of the new buffer. Note that BUFFER must be 161 large enough to keep the entire text; allocataing it 3 times of 162 TEXTLEN is sufficient. */ 163 static char * 164 copy_and_escape (char *buffer, const void *text, size_t textlen) 165 { 166 int i; 167 const unsigned char *s = (unsigned char *)text; 168 char *p = buffer; 169 170 for (i=0; i < textlen; i++) 171 { 172 if (s[i] < ' ' || s[i] == '+') 173 { 174 snprintf (p, 4, "%%%02X", s[i]); 175 p += 3; 176 } 177 else if (s[i] == ' ') 178 *p++ = '+'; 179 else 180 *p++ = s[i]; 181 } 182 return p; 183 } 184 185 186 187 /* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH 188 because not all backends might be able to return a proper 189 C-string.). Returns: A value between -100 and 100 to give an 190 estimate of the passphrase's quality. Negative values are use if 191 the caller won't even accept that passphrase. Note that we expect 192 just one data line which should not be escaped in any represent a 193 numeric signed decimal value. Extra data is currently ignored but 194 should not be send at all. */ 195 int 196 pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length) 197 { 198 assuan_context_t ctx = pin->ctx_assuan; 199 const char prefix[] = "INQUIRE QUALITY "; 200 char *command; 201 char *line; 202 size_t linelen; 203 int gotvalue = 0; 204 int value = 0; 205 int rc; 206 207 if (!ctx) 208 return 0; /* Can't run the callback. */ 209 210 if (length > 300) 211 length = 300; /* Limit so that it definitely fits into an Assuan 212 line. */ 213 214 command = secmem_malloc (strlen (prefix) + 3*length + 1); 215 if (!command) 216 return 0; 217 strcpy (command, prefix); 218 copy_and_escape (command + strlen(command), passphrase, length); 219 rc = assuan_write_line (ctx, command); 220 secmem_free (command); 221 if (rc) 222 { 223 fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); 224 return 0; 225 } 226 227 for (;;) 228 { 229 do 230 { 231 rc = assuan_read_line (ctx, &line, &linelen); 232 if (rc) 233 { 234 fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); 235 return 0; 236 } 237 } 238 while (*line == '#' || !linelen); 239 if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' 240 && (!line[3] || line[3] == ' ')) 241 break; /* END command received*/ 242 if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' 243 && (!line[3] || line[3] == ' ')) 244 break; /* CAN command received*/ 245 if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' 246 && (!line[3] || line[3] == ' ')) 247 break; /* ERR command received*/ 248 if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) 249 continue; 250 gotvalue = 1; 251 value = atoi (line+2); 252 } 253 if (value < -100) 254 value = -100; 255 else if (value > 100) 256 value = 100; 257 258 return value; 259 } 260 261 262 263 /* Try to make room for at least LEN bytes in the pinentry. Returns 264 new buffer on success and 0 on failure or when the old buffer is 265 sufficient. */ 266 char * 267 pinentry_setbufferlen (pinentry_t pin, int len) 268 { 269 char *newp; 270 271 if (pin->pin_len) 272 assert (pin->pin); 273 else 274 assert (!pin->pin); 275 276 if (len < 2048) 277 len = 2048; 278 279 if (len <= pin->pin_len) 280 return pin->pin; 281 282 newp = secmem_realloc (pin->pin, len); 283 if (newp) 284 { 285 pin->pin = newp; 286 pin->pin_len = len; 287 } 288 else 289 { 290 secmem_free (pin->pin); 291 pin->pin = 0; 292 pin->pin_len = 0; 293 } 294 return newp; 295 } 296 297 static void 298 pinentry_setbuffer_clear (pinentry_t pin) 299 { 300 if (! pin->pin) 301 { 302 assert (pin->pin_len == 0); 303 return; 304 } 305 306 assert (pin->pin_len > 0); 307 308 secmem_free (pin->pin); 309 pin->pin = NULL; 310 pin->pin_len = 0; 311 } 312 313 static void 314 pinentry_setbuffer_init (pinentry_t pin) 315 { 316 pinentry_setbuffer_clear (pin); 317 pinentry_setbufferlen (pin, 0); 318 } 319 320 /* passphrase better be alloced with secmem_alloc. */ 321 void 322 pinentry_setbuffer_use (pinentry_t pin, char *passphrase, int len) 323 { 324 if (! passphrase) 325 { 326 assert (len == 0); 327 pinentry_setbuffer_clear (pin); 328 329 return; 330 } 331 332 if (passphrase && len == 0) 333 len = strlen (passphrase) + 1; 334 335 if (pin->pin) 336 secmem_free (pin->pin); 337 338 pin->pin = passphrase; 339 pin->pin_len = len; 340 } 341 342 static struct assuan_malloc_hooks assuan_malloc_hooks = { 343 secmem_malloc, secmem_realloc, secmem_free 344 }; 345 346 /* Initialize the secure memory subsystem, drop privileges and return. 347 Must be called early. */ 348 void 349 pinentry_init (const char *pgmname) 350 { 351 /* Store away our name. */ 352 if (strlen (pgmname) > sizeof this_pgmname - 2) 353 abort (); 354 strcpy (this_pgmname, pgmname); 355 356 gpgrt_check_version (NULL); 357 358 /* Initialize secure memory. 1 is too small, so the default size 359 will be used. */ 360 secmem_init (1); 361 secmem_set_flags (SECMEM_WARN); 362 drop_privs (); 363 364 if (atexit (secmem_term)) 365 { 366 /* FIXME: Could not register at-exit function, bail out. */ 367 } 368 369 assuan_set_malloc_hooks (&assuan_malloc_hooks); 370 } 371 372 /* Simple test to check whether DISPLAY is set or the option --display 373 was given. Used to decide whether the GUI or curses should be 374 initialized. */ 375 int 376 pinentry_have_display (int argc, char **argv) 377 { 378 for (; argc; argc--, argv++) 379 if (!strcmp (*argv, "--display") || !strncmp (*argv, "--display=", 10)) 380 return 1; 381 return 0; 382 } 383 384 385 386 /* Print usage information and and provide strings for help. */ 387 static const char * 388 my_strusage( int level ) 389 { 390 const char *p; 391 392 switch (level) 393 { 394 case 11: p = this_pgmname; break; 395 case 12: p = "pinentry"; break; 396 case 13: p = PACKAGE_VERSION; break; 397 case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break; 398 case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break; 399 case 1: 400 case 40: 401 { 402 static char *str; 403 404 if (!str) 405 { 406 size_t n = 50 + strlen (this_pgmname); 407 str = malloc (n); 408 if (str) 409 snprintf (str, n, "Usage: %s [options] (-h for help)", 410 this_pgmname); 411 } 412 p = str; 413 } 414 break; 415 case 41: 416 p = "Ask securely for a secret and print it to stdout."; 417 break; 418 419 case 42: 420 p = "1"; /* Flag print 40 as part of 41. */ 421 break; 422 423 default: p = NULL; break; 424 } 425 return p; 426 } 427 428 429 char * 430 parse_color (char *arg, pinentry_color_t *color_p, int *bright_p) 431 { 432 static struct 433 { 434 const char *name; 435 pinentry_color_t color; 436 } colors[] = { { "none", PINENTRY_COLOR_NONE }, 437 { "default", PINENTRY_COLOR_DEFAULT }, 438 { "black", PINENTRY_COLOR_BLACK }, 439 { "red", PINENTRY_COLOR_RED }, 440 { "green", PINENTRY_COLOR_GREEN }, 441 { "yellow", PINENTRY_COLOR_YELLOW }, 442 { "blue", PINENTRY_COLOR_BLUE }, 443 { "magenta", PINENTRY_COLOR_MAGENTA }, 444 { "cyan", PINENTRY_COLOR_CYAN }, 445 { "white", PINENTRY_COLOR_WHITE } }; 446 447 int i; 448 char *new_arg; 449 pinentry_color_t color = PINENTRY_COLOR_DEFAULT; 450 451 if (!arg) 452 return NULL; 453 454 new_arg = strchr (arg, ','); 455 if (new_arg) 456 new_arg++; 457 458 if (bright_p) 459 { 460 const char *bname[] = { "bright-", "bright", "bold-", "bold" }; 461 462 *bright_p = 0; 463 for (i = 0; i < sizeof (bname) / sizeof (bname[0]); i++) 464 if (!strncasecmp (arg, bname[i], strlen (bname[i]))) 465 { 466 *bright_p = 1; 467 arg += strlen (bname[i]); 468 } 469 } 470 471 for (i = 0; i < sizeof (colors) / sizeof (colors[0]); i++) 472 if (!strncasecmp (arg, colors[i].name, strlen (colors[i].name))) 473 color = colors[i].color; 474 475 *color_p = color; 476 return new_arg; 477 } 478 479 /* Parse the command line options. May exit the program if only help 480 or version output is requested. */ 481 void 482 pinentry_parse_opts (int argc, char *argv[]) 483 { 484 static ARGPARSE_OPTS opts[] = { 485 ARGPARSE_s_n('d', "debug", "Turn on debugging output"), 486 ARGPARSE_s_s('D', "display", "|DISPLAY|Set the X display"), 487 ARGPARSE_s_s('T', "ttyname", "|FILE|Set the tty terminal node name"), 488 ARGPARSE_s_s('N', "ttytype", "|NAME|Set the tty terminal type"), 489 ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"), 490 ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"), 491 ARGPARSE_s_i('o', "timeout", 492 "|SECS|Timeout waiting for input after this many seconds"), 493 ARGPARSE_s_n('g', "no-global-grab", 494 "Grab keyboard only while window is focused"), 495 ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"), 496 ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"), 497 ARGPARSE_end() 498 }; 499 ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; 500 501 set_strusage (my_strusage); 502 503 pinentry_reset (1); 504 505 while (arg_parse (&pargs, opts)) 506 { 507 switch (pargs.r_opt) 508 { 509 case 'd': 510 pinentry.debug = 1; 511 break; 512 case 'g': 513 pinentry.grab = 0; 514 break; 515 516 case 'D': 517 /* Note, this is currently not used because the GUI engine 518 has already been initialized when parsing these options. */ 519 pinentry.display = strdup (pargs.r.ret_str); 520 if (!pinentry.display) 521 { 522 exit (EXIT_FAILURE); 523 } 524 break; 525 case 'T': 526 pinentry.ttyname = strdup (pargs.r.ret_str); 527 if (!pinentry.ttyname) 528 { 529 exit (EXIT_FAILURE); 530 } 531 break; 532 case 'N': 533 pinentry.ttytype = strdup (pargs.r.ret_str); 534 if (!pinentry.ttytype) 535 { 536 exit (EXIT_FAILURE); 537 } 538 break; 539 case 'C': 540 pinentry.lc_ctype = strdup (pargs.r.ret_str); 541 if (!pinentry.lc_ctype) 542 { 543 exit (EXIT_FAILURE); 544 } 545 break; 546 case 'M': 547 pinentry.lc_messages = strdup (pargs.r.ret_str); 548 if (!pinentry.lc_messages) 549 { 550 exit (EXIT_FAILURE); 551 } 552 break; 553 case 'W': 554 pinentry.parent_wid = pargs.r.ret_ulong; 555 break; 556 557 case 'c': 558 { 559 char *tmpstr = pargs.r.ret_str; 560 561 tmpstr = parse_color (tmpstr, &pinentry.color_fg, 562 &pinentry.color_fg_bright); 563 tmpstr = parse_color (tmpstr, &pinentry.color_bg, NULL); 564 tmpstr = parse_color (tmpstr, &pinentry.color_so, 565 &pinentry.color_so_bright); 566 } 567 break; 568 569 case 'o': 570 pinentry.timeout = pargs.r.ret_int; 571 break; 572 573 default: 574 pargs.err = ARGPARSE_PRINT_WARNING; 575 break; 576 } 577 } 578 } 579 580 581 static gpg_error_t 582 option_handler (assuan_context_t ctx, const char *key, const char *value) 583 { 584 (void)ctx; 585 586 if (!strcmp (key, "no-grab") && !*value) 587 pinentry.grab = 0; 588 else if (!strcmp (key, "grab") && !*value) 589 pinentry.grab = 1; 590 else if (!strcmp (key, "debug-wait")) 591 { 592 } 593 else if (!strcmp (key, "display")) 594 { 595 if (pinentry.display) 596 free (pinentry.display); 597 pinentry.display = strdup (value); 598 if (!pinentry.display) 599 return gpg_error_from_syserror (); 600 } 601 else if (!strcmp (key, "ttyname")) 602 { 603 if (pinentry.ttyname) 604 free (pinentry.ttyname); 605 pinentry.ttyname = strdup (value); 606 if (!pinentry.ttyname) 607 return gpg_error_from_syserror (); 608 } 609 else if (!strcmp (key, "ttytype")) 610 { 611 if (pinentry.ttytype) 612 free (pinentry.ttytype); 613 pinentry.ttytype = strdup (value); 614 if (!pinentry.ttytype) 615 return gpg_error_from_syserror (); 616 } 617 else if (!strcmp (key, "lc-ctype")) 618 { 619 if (pinentry.lc_ctype) 620 free (pinentry.lc_ctype); 621 pinentry.lc_ctype = strdup (value); 622 if (!pinentry.lc_ctype) 623 return gpg_error_from_syserror (); 624 } 625 else if (!strcmp (key, "lc-messages")) 626 { 627 if (pinentry.lc_messages) 628 free (pinentry.lc_messages); 629 pinentry.lc_messages = strdup (value); 630 if (!pinentry.lc_messages) 631 return gpg_error_from_syserror (); 632 } 633 else if (!strcmp (key, "parent-wid")) 634 { 635 pinentry.parent_wid = atoi (value); 636 /* FIXME: Use strtol and add some error handling. */ 637 } 638 else if (!strcmp (key, "touch-file")) 639 { 640 if (pinentry.touch_file) 641 free (pinentry.touch_file); 642 pinentry.touch_file = strdup (value); 643 if (!pinentry.touch_file) 644 return gpg_error_from_syserror (); 645 } 646 else if (!strcmp (key, "default-ok")) 647 { 648 pinentry.default_ok = strdup (value); 649 if (!pinentry.default_ok) 650 return gpg_error_from_syserror (); 651 } 652 else if (!strcmp (key, "default-cancel")) 653 { 654 pinentry.default_cancel = strdup (value); 655 if (!pinentry.default_cancel) 656 return gpg_error_from_syserror (); 657 } 658 else if (!strcmp (key, "default-prompt")) 659 { 660 pinentry.default_prompt = strdup (value); 661 if (!pinentry.default_prompt) 662 return gpg_error_from_syserror (); 663 } 664 else if (!strcmp (key, "default-pwmngr")) 665 { 666 pinentry.default_pwmngr = strdup (value); 667 if (!pinentry.default_pwmngr) 668 return gpg_error_from_syserror (); 669 } 670 else if (!strcmp (key, "allow-external-password-cache") && !*value) 671 { 672 pinentry.allow_external_password_cache = 1; 673 pinentry.tried_password_cache = 0; 674 } 675 else if (!strcmp (key, "allow-emacs-prompt") && !*value) 676 { 677 return gpg_error (GPG_ERR_NOT_SUPPORTED); 678 } 679 else 680 return gpg_error (GPG_ERR_UNKNOWN_OPTION); 681 return 0; 682 } 683 684 685 /* Note, that it is sufficient to allocate the target string D as 686 long as the source string S, i.e.: strlen(s)+1; */ 687 static void 688 strcpy_escaped (char *d, const char *s) 689 { 690 while (*s) 691 { 692 if (*s == '%' && s[1] && s[2]) 693 { 694 s++; 695 *d++ = xtoi_2 ( s); 696 s += 2; 697 } 698 else 699 *d++ = *s++; 700 } 701 *d = 0; 702 } 703 704 705 static gpg_error_t 706 cmd_setdesc (assuan_context_t ctx, char *line) 707 { 708 char *newd; 709 710 (void)ctx; 711 712 newd = malloc (strlen (line) + 1); 713 if (!newd) 714 return gpg_error_from_syserror (); 715 716 strcpy_escaped (newd, line); 717 if (pinentry.description) 718 free (pinentry.description); 719 pinentry.description = newd; 720 return 0; 721 } 722 723 724 static gpg_error_t 725 cmd_setprompt (assuan_context_t ctx, char *line) 726 { 727 char *newp; 728 729 (void)ctx; 730 731 newp = malloc (strlen (line) + 1); 732 if (!newp) 733 return gpg_error_from_syserror (); 734 735 strcpy_escaped (newp, line); 736 if (pinentry.prompt) 737 free (pinentry.prompt); 738 pinentry.prompt = newp; 739 return 0; 740 } 741 742 743 /* The data provided at LINE may be used by pinentry implementations 744 to identify a key for caching strategies of its own. The empty 745 string and --clear mean that the key does not have a stable 746 identifier. */ 747 static gpg_error_t 748 cmd_setkeyinfo (assuan_context_t ctx, char *line) 749 { 750 (void)ctx; 751 752 if (pinentry.keyinfo) 753 free (pinentry.keyinfo); 754 755 if (*line && strcmp(line, "--clear") != 0) 756 pinentry.keyinfo = strdup (line); 757 else 758 pinentry.keyinfo = NULL; 759 760 return 0; 761 } 762 763 764 static gpg_error_t 765 cmd_setrepeat (assuan_context_t ctx, char *line) 766 { 767 char *p; 768 769 (void)ctx; 770 771 p = malloc (strlen (line) + 1); 772 if (!p) 773 return gpg_error_from_syserror (); 774 775 strcpy_escaped (p, line); 776 free (pinentry.repeat_passphrase); 777 pinentry.repeat_passphrase = p; 778 return 0; 779 } 780 781 782 static gpg_error_t 783 cmd_setrepeaterror (assuan_context_t ctx, char *line) 784 { 785 char *p; 786 787 (void)ctx; 788 789 p = malloc (strlen (line) + 1); 790 if (!p) 791 return gpg_error_from_syserror (); 792 793 strcpy_escaped (p, line); 794 free (pinentry.repeat_error_string); 795 pinentry.repeat_error_string = p; 796 return 0; 797 } 798 799 800 static gpg_error_t 801 cmd_seterror (assuan_context_t ctx, char *line) 802 { 803 char *newe; 804 805 (void)ctx; 806 807 newe = malloc (strlen (line) + 1); 808 if (!newe) 809 return gpg_error_from_syserror (); 810 811 strcpy_escaped (newe, line); 812 if (pinentry.error) 813 free (pinentry.error); 814 pinentry.error = newe; 815 return 0; 816 } 817 818 819 static gpg_error_t 820 cmd_setok (assuan_context_t ctx, char *line) 821 { 822 char *newo; 823 824 (void)ctx; 825 826 newo = malloc (strlen (line) + 1); 827 if (!newo) 828 return gpg_error_from_syserror (); 829 830 strcpy_escaped (newo, line); 831 if (pinentry.ok) 832 free (pinentry.ok); 833 pinentry.ok = newo; 834 return 0; 835 } 836 837 838 static gpg_error_t 839 cmd_setnotok (assuan_context_t ctx, char *line) 840 { 841 char *newo; 842 843 (void)ctx; 844 845 newo = malloc (strlen (line) + 1); 846 if (!newo) 847 return gpg_error_from_syserror (); 848 849 strcpy_escaped (newo, line); 850 if (pinentry.notok) 851 free (pinentry.notok); 852 pinentry.notok = newo; 853 return 0; 854 } 855 856 857 static gpg_error_t 858 cmd_setcancel (assuan_context_t ctx, char *line) 859 { 860 char *newc; 861 862 (void)ctx; 863 864 newc = malloc (strlen (line) + 1); 865 if (!newc) 866 return gpg_error_from_syserror (); 867 868 strcpy_escaped (newc, line); 869 if (pinentry.cancel) 870 free (pinentry.cancel); 871 pinentry.cancel = newc; 872 return 0; 873 } 874 875 876 static gpg_error_t 877 cmd_settimeout (assuan_context_t ctx, char *line) 878 { 879 (void)ctx; 880 881 if (line && *line) 882 pinentry.timeout = atoi (line); 883 884 return 0; 885 } 886 887 static gpg_error_t 888 cmd_settitle (assuan_context_t ctx, char *line) 889 { 890 char *newt; 891 892 (void)ctx; 893 894 newt = malloc (strlen (line) + 1); 895 if (!newt) 896 return gpg_error_from_syserror (); 897 898 strcpy_escaped (newt, line); 899 if (pinentry.title) 900 free (pinentry.title); 901 pinentry.title = newt; 902 return 0; 903 } 904 905 static gpg_error_t 906 cmd_setqualitybar (assuan_context_t ctx, char *line) 907 { 908 char *newval; 909 910 (void)ctx; 911 912 if (!*line) 913 line = "Quality:"; 914 915 newval = malloc (strlen (line) + 1); 916 if (!newval) 917 return gpg_error_from_syserror (); 918 919 strcpy_escaped (newval, line); 920 if (pinentry.quality_bar) 921 free (pinentry.quality_bar); 922 pinentry.quality_bar = newval; 923 return 0; 924 } 925 926 /* Set the tooltip to be used for a quality bar. */ 927 static gpg_error_t 928 cmd_setqualitybar_tt (assuan_context_t ctx, char *line) 929 { 930 char *newval; 931 932 (void)ctx; 933 934 if (*line) 935 { 936 newval = malloc (strlen (line) + 1); 937 if (!newval) 938 return gpg_error_from_syserror (); 939 940 strcpy_escaped (newval, line); 941 } 942 else 943 newval = NULL; 944 if (pinentry.quality_bar_tt) 945 free (pinentry.quality_bar_tt); 946 pinentry.quality_bar_tt = newval; 947 return 0; 948 } 949 950 951 static gpg_error_t 952 cmd_getpin (assuan_context_t ctx, char *line) 953 { 954 int result; 955 int set_prompt = 0; 956 int just_read_password_from_cache = 0; 957 958 (void)line; 959 960 pinentry_setbuffer_init (&pinentry); 961 if (!pinentry.pin) 962 return gpg_error (GPG_ERR_ENOMEM); 963 964 /* Try reading from the password cache. */ 965 if (/* If repeat passphrase is set, then we don't want to read from 966 the cache. */ 967 ! pinentry.repeat_passphrase 968 /* Are we allowed to read from the cache? */ 969 && pinentry.allow_external_password_cache 970 && pinentry.keyinfo 971 /* Only read from the cache if we haven't already tried it. */ 972 && ! pinentry.tried_password_cache 973 /* If the last read resulted in an error, then don't read from 974 the cache. */ 975 && ! pinentry.error) 976 { 977 char *password; 978 979 pinentry.tried_password_cache = 1; 980 981 password = password_cache_lookup (pinentry.keyinfo); 982 if (password) 983 /* There is a cached password. Try it. */ 984 { 985 int len = strlen(password) + 1; 986 if (len > pinentry.pin_len) 987 len = pinentry.pin_len; 988 989 memcpy (pinentry.pin, password, len); 990 pinentry.pin[len] = '\0'; 991 992 secmem_free (password); 993 994 pinentry.pin_from_cache = 1; 995 996 assuan_write_status (ctx, "PASSWORD_FROM_CACHE", ""); 997 998 /* Result is the length of the password not including the 999 NUL terminator. */ 1000 result = len - 1; 1001 1002 just_read_password_from_cache = 1; 1003 1004 goto out; 1005 } 1006 } 1007 1008 /* The password was not cached (or we are not allowed to / cannot 1009 use the cache). Prompt the user. */ 1010 pinentry.pin_from_cache = 0; 1011 1012 if (!pinentry.prompt) 1013 { 1014 pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:"; 1015 set_prompt = 1; 1016 } 1017 pinentry.locale_err = 0; 1018 pinentry.specific_err = 0; 1019 pinentry.close_button = 0; 1020 pinentry.repeat_okay = 0; 1021 pinentry.one_button = 0; 1022 pinentry.ctx_assuan = ctx; 1023 result = (*pinentry_cmd_handler) (&pinentry); 1024 pinentry.ctx_assuan = NULL; 1025 if (pinentry.error) 1026 { 1027 free (pinentry.error); 1028 pinentry.error = NULL; 1029 } 1030 if (pinentry.repeat_passphrase) 1031 { 1032 free (pinentry.repeat_passphrase); 1033 pinentry.repeat_passphrase = NULL; 1034 } 1035 if (set_prompt) 1036 pinentry.prompt = NULL; 1037 1038 pinentry.quality_bar = 0; /* Reset it after the command. */ 1039 1040 if (pinentry.close_button) 1041 assuan_write_status (ctx, "BUTTON_INFO", "close"); 1042 1043 if (result < 0) 1044 { 1045 pinentry_setbuffer_clear (&pinentry); 1046 if (pinentry.specific_err) 1047 return pinentry.specific_err; 1048 return (pinentry.locale_err 1049 ? gpg_error (GPG_ERR_LOCALE_PROBLEM) 1050 : gpg_error (GPG_ERR_CANCELED)); 1051 } 1052 1053 out: 1054 if (result) 1055 { 1056 if (pinentry.repeat_okay) 1057 assuan_write_status (ctx, "PIN_REPEATED", ""); 1058 result = assuan_send_data (ctx, pinentry.pin, strlen(pinentry.pin)); 1059 if (!result) 1060 result = assuan_send_data (ctx, NULL, 0); 1061 1062 if (/* GPG Agent says it's okay. */ 1063 pinentry.allow_external_password_cache && pinentry.keyinfo 1064 /* We didn't just read it from the cache. */ 1065 && ! just_read_password_from_cache 1066 /* And the user said it's okay. */ 1067 && pinentry.may_cache_password) 1068 /* Cache the password. */ 1069 password_cache_save (pinentry.keyinfo, pinentry.pin); 1070 } 1071 1072 pinentry_setbuffer_clear (&pinentry); 1073 1074 return result; 1075 } 1076 1077 1078 /* Note that the option --one-button is a hack to allow the use of old 1079 pinentries while the caller is ignoring the result. Given that 1080 options have never been used or flagged as an error the new option 1081 is an easy way to enable the messsage mode while not requiring to 1082 update pinentry or to have the caller test for the message 1083 command. New applications which are free to require an updated 1084 pinentry should use MESSAGE instead. */ 1085 static gpg_error_t 1086 cmd_confirm (assuan_context_t ctx, char *line) 1087 { 1088 int result; 1089 1090 pinentry.one_button = !!strstr (line, "--one-button"); 1091 pinentry.quality_bar = 0; 1092 pinentry.close_button = 0; 1093 pinentry.locale_err = 0; 1094 pinentry.specific_err = 0; 1095 pinentry.canceled = 0; 1096 pinentry_setbuffer_clear (&pinentry); 1097 result = (*pinentry_cmd_handler) (&pinentry); 1098 if (pinentry.error) 1099 { 1100 free (pinentry.error); 1101 pinentry.error = NULL; 1102 } 1103 1104 if (pinentry.close_button) 1105 assuan_write_status (ctx, "BUTTON_INFO", "close"); 1106 1107 if (result) 1108 return 0; 1109 1110 if (pinentry.specific_err) 1111 return pinentry.specific_err; 1112 1113 if (pinentry.locale_err) 1114 return gpg_error (GPG_ERR_LOCALE_PROBLEM); 1115 1116 if (pinentry.one_button) 1117 return 0; 1118 1119 if (pinentry.canceled) 1120 return gpg_error (GPG_ERR_CANCELED); 1121 return gpg_error (GPG_ERR_NOT_CONFIRMED); 1122 } 1123 1124 1125 static gpg_error_t 1126 cmd_message (assuan_context_t ctx, char *line) 1127 { 1128 (void)line; 1129 1130 return cmd_confirm (ctx, "--one-button"); 1131 } 1132 1133 /* GETINFO <what> 1134 1135 Multipurpose function to return a variety of information. 1136 Supported values for WHAT are: 1137 1138 version - Return the version of the program. 1139 pid - Return the process id of the server. 1140 */ 1141 static gpg_error_t 1142 cmd_getinfo (assuan_context_t ctx, char *line) 1143 { 1144 int rc; 1145 1146 if (!strcmp (line, "version")) 1147 { 1148 const char *s = VERSION; 1149 rc = assuan_send_data (ctx, s, strlen (s)); 1150 } 1151 else if (!strcmp (line, "pid")) 1152 { 1153 char numbuf[50]; 1154 1155 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ()); 1156 rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); 1157 } 1158 else 1159 rc = gpg_error (GPG_ERR_ASS_PARAMETER); 1160 return rc; 1161 } 1162 1163 /* CLEARPASSPHRASE <cacheid> 1164 1165 Clear the cache passphrase associated with the key identified by 1166 cacheid. 1167 */ 1168 static gpg_error_t 1169 cmd_clear_passphrase (assuan_context_t ctx, char *line) 1170 { 1171 (void)ctx; 1172 1173 if (! line) 1174 return gpg_error (GPG_ERR_ASS_INV_VALUE); 1175 1176 /* Remove leading and trailing white space. */ 1177 while (*line == ' ') 1178 line ++; 1179 while (line[strlen (line) - 1] == ' ') 1180 line[strlen (line) - 1] = 0; 1181 1182 switch (password_cache_clear (line)) 1183 { 1184 case 1: return 0; 1185 case 0: return gpg_error (GPG_ERR_ASS_INV_VALUE); 1186 default: return gpg_error (GPG_ERR_ASS_GENERAL); 1187 } 1188 } 1189 1190 /* Tell the assuan library about our commands. */ 1191 static gpg_error_t 1192 register_commands (assuan_context_t ctx) 1193 { 1194 static struct 1195 { 1196 const char *name; 1197 gpg_error_t (*handler) (assuan_context_t, char *line); 1198 } table[] = 1199 { 1200 { "SETDESC", cmd_setdesc }, 1201 { "SETPROMPT", cmd_setprompt }, 1202 { "SETKEYINFO", cmd_setkeyinfo }, 1203 { "SETREPEAT", cmd_setrepeat }, 1204 { "SETREPEATERROR", cmd_setrepeaterror }, 1205 { "SETERROR", cmd_seterror }, 1206 { "SETOK", cmd_setok }, 1207 { "SETNOTOK", cmd_setnotok }, 1208 { "SETCANCEL", cmd_setcancel }, 1209 { "GETPIN", cmd_getpin }, 1210 { "CONFIRM", cmd_confirm }, 1211 { "MESSAGE", cmd_message }, 1212 { "SETQUALITYBAR", cmd_setqualitybar }, 1213 { "SETQUALITYBAR_TT", cmd_setqualitybar_tt }, 1214 { "GETINFO", cmd_getinfo }, 1215 { "SETTITLE", cmd_settitle }, 1216 { "SETTIMEOUT", cmd_settimeout }, 1217 { "CLEARPASSPHRASE", cmd_clear_passphrase }, 1218 { NULL } 1219 }; 1220 int i, j; 1221 gpg_error_t rc; 1222 1223 for (i = j = 0; table[i].name; i++) 1224 { 1225 rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL); 1226 if (rc) 1227 return rc; 1228 } 1229 return 0; 1230 } 1231 1232 1233 int 1234 pinentry_loop2 (int infd, int outfd) 1235 { 1236 gpg_error_t rc; 1237 assuan_fd_t filedes[2]; 1238 assuan_context_t ctx; 1239 1240 /* Extra check to make sure we have dropped privs. */ 1241 if (getuid() != geteuid()) 1242 abort (); 1243 1244 rc = assuan_new (&ctx); 1245 if (rc) 1246 { 1247 fprintf (stderr, "server context creation failed: %s\n", 1248 gpg_strerror (rc)); 1249 return -1; 1250 } 1251 1252 /* For now we use a simple pipe based server so that we can work 1253 from scripts. We will later add options to run as a daemon and 1254 wait for requests on a Unix domain socket. */ 1255 filedes[0] = assuan_fdopen (infd); 1256 filedes[1] = assuan_fdopen (outfd); 1257 rc = assuan_init_pipe_server (ctx, filedes); 1258 if (rc) 1259 { 1260 fprintf (stderr, "%s: failed to initialize the server: %s\n", 1261 this_pgmname, gpg_strerror (rc)); 1262 return -1; 1263 } 1264 rc = register_commands (ctx); 1265 if (rc) 1266 { 1267 fprintf (stderr, "%s: failed to the register commands with Assuan: %s\n", 1268 this_pgmname, gpg_strerror (rc)); 1269 return -1; 1270 } 1271 1272 assuan_register_option_handler (ctx, option_handler); 1273 assuan_register_reset_notify (ctx, pinentry_assuan_reset_handler); 1274 1275 for (;;) 1276 { 1277 rc = assuan_accept (ctx); 1278 if (rc == -1) 1279 break; 1280 else if (rc) 1281 { 1282 fprintf (stderr, "%s: Assuan accept problem: %s\n", 1283 this_pgmname, gpg_strerror (rc)); 1284 break; 1285 } 1286 1287 rc = assuan_process (ctx); 1288 if (rc) 1289 { 1290 fprintf (stderr, "%s: Assuan processing failed: %s\n", 1291 this_pgmname, gpg_strerror (rc)); 1292 continue; 1293 } 1294 } 1295 1296 assuan_release (ctx); 1297 return 0; 1298 } 1299 1300 1301 /* Start the pinentry event loop. The program will start to process 1302 Assuan commands until it is finished or an error occurs. If an 1303 error occurs, -1 is returned. Otherwise, 0 is returned. */ 1304 int 1305 pinentry_loop (void) 1306 { 1307 return pinentry_loop2 (STDIN_FILENO, STDOUT_FILENO); 1308 }