diff --git a/CHANGELOG.md b/CHANGELOG.md index 70505c9e5719ceba2d40ba2b6c1b197e8eefe603..f66c4ca07a1a300bc6d180954bb6fa82fca3c8f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,9 +48,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - #14 - Handle files on file system without File entity: Those entries are returned without ID but with a notice now. +* #11 - pam_authentication leaks the password to unprivileged processes on the + same machine. + ### Security (in case of vulnerabilities) - TLS is by default restricted to v1.2 and v1.3 now. +* #11 - pam_authentication leaks the password to unprivileged processes on the + same machine. ## [0.1.0] - 2018-10-09 diff --git a/misc/pam_authentication/makefile b/misc/pam_authentication/makefile index 47830dc9451abcd3baddb7cce9478e7998287afd..0cd1b7d250358a116a32a45ba18875d5f72d887a 100644 --- a/misc/pam_authentication/makefile +++ b/misc/pam_authentication/makefile @@ -4,6 +4,8 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen +# Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> +# Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -23,5 +25,5 @@ # Makefile for pam_authentication.c main: pam_authentication.c - [ -d ./bin ] || mkdir ./bin + mkdir -p ./bin gcc -o ./bin/pam_authentication pam_authentication.c -lpam -lpam_misc diff --git a/misc/pam_authentication/pam_authentication.c b/misc/pam_authentication/pam_authentication.c index 5d71ec2973fa59d18d10ffa4918a5236707b85af..4abef5bddb2a6c11ecefdcc8a1bf9179835bca84 100644 --- a/misc/pam_authentication/pam_authentication.c +++ b/misc/pam_authentication/pam_authentication.c @@ -4,6 +4,8 @@ * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> + * Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -23,17 +25,31 @@ // Pam Authentication // A. Schlemmer, 07/2018 -#include <security/pam_appl.h> -#include <security/pam_misc.h> +/* +Note: This program needs sufficient right to authenticate against anyone but +oneself. This can be done for example by changing the effective group id: + +``` +$ ls -l bin +-rwxrwsrwx 1 root shadow 16992 Apr 28 07:45 pam_authentication +``` +*/ + +#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <termios.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> -char * password; // needs to be global +char *password; // needs to be global int supply_password(int num_msg, const struct pam_message **msgm, struct pam_response **responsep, void *appdata_ptr) { - struct pam_response* response = (struct pam_response*)calloc(sizeof(struct pam_response), num_msg); + struct pam_response *response = + (struct pam_response*)calloc(sizeof(struct pam_response), num_msg); int i; for (i=0; i<num_msg; i++) { if (msgm[i]->msg_style == PAM_PROMPT_ECHO_OFF) { @@ -51,24 +67,95 @@ static struct pam_conv conv = NULL }; -int main(int args, char** argv) { - if (args != 3) { - fprintf(stderr, "Usage: pam_authentication username password\n"); +/** + * @brief Obtain the password from the given file. + * + * @param filename: If "-", read from stdin. + * + * @return 0 if successful, else 1. + */ +bool get_password(char *filename) { + // With code from https://stackoverflow.com/a/1196696/232888 + // by user https://stackoverflow.com/users/89266/dfa + struct termios backup, secret_setting; + bool is_tty = isatty(fileno(stdin)); + /* disable echo */ + if (is_tty) { + tcgetattr(fileno(stdin), &backup); + secret_setting = backup; + secret_setting.c_lflag &= ~ECHO; + secret_setting.c_lflag |= ECHONL; + + if (tcsetattr(fileno(stdin), TCSANOW, &secret_setting) != 0) { + perror("Setting echo-less output flags failed."); + return EXIT_FAILURE; + } + } + + FILE *pwfile; + if (strcmp(filename, "-")) { + pwfile = fopen(filename, "r"); + if (pwfile == NULL) { + perror(filename); + if (is_tty) { + tcsetattr(fileno(stdin), TCSANOW, &backup); + } + return false; + } + } else { + pwfile = stdin; + printf("Enter the password: "); + } + password = NULL; + size_t n = 0; + ssize_t pwlen = getline(&password, &n, pwfile); + if (strcmp(filename, "-")) { + fclose(pwfile); + } + password[pwlen - 1] = 0; + + /* restore terminal settings */ + if (is_tty) { + if (tcsetattr(fileno(stdin), TCSANOW, &backup) != 0) { + perror("Resetting output flags failed."); + } + } + + return true; +} + +int main(int argc, char **argv) { + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage: pam_authentication <username> [<password_file>]\n"); return 2; } pam_handle_t *pamh; - char * username = argv[1]; - password = argv[2]; + char *username = argv[1]; + char *pw_file = "-"; + if (argc == 3) { + pw_file = argv[2]; + } + + if (! get_password(pw_file)) { + fprintf(stderr, "Error while reading password.\n"); + return 3; + } + int res = pam_start("login", username, &conv, &pamh); if (!res == PAM_SUCCESS) { fprintf(stderr, "Error in starting pam authentication.\n"); return 2; } - + /* printf("\n>%s<\n", password); // Warning: this prints the password! */ res = pam_authenticate(pamh, 0); - // printf("Return code %i: %s\n", res, pam_strerror(pamh, res)); + +/* printf("PAM_AUTH_ERR: %i\n\ */ +/* PAM_CRED_INSUFFICIENT: %i\n\ */ +/* PAM_AUTHINFO_UNAVAIL: %i\n", PAM_AUTH_ERR, PAM_CRED_INSUFFICIENT, PAM_AUTHINFO_UNAVAIL); */ +/* printf("Return code (success=%i) %i: %s\n", PAM_SUCCESS, res, pam_strerror(pamh, res)); */ + free(password); return res; } diff --git a/misc/pam_authentication/pam_authentication.sh b/misc/pam_authentication/pam_authentication.sh index e2a6fb76d8bada2f21749d1e9c9f3f5330ef8555..972e48f1ccc9c65ca0c56773f7e20a5da0977ebb 100755 --- a/misc/pam_authentication/pam_authentication.sh +++ b/misc/pam_authentication/pam_authentication.sh @@ -5,6 +5,8 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen +# Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> +# Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,7 +23,7 @@ # # ** end header # -if ./bin/pam_authentication $1 $2 ; then +if ./bin/pam_authentication $1 ; then echo "[OK]" exit 0 else diff --git a/src/main/java/caosdb/server/accessControl/Pam.java b/src/main/java/caosdb/server/accessControl/Pam.java index 606fddb6858968c9ccf363dfd5fb703d4b264913..0cae6fd74ae3924e868757e1f058a430a23b1ff3 100644 --- a/src/main/java/caosdb/server/accessControl/Pam.java +++ b/src/main/java/caosdb/server/accessControl/Pam.java @@ -4,8 +4,9 @@ * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2019 IndiScale GmbH - * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com) + * Copyright (C) 2019, 2020 Indiscale GmbH <info@indiscale.com> + * Copyright (C) 2019 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -70,9 +71,13 @@ public class Pam implements UserSource { final File script = new File(this.pam_script); - final ProcessBuilder pb = new ProcessBuilder(script.getAbsolutePath(), username, password); + final ProcessBuilder pb = new ProcessBuilder(script.getAbsolutePath(), username); pb.directory(script.getParentFile()); - return pb.start(); + final Process p = pb.start(); + p.getOutputStream().write(password.getBytes()); + p.getOutputStream().write('\n'); + p.getOutputStream().flush(); + return p; } @Override