зеркало из
				https://github.com/quitesimpleorg/asteriskify.git
				synced 2025-10-30 18:09:30 +01:00 
			
		
		
		
	Initial commit
Этот коммит содержится в:
		
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
										Обычный файл
									
								
							| @@ -0,0 +1,5 @@ | ||||
| asteriskify: asteriskify.c | ||||
| 	$(CC) -Wall -Wextra -static -o asteriskify asteriskify.c | ||||
| 	 | ||||
| clean: asteriskify | ||||
| 	rm -f asteriskify | ||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
										Обычный файл
									
								
							| @@ -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
									
									
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										234
									
								
								asteriskify.c
									
									
									
									
									
										Обычный файл
									
								
							| @@ -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; | ||||
| } | ||||
		Ссылка в новой задаче
	
	Block a user