/**
* libpassphrase – Personalisable library for TTY passphrase reading
*
* Copyright © 2013 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 .
*/
#include
#include
#include
#include
#include "passphrase.h"
#define START_PASSPHRASE_LIMIT 32
#ifndef PASSPHRASE_ECHO
/**
* The original TTY settings
*/
static struct termios saved_stty;
#endif
#ifndef PASSPHRASE_REALLOC
static inline char* xrealloc(char* array, size_t size)
{
char* rc = malloc(size);
int i;
if (rc)
for (i = 0; *(array + i); i++)
{
*(rc + i) = *(array + i);
*(array + i) = 0;
}
else
for (i = 0; *(array + i); i++)
*(array + i) = 0;
free(array);
return rc;
}
#else
#define xrealloc realloc
#endif
#define xprintf(...) ({ printf(__VA_ARGS__); fflush(stdout); })
/**
* Reads the passphrase from stdin
*
* @return The passphrase, should be wiped `free`:ed, `NULL` on error
*/
char* passphrase_read(void)
{
char* rc = malloc(START_PASSPHRASE_LIMIT * sizeof(char));
long size = START_PASSPHRASE_LIMIT;
long len = 0;
int c;
if (rc == NULL)
return NULL;
/* Read password until EOF or Enter, skip all \0 as that
is probably not a part of the passphrase (good luck typing
that in X.org) and can be echoed into stdin by the kernel. */
for (;;)
{
c = getchar();
if ((c < 0) || (c == '\n'))
break;
if (c != 0)
{
#ifdef PASSPHRASE_STAR
if ((c == 8) || (c == 127))
{
if (len == 0)
continue;
xprintf("\033[D \033[D");
*(rc + --len) = 0;
continue;
}
putchar('*');
#endif
*(rc + len++) = c;
if (len == size)
if ((rc = xrealloc(rc, (size <<= 1L) * sizeof(char))) == NULL)
return rc;
}
}
/* NUL-terminate passphrase */
*(rc + len) = 0;
#ifndef PASSPHRASE_ECHO
printf("\n");
#endif
return rc;
}
/**
* Disable echoing and do anything else to the terminal settnings `passphrase_read` requires
*/
void passphrase_disable_echo(void)
{
#ifndef PASSPHRASE_ECHO
struct termios stty;
tcgetattr(STDIN_FILENO, &stty);
saved_stty = stty;
stty.c_lflag &= ~ECHO;
#ifdef PASSPHRASE_STAR
stty.c_lflag &= ~ICANON;
#endif
tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty);
#endif
}
/**
* Undo the actions of `passphrase_disable_echo`
*/
void passphrase_reenable_echo(void)
{
#ifndef PASSPHRASE_ECHO
tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
#endif
}