hlogin/hlogin.c

131 lines
3.0 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 <security/_pam_types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <locale.h>
#include "gettext.h"
#include <unistd.h>
#include <security/pam_appl.h>
#include <security/pam_misc.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;
}
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
pam_handle_t *pam = 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
return EXIT_FAILURE;
}
ui_init();
// prompt for username
ui_setup_dialog(_("Login name:"), false);
int 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;
}