From 3e3f045d650a839d21f7b649da7aa5c19bd2e38b Mon Sep 17 00:00:00 2001 From: Aylur Date: Sun, 1 Sep 2024 14:17:36 +0200 Subject: monorepo structuring --- lib/auth/src/astal-auth.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 lib/auth/src/astal-auth.c (limited to 'lib/auth/src/astal-auth.c') diff --git a/lib/auth/src/astal-auth.c b/lib/auth/src/astal-auth.c new file mode 100644 index 0000000..1ac2bd7 --- /dev/null +++ b/lib/auth/src/astal-auth.c @@ -0,0 +1,153 @@ +#include "astal-auth.h" + +#include +#include +#include + +GMainLoop *loop; + +static void cleanup_and_quit(AstalAuthPam *pam, int status) { + g_object_unref(pam); + g_main_loop_quit(loop); + exit(status); +} + +static char *read_secret(const char *msg, gboolean echo) { + struct termios oldt, newt; + char *password = NULL; + size_t size = 0; + ssize_t len; + + if (tcgetattr(STDIN_FILENO, &oldt) != 0) { + return NULL; + } + newt = oldt; + if (echo) { + newt.c_lflag |= ECHO; + } else { + newt.c_lflag &= ~(ECHO); + } + if (tcsetattr(STDIN_FILENO, TCSANOW, &newt) != 0) { + return NULL; + } + g_print("%s", msg); + if ((len = getline(&password, &size, stdin)) == -1) { + g_free(password); + return NULL; + } + + if (password[len - 1] == '\n') { + password[len - 1] = '\0'; + } + + printf("\n"); + + if (tcsetattr(STDIN_FILENO, TCSANOW, &oldt) != 0) { + return NULL; + } + + return password; +} + +static void authenticate(AstalAuthPam *pam) { + static int attempts = 0; + if (attempts >= 3) { + g_print("%d failed attempts.\n", attempts); + cleanup_and_quit(pam, EXIT_FAILURE); + } + if (!astal_auth_pam_start_authenticate(pam)) { + g_print("could not start authentication process\n"); + cleanup_and_quit(pam, EXIT_FAILURE); + } + attempts++; +} + +static void on_visible(AstalAuthPam *pam, const gchar *data) { + char *secret = read_secret(data, TRUE); + if (secret == NULL) cleanup_and_quit(pam, EXIT_FAILURE); + astal_auth_pam_supply_secret(pam, secret); + g_free(secret); +} + +static void on_hidden(AstalAuthPam *pam, const gchar *data, gchar *secret) { + if (!secret) secret = read_secret(data, FALSE); + if (secret == NULL) cleanup_and_quit(pam, EXIT_FAILURE); + astal_auth_pam_supply_secret(pam, secret); + g_free(secret); +} + +static void on_info(AstalAuthPam *pam, const gchar *data) { + g_print("info: %s\n", data); + astal_auth_pam_supply_secret(pam, NULL); +} + +static void on_error(AstalAuthPam *pam, const gchar *data) { + g_print("error: %s\n", data); + astal_auth_pam_supply_secret(pam, NULL); +} + +static void on_success(AstalAuthPam *pam) { + g_print("Authentication successful\n"); + cleanup_and_quit(pam, EXIT_SUCCESS); +} + +static void on_fail(AstalAuthPam *pam, const gchar *data, gboolean retry) { + g_print("%s\n", data); + if (retry) + authenticate(pam); + else + cleanup_and_quit(pam, EXIT_FAILURE); +} + +int main(int argc, char **argv) { + char *password = NULL; + char *username = NULL; + char *service = NULL; + + int opt; + const char *optstring = "p:u:s:"; + + static struct option long_options[] = {{"password", required_argument, NULL, 'p'}, + {"username", required_argument, NULL, 'u'}, + {"service", required_argument, NULL, 's'}, + {NULL, 0, NULL, 0}}; + + while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (opt) { + case 'p': + password = optarg; + break; + case 'u': + username = optarg; + break; + case 's': + service = optarg; + break; + default: + g_print("Usage: %s [-p password] [-u username] [-s service]\n", argv[0]); + exit(EXIT_FAILURE); + } + } + + loop = g_main_loop_new(NULL, FALSE); + + AstalAuthPam *pam = g_object_new(ASTAL_AUTH_TYPE_PAM, NULL); + + if (username) astal_auth_pam_set_username(pam, username); + if (service) astal_auth_pam_set_service(pam, service); + if (password) { + g_signal_connect(pam, "fail", G_CALLBACK(on_fail), (void *)FALSE); + } else { + g_signal_connect(pam, "auth-prompt-visible", G_CALLBACK(on_visible), NULL); + g_signal_connect(pam, "auth-info", G_CALLBACK(on_info), NULL); + g_signal_connect(pam, "auth-error", G_CALLBACK(on_error), NULL); + g_signal_connect(pam, "fail", G_CALLBACK(on_fail), (void *)TRUE); + } + + g_signal_connect(pam, "auth-prompt-hidden", G_CALLBACK(on_hidden), g_strdup(password)); + g_signal_connect(pam, "success", G_CALLBACK(on_success), NULL); + + authenticate(pam); + + g_main_loop_run(loop); +} -- cgit v1.2.3