summaryrefslogtreecommitdiff
path: root/multi_auth.c
diff options
context:
space:
mode:
authorOlivier Gayot <duskcoder@gmail.com>2015-12-15 22:34:44 +0100
committerOlivier Gayot <duskcoder@gmail.com>2015-12-15 22:34:44 +0100
commitffdce9f16ed386cb9668a8a97967212a0acb4647 (patch)
treea4609d554ff8ade91ea07286dc7bb0ae83027673 /multi_auth.c
first version
Signed-off-by: Olivier Gayot <duskcoder@gmail.com>
Diffstat (limited to 'multi_auth.c')
-rw-r--r--multi_auth.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/multi_auth.c b/multi_auth.c
new file mode 100644
index 0000000..ba8ec1d
--- /dev/null
+++ b/multi_auth.c
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sched.h>
+#include <dlfcn.h>
+
+#define countof(_x) ((int)((sizeof((_x)) / sizeof((_x)[0]))))
+
+struct module_args_t {
+ int (*callback)(pam_handle_t *, int, int, const char **);
+ pam_handle_t *handler;
+ int flags;
+ int argc;
+ const char **argv;
+};
+
+struct auth_module_t {
+ const char *name;
+ const char *path;
+ const char *symbol;
+
+ struct module_args_t args;
+
+ void *dl_handler;
+
+ pid_t pid;
+};
+
+static
+struct auth_module_t modules_g[] = {
+ {
+ .name = "unix",
+ .path = "/usr/lib/security/pam_unix.so",
+ .symbol = "pam_sm_authenticate",
+ }, {
+ .name = "other",
+ .path = "/home/camel_case/dev/fingerprint/pam_other.so",
+ .symbol = "pam_sm_authenticate",
+ },
+};
+
+static int multi_auth_init(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ for (int i = 0; i < countof(modules_g); ++i) {
+ struct auth_module_t *mod = &modules_g[i];
+
+ mod->dl_handler = dlopen(mod->path, RTLD_NOW);
+
+ if (mod->dl_handler == NULL) {
+ fprintf(stderr, "%s: %m\n", mod->path);
+ return PAM_SYSTEM_ERR;
+ }
+
+ mod->args.callback = dlsym(mod->dl_handler, mod->symbol);
+ mod->args.handler = pamh;
+ mod->args.flags = flags;
+ mod->args.argc = argc;
+ mod->args.argv = argv;
+
+ if (mod->args.callback == NULL) {
+ return PAM_SYSTEM_ERR;
+ }
+ }
+
+ return 0;
+}
+
+static void multi_auth_fini(void)
+{
+ for (int i = 0; i < countof(modules_g); ++i) {
+ dlclose(modules_g[i].dl_handler);
+ }
+}
+
+static int module_auth_main(void *_args)
+{
+ struct module_args_t *args = _args;
+
+ /* the child is supposed to close after returning from this function */
+ return args->callback(args->handler, args->flags, args->argc, args->argv);
+}
+
+static int perform_auth(void)
+{
+ for (int i = 0; i < countof(modules_g); ++i) {
+#define STACK_SIZE (1000 * 1000)
+ struct auth_module_t *mod = &modules_g[i];
+
+ void *stack = malloc(STACK_SIZE);
+
+ if (stack == NULL) {
+ return PAM_AUTH_ERR;
+ }
+
+ int clone_flags = CLONE_NEWUTS|SIGCHLD;
+
+ modules_g[i].pid = clone(module_auth_main, stack + STACK_SIZE, clone_flags, &mod->args);
+
+ if (modules_g[i].pid == -1) {
+ return PAM_SYSTEM_ERR;
+ }
+#undef STACK_SIZE
+ }
+
+ for (int i = 0; i < countof(modules_g); ++i) {
+ int status;
+
+ do {
+ waitpid(-1, &status, 0);
+
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ if (WIFEXITED(status)) {
+ for (int j = 0; j < countof(modules_g); ++j) {
+ kill(modules_g[j].pid, SIGKILL);
+ }
+
+ return (WEXITSTATUS(status) == 0) ? PAM_SUCCESS : PAM_AUTH_ERR;
+ }
+ }
+
+ return PAM_AUTH_ERR;
+}
+
+ PAM_EXTERN
+int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ (void)pamh;
+ (void)flags;
+ (void)argc;
+ (void)argv;
+ return PAM_SUCCESS;
+}
+
+ PAM_EXTERN
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+
+ int ret = multi_auth_init(pamh, flags, argc, argv);
+
+ if (ret == 0) {
+ ret = perform_auth();
+ }
+
+ multi_auth_fini();
+ return ret;
+}