mirror of
https://github.com/quitesimpleorg/asteriskify.git
synced 2024-12-22 04:09:49 +01:00
Initial commit
This commit is contained in:
commit
2103dfdac6
5
Makefile
Normal file
5
Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
asteriskify: asteriskify.c
|
||||
$(CC) -Wall -Wextra -static -o asteriskify asteriskify.c
|
||||
|
||||
clean: asteriskify
|
||||
rm -f asteriskify
|
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
||||
# asteriskify - Linux console password prompt with asterisks
|
||||
|
||||
## Usage
|
||||
```
|
||||
asteriskify | cryptsetup luksOpen ...
|
||||
```
|
||||
|
||||
Pipe it to anything that receives credentials over stdin, such as cryptsetup.
|
||||
|
||||
To switch between clear and asterisk mode, press TAB. To reveal only the last character, use CTRL + R.
|
||||
|
||||
Note: Expects ASCII or UTF-8 encoding for asterisk mode
|
||||
|
||||
## Alternatives
|
||||
Others may exist, but my quick research only found systemd-ask-password which is unsuitable for my use case (inside a my own minimal initramfs boot image).
|
||||
|
234
asteriskify.c
Normal file
234
asteriskify.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Albert Schwarzkopf <dev at quitesimple dot org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PWBUF_SIZE 256
|
||||
|
||||
#define MODE_ECHO 0
|
||||
#define MODE_STARS 1
|
||||
|
||||
struct termios saved_termios;
|
||||
uint8_t *pwbuf = NULL;
|
||||
size_t pwbufsize = 0;
|
||||
size_t pwindex = 0;
|
||||
int current_mode = MODE_ECHO;
|
||||
|
||||
void enter_raw_mode() {
|
||||
struct termios raw = saved_termios;
|
||||
raw.c_lflag &= ~(ECHO | ICANON);
|
||||
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed tcsetattr\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_console()
|
||||
{
|
||||
if(tcgetattr(STDIN_FILENO, &saved_termios) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed tcgetattr\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
enter_raw_mode();
|
||||
}
|
||||
|
||||
void restore_console()
|
||||
{
|
||||
if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_termios) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed tcsetattr\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void allocate_pw_buf()
|
||||
{
|
||||
pwbuf = calloc(PWBUF_SIZE, sizeof(uint8_t));
|
||||
if(pwbuf == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int lock = mlock(pwbuf, PWBUF_SIZE);
|
||||
if(lock != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to mlock buffer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pwbufsize = PWBUF_SIZE;
|
||||
}
|
||||
|
||||
void grow_pw_buf()
|
||||
{
|
||||
size_t newsize = pwbufsize + PWBUF_SIZE;
|
||||
uint8_t *newbuf = calloc(newsize, sizeof(uint8_t));
|
||||
if(newbuf == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int lock = mlock(newbuf, newsize);
|
||||
if(lock != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to mlock buffer\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
memcpy(newbuf, pwbuf, pwbufsize);
|
||||
explicit_bzero(pwbuf, pwbufsize);
|
||||
pwbuf = newbuf;
|
||||
pwbufsize = newsize;
|
||||
}
|
||||
|
||||
void exit_handler()
|
||||
{
|
||||
explicit_bzero(pwbuf, pwbufsize);
|
||||
explicit_bzero(&pwbufsize, sizeof(pwbufsize));
|
||||
explicit_bzero(&pwindex, sizeof(pwbufsize));
|
||||
|
||||
restore_console();
|
||||
}
|
||||
|
||||
void clear_term_line()
|
||||
{
|
||||
const char *clearcmd = "\33[2K\r";
|
||||
write(STDERR_FILENO, clearcmd, strlen(clearcmd));
|
||||
}
|
||||
|
||||
void print_password()
|
||||
{
|
||||
clear_term_line();
|
||||
char *prompt = "Password: ";
|
||||
write(STDERR_FILENO, prompt, strlen(prompt));
|
||||
if(current_mode == MODE_ECHO)
|
||||
{
|
||||
write(STDERR_FILENO, pwbuf, pwindex);
|
||||
}
|
||||
if(current_mode == MODE_STARS)
|
||||
{
|
||||
for(size_t i = 0; i < pwindex; i++)
|
||||
{
|
||||
uint8_t n = pwbuf[i];
|
||||
/* Skip utf-8 byte 2-4, we won't print an asterisk for those*/
|
||||
if((n >>6) == 0b10)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
char mask = '*';
|
||||
write(STDERR_FILENO, &mask, 1);
|
||||
}
|
||||
}
|
||||
fsync(STDERR_FILENO);
|
||||
}
|
||||
|
||||
void switch_mode()
|
||||
{
|
||||
current_mode = ( current_mode + 1 ) % 2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if(atexit(exit_handler) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to register exit handler\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
setup_console();
|
||||
|
||||
allocate_pw_buf();
|
||||
|
||||
print_password();
|
||||
|
||||
uint8_t c;
|
||||
while (read(STDIN_FILENO, &c, 1) == 1)
|
||||
{
|
||||
if(iscntrl(c))
|
||||
{
|
||||
if(c == '\t')
|
||||
{
|
||||
switch_mode();
|
||||
print_password();
|
||||
}
|
||||
if(c == 27) /* Escape sequence */
|
||||
{
|
||||
int remaining = 0;
|
||||
int ret = ioctl (STDIN_FILENO,FIONREAD,&remaining);
|
||||
if(ret != 0)
|
||||
{
|
||||
fprintf(stderr, "ioctl() failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char tmp;
|
||||
/* Just consume them, we don't care */
|
||||
while(remaining--)
|
||||
{
|
||||
read(STDIN_FILENO, &tmp, 1);
|
||||
}
|
||||
}
|
||||
if(c == 18) /* Control + R, device control 2. or "reveal" for us :-) */
|
||||
{
|
||||
if(pwindex > 0)
|
||||
{
|
||||
char c = '\b';
|
||||
write(STDERR_FILENO, &c, 1);
|
||||
write(STDERR_FILENO, &pwbuf[pwindex-1], 1);
|
||||
fsync(STDERR_FILENO);
|
||||
}
|
||||
}
|
||||
if(c == 127) /* Backspace */
|
||||
{
|
||||
if(pwindex > 0)
|
||||
{
|
||||
--pwindex;
|
||||
}
|
||||
print_password();
|
||||
continue;
|
||||
}
|
||||
if(c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(pwindex == pwbufsize)
|
||||
{
|
||||
grow_pw_buf();
|
||||
}
|
||||
|
||||
pwbuf[pwindex] = c;
|
||||
++pwindex;
|
||||
|
||||
print_password();
|
||||
}
|
||||
clear_term_line();
|
||||
|
||||
fsync(STDERR_FILENO);
|
||||
write(STDOUT_FILENO, pwbuf, pwindex);
|
||||
fsync(STDOUT_FILENO);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user