commit message
This commit is contained in:
parent
235c2ccdee
commit
6e391e2324
5 changed files with 179 additions and 12 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,15 +4,18 @@
|
||||||
tmp/
|
tmp/
|
||||||
.ccls-cache/
|
.ccls-cache/
|
||||||
.deps/
|
.deps/
|
||||||
|
.directory
|
||||||
|
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
build/
|
build/
|
||||||
|
build-aux/
|
||||||
po/*.gmo
|
po/*.gmo
|
||||||
po/Makefile
|
po/Makefile
|
||||||
po/Makefile.in
|
po/Makefile.in
|
||||||
po/POTFILES
|
po/POTFILES
|
||||||
po/*.po~
|
po/*.po~
|
||||||
|
|
||||||
|
aclocal.m4
|
||||||
config.h
|
config.h
|
||||||
config.in
|
config.in
|
||||||
config.status
|
config.status
|
||||||
|
|
|
@ -3,3 +3,8 @@ A replacement for `/bin/login` which provides a friendly TUI greeter.
|
||||||
|
|
||||||
*DISCLAIMER:* While I'm reasonably sure this program is secure, I can't
|
*DISCLAIMER:* While I'm reasonably sure this program is secure, I can't
|
||||||
guarantee that for certain. Use it at your own risk.
|
guarantee that for certain. Use it at your own risk.
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
- [ ] UTF-8 support
|
||||||
|
- [ ] Respect `/etc/login.defs`
|
||||||
|
- [ ] Appearance customization
|
||||||
|
|
22
hlogin.c
22
hlogin.c
|
@ -19,7 +19,6 @@
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <security/_pam_types.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -28,8 +27,12 @@
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <security/_pam_types.h>
|
||||||
#include <security/pam_appl.h>
|
#include <security/pam_appl.h>
|
||||||
#include <security/pam_misc.h>
|
#include <security/pam_misc.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
|
@ -88,16 +91,27 @@ FAILURE:
|
||||||
return PAM_CONV_ERR;
|
return PAM_CONV_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** number of seconds to hang after a login failure or error **/
|
||||||
|
unsigned int fail_delay = 3;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||||
textdomain(PACKAGE);
|
textdomain(PACKAGE);
|
||||||
|
|
||||||
|
openlog("hlogin", LOG_ODELAY, LOG_AUTHPRIV);
|
||||||
|
|
||||||
pam_handle_t *pam = NULL;
|
pam_handle_t *pam = NULL;
|
||||||
struct pam_conv conv = { .conv = pam_conv_handler, .appdata_ptr = NULL };
|
struct pam_conv conv = { .conv = pam_conv_handler, .appdata_ptr = NULL };
|
||||||
if (pam_start("login", NULL, &conv, &pam) != PAM_SUCCESS) {
|
|
||||||
// TODO log error & pause before exiting
|
result = pam_start("login", NULL, &conv, &pam);
|
||||||
|
if (result != PAM_SUCCESS) {
|
||||||
|
syslog(LOG_ERR, _("Couldn't initialize PAM: %s"), pam_strerror(pam, result));
|
||||||
|
fprintf(stderr, _("pam_start error: %s. Abort.\n"), pam_strerror(pam, result));
|
||||||
|
sleep(fail_delay);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +119,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
// prompt for username
|
// prompt for username
|
||||||
ui_setup_dialog(_("Login name:"), false);
|
ui_setup_dialog(_("Login name:"), false);
|
||||||
int result = ui_run();
|
result = ui_run();
|
||||||
char *login_name = ui_get_text();
|
char *login_name = ui_get_text();
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
goto END;
|
goto END;
|
||||||
|
|
156
ui.c
156
ui.c
|
@ -20,7 +20,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#include <panel.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -47,6 +46,12 @@ PANEL *login_p;
|
||||||
WINDOW *login_shadow_w;
|
WINDOW *login_shadow_w;
|
||||||
PANEL *login_shadow_p;
|
PANEL *login_shadow_p;
|
||||||
|
|
||||||
|
WINDOW *error_w;
|
||||||
|
PANEL *error_p;
|
||||||
|
|
||||||
|
WINDOW *error_shadow_w;
|
||||||
|
PANEL *error_shadow_p;
|
||||||
|
|
||||||
const int login_rows = 8;
|
const int login_rows = 8;
|
||||||
const int login_cols = 48;
|
const int login_cols = 48;
|
||||||
|
|
||||||
|
@ -115,6 +120,7 @@ FAILURE:
|
||||||
return unknown_str;
|
return unknown_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
char *xgetnisdomainname()
|
char *xgetnisdomainname()
|
||||||
{
|
{
|
||||||
size_t len = HOST_NAME_MAX;
|
size_t len = HOST_NAME_MAX;
|
||||||
|
@ -136,6 +142,7 @@ char *xgetnisdomainname()
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
char erase_ch;
|
char erase_ch;
|
||||||
|
|
||||||
|
@ -154,6 +161,16 @@ void ui_setup_dialog(char *prompt, bool password)
|
||||||
paint_login();
|
paint_login();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ui_setup_message(char *text)
|
||||||
|
{
|
||||||
|
msg = text;
|
||||||
|
// TODO insert word wrap logic here
|
||||||
|
int msg_len = strlen(text);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** ui_init - initialize the UI subsystem
|
/** ui_init - initialize the UI subsystem
|
||||||
*/
|
*/
|
||||||
void ui_init()
|
void ui_init()
|
||||||
|
@ -250,9 +267,9 @@ void paint_login()
|
||||||
wmove(login_w, 3, 3);
|
wmove(login_w, 3, 3);
|
||||||
whline(login_w, ' ', login_cols - 6);
|
whline(login_w, ' ', login_cols - 6);
|
||||||
if (!hide_input)
|
if (!hide_input)
|
||||||
waddnstr(login_w, input_buf, login_cols - 6);
|
waddnstr(login_w, input_buf + input_scroll, login_cols - 6);
|
||||||
else {
|
else {
|
||||||
int num_dots = strlen(input_buf);
|
int num_dots = strlen(input_buf) - input_scroll;
|
||||||
if (num_dots > login_cols - 6)
|
if (num_dots > login_cols - 6)
|
||||||
num_dots = login_cols - 6;
|
num_dots = login_cols - 6;
|
||||||
whline(login_w, '*', num_dots);
|
whline(login_w, '*', num_dots);
|
||||||
|
@ -275,7 +292,7 @@ void paint_login()
|
||||||
int ui_update()
|
int ui_update()
|
||||||
{
|
{
|
||||||
paint_back();
|
paint_back();
|
||||||
wmove(login_w, 3, 3 + input_pos);
|
wmove(login_w, 3, 3 + input_pos - input_scroll);
|
||||||
|
|
||||||
update_panels();
|
update_panels();
|
||||||
doupdate();
|
doupdate();
|
||||||
|
@ -290,11 +307,15 @@ int ui_update()
|
||||||
input_backdel_char();
|
input_backdel_char();
|
||||||
else if (ch == 0x7F || ch == KEY_DC)
|
else if (ch == 0x7F || ch == KEY_DC)
|
||||||
input_del_char();
|
input_del_char();
|
||||||
else if (ch == KEY_LEFT && input_pos > 0)
|
else if (ch == KEY_LEFT && input_pos > 0) {
|
||||||
input_pos--;
|
input_pos--;
|
||||||
else if (ch == KEY_RIGHT && input_pos < strlen(input_buf))
|
if (input_pos < input_scroll)
|
||||||
|
input_scroll--;
|
||||||
|
} else if (ch == KEY_RIGHT && input_pos < strlen(input_buf)) {
|
||||||
input_pos++;
|
input_pos++;
|
||||||
else if (ch == '\t')
|
if (input_pos >= (input_scroll + login_cols - 6))
|
||||||
|
input_scroll++;
|
||||||
|
} else if (ch == '\t')
|
||||||
btn_focus = (btn_focus + 1) % btn_count;
|
btn_focus = (btn_focus + 1) % btn_count;
|
||||||
else if (ch == 0x1B) // escape
|
else if (ch == 0x1B) // escape
|
||||||
return -2;
|
return -2;
|
||||||
|
@ -336,6 +357,8 @@ void input_add_char(char ch)
|
||||||
if (input_buf[i] == '\0')
|
if (input_buf[i] == '\0')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (input_pos >= (input_scroll + login_cols - 6))
|
||||||
|
input_scroll++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_backdel_char()
|
void input_backdel_char()
|
||||||
|
@ -351,11 +374,13 @@ void input_del_char()
|
||||||
if (input_buf[input_pos] == '\0')
|
if (input_buf[input_pos] == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = input_pos; i < (input_buflen - 1); i++) {
|
for (int i = input_pos; i < input_buflen - 1; i++) {
|
||||||
input_buf[i] = input_buf[i + 1];
|
input_buf[i] = input_buf[i + 1];
|
||||||
if (input_buf[i] == '\0')
|
if (input_buf[i] == '\0')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if ((input_scroll + login_cols - 6) > strlen(input_buf) && input_scroll > 0)
|
||||||
|
input_scroll--;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attr_t light = A_BOLD | COLOR_PAIR(3);
|
const attr_t light = A_BOLD | COLOR_PAIR(3);
|
||||||
|
@ -383,3 +408,118 @@ void draw_outline(WINDOW *win, int height, int width, int y, int x, bool inset)
|
||||||
|
|
||||||
wattroff(win, A_ALTCHARSET);
|
wattroff(win, A_ALTCHARSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** output_word - used in word_wrap
|
||||||
|
*/
|
||||||
|
void output_word(char *word, size_t len,
|
||||||
|
char **out, size_t *out_size, int *out_pos,
|
||||||
|
int *line_pos, int *lines, int width)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i < len) {
|
||||||
|
int space = width - (*line_pos);
|
||||||
|
int remain = len - i;
|
||||||
|
if (space > remain) { // can fit on line
|
||||||
|
if ((*out_size) < (*out_pos) + remain) {
|
||||||
|
*out_size *= 2;
|
||||||
|
*out = realloc(*out, sizeof(char) * (*out_size));
|
||||||
|
}
|
||||||
|
// copy word
|
||||||
|
memcpy((*out) + (*out_pos), word + i, sizeof(char) * remain);
|
||||||
|
i += remain;
|
||||||
|
*out_pos += remain;
|
||||||
|
*line_pos += remain;
|
||||||
|
} else {
|
||||||
|
if ((*out_size) < (*out_pos) + space + 1) {
|
||||||
|
*out_size *= 2;
|
||||||
|
*out = realloc(*out, sizeof(char) * (*out_size));
|
||||||
|
}
|
||||||
|
// copy part of word
|
||||||
|
memcpy((*out) + (*out_pos), word + i, sizeof(char) * space);
|
||||||
|
i += space;
|
||||||
|
*out_pos += space;
|
||||||
|
// add newline
|
||||||
|
(*out)[(*out_pos)++] = '\n';
|
||||||
|
*line_pos = 0;
|
||||||
|
(*lines)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *word_wrap(char *text, int width, int max_word, int *lines)
|
||||||
|
{
|
||||||
|
// output buffer
|
||||||
|
size_t out_size = 256;
|
||||||
|
char *out = malloc(sizeof(char) * out_size);
|
||||||
|
int out_pos = 0;
|
||||||
|
// word buffer
|
||||||
|
char *word = malloc(sizeof(char) * max_word);
|
||||||
|
int word_len = 0;
|
||||||
|
|
||||||
|
int line_pos = 0;
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
while ((ch = *text) != '\0') {
|
||||||
|
text++;
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '\n':
|
||||||
|
case ' ':
|
||||||
|
if (word[0] == '\0')
|
||||||
|
word_len = 0;
|
||||||
|
// ensure buffer is large enough
|
||||||
|
if (out_size < out_pos + word_len + 2) {
|
||||||
|
out_size *= 2;
|
||||||
|
out = realloc(out, sizeof(char) * out_size);
|
||||||
|
}
|
||||||
|
if (word_len > 0) {
|
||||||
|
// do we have to wrap to a new line?
|
||||||
|
if (line_pos + word_len > width) {
|
||||||
|
out[out_pos++] = '\n';
|
||||||
|
line_pos = 0;
|
||||||
|
(*lines)++;
|
||||||
|
}
|
||||||
|
memcpy(out + out_pos, word, sizeof(char) * word_len);
|
||||||
|
word_len = 0;
|
||||||
|
out_pos += word_len;
|
||||||
|
line_pos += word_len;
|
||||||
|
}
|
||||||
|
// output \n
|
||||||
|
if (ch == '\n' || line_pos >= width) {
|
||||||
|
out[out_pos++] = '\n';
|
||||||
|
line_pos = 0;
|
||||||
|
(*lines)++;
|
||||||
|
} else {
|
||||||
|
out[out_pos++] = ' ';
|
||||||
|
line_pos++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// word longer than word buffer
|
||||||
|
if (word_len >= max_word) {
|
||||||
|
if (word[0] != '\0') {
|
||||||
|
// write what we have
|
||||||
|
output_word(word, word_len,
|
||||||
|
&out, &out_size, &out_pos,
|
||||||
|
&line_pos, lines, width);
|
||||||
|
word[0] = '\0';
|
||||||
|
}
|
||||||
|
// ensure buffer is large enough
|
||||||
|
if (out_size < out_pos + 2) {
|
||||||
|
out_size *= 2;
|
||||||
|
out = realloc(out, sizeof(char) * out_size);
|
||||||
|
}
|
||||||
|
// write char and maybe newline
|
||||||
|
out[out_pos++] = ch;
|
||||||
|
if ((++line_pos) >= width) {
|
||||||
|
out[out_pos++] = '\n';
|
||||||
|
line_pos = 0;
|
||||||
|
(*lines)++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
word[word_len++] = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(word);
|
||||||
|
}
|
||||||
|
|
5
ui.h
5
ui.h
|
@ -17,6 +17,8 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with hlogin. If not, see <https://www.gnu.org/licenses/>.
|
* along with hlogin. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#define _XOPEN_SOURCE 600
|
||||||
|
|
||||||
#ifndef __UI_H
|
#ifndef __UI_H
|
||||||
#define __UI_H
|
#define __UI_H
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ void paint_back();
|
||||||
void paint_login();
|
void paint_login();
|
||||||
|
|
||||||
void ui_setup_dialog(char *prompt, bool password);
|
void ui_setup_dialog(char *prompt, bool password);
|
||||||
|
void ui_setup_message(char *text);
|
||||||
|
|
||||||
int ui_update();
|
int ui_update();
|
||||||
int ui_run();
|
int ui_run();
|
||||||
|
@ -42,4 +45,6 @@ void input_del_char();
|
||||||
|
|
||||||
void draw_outline(WINDOW *win, int height, int width, int y, int x, bool inset);
|
void draw_outline(WINDOW *win, int height, int width, int y, int x, bool inset);
|
||||||
|
|
||||||
|
char *word_wrap(char *text, int width, int max_word, int *lines);
|
||||||
|
|
||||||
#endif // __UI_H
|
#endif // __UI_H
|
||||||
|
|
Loading…
Reference in a new issue