/* The okay button has been clicked or the enter enter key in the text field. */ static void ok_button_clicked (HWND dlg, pinentry_t pe) { char *s_utf8; wchar_t *w_buffer; size_t w_buffer_size = 255; unsigned int nchar; pe->locale_err = 1; w_buffer = secmem_malloc ((w_buffer_size + 1) * sizeof *w_buffer); if (!w_buffer) return; nchar = GetDlgItemTextW (dlg, IDC_PINENT_TEXT, w_buffer, w_buffer_size); s_utf8 = wchar_to_utf8 (w_buffer, nchar, 1); secmem_free (w_buffer); if (s_utf8) { passphrase_ok = 1; pinentry_setbufferlen (pe, strlen (s_utf8) + 1); if (pe->pin) strcpy (pe->pin, s_utf8); secmem_free (s_utf8); pe->locale_err = 0; pe->result = pe->pin? strlen (pe->pin) : 0; } }
static int cmd_getpin (ASSUAN_CONTEXT ctx, char *line) { int result; int set_prompt = 0; pinentry.pin = secmem_malloc (pinentry.pin_len); if (!pinentry.pin) return ASSUAN_Out_Of_Core; if (!pinentry.prompt) { pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:"; set_prompt = 1; } pinentry.locale_err = 0; pinentry.close_button = 0; pinentry.one_button = 0; pinentry.ctx_assuan = ctx; result = (*pinentry_cmd_handler) (&pinentry); pinentry.ctx_assuan = NULL; if (pinentry.error) { free (pinentry.error); pinentry.error = NULL; } if (set_prompt) pinentry.prompt = NULL; pinentry.quality_bar = 0; /* Reset it after the command. */ if (pinentry.close_button) assuan_write_status (ctx, "BUTTON_INFO", "close"); if (result < 0) { if (pinentry.pin) { secmem_free (pinentry.pin); pinentry.pin = NULL; } return pinentry.locale_err? ASSUAN_Locale_Problem: ASSUAN_Canceled; } if (result) { result = assuan_send_data (ctx, pinentry.pin, result); if (!result) result = assuan_send_data (ctx, NULL, 0); } if (pinentry.pin) { secmem_free (pinentry.pin); pinentry.pin = NULL; } return result; }
/* Convert a wchar to UTF8. Caller needs to release the string. Returns NULL on error. */ static char * wchar_to_utf8 (const wchar_t *string, size_t len, int secure) { int n; char *result; /* Note, that CP_UTF8 is not defined in Windows versions earlier than NT. */ n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL); if (n < 0) return NULL; result = secure? secmem_malloc (n+1) : malloc (n+1); if (!result) return NULL; n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL); if (n < 0) { if (secure) secmem_free (result); else free (result); return NULL; } return result; }
static void button_clicked (GtkWidget *widget, gpointer data) { if (data) { /* Okay button hit or Enter used in the text field. */ const char *s; char *s_utf8; char *s_buffer; if (pinentry->enhanced) { printf("Options: %s\nTimeout: %d\n\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(insure)) ? "insure" : "", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(time_out))); } pinentry->locale_err = 1; s = gtk_secure_entry_get_text (GTK_SECURE_ENTRY(entry)); if (!s) s = ""; s_buffer = secmem_malloc (strlen (s) + 1); if (s_buffer) { strcpy (s_buffer, s); s_utf8 = pinentry_local_to_utf8 (pinentry->lc_ctype, s_buffer, 1); secmem_free (s_buffer); if (s_utf8) { passphrase_ok = 1; pinentry_setbufferlen (pinentry, strlen (s_utf8) + 1); if (pinentry->pin) strcpy (pinentry->pin, s_utf8); secmem_free (s_utf8); pinentry->locale_err = 0; } } } gtk_main_quit (); }
/* Try to make room for at least LEN bytes in the pinentry. Returns new buffer on success and 0 on failure or when the old buffer is sufficient. */ char * pinentry_setbufferlen (pinentry_t pin, int len) { char *newp; if (len < pinentry.pin_len) return NULL; newp = secmem_realloc (pin->pin, 2 * pin->pin_len); if (newp) { pin->pin = newp; pin->pin_len *= 2; } else { secmem_free (pin->pin); pin->pin = 0; pin->pin_len = 0; } return newp; }
void * secmexrealloc( void *p, size_t newsize ) { MEMBLOCK *mb; size_t size; void *a; mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); size = mb->size; if (size < sizeof(MEMBLOCK)) log_bug ("secure memory corrupted at block %p\n", (void *)mb); size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c); if( newsize <= size ) return p; /* It is easier not to shrink the memory. */ a = secmem_malloc( newsize ); if ( a ) { memcpy(a, p, size); memset((char*)a+size, 0, newsize-size); secmem_free(p); } return a; }
static int dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type) { struct dialog diag; FILE *ttyfi = NULL; FILE *ttyfo = NULL; SCREEN *screen = 0; int done = 0; char *pin_utf8; int alt = 0; #ifndef HAVE_DOSISH_SYSTEM int no_input = 1; #endif #ifdef HAVE_NCURSESW char *old_ctype = NULL; if (pinentry->lc_ctype) { old_ctype = strdup (setlocale (LC_CTYPE, NULL)); setlocale (LC_CTYPE, pinentry->lc_ctype); } else setlocale (LC_CTYPE, ""); #endif /* Open the desired terminal if necessary. */ if (tty_name) { ttyfi = fopen (tty_name, "r"); if (!ttyfi) { pinentry->specific_err = ASSUAN_ENOENT; return -1; } ttyfo = fopen (tty_name, "w"); if (!ttyfo) { int err = errno; fclose (ttyfi); errno = err; pinentry->specific_err = ASSUAN_ENOENT; return -1; } screen = newterm (tty_type, ttyfo, ttyfi); set_term (screen); } else { if (!init_screen) { if (!(isatty(fileno(stdin)) && isatty(fileno(stdout)))) { errno = ENOTTY; pinentry->specific_err = ASSUAN_ENOTTY; return -1; } init_screen = 1; initscr (); } else clear (); } keypad (stdscr, TRUE); /* Enable keyboard mapping. */ nonl (); /* Tell curses not to do NL->CR/NL on output. */ cbreak (); /* Take input chars one at a time, no wait for \n. */ noecho (); /* Don't echo input - in color. */ if (has_colors ()) { start_color (); #ifdef NCURSES_VERSION use_default_colors (); #endif if (pinentry->color_so == PINENTRY_COLOR_DEFAULT) { pinentry->color_so = PINENTRY_COLOR_RED; pinentry->color_so_bright = 1; } if (COLOR_PAIRS >= 2) { init_pair (1, pinentry_color[pinentry->color_fg], pinentry_color[pinentry->color_bg]); init_pair (2, pinentry_color[pinentry->color_so], pinentry_color[pinentry->color_bg]); bkgd (COLOR_PAIR (1)); attron (COLOR_PAIR (1) | (pinentry->color_fg_bright ? A_BOLD : 0)); } } refresh (); /* Create the dialog. */ if (dialog_create (pinentry, &diag)) { /* Note: pinentry->specific_err has already been set. */ endwin (); if (screen) delscreen (screen); #ifdef HAVE_NCURSESW if (old_ctype) { setlocale (LC_CTYPE, old_ctype); free (old_ctype); } #endif if (ttyfi) fclose (ttyfi); if (ttyfo) fclose (ttyfo); return -2; } dialog_switch_pos (&diag, diag.pinentry->pin ? DIALOG_POS_PIN : DIALOG_POS_OK); #ifndef HAVE_DOSISH_SYSTEM wtimeout (stdscr, 70); #endif do { int c; c = wgetch (stdscr); /* Refresh, accept single keystroke of input. */ #ifndef HAVE_DOSISH_SYSTEM if (timed_out && no_input) { done = -2; break; } #endif switch (c) { case ERR: #ifndef HAVE_DOSISH_SYSTEM continue; #else done = -2; break; #endif case 27: /* Alt was pressed. */ alt = 1; /* Get the next key press. */ continue; case KEY_LEFT: case KEY_UP: switch (diag.pos) { case DIALOG_POS_OK: if (diag.pinentry->pin) dialog_switch_pos (&diag, DIALOG_POS_PIN); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_CANCEL: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_OK); break; default: break; } break; case KEY_RIGHT: case KEY_DOWN: switch (diag.pos) { case DIALOG_POS_PIN: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_OK: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; default: break; } break; case '\t': switch (diag.pos) { case DIALOG_POS_PIN: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_OK: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_CANCEL: if (diag.pinentry->pin) dialog_switch_pos (&diag, DIALOG_POS_PIN); else dialog_switch_pos (&diag, DIALOG_POS_OK); break; default: break; } break; case '\005': done = -2; break; case '\r': switch (diag.pos) { case DIALOG_POS_PIN: case DIALOG_POS_OK: done = 1; break; case DIALOG_POS_NOTOK: done = -1; break; case DIALOG_POS_CANCEL: done = -2; break; case DIALOG_POS_NONE: break; } break; default: if (diag.pos == DIALOG_POS_PIN) dialog_input (&diag, alt, c); } #ifndef HAVE_DOSISH_SYSTEM no_input = 0; #endif if (c != -1) alt = 0; } while (!done); if (diag.pinentry->pin) /* NUL terminate the passphrase. dialog_run makes sure there is enough space for the terminating NUL byte. */ diag.pinentry->pin[diag.pin_len] = 0; set_cursor_state (1); endwin (); if (screen) delscreen (screen); #ifdef HAVE_NCURSESW if (old_ctype) { setlocale (LC_CTYPE, old_ctype); free (old_ctype); } #endif if (ttyfi) fclose (ttyfi); if (ttyfo) fclose (ttyfo); /* XXX Factor out into dialog_release or something. */ free (diag.ok); if (diag.cancel) free (diag.cancel); if (diag.notok) free (diag.notok); if (pinentry->pin) { pinentry->locale_err = 1; pin_utf8 = pinentry_local_to_utf8 (pinentry->lc_ctype, pinentry->pin, 1); if (pin_utf8) { pinentry_setbufferlen (pinentry, strlen (pin_utf8) + 1); if (pinentry->pin) strcpy (pinentry->pin, pin_utf8); secmem_free (pin_utf8); pinentry->locale_err = 0; } } if (done == -2) pinentry->canceled = 1; if (diag.pinentry->pin) return done < 0 ? -1 : diag.pin_len; else return done < 0 ? 0 : 1; }
/* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH because not all backends might be able to return a proper C-string.). Returns: A value between -100 and 100 to give an estimate of the passphrase's quality. Negative values are use if the caller won't even accept that passphrase. Note that we expect just one data line which should not be escaped in any represent a numeric signed decimal value. Extra data is currently ignored but should not be send at all. */ int pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length) { ASSUAN_CONTEXT ctx = pin->ctx_assuan; const char prefix[] = "INQUIRE QUALITY "; char *command; char *line; size_t linelen; int gotvalue = 0; int value = 0; int rc; if (!ctx) return 0; /* Can't run the callback. */ if (length > 300) length = 300; /* Limit so that it definitely fits into an Assuan line. */ command = secmem_malloc (strlen (prefix) + 3*length + 1); if (!command) return 0; strcpy (command, prefix); copy_and_escape (command + strlen(command), passphrase, length); rc = assuan_write_line (ctx, command); secmem_free (command); if (rc) { fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); return 0; } for (;;) { do { rc = assuan_read_line (ctx, &line, &linelen); if (rc) { fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); return 0; } } while (*line == '#' || !linelen); if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && (!line[3] || line[3] == ' ')) break; /* END command received*/ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' && (!line[3] || line[3] == ' ')) break; /* CAN command received*/ if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && (!line[3] || line[3] == ' ')) break; /* ERR command received*/ if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue; gotvalue = 1; value = atoi (line+2); } if (value < -100) value = -100; else if (value > 100) value = 100; return value; }
/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8. With SECURE set to true, use secure memory for the returned buffer. Return NULL on error. */ char * pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure) { char *old_ctype; char *source_encoding; iconv_t cd; const char *input = text; size_t input_len = strlen (text) + 1; char *output; size_t output_len; char *output_buf; size_t processed; /* If no locale setting could be determined, simply copy the string. */ if (!lc_ctype) { fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n", this_pgmname); output_buf = secure? secmem_malloc (input_len) : malloc (input_len); if (output_buf) strcpy (output_buf, input); return output_buf; } old_ctype = strdup (setlocale (LC_CTYPE, NULL)); if (!old_ctype) return NULL; setlocale (LC_CTYPE, lc_ctype); source_encoding = nl_langinfo (CODESET); setlocale (LC_CTYPE, old_ctype); free (old_ctype); /* This is overkill, but simplifies the iconv invocation greatly. */ output_len = input_len * MB_LEN_MAX; output_buf = output = secure? secmem_malloc (output_len):malloc (output_len); if (!output) return NULL; cd = iconv_open ("UTF-8", source_encoding); if (cd == (iconv_t) -1) { fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n", this_pgmname, source_encoding? source_encoding : "?", strerror (errno)); if (secure) secmem_free (output_buf); else free (output_buf); return NULL; } processed = iconv (cd, &input, &input_len, &output, &output_len); iconv_close (cd); if (processed == (size_t) -1 || input_len) { fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n", this_pgmname, source_encoding? source_encoding : "?", strerror (errno)); if (secure) secmem_free (output_buf); else free (output_buf); return NULL; } return output_buf; }
static int dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type) { struct dialog diag; FILE *ttyfi = NULL; FILE *ttyfo = NULL; SCREEN *screen = 0; int done = 0; char *pin_utf8; /* Open the desired terminal if necessary. */ if (tty_name) { ttyfi = fopen (tty_name, "r"); if (!ttyfi) return -1; ttyfo = fopen (tty_name, "w"); if (!ttyfo) { int err = errno; fclose (ttyfi); errno = err; return -1; } screen = newterm ((char *)tty_type, ttyfo, ttyfi); set_term (screen); } else { if (!init_screen) { init_screen = 1; initscr (); } else clear (); } keypad (stdscr, TRUE); /* Enable keyboard mapping. */ nonl (); /* Tell curses not to do NL->CR/NL on output. */ cbreak (); /* Take input chars one at a time, no wait for \n. */ noecho (); /* Don't echo input - in color. */ if (has_colors ()) { start_color (); use_default_colors (); if (pinentry->color_so == PINENTRY_COLOR_DEFAULT) { pinentry->color_so = PINENTRY_COLOR_RED; pinentry->color_so_bright = 1; } if (COLOR_PAIRS >= 2) { init_pair (1, pinentry_color[pinentry->color_fg], pinentry_color[pinentry->color_bg]); init_pair (2, pinentry_color[pinentry->color_so], pinentry_color[pinentry->color_bg]); bkgd (COLOR_PAIR (1)); attron (COLOR_PAIR (1) | (pinentry->color_fg_bright ? A_BOLD : 0)); } } refresh (); /* XXX */ if (dialog_create (pinentry, &diag)) return -2; dialog_switch_pos (&diag, diag.pin ? DIALOG_POS_PIN : DIALOG_POS_OK); do { int c; c = getch (); /* Refresh, accept single keystroke of input. */ switch (c) { case KEY_LEFT: case KEY_UP: switch (diag.pos) { case DIALOG_POS_OK: if (diag.pin) dialog_switch_pos (&diag, DIALOG_POS_PIN); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_CANCEL: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_OK); break; default: break; } break; case KEY_RIGHT: case KEY_DOWN: switch (diag.pos) { case DIALOG_POS_PIN: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_OK: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; default: break; } break; case '\t': switch (diag.pos) { case DIALOG_POS_PIN: dialog_switch_pos (&diag, DIALOG_POS_OK); break; case DIALOG_POS_OK: if (diag.notok) dialog_switch_pos (&diag, DIALOG_POS_NOTOK); else dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_NOTOK: dialog_switch_pos (&diag, DIALOG_POS_CANCEL); break; case DIALOG_POS_CANCEL: if (diag.pin) dialog_switch_pos (&diag, DIALOG_POS_PIN); else dialog_switch_pos (&diag, DIALOG_POS_OK); break; default: break; } break; case '\005': done = -2; break; case '\r': switch (diag.pos) { case DIALOG_POS_PIN: case DIALOG_POS_OK: done = 1; break; case DIALOG_POS_NOTOK: done = -1; break; case DIALOG_POS_CANCEL: done = -2; break; case DIALOG_POS_NONE: break; } break; default: if (diag.pos == DIALOG_POS_PIN) dialog_input (&diag, c); } } while (!done); set_cursor_state (1); endwin (); if (screen) delscreen (screen); if (ttyfi) fclose (ttyfi); if (ttyfo) fclose (ttyfo); /* XXX Factor out into dialog_release or something. */ free (diag.ok); if (diag.cancel) free (diag.cancel); if (diag.notok) free (diag.notok); if (pinentry->pin) { pinentry->locale_err = 1; pin_utf8 = pinentry_local_to_utf8 (pinentry->lc_ctype, pinentry->pin, 1); if (pin_utf8) { pinentry_setbufferlen (pinentry, strlen (pin_utf8) + 1); if (pinentry->pin) strcpy (pinentry->pin, pin_utf8); secmem_free (pin_utf8); pinentry->locale_err = 0; } } if (done == -2) pinentry->canceled = 1; return diag.pin ? (done < 0 ? -1 : diag.pin_len) : (done < 0 ? 0 : 1); }