145 lines
3.3 KiB
C
145 lines
3.3 KiB
C
/*
|
|
* hlogin(1)
|
|
*
|
|
* Copyleft (C) 2022 ~keith <keith@keithhacks.cyou>
|
|
*
|
|
* This file is part of hlogin.
|
|
*
|
|
* hlogin 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, version 3.
|
|
*
|
|
* hlogin 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 hlogin. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <locale.h>
|
|
#include "gettext.h"
|
|
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <security/_pam_types.h>
|
|
#include <security/pam_appl.h>
|
|
#include <security/pam_misc.h>
|
|
#include <syslog.h>
|
|
#include <pwd.h>
|
|
|
|
#include "ui.h"
|
|
|
|
#define VAR_(x) #x
|
|
#define VAR(x) VAR_(x)
|
|
#pragma message "LOCALEDIR=" VAR(LOCALEDIR)
|
|
|
|
int pam_conv_handler(int msgc, const struct pam_message *msgv[], struct pam_response **resp, void *appdata_ptr)
|
|
{
|
|
if (msgc <= 0)
|
|
return PAM_CONV_ERR;
|
|
|
|
struct pam_response *result = calloc(msgc, sizeof(struct pam_response));
|
|
if (!result)
|
|
return PAM_CONV_ERR;
|
|
|
|
for (int i = 0; i < msgc; i++) {
|
|
int r;
|
|
char *text;
|
|
switch (msgv[i]->msg_style) {
|
|
case PAM_PROMPT_ECHO_OFF:
|
|
case PAM_PROMPT_ECHO_ON:
|
|
ui_setup_dialog((char *) msgv[i]->msg, msgv[i]->msg_style == PAM_PROMPT_ECHO_OFF);
|
|
r = ui_run();
|
|
text = ui_get_text();
|
|
if (r != 0) {
|
|
_pam_overwrite(text);
|
|
free(text);
|
|
text = NULL;
|
|
}
|
|
result[i].resp_retcode = 0;
|
|
result[i].resp = text;
|
|
break;
|
|
case PAM_ERROR_MSG:
|
|
case PAM_TEXT_INFO:
|
|
goto FAILURE; // TODO implement info/error dialog
|
|
default:
|
|
goto FAILURE;
|
|
}
|
|
}
|
|
|
|
*resp = result;
|
|
return PAM_SUCCESS;
|
|
|
|
FAILURE:
|
|
if (result) {
|
|
for (int i = 0; i < msgc; i++) {
|
|
if (result[i].resp) {
|
|
_pam_overwrite(result[i].resp);
|
|
free(result[i].resp);
|
|
}
|
|
}
|
|
free(result);
|
|
result = NULL;
|
|
}
|
|
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 result;
|
|
|
|
setlocale(LC_ALL, "");
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
textdomain(PACKAGE);
|
|
|
|
openlog("hlogin", LOG_ODELAY, LOG_AUTHPRIV);
|
|
|
|
pam_handle_t *pam = NULL;
|
|
struct pam_conv conv = { .conv = pam_conv_handler, .appdata_ptr = NULL };
|
|
|
|
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;
|
|
}
|
|
|
|
ui_init();
|
|
|
|
// prompt for username
|
|
ui_setup_dialog(_("Login name:"), false);
|
|
result = ui_run();
|
|
char *login_name = ui_get_text();
|
|
if (result != 0)
|
|
goto END;
|
|
|
|
result = pam_set_item(pam, PAM_USER, login_name);
|
|
if (result != PAM_SUCCESS) {
|
|
endwin();
|
|
printf("pam_set_item error: %s\n", pam_strerror(pam, result));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
result = pam_authenticate(pam, 0);
|
|
if (result != PAM_SUCCESS) {
|
|
endwin();
|
|
printf("pam_authenticate error: %s\n", pam_strerror(pam, result));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
END:
|
|
endwin();
|
|
return EXIT_SUCCESS;
|
|
}
|