/** * libpassphrase – Personalisable library for TTY passphrase reading * * Copyright © 2013, 2014, 2015 Mattias Andrée (maandree@member.fsf.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PASSPHRASE_HELPER_H #define PASSPHRASE_HELPER_H /* Fix conflicting configurations */ #if defined(PASSPHRASE_TEXT) && defined(PASSPHRASE_STAR) # warning You cannot have both PASSPHRASE_TEXT and PASSPHRASE_STAR # undef PASSPHRASE_TEXT #endif #if defined(PASSPHRASE_STAR) && defined(PASSPHRASE_ECHO) # warning You cannot have both PASSPHRASE_STAR and PASSPHRASE_ECHO # undef PASSPHRASE_ECHO #endif #if defined(PASSPHRASE_TEXT) && defined(PASSPHRASE_ECHO) # warning You cannot have both PASSPHRASE_TEXT and PASSPHRASE_ECHO # undef PASSPHRASE_ECHO #endif /* Default texts */ #ifndef PASSPHRASE_STAR_CHAR # define PASSPHRASE_STAR_CHAR "*" #endif #ifndef PASSPHRASE_TEXT_EMPTY # define PASSPHRASE_TEXT_EMPTY "(empty)" #endif #ifndef PASSPHRASE_TEXT_NOT_EMPTY # define PASSPHRASE_TEXT_NOT_EMPTY "(not empty)" #endif /* Control keys. */ /** * Home-key. * Character sequences: \e[1~ \eOH * Control-key combination: ^A */ #define KEY_HOME -1 /** * Insert-key. * Character sequences: \e[2~ */ #define KEY_INSERT -2 /** * Delete-key. * Character sequences: \e[3~ * Control-key combination: ^D */ #define KEY_DELETE -3 /** * End-key. * Character sequences: \e[4~ \eOF * Control-key combination: ^E */ #define KEY_END -4 /** * Erase-key, also known as backspace. * Character sequences: \d8 \d127 */ #define KEY_ERASE -5 /** * Right-key. * Character sequences: \e[C * Control-key combination: ^F */ #define KEY_RIGHT -6 /** * Left-key. * Character sequences: \e[D * Control-key combination: ^B */ #define KEY_LEFT -7 /* Use by macros below to ensure that the result is not used. */ #define VOID(...) do { __VA_ARGS__; } while (0) /* Custom fflush and fprintf */ #if defined(PASSPHRASE_STAR) || defined(PASSPHRASE_TEXT) # define xprintf(...) VOID(fprintf(stderr, __VA_ARGS__)) # define xflush() VOID(fflush(stderr)) #elif defined(PASSPHRASE_MOVE) && !defined(PASSPHRASE_ECHO) # define xprintf(...) VOID() # define xflush() VOID() #elif defined(PASSPHRASE_MOVE) # define xprintf(...) VOID(fprintf(stderr, __VA_ARGS__)) # define xflush() VOID(fflush(stderr)) #else # define xflush() VOID(fflush(stderr)) #endif /* Custom putchar */ #if defined(PASSPHRASE_STAR) # define xputchar(C) VOID(((C & 0xC0) != 0x80) ? fprintf(stderr, "%s", PASSPHRASE_STAR_CHAR) : 0) #elif defined(PASSPHRASE_ECHO) && defined(PASSPHRASE_MOVE) # define xputchar(C) VOID(fputc(C, stderr)) #else # define xputchar(C) VOID() #endif /* Is insert active by default? */ #if defined(PASSPHRASE_OVERRIDE) && defined(PASSPHRASE_INSERT) # if defined(DEFAULT_INSERT) # define DEFAULT_INSERT_VALUE 1 # else # define DEFAULT_INSERT_VALUE 0 # endif #endif /* PASSPHRASE_INVALID's affect */ #if defined(PASSPHRASE_INVALID) # define null_terminate() VOID(*(rc + len) = 0) #else # define null_terminate() VOID() #endif /* Implementation of the right-key's action */ #if defined(PASSPHRASE_TEXT) # define move_right() \ do { \ do \ point++; \ while ((len != point) && ((*(rc + point) & 0xC0) == 0x80)); \ } while (0) #else # define move_right() \ do { \ xprintf("\033[C"); \ do \ point++; \ while ((len != point) && ((*(rc + point) & 0xC0) == 0x80)); \ } while (0) #endif /* Implementation of the left-key's action */ #if defined(PASSPHRASE_TEXT) # define move_left() \ do { \ point--; \ while (point && ((*(rc + point) & 0xC0) == 0x80)) \ point--; \ } while (0) #else # define move_left() \ do { \ xprintf("\033[D"); \ point--; \ while (point && ((*(rc + point) & 0xC0) == 0x80)) \ point--; \ } while (0) #endif /* Implementation of the home-key's action */ #if defined(PASSPHRASE_TEXT) # define move_home() VOID(point = 0) #else # define move_home() \ do { \ size_t n = 0; \ for (i = 0; i < point; i++) \ if ((*(rc + i) & 0xC0) != 0x80) \ n++; \ xprintf("\033[%zuD", n); \ point = 0; \ } while (0) #endif /* Implementation of the end-key's action */ #if defined(PASSPHRASE_TEXT) # define move_end() VOID(point = len) #else # define move_end() \ do { \ size_t n = 0; \ for (i = point; i < len; i++) \ if ((*(rc + i) & 0xC0) != 0x80) \ n++; \ xprintf("\033[%zuC", n); \ point = len; \ } while (0) #endif /* Implementation of the delete-key's action upon the passphrase buffer */ #define delete_next() \ do { \ null_terminate(); \ do \ { \ for (i = point; i < len; i++) \ *(rc + i) = *(rc + i + 1); \ len--; \ } \ while ((len != point) && ((*(rc + point) & 0xC0) == 0x80)); \ } while (0) /* Implementation of the erase-key's action upon the passphrase buffer */ #if defined(PASSPHRASE_MOVE) # define erase_prev() \ do { \ char redo = 1; \ null_terminate(); \ while (redo) \ { \ redo = (*(rc + point - 1) & 0xC0) == 0x80; \ for (i = point; i < len; i++) \ *(rc + i - 1) = *(rc + i); \ if (point <= len) \ *(rc + len - 1) = *(rc + len); \ point--; \ len--; \ } \ } while (0) #else # define erase_prev() VOID(*(rc + --len) = 0) #endif #ifdef PASSPHRASE_MOVE # define move_point() VOID(point++) #else # define move_point() VOID() #endif #if defined(PASSPHRASE_TEXT) # define append_char() \ do { \ if (len == 0) \ { \ xprintf("\033[K"); \ xprintf("%s%zn", PASSPHRASE_TEXT_NOT_EMPTY, &printed_len); \ if (printed_len) \ xprintf("\033[%zuD", printed_len); \ } \ *(rc + len++) = (char)c; \ move_point(); \ } while (0) #else # define append_char() \ do { \ xputchar(c); \ *(rc + len++) = (char)c; \ move_point(); \ } while (0) #endif #if defined(PASSPHRASE_TEXT) # define insert_char() \ do { \ for (i = len; i > point; i--) \ *(rc + i) = *(rc + i - 1); \ len++; \ *(rc + point++) = (char)c; \ } while(0) #else # define insert_char() \ do { \ if ((c & 0xC0) != 0x80) \ xprintf("\033[@"); \ xputchar(c); \ for (i = len; i > point; i--) \ *(rc + i) = *(rc + i - 1); \ len++; \ *(rc + point++) = (char)c; \ } while (0) #endif #define override_char() \ do { \ size_t n = 1; \ char cn = (char)c; \ while ((*(rc + point + n) & 0xC0) == 0x80) \ n++; \ for (i = point + n; i < len; i++) \ *(rc + i - n) = *(rc + i); \ passphrase_wipe(rc + len - n, n); \ len -= n; \ n = 0; \ while (cn & 0x80) \ { \ cn = (char)(cn << 1); \ n++; \ } \ n = n ?: 1; \ if (len + n > size) \ { \ if ((rc = xrealloc(rc, size, size << 1L)) == NULL) \ return NULL; \ size <<= 1L; \ } \ len += n; \ for (i = len - 1; i > point + n; i--) \ *(rc + i) = *(rc + i - n); \ if (len - 1 >= point + n) \ *(rc + point + n) = *(rc + point); \ for (i = 0; i < n; i++) \ { \ if (i) \ c = getchar(); \ xputchar(c); \ *(rc + point++) = (char)c; \ } \ } while (0) /* Implementation of the delete-key's action upon the display */ #if defined(PASSPHRASE_TEXT) # define print_delete()\ do { \ if (len) \ break; \ xprintf("\033[K%s%zn", PASSPHRASE_TEXT_EMPTY, &printed_len); \ if (printed_len - 3) \ xprintf("\033[%zuD", printed_len - 3); \ } while (0) #else # define print_delete() VOID(xprintf("\033[P")) #endif /* Implementation of the erase-key's action upon the display */ #if defined(PASSPHRASE_TEXT) # define print_erase() \ do { \ if (len) \ break; \ xprintf("\033[K%s%zn", PASSPHRASE_TEXT_EMPTY, &printed_len); \ if (printed_len - 3) \ xprintf("\033[%zuD", printed_len - 3); \ } while (0) #elif defined(PASSPHRASE_MOVE) # define print_erase() VOID(xprintf("\033[D\033[P")) #elif defined(PASSPHRASE_STAR) # define print_erase() VOID(xprintf("\033[D \033[D")) #endif #define xpipe(pair) \ do { \ if (pipe(pair)) \ { \ pair[0] = pair[1] = -1; \ goto fail; \ } \ } while (0) #endif