summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/meson.build6
-rw-r--r--include/auth.h2
-rw-r--r--src/astal-auth.c156
-rw-r--r--src/meson.build15
4 files changed, 172 insertions, 7 deletions
diff --git a/examples/meson.build b/examples/meson.build
index 3a2faf4..cf23d3f 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,12 +1,8 @@
-astal_auth = declare_dependency(
- link_with : astal_auth_lib,
- include_directories : astal_auth_inc)
-
deps_example = [
dependency('gobject-2.0'),
dependency('libbsd'),
- astal_auth
+ libastal_auth
]
astal_auth_full_exmple = executable(
diff --git a/include/auth.h b/include/auth.h
index bc1c28c..9224dde 100644
--- a/include/auth.h
+++ b/include/auth.h
@@ -74,7 +74,7 @@ gboolean astal_auth_pam_start_authenticate(AstalAuthPam *self);
/**
* astal_auth_pam_supply_secret
* @self: a AstalAuthPam Object
- * @secret: (nullable) the secret to be provided to pam. Can be NULL.
+ * @secret: (nullable): the secret to be provided to pam. Can be NULL.
*
* provides pam with a secret. This method must be called exactly once after a
* auth-* signal is emitted.
diff --git a/src/astal-auth.c b/src/astal-auth.c
new file mode 100644
index 0000000..6f0a73b
--- /dev/null
+++ b/src/astal-auth.c
@@ -0,0 +1,156 @@
+#include "auth.h"
+#include <termios.h>
+#include <stdio.h>
+#include <getopt.h>
+
+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);
+}
diff --git a/src/meson.build b/src/meson.build
index 78f1f2c..9f02aae 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -17,6 +17,19 @@ astal_auth_lib = library(
install : true
)
+libastal_auth = declare_dependency(
+ link_with : astal_auth_lib,
+ include_directories : astal_auth_inc)
+
+astal_auth_executable = executable(
+ 'astal-auth',
+ files('astal-auth.c'),
+ dependencies : [
+ dependency('gobject-2.0'),
+ libastal_auth
+ ],
+ install : true)
+
pkg_config_name = 'astal-auth-' + lib_so_version
if get_option('introspection')
@@ -49,4 +62,4 @@ pkg_config.generate(
filebase : pkg_config_name,
subdirs : 'astal',
description : 'astal authentication module',
- url : 'https://github.com/kotontrion/astal-auth')
+ url : 'https://github.com/astal-sh/libastal-auth')