From 96b2f26c68e621f8605b87da01030de02b90c18d Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Sat, 25 Jan 2025 12:04:05 +0100 Subject: namespacing: Add FreeRDPv3 support and drop the FreeRDP version number from project name and project files. --- README.md | 4 +- configure.ac | 42 +++- include/pam-freerdp.h | 29 +++ include/pam-freerdp2.h | 29 --- src/Makefile.am | 48 ++--- src/freerdp-auth-check.c | 142 +++++++++++++ src/freerdp2-auth-check.c | 124 ----------- src/pam-freerdp-children.c | 230 ++++++++++++++++++++ src/pam-freerdp-children.h | 32 +++ src/pam-freerdp-private.h | 32 +++ src/pam-freerdp.c | 472 +++++++++++++++++++++++++++++++++++++++++ src/pam-freerdp2-children.c | 230 -------------------- src/pam-freerdp2-children.h | 32 --- src/pam-freerdp2-private.h | 32 --- src/pam-freerdp2.c | 472 ----------------------------------------- tests/Makefile.am | 44 ++-- tests/mock_guest.c | 2 +- tests/mock_pam.c | 22 +- tests/test-freerdp-auth.c | 57 +++++ tests/test-freerdp-wrapper.cc | 90 ++++++++ tests/test-freerdp2-auth.c | 57 ----- tests/test-freerdp2-wrapper.cc | 90 -------- 22 files changed, 1183 insertions(+), 1129 deletions(-) create mode 100644 include/pam-freerdp.h delete mode 100644 include/pam-freerdp2.h create mode 100644 src/freerdp-auth-check.c delete mode 100644 src/freerdp2-auth-check.c create mode 100644 src/pam-freerdp-children.c create mode 100644 src/pam-freerdp-children.h create mode 100644 src/pam-freerdp-private.h create mode 100644 src/pam-freerdp.c delete mode 100644 src/pam-freerdp2-children.c delete mode 100644 src/pam-freerdp2-children.h delete mode 100644 src/pam-freerdp2-private.h delete mode 100644 src/pam-freerdp2.c create mode 100644 tests/test-freerdp-auth.c create mode 100644 tests/test-freerdp-wrapper.cc delete mode 100644 tests/test-freerdp2-auth.c delete mode 100644 tests/test-freerdp2-wrapper.cc diff --git a/README.md b/README.md index 94ff9b7..630da88 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# PAM FreeRDP2 +# PAM FreeRDP -A small PAM module to check an RDP Server (using FreeRDP2) for credentials. +A small PAM module to check an RDP Server (using FreeRDPv2/FreeRDPv3) for credentials. This PAM module is needed for Arctica Greeter's Remote Logon feature. diff --git a/configure.ac b/configure.ac index 68a6cec..2423b37 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([libpam-freerdp2], [2.0.0]) +AC_INIT([libpam-freerdp], [2.0.0]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIRS([m4]) @@ -26,8 +26,44 @@ fi # FreeRDP ########################### -PKG_CHECK_MODULES(FREERDP2, freerdp2) -PKG_CHECK_MODULES(WINPR2, winpr2) +dnl GTK version selection. +AC_MSG_CHECKING([whether to build against FreeRDPv3]) +AC_ARG_ENABLE([freerdp3], + [AS_HELP_STRING([--enable-freerdp3], + [Build against FreeRDPv3])], + [enable_freerdp3=$enableval], + [enable_freerdp3=no]) +AC_MSG_RESULT([$enable_freerdp3]) +with_freerdp3=$enable_freerdp3 + +AS_IF([test "x$enable_freerdp3" != 'xno'], + [PKG_CHECK_MODULES([FREERDP], + [freerdp3], + [freerdp3_modules=yes], + [freerdp3_modules=no]) + PKG_CHECK_MODULES([WINPR], + [winpr3]) + AC_MSG_CHECKING([for FreeRDPv3 libraries]) + AC_MSG_RESULT([$freerdp3_modules]) + AS_IF([test "x$freerdp3_modules" = 'xno'], + [AC_MSG_ERROR([requested FreeRDPv3, but not found])], + [with_freerdp3=yes])]) +AS_IF([test "x$with_freerdp3" = 'xno'], + [PKG_CHECK_MODULES([FREERDP], + [freerdp2], + [freerdp2_modules=yes], + [freerdp2_modules=no]) + PKG_CHECK_MODULES([WINPR], + [winpr2]) + AC_MSG_CHECKING([for FreeRDPv2 libraries]) + AC_MSG_RESULT([$freerdp2_modules]) + AS_IF([test "x$freerdp2_modules" = 'xno'], + [AC_MSG_ERROR([requested FreeRDPv2, but not found])])]) +AC_SUBST([FREERDP_CFLAGS]) +AC_SUBST([FREERDP_LIBS]) +AC_SUBST([WINPR_CFLAGS]) +AC_SUBST([WINPR_LIBS]) +AM_CONDITIONAL([HAVE_FREERDP3], [test "x$with_freerdp3" != 'xno']) ########################### # PAM Module dir diff --git a/include/pam-freerdp.h b/include/pam-freerdp.h new file mode 100644 index 0000000..7d5e277 --- /dev/null +++ b/include/pam-freerdp.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2012-2013 Mike Gabriel + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Mike Gabriel + */ + +#ifndef _PAM_FREERDP_H_ +#define _PAM_FREERDP_H_ + +#define PAM_FREERDP_PROMPT_GUESTLOGIN "login:" +#define PAM_FREERDP_PROMPT_USER "remote login:" +#define PAM_FREERDP_PROMPT_HOST "remote host:" +#define PAM_FREERDP_PROMPT_DOMAIN "remote domain:" +#define PAM_FREERDP_PROMPT_PASSWORD "password:" + +#endif //_PAM_FREERDP_H_ diff --git a/include/pam-freerdp2.h b/include/pam-freerdp2.h deleted file mode 100644 index 3635a4f..0000000 --- a/include/pam-freerdp2.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2012-2013 Mike Gabriel - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Mike Gabriel - */ - -#ifndef _PAM_FREERDP2_H_ -#define _PAM_FREERDP2_H_ - -#define PAM_FREERDP2_PROMPT_GUESTLOGIN "login:" -#define PAM_FREERDP2_PROMPT_USER "remote login:" -#define PAM_FREERDP2_PROMPT_HOST "remote host:" -#define PAM_FREERDP2_PROMPT_DOMAIN "remote domain:" -#define PAM_FREERDP2_PROMPT_PASSWORD "password:" - -#endif //_PAM_FREERDP2_H_ diff --git a/src/Makefile.am b/src/Makefile.am index ab3deed..7e25fd6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,62 +1,62 @@ NULL = pamlibdir = $(PAMMODULEDIR) -pamlib_LTLIBRARIES = pam_freerdp2.la +pamlib_LTLIBRARIES = pam_freerdp.la -pam_freerdp2_la_SOURCES = \ +pam_freerdp_la_SOURCES = \ auth-check-path.c auth-check-path.h \ - pam-freerdp2.c \ - pam-freerdp2-children.c \ + pam-freerdp.c \ + pam-freerdp-children.c \ $(NULL) -pam_freerdp2_la_LDFLAGS = \ +pam_freerdp_la_LDFLAGS = \ -no-undefined \ -module \ -avoid-version \ $(COVERAGE_LDFLAGS) \ $(NULL) -pam_freerdp2_la_CFLAGS = \ +pam_freerdp_la_CFLAGS = \ -Wall -Werror \ - -DAUTH_CHECK="\"$(libexecdir)/freerdp2-auth-check\"" \ + -DAUTH_CHECK="\"$(libexecdir)/freerdp-auth-check\"" \ $(COVERAGE_CFLAGS) \ $(NULL) -pam_freerdp2_la_CPPFLAGS = \ +pam_freerdp_la_CPPFLAGS = \ -I$(top_srcdir)/include \ $(NULL) -pam_freerdp2_la_LIBADD = \ +pam_freerdp_la_LIBADD = \ -lpam \ $(NULL) -pam_freerdp2includedir = $(includedir)/security/ -pam_freerdp2include_HEADERS = \ - $(top_srcdir)/include/pam-freerdp2.h \ +pam_freerdpincludedir = $(includedir)/security/ +pam_freerdpinclude_HEADERS = \ + $(top_srcdir)/include/pam-freerdp.h \ $(NULL) libexec_PROGRAMS = \ - freerdp2-auth-check \ + freerdp-auth-check \ $(NULL) -freerdp2_auth_check_SOURCES = \ - freerdp2-auth-check.c \ +freerdp_auth_check_SOURCES = \ + freerdp-auth-check.c \ $(NULL) -freerdp2_auth_check_CFLAGS = \ +freerdp_auth_check_CFLAGS = \ -Wall -Werror \ - $(FREERDP2_CFLAGS) \ - $(WINPR2_CFLAGS) \ + $(FREERDP_CFLAGS) \ + $(WINPR_CFLAGS) \ $(COVERAGE_CFLAGS) \ $(NULL) -freerdp2_auth_check_LDADD = \ - $(FREERDP2_LIBS) \ - $(WINPR2_LIBS) \ +freerdp_auth_check_LDADD = \ + $(FREERDP_LIBS) \ + $(WINPR_LIBS) \ $(NULL) -freerdp2_auth_check_LDFLAGS = \ - $(FREERDP2_LDFLAGS) \ - $(WINPR2_LDFLAGS) \ +freerdp_auth_check_LDFLAGS = \ + $(FREERDP_LDFLAGS) \ + $(WINPR_LDFLAGS) \ $(COVERAGE_LDFLAGS) \ $(NULL) diff --git a/src/freerdp-auth-check.c b/src/freerdp-auth-check.c new file mode 100644 index 0000000..7a60f7e --- /dev/null +++ b/src/freerdp-auth-check.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Ted Gould + */ + +#include +#include +#include +#include +#include + + +BOOL +auth_context_new (freerdp __attribute__((unused)) *instance, rdpContext __attribute__((unused)) *context) +{ + return TRUE; +} + +void +auth_context_free (freerdp __attribute__((unused)) *instance, rdpContext __attribute__((unused)) *context) +{ + return; +} + +BOOL +auth_pre_connect (freerdp __attribute__((unused)) *instance) +{ + return TRUE; +} + +BOOL +auth_post_connect (freerdp __attribute__((unused)) *instance) +{ + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + char password[512]; + if (argc != 4) { + printf("Usage: echo | freerdp-auth-check [:] \n\n"); + printf("ERROR: Incorrect number of parameters.\n\n"); + return -1; + } + + if (scanf("%511s", password) != 1) { + return -1; + } + + if (mlock(password, sizeof(password)) != 0) { + return -1; + } + +#ifndef ENABLE_WLOG + wLog* root = WLog_GetRoot(); + + if (!WLog_SetStringLogLevel(root, "OFF")){ + return -1; + } +#endif + freerdp * instance = freerdp_new(); + + instance->PreConnect = auth_pre_connect; + instance->PostConnect = auth_post_connect; + + instance->ContextSize = sizeof(rdpContext); + instance->ContextNew = auth_context_new; + instance->ContextFree = auth_context_free; + + if (!freerdp_context_new(instance)) { + printf("Couldn't create freerdp_context\n"); + return -1; + } + + char * colonloc = strstr(argv[1], ":"); + if (colonloc != NULL) { + /* We've got a port to deal with */ + colonloc[0] = '\0'; + colonloc++; +#if FREERDP_VERSION_MAJOR >= 3 + freerdp_settings_set_uint32(instance->context->settings, FreeRDP_ServerPort, strtoul(colonloc, NULL, 10)); +#else + instance->settings->ServerPort = strtoul(colonloc, NULL, 10); +#endif + } + +#if FREERDP_VERSION_MAJOR >= 3 + freerdp_settings_set_bool(instance->context->settings, FreeRDP_AuthenticationOnly, TRUE); + freerdp_settings_set_string(instance->context->settings, FreeRDP_ServerHostname, argv[1]); + freerdp_settings_set_string(instance->context->settings, FreeRDP_Username, argv[2]); + freerdp_settings_set_string(instance->context->settings, FreeRDP_Domain, argv[3]); + freerdp_settings_set_string(instance->context->settings, FreeRDP_Password, password); +#else + instance->settings->AuthenticationOnly = TRUE; + instance->settings->ServerHostname = argv[1]; + instance->settings->Username = argv[2]; + instance->settings->Domain = argv[3]; + instance->settings->Password = password; +#endif + + BOOL connection_successful; + connection_successful = freerdp_connect(instance); + freerdp_disconnect(instance); + + memset(password, 0, sizeof(password)); + munlock(password, sizeof(password)); +#if FREERDP_VERSION_MAJOR >= 3 + freerdp_settings_set_string(instance->context->settings, FreeRDP_Password, NULL); + freerdp_settings_set_string(instance->context->settings, FreeRDP_ServerHostname, NULL); + freerdp_settings_set_string(instance->context->settings, FreeRDP_Username, NULL); + freerdp_settings_set_string(instance->context->settings, FreeRDP_Domain, NULL); +#else + instance->settings->Password = NULL; + instance->settings->ServerHostname = NULL; + instance->settings->Username = NULL; + instance->settings->Domain = NULL; +#endif + + int retval = 0; + if (!connection_successful) { + retval = freerdp_get_last_error(instance->context); + } + + freerdp_context_free(instance); + freerdp_free(instance); + + return retval; +} diff --git a/src/freerdp2-auth-check.c b/src/freerdp2-auth-check.c deleted file mode 100644 index ab3b1fd..0000000 --- a/src/freerdp2-auth-check.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Ted Gould - */ - -#include -#include -#include -#include -#include - - -BOOL -auth_context_new (freerdp __attribute__((unused)) *instance, rdpContext __attribute__((unused)) *context) -{ - return TRUE; -} - -void -auth_context_free (freerdp __attribute__((unused)) *instance, rdpContext __attribute__((unused)) *context) -{ - return; -} - -BOOL -auth_pre_connect (freerdp __attribute__((unused)) *instance) -{ - return TRUE; -} - -BOOL -auth_post_connect (freerdp __attribute__((unused)) *instance) -{ - return TRUE; -} - -int -main (int argc, char *argv[]) -{ - char password[512]; - if (argc != 4) { - printf("Usage: echo | freerdp2-auth-check [:] \n\n"); - printf("ERROR: Incorrect number of parameters.\n\n"); - return -1; - } - - if (scanf("%511s", password) != 1) { - return -1; - } - - if (mlock(password, sizeof(password)) != 0) { - return -1; - } - -#ifndef ENABLE_WLOG - wLog* root = WLog_GetRoot(); - - if (!WLog_SetStringLogLevel(root, "OFF")){ - return -1; - } -#endif - freerdp * instance = freerdp_new(); - - instance->PreConnect = auth_pre_connect; - instance->PostConnect = auth_post_connect; - - instance->ContextSize = sizeof(rdpContext); - instance->ContextNew = auth_context_new; - instance->ContextFree = auth_context_free; - - if (!freerdp_context_new(instance)) { - printf("Couldn't create freerdp_context\n"); - return -1; - } - - char * colonloc = strstr(argv[1], ":"); - if (colonloc != NULL) { - /* We've got a port to deal with */ - colonloc[0] = '\0'; - colonloc++; - - instance->settings->ServerPort = strtoul(colonloc, NULL, 10); - } - - instance->settings->AuthenticationOnly = TRUE; - instance->settings->ServerHostname = argv[1]; - instance->settings->Username = argv[2]; - instance->settings->Domain = argv[3]; - instance->settings->Password = password; - - BOOL connection_successful; - connection_successful = freerdp_connect(instance); - freerdp_disconnect(instance); - - memset(password, 0, sizeof(password)); - munlock(password, sizeof(password)); - instance->settings->Password = NULL; - instance->settings->ServerHostname = NULL; - instance->settings->Username = NULL; - instance->settings->Domain = NULL; - - int retval = 0; - if (!connection_successful) { - retval = freerdp_get_last_error(instance->context); - } - - freerdp_context_free(instance); - freerdp_free(instance); - - return retval; -} diff --git a/src/pam-freerdp-children.c b/src/pam-freerdp-children.c new file mode 100644 index 0000000..8cd4ef8 --- /dev/null +++ b/src/pam-freerdp-children.c @@ -0,0 +1,230 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Ted Gould + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pam-freerdp-children.h" +#include "auth-check-path.h" + +void +pam_sm_authenticate_helper (int *stdinpipe, const char* username, const char* rhost, const char* ruser, const char* rdomain) +{ + + dup2(stdinpipe[0], 0); + + char * args[5]; + + args[0] = (char *)auth_check_path; + args[1] = (char *)rhost; + args[2] = (char *)ruser; + args[3] = (char *)rdomain; + args[4] = NULL; + + struct passwd * pwdent = getpwnam(username); + if (pwdent == NULL) { + _exit(EXIT_FAILURE); + } + + /* Setting groups, but allowing EPERM as if we're not 100% root + we might not be able to do this */ + if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { + _exit(EXIT_FAILURE); + } + + if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || + setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { + _exit(EXIT_FAILURE); + } + + if (clearenv() != 0) { + _exit(EXIT_FAILURE); + } + + if (chdir(pwdent->pw_dir) != 0) { + _exit(EXIT_FAILURE); + } + + setenv("HOME", pwdent->pw_dir, 1); + + execvp(args[0], args); + _exit(0); +} + +int +session_socket_handler (struct passwd * pwdent, int readypipe, const char * ruser, const char * rhost, const char * rdomain, const char * password) +{ + /* Socket stuff */ + int socketfd = 0; + struct sockaddr_un socket_addr; + + /* Connected user */ + socklen_t connected_addr_size; + int connectfd = 0; + struct sockaddr_un connected_addr; + + /* Our buffer */ + char * buffer = NULL; + int buffer_len = 0; + int buffer_fill = 0; + + /* Track write out */ + int writedata = 0; + + /* Track ready writing */ + int readywrite = 0; + + /* Setting groups, but allowing EPERM as if we're not 100% root + we might not be able to do this */ + if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { + _exit(EXIT_FAILURE); + } + + if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || + setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { + /* Don't need to clean up yet */ + return EXIT_FAILURE; + } + + if (clearenv() != 0) { + /* Don't need to clean up yet */ + return EXIT_FAILURE; + } + + if (chdir(pwdent->pw_dir) != 0) { + /* Don't need to clean up yet */ + return EXIT_FAILURE; + } + + if (rdomain[0] == '\0') { + rdomain = "."; + } + + /* Build this up as a buffer so we can just write it and see that + very, very clearly */ + buffer_len += strlen(ruser) + 1; /* Add one for the space */ + buffer_len += strlen(rhost) + 1; /* Add one for the space */ + buffer_len += strlen(rdomain) + 1; /* Add one for the space */ + buffer_len += strlen(password) + 1; /* Add one for the NULL */ + + if (buffer_len < 5) { + /* Don't need to clean up yet */ + return EXIT_FAILURE; + } + + buffer = malloc(buffer_len); + + if (buffer == NULL) { + /* Don't need to clean up yet */ + return EXIT_FAILURE; + } + + /* Lock the buffer before writing */ + if (mlock(buffer, buffer_len) != 0) { + /* We can't lock, we go home */ + goto cleanup; + } + + buffer_fill = snprintf(buffer, buffer_len, "%s %s %s %s", ruser, password, rdomain, rhost); + if (buffer_fill > buffer_len) { + /* This really shouldn't happen, but if for some reason we have an + difference between they way that the lengths are calculated we want + to catch that. */ + goto cleanup; + } + + /* Make our socket and bind it */ + socketfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (socketfd < 0) { + goto cleanup; + } + + memset(&socket_addr, 0, sizeof(struct sockaddr_un)); + socket_addr.sun_family = AF_UNIX; + strncpy(socket_addr.sun_path, pwdent->pw_dir, sizeof(socket_addr.sun_path) - 1); + strncpy(socket_addr.sun_path + strlen(pwdent->pw_dir), "/.freerdp-socket", (sizeof(socket_addr.sun_path) - strlen(pwdent->pw_dir)) - 1); + + /* We bind the socket before forking so that we ensure that + there isn't a race condition to get to it. Things will block + otherwise. */ + if (bind(socketfd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) < 0) { + goto cleanup; + } + + /* Set the socket file permissions to be 600 and the user and group + to be the guest user. NOTE: This won't protect on BSD */ + if (chmod(socket_addr.sun_path, S_IRUSR | S_IWUSR) != 0 || + chown(socket_addr.sun_path, pwdent->pw_uid, pwdent->pw_gid) != 0) { + goto cleanup; + } + + if (listen(socketfd, 1) < 0) { + goto cleanup; + } + + readywrite = write(readypipe, ALL_GOOD_SIGNAL, strlen(ALL_GOOD_SIGNAL) + 1); + if (readywrite != strlen(ALL_GOOD_SIGNAL) + 1) { + goto cleanup; + } + + connected_addr_size = sizeof(struct sockaddr_un); + connectfd = accept(socketfd, (struct sockaddr *)&connected_addr, &connected_addr_size); + if (connectfd < 0) { + goto cleanup; + } + + writedata = write(connectfd, buffer, buffer_len); + +cleanup: + if (socketfd != 0) { + close(socketfd); + } + if (connectfd != 0) { + close(connectfd); + } + + if (buffer != NULL) { + memset(buffer, 0, buffer_len); + munlock(buffer, buffer_len); + free(buffer); + buffer = NULL; + } + + /* This should be only true on the write, so we can use this to check + out as writedata is init to 0 */ + if (writedata == buffer_len) { + _exit (0); + } + + _exit(EXIT_FAILURE); +} diff --git a/src/pam-freerdp-children.h b/src/pam-freerdp-children.h new file mode 100644 index 0000000..1109587 --- /dev/null +++ b/src/pam-freerdp-children.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Ted Gould + */ + +#ifndef _PAM_FREERDP_CHILDREN_H_ +#define _PAM_FREERDP_CHILDREN_H_ + +#define PAM_TYPE_RDP_USER 1234 +#define PAM_TYPE_RDP_SERVER 1235 +#define PAM_TYPE_RDP_DOMAIN 1236 +#define ALL_GOOD_SIGNAL "Ar, ready to authenticate cap'n" + +void +pam_sm_authenticate_helper (int *stdinpipe, const char* username, const char* rhost, const char* ruser, const char* rdomain); + +int +session_socket_handler (struct passwd * pwdent, int readypipe, const char * ruser, const char * rhost, const char * rdomain, const char * password); +#endif //_PAM_FREERDP_CHILDREN_H_ diff --git a/src/pam-freerdp-private.h b/src/pam-freerdp-private.h new file mode 100644 index 0000000..0b7520f --- /dev/null +++ b/src/pam-freerdp-private.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2018 Mike Gabriel + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Mike Gabriel + * Author libpam-freerdp (where we forked from): Ted Gould + */ + +#ifndef _PAM_FREERDP_PRIVATE_H_ +#define _PAM_FREERDP_PRIVATE_H_ + +PAM_EXTERN int +pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv); +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char ** argv); +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, const char **argv); +PAM_EXTERN int +pam_sm_setcred (pam_handle_t *pamh, int flags, int argc, const char ** argv); + +#endif //_PAM_FREERDP_PRIVATE_H_ diff --git a/src/pam-freerdp.c b/src/pam-freerdp.c new file mode 100644 index 0000000..8bf505f --- /dev/null +++ b/src/pam-freerdp.c @@ -0,0 +1,472 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Ted Gould + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAM_SM_AUTH +#define PAM_SM_SESSION +#include +#include +#include + +#include "pam-freerdp.h" + +#include "pam-freerdp-children.h" +#include "auth-check-path.h" + +static int unpriveleged_kill (struct passwd * pwdent); + +static char * global_rdp_user = NULL; +static char * global_rdp_domain = NULL; +static char * global_rdp_server = NULL; +/* FIXME? This is a work around to the fact that PAM seems to be clearing + the auth token between authorize and open_session. Which then requires + us to save it. Seems like we're the wrong people to do it, but we have + no choice */ +static char * global_password = NULL; + +/* Either grab a value or prompt for it */ +static char * +get_item (pam_handle_t * pamh, int type) +{ + /* Check to see if we just have the value. If we do, great + let's dup it some we're consistently allocating memory */ + if ((type == PAM_USER) || (type == PAM_AUTHTOK)) { + /* If it's not an RDP parameter type we can use the PAM functions because the PAM + functions don't support RDP parameters */ + char * value = NULL; + if (pam_get_item(pamh, type, (const void **)&value) == PAM_SUCCESS && value != NULL) { + return value; + } + if (type == PAM_AUTHTOK && global_password != NULL) { + /* If we're looking for a password, we didn't get one, before + prompting see if we've got a global one. */ + return global_password; + } + } else { + /* Here we deal with all RDP specific parameters */ + if ((type == PAM_TYPE_RDP_USER) && (global_rdp_user != NULL)) { + return global_rdp_user; + } + if ((type == PAM_TYPE_RDP_SERVER) && (global_rdp_server != NULL)) { + return global_rdp_server; + } + if ((type == PAM_TYPE_RDP_DOMAIN) && (global_rdp_domain != NULL)) { + return global_rdp_domain; + } + } + /* Now we need to prompt */ + + /* Build up the message we're prompting for */ + struct pam_message message; + const struct pam_message * pmessage = &message; + + message.msg = NULL; + message.msg_style = PAM_PROMPT_ECHO_ON; + + switch (type) { + case PAM_USER: + message.msg = PAM_FREERDP_PROMPT_GUESTLOGIN; + break; + case PAM_TYPE_RDP_USER: + message.msg = PAM_FREERDP_PROMPT_USER; + break; + case PAM_TYPE_RDP_SERVER: + message.msg = PAM_FREERDP_PROMPT_HOST; + break; + case PAM_AUTHTOK: + message.msg = PAM_FREERDP_PROMPT_PASSWORD; + message.msg_style = PAM_PROMPT_ECHO_OFF; + break; + case PAM_TYPE_RDP_DOMAIN: + message.msg = PAM_FREERDP_PROMPT_DOMAIN; + break; + default: + return NULL; + } + + struct pam_conv * conv = NULL; + if (pam_get_item(pamh, PAM_CONV, (const void **)&conv) != PAM_SUCCESS || conv == NULL || conv->conv == NULL) { + return NULL; + } + + struct pam_response * responses = NULL; + if (conv->conv(1, &pmessage, &responses, conv->appdata_ptr) != PAM_SUCCESS || responses == NULL) { + return NULL; + } + + char * promptval = responses->resp; + free(responses); + + /* If we didn't get anything, just move on */ + if (promptval == NULL) { + return NULL; + } + + if (type == PAM_AUTHTOK) { + if (strlen(promptval) == 0){ + free(promptval); + return NULL; + } + + if (mlock(promptval, strlen(promptval) + 1) != 0) { + free(promptval); + return NULL; + } + } + + /* The way that xfreerdp does parsing means that we can't handle + spaces in the username. Let's block them as early as possible. + Though, if the xfreerdp part gets fixed, we want this to disappear + http://launchpad.net/bugs/1053102 + */ + if (type == PAM_TYPE_RDP_USER) { + if (strstr(promptval, " ") != NULL) { + free(promptval); + return NULL; + } + } + + if (type == PAM_TYPE_RDP_SERVER) { + char * subloc = strstr(promptval, "://"); + if (subloc != NULL) { + char * original = promptval; + char * newish = subloc + strlen("://"); + char * endslash = strstr(newish, "/"); + + if (endslash != NULL) { + endslash[0] = '\0'; + } + + promptval = strdup(newish); + free(original); + } + } + + char * retval = NULL; + if (promptval != NULL) { /* Can't believe it really would be at this point, but let's be sure */ + if ((type == PAM_USER) || (type == PAM_AUTHTOK)) { + /* We can only use the PAM functions for types supported by PAM */ + pam_set_item(pamh, type, (const void *)promptval); + /* We're returning the value saved by PAM so we can clear promptval */ + pam_get_item(pamh, type, (const void **)&retval); + } + /* Here we deal with all RDP specific parameters */ + if (type == PAM_TYPE_RDP_USER) { + /* The remote user can be saved globally */ + if (global_rdp_user != NULL) { + free(global_rdp_user); + } + global_rdp_user = strdup(promptval); + retval = global_rdp_user; + } + if (type == PAM_TYPE_RDP_SERVER) { + /* The remote server can be saved globally */ + if (global_rdp_server != NULL) { + free(global_rdp_server); + } + global_rdp_server = strdup(promptval); + retval = global_rdp_server; + } + if (type == PAM_TYPE_RDP_DOMAIN) { + /* The remote domain can be saved globally */ + if (global_rdp_domain != NULL) { + free(global_rdp_domain); + } + global_rdp_domain = strdup(promptval); + retval = global_rdp_domain; + } + if (type == PAM_AUTHTOK) { + /* We also save the password globally if we've got one */ + if (global_password != NULL) { + memset(global_password, 0, strlen(global_password)); + munlock(global_password, strlen(global_password) + 1); + free(global_password); + } + global_password = strdup(promptval); + if (mlock(global_password, strlen(global_password) + 1) != 0) { + /* Woah, can't lock it. Can't keep it. */ + free(global_password); + global_password = NULL; + } else { + retval = global_password; + } + } + + if (type == PAM_AUTHTOK) { + memset(promptval, 0, strlen(promptval) + 1); + munlock(promptval, strlen(promptval) + 1); + } + + free(promptval); + } + + return retval; +} + +#define GET_ITEM(val, type) \ + if ((val = get_item(pamh, type)) == NULL) { \ + retval = PAM_AUTH_ERR; \ + goto done; \ + } + +/* Authenticate. We need to make sure we have a user account, that + there are remote accounts and then verify them with FreeRDP */ +PAM_EXTERN int +pam_sm_authenticate (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) +{ + char * username = NULL; + char * password = NULL; + char * ruser = NULL; + char * rhost = NULL; + char * rdomain = NULL; + int retval = PAM_IGNORE; + + /* Get all the values, or prompt for them, or return with + an auth error */ + GET_ITEM(username, PAM_USER); + GET_ITEM(ruser, PAM_TYPE_RDP_USER); + GET_ITEM(rhost, PAM_TYPE_RDP_SERVER); + GET_ITEM(rdomain, PAM_TYPE_RDP_DOMAIN); + GET_ITEM(password, PAM_AUTHTOK); + + int stdinpipe[2]; + if (pipe(stdinpipe) != 0) { + retval = PAM_SYSTEM_ERR; + goto done; + } + + /* At this point we should have the values, let's check the auth */ + pid_t pid; + switch (pid = fork()) { + case 0: { /* child */ + pam_sm_authenticate_helper (stdinpipe, username, rhost, ruser, rdomain); + break; + } + case -1: { /* fork'n error! */ + retval = PAM_SYSTEM_ERR; + break; + } + default: { + int forkret = 0; + int bytesout = 0; + + bytesout += write(stdinpipe[1], password, strlen(password)); + bytesout += write(stdinpipe[1], "\n", 1); + + close(stdinpipe[1]); + + if (waitpid(pid, &forkret, 0) < 0 || bytesout == 0) { + retval = PAM_SYSTEM_ERR; + } else if (forkret == 0) { + retval = PAM_SUCCESS; + } else { + retval = PAM_AUTH_ERR; + } + } + } + + /* Return our status */ +done: + return retval; +} + + + +pid_t session_pid = 0; +/* Open Session. Here we need to fork a little process so that we can + give the credentials to the session itself so that it can startup the + xfreerdp viewer for the login */ +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) +{ + char * username = NULL; + char * password = NULL; + char * ruser = NULL; + char * rhost = NULL; + char * rdomain = NULL; + int retval = PAM_SUCCESS; + + /* Get all the values, or prompt for them, or return with + an auth error */ + GET_ITEM(username, PAM_USER); + GET_ITEM(ruser, PAM_TYPE_RDP_USER); + GET_ITEM(rhost, PAM_TYPE_RDP_SERVER); + GET_ITEM(rdomain, PAM_TYPE_RDP_DOMAIN); + GET_ITEM(password, PAM_AUTHTOK); + + struct passwd * pwdent = getpwnam(username); + if (pwdent == NULL) { + retval = PAM_SYSTEM_ERR; + goto done; + } + + if (session_pid != 0) { + unpriveleged_kill(pwdent); + } + + int sessionready[2]; + if (pipe(sessionready) != 0) { + retval = PAM_SYSTEM_ERR; + goto done; + } + + pid_t pid = fork(); + if (pid == 0) { + + int ret = session_socket_handler(pwdent, sessionready[1], ruser, rhost, rdomain, password); + + close(sessionready[1]); + _exit(ret); + } else if (pid < 0) { + close(sessionready[0]); + close(sessionready[1]); + + retval = PAM_SYSTEM_ERR; + } else { + char readbuffer[strlen(ALL_GOOD_SIGNAL) + 1]; + int readlen = 0; + + readlen = read(sessionready[0], readbuffer, strlen(ALL_GOOD_SIGNAL) + 1); + + close(sessionready[0]); + + if (readlen == strlen(ALL_GOOD_SIGNAL) + 1) { + session_pid = pid; + } else { + retval = PAM_SYSTEM_ERR; + } + } + +done: + return retval; +} + +/* Close Session. Make sure our little guy has died so he doesn't become + a zombie and eat things. */ +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) +{ + if (session_pid == 0) { + return PAM_IGNORE; + } + + char * username = NULL; + int retval = PAM_SUCCESS; + + GET_ITEM(username, PAM_USER); + + struct passwd * pwdent = getpwnam(username); + if (pwdent == NULL) { + retval = PAM_SYSTEM_ERR; + goto done; + } + + retval = unpriveleged_kill(pwdent); + +done: + return retval; +} + +/* Drop privs and try to kill the process with the PID of session_pid. + This ensures that we don't kill something important if there is PID wrap + around. */ +static int +unpriveleged_kill (struct passwd * pwdent) +{ + int retval = PAM_SUCCESS; + + pid_t pid = fork(); + if (pid == 0) { + /* Setting groups, but allowing EPERM as if we're not 100% root + we might not be able to do this */ + if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { + _exit(EXIT_FAILURE); + } + + if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || + setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { + _exit(EXIT_FAILURE); + } + + if (clearenv() != 0) { + _exit(EXIT_FAILURE); + } + + int killval = kill(session_pid, SIGKILL); + session_pid = 0; + + if (killval != 0) { + printf("Unable to kill\n"); + } + + /* NOTE: We're ignoring whether we could kill it or not. It'd be nice to + track that but there are a lot of reason that we could fail there and + it's not a bad thing. Really we're attempting a best effort to clean up + we won't be able to guarantee it. */ + _exit(EXIT_SUCCESS); + } else if (pid < 0) { + retval = PAM_SYSTEM_ERR; + } else { + int forkret = 0; + + if (waitpid(pid, &forkret, 0) < 0) { + retval = PAM_SYSTEM_ERR; + } + } + + /* We reset this no matter. If we error'd trying to do it, we don't + want to try again. We'll just return the error for this time. */ + session_pid = 0; + + return retval; +} + +/* LightDM likes to have this function around, but we don't need it as we + don't have a token hanging around. */ +PAM_EXTERN int +pam_sm_setcred (pam_handle_t __attribute__((unused)) *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) +{ + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +struct pam_module _pam_freerdp_modstruct = { + "pam_freerdp", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif diff --git a/src/pam-freerdp2-children.c b/src/pam-freerdp2-children.c deleted file mode 100644 index 91b4a3a..0000000 --- a/src/pam-freerdp2-children.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Ted Gould - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "pam-freerdp2-children.h" -#include "auth-check-path.h" - -void -pam_sm_authenticate_helper (int *stdinpipe, const char* username, const char* rhost, const char* ruser, const char* rdomain) -{ - - dup2(stdinpipe[0], 0); - - char * args[5]; - - args[0] = (char *)auth_check_path; - args[1] = (char *)rhost; - args[2] = (char *)ruser; - args[3] = (char *)rdomain; - args[4] = NULL; - - struct passwd * pwdent = getpwnam(username); - if (pwdent == NULL) { - _exit(EXIT_FAILURE); - } - - /* Setting groups, but allowing EPERM as if we're not 100% root - we might not be able to do this */ - if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { - _exit(EXIT_FAILURE); - } - - if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || - setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { - _exit(EXIT_FAILURE); - } - - if (clearenv() != 0) { - _exit(EXIT_FAILURE); - } - - if (chdir(pwdent->pw_dir) != 0) { - _exit(EXIT_FAILURE); - } - - setenv("HOME", pwdent->pw_dir, 1); - - execvp(args[0], args); - _exit(0); -} - -int -session_socket_handler (struct passwd * pwdent, int readypipe, const char * ruser, const char * rhost, const char * rdomain, const char * password) -{ - /* Socket stuff */ - int socketfd = 0; - struct sockaddr_un socket_addr; - - /* Connected user */ - socklen_t connected_addr_size; - int connectfd = 0; - struct sockaddr_un connected_addr; - - /* Our buffer */ - char * buffer = NULL; - int buffer_len = 0; - int buffer_fill = 0; - - /* Track write out */ - int writedata = 0; - - /* Track ready writing */ - int readywrite = 0; - - /* Setting groups, but allowing EPERM as if we're not 100% root - we might not be able to do this */ - if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { - _exit(EXIT_FAILURE); - } - - if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || - setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { - /* Don't need to clean up yet */ - return EXIT_FAILURE; - } - - if (clearenv() != 0) { - /* Don't need to clean up yet */ - return EXIT_FAILURE; - } - - if (chdir(pwdent->pw_dir) != 0) { - /* Don't need to clean up yet */ - return EXIT_FAILURE; - } - - if (rdomain[0] == '\0') { - rdomain = "."; - } - - /* Build this up as a buffer so we can just write it and see that - very, very clearly */ - buffer_len += strlen(ruser) + 1; /* Add one for the space */ - buffer_len += strlen(rhost) + 1; /* Add one for the space */ - buffer_len += strlen(rdomain) + 1; /* Add one for the space */ - buffer_len += strlen(password) + 1; /* Add one for the NULL */ - - if (buffer_len < 5) { - /* Don't need to clean up yet */ - return EXIT_FAILURE; - } - - buffer = malloc(buffer_len); - - if (buffer == NULL) { - /* Don't need to clean up yet */ - return EXIT_FAILURE; - } - - /* Lock the buffer before writing */ - if (mlock(buffer, buffer_len) != 0) { - /* We can't lock, we go home */ - goto cleanup; - } - - buffer_fill = snprintf(buffer, buffer_len, "%s %s %s %s", ruser, password, rdomain, rhost); - if (buffer_fill > buffer_len) { - /* This really shouldn't happen, but if for some reason we have an - difference between they way that the lengths are calculated we want - to catch that. */ - goto cleanup; - } - - /* Make our socket and bind it */ - socketfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (socketfd < 0) { - goto cleanup; - } - - memset(&socket_addr, 0, sizeof(struct sockaddr_un)); - socket_addr.sun_family = AF_UNIX; - strncpy(socket_addr.sun_path, pwdent->pw_dir, sizeof(socket_addr.sun_path) - 1); - strncpy(socket_addr.sun_path + strlen(pwdent->pw_dir), "/.freerdp2-socket", (sizeof(socket_addr.sun_path) - strlen(pwdent->pw_dir)) - 1); - - /* We bind the socket before forking so that we ensure that - there isn't a race condition to get to it. Things will block - otherwise. */ - if (bind(socketfd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) < 0) { - goto cleanup; - } - - /* Set the socket file permissions to be 600 and the user and group - to be the guest user. NOTE: This won't protect on BSD */ - if (chmod(socket_addr.sun_path, S_IRUSR | S_IWUSR) != 0 || - chown(socket_addr.sun_path, pwdent->pw_uid, pwdent->pw_gid) != 0) { - goto cleanup; - } - - if (listen(socketfd, 1) < 0) { - goto cleanup; - } - - readywrite = write(readypipe, ALL_GOOD_SIGNAL, strlen(ALL_GOOD_SIGNAL) + 1); - if (readywrite != strlen(ALL_GOOD_SIGNAL) + 1) { - goto cleanup; - } - - connected_addr_size = sizeof(struct sockaddr_un); - connectfd = accept(socketfd, (struct sockaddr *)&connected_addr, &connected_addr_size); - if (connectfd < 0) { - goto cleanup; - } - - writedata = write(connectfd, buffer, buffer_len); - -cleanup: - if (socketfd != 0) { - close(socketfd); - } - if (connectfd != 0) { - close(connectfd); - } - - if (buffer != NULL) { - memset(buffer, 0, buffer_len); - munlock(buffer, buffer_len); - free(buffer); - buffer = NULL; - } - - /* This should be only true on the write, so we can use this to check - out as writedata is init to 0 */ - if (writedata == buffer_len) { - _exit (0); - } - - _exit(EXIT_FAILURE); -} diff --git a/src/pam-freerdp2-children.h b/src/pam-freerdp2-children.h deleted file mode 100644 index dac3b19..0000000 --- a/src/pam-freerdp2-children.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Ted Gould - */ - -#ifndef _PAM_FREERDP2_CHILDREN_H_ -#define _PAM_FREERDP2_CHILDREN_H_ - -#define PAM_TYPE_RDP_USER 1234 -#define PAM_TYPE_RDP_SERVER 1235 -#define PAM_TYPE_RDP_DOMAIN 1236 -#define ALL_GOOD_SIGNAL "Ar, ready to authenticate cap'n" - -void -pam_sm_authenticate_helper (int *stdinpipe, const char* username, const char* rhost, const char* ruser, const char* rdomain); - -int -session_socket_handler (struct passwd * pwdent, int readypipe, const char * ruser, const char * rhost, const char * rdomain, const char * password); -#endif //_PAM_FREERDP2_CHILDREN_H_ diff --git a/src/pam-freerdp2-private.h b/src/pam-freerdp2-private.h deleted file mode 100644 index 74663ef..0000000 --- a/src/pam-freerdp2-private.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright © 2018 Mike Gabriel - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Mike Gabriel - * Author libpam-freerdp (where we forked from): Ted Gould - */ - -#ifndef _PAM_FREERDP2_PRIVATE_H_ -#define _PAM_FREERDP2_PRIVATE_H_ - -PAM_EXTERN int -pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv); -PAM_EXTERN int -pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char ** argv); -PAM_EXTERN int -pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, const char **argv); -PAM_EXTERN int -pam_sm_setcred (pam_handle_t *pamh, int flags, int argc, const char ** argv); - -#endif //_PAM_FREERDP2_PRIVATE_H_ diff --git a/src/pam-freerdp2.c b/src/pam-freerdp2.c deleted file mode 100644 index 593dde5..0000000 --- a/src/pam-freerdp2.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Ted Gould - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PAM_SM_AUTH -#define PAM_SM_SESSION -#include -#include -#include - -#include "pam-freerdp2.h" - -#include "pam-freerdp2-children.h" -#include "auth-check-path.h" - -static int unpriveleged_kill (struct passwd * pwdent); - -static char * global_rdp_user = NULL; -static char * global_rdp_domain = NULL; -static char * global_rdp_server = NULL; -/* FIXME? This is a work around to the fact that PAM seems to be clearing - the auth token between authorize and open_session. Which then requires - us to save it. Seems like we're the wrong people to do it, but we have - no choice */ -static char * global_password = NULL; - -/* Either grab a value or prompt for it */ -static char * -get_item (pam_handle_t * pamh, int type) -{ - /* Check to see if we just have the value. If we do, great - let's dup it some we're consistently allocating memory */ - if ((type == PAM_USER) || (type == PAM_AUTHTOK)) { - /* If it's not an RDP parameter type we can use the PAM functions because the PAM - functions don't support RDP parameters */ - char * value = NULL; - if (pam_get_item(pamh, type, (const void **)&value) == PAM_SUCCESS && value != NULL) { - return value; - } - if (type == PAM_AUTHTOK && global_password != NULL) { - /* If we're looking for a password, we didn't get one, before - prompting see if we've got a global one. */ - return global_password; - } - } else { - /* Here we deal with all RDP specific parameters */ - if ((type == PAM_TYPE_RDP_USER) && (global_rdp_user != NULL)) { - return global_rdp_user; - } - if ((type == PAM_TYPE_RDP_SERVER) && (global_rdp_server != NULL)) { - return global_rdp_server; - } - if ((type == PAM_TYPE_RDP_DOMAIN) && (global_rdp_domain != NULL)) { - return global_rdp_domain; - } - } - /* Now we need to prompt */ - - /* Build up the message we're prompting for */ - struct pam_message message; - const struct pam_message * pmessage = &message; - - message.msg = NULL; - message.msg_style = PAM_PROMPT_ECHO_ON; - - switch (type) { - case PAM_USER: - message.msg = PAM_FREERDP2_PROMPT_GUESTLOGIN; - break; - case PAM_TYPE_RDP_USER: - message.msg = PAM_FREERDP2_PROMPT_USER; - break; - case PAM_TYPE_RDP_SERVER: - message.msg = PAM_FREERDP2_PROMPT_HOST; - break; - case PAM_AUTHTOK: - message.msg = PAM_FREERDP2_PROMPT_PASSWORD; - message.msg_style = PAM_PROMPT_ECHO_OFF; - break; - case PAM_TYPE_RDP_DOMAIN: - message.msg = PAM_FREERDP2_PROMPT_DOMAIN; - break; - default: - return NULL; - } - - struct pam_conv * conv = NULL; - if (pam_get_item(pamh, PAM_CONV, (const void **)&conv) != PAM_SUCCESS || conv == NULL || conv->conv == NULL) { - return NULL; - } - - struct pam_response * responses = NULL; - if (conv->conv(1, &pmessage, &responses, conv->appdata_ptr) != PAM_SUCCESS || responses == NULL) { - return NULL; - } - - char * promptval = responses->resp; - free(responses); - - /* If we didn't get anything, just move on */ - if (promptval == NULL) { - return NULL; - } - - if (type == PAM_AUTHTOK) { - if (strlen(promptval) == 0){ - free(promptval); - return NULL; - } - - if (mlock(promptval, strlen(promptval) + 1) != 0) { - free(promptval); - return NULL; - } - } - - /* The way that xfreerdp does parsing means that we can't handle - spaces in the username. Let's block them as early as possible. - Though, if the xfreerdp part gets fixed, we want this to disappear - http://launchpad.net/bugs/1053102 - */ - if (type == PAM_TYPE_RDP_USER) { - if (strstr(promptval, " ") != NULL) { - free(promptval); - return NULL; - } - } - - if (type == PAM_TYPE_RDP_SERVER) { - char * subloc = strstr(promptval, "://"); - if (subloc != NULL) { - char * original = promptval; - char * newish = subloc + strlen("://"); - char * endslash = strstr(newish, "/"); - - if (endslash != NULL) { - endslash[0] = '\0'; - } - - promptval = strdup(newish); - free(original); - } - } - - char * retval = NULL; - if (promptval != NULL) { /* Can't believe it really would be at this point, but let's be sure */ - if ((type == PAM_USER) || (type == PAM_AUTHTOK)) { - /* We can only use the PAM functions for types supported by PAM */ - pam_set_item(pamh, type, (const void *)promptval); - /* We're returning the value saved by PAM so we can clear promptval */ - pam_get_item(pamh, type, (const void **)&retval); - } - /* Here we deal with all RDP specific parameters */ - if (type == PAM_TYPE_RDP_USER) { - /* The remote user can be saved globally */ - if (global_rdp_user != NULL) { - free(global_rdp_user); - } - global_rdp_user = strdup(promptval); - retval = global_rdp_user; - } - if (type == PAM_TYPE_RDP_SERVER) { - /* The remote server can be saved globally */ - if (global_rdp_server != NULL) { - free(global_rdp_server); - } - global_rdp_server = strdup(promptval); - retval = global_rdp_server; - } - if (type == PAM_TYPE_RDP_DOMAIN) { - /* The remote domain can be saved globally */ - if (global_rdp_domain != NULL) { - free(global_rdp_domain); - } - global_rdp_domain = strdup(promptval); - retval = global_rdp_domain; - } - if (type == PAM_AUTHTOK) { - /* We also save the password globally if we've got one */ - if (global_password != NULL) { - memset(global_password, 0, strlen(global_password)); - munlock(global_password, strlen(global_password) + 1); - free(global_password); - } - global_password = strdup(promptval); - if (mlock(global_password, strlen(global_password) + 1) != 0) { - /* Woah, can't lock it. Can't keep it. */ - free(global_password); - global_password = NULL; - } else { - retval = global_password; - } - } - - if (type == PAM_AUTHTOK) { - memset(promptval, 0, strlen(promptval) + 1); - munlock(promptval, strlen(promptval) + 1); - } - - free(promptval); - } - - return retval; -} - -#define GET_ITEM(val, type) \ - if ((val = get_item(pamh, type)) == NULL) { \ - retval = PAM_AUTH_ERR; \ - goto done; \ - } - -/* Authenticate. We need to make sure we have a user account, that - there are remote accounts and then verify them with FreeRDP */ -PAM_EXTERN int -pam_sm_authenticate (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) -{ - char * username = NULL; - char * password = NULL; - char * ruser = NULL; - char * rhost = NULL; - char * rdomain = NULL; - int retval = PAM_IGNORE; - - /* Get all the values, or prompt for them, or return with - an auth error */ - GET_ITEM(username, PAM_USER); - GET_ITEM(ruser, PAM_TYPE_RDP_USER); - GET_ITEM(rhost, PAM_TYPE_RDP_SERVER); - GET_ITEM(rdomain, PAM_TYPE_RDP_DOMAIN); - GET_ITEM(password, PAM_AUTHTOK); - - int stdinpipe[2]; - if (pipe(stdinpipe) != 0) { - retval = PAM_SYSTEM_ERR; - goto done; - } - - /* At this point we should have the values, let's check the auth */ - pid_t pid; - switch (pid = fork()) { - case 0: { /* child */ - pam_sm_authenticate_helper (stdinpipe, username, rhost, ruser, rdomain); - break; - } - case -1: { /* fork'n error! */ - retval = PAM_SYSTEM_ERR; - break; - } - default: { - int forkret = 0; - int bytesout = 0; - - bytesout += write(stdinpipe[1], password, strlen(password)); - bytesout += write(stdinpipe[1], "\n", 1); - - close(stdinpipe[1]); - - if (waitpid(pid, &forkret, 0) < 0 || bytesout == 0) { - retval = PAM_SYSTEM_ERR; - } else if (forkret == 0) { - retval = PAM_SUCCESS; - } else { - retval = PAM_AUTH_ERR; - } - } - } - - /* Return our status */ -done: - return retval; -} - - - -pid_t session_pid = 0; -/* Open Session. Here we need to fork a little process so that we can - give the credentials to the session itself so that it can startup the - xfreerdp viewer for the login */ -PAM_EXTERN int -pam_sm_open_session (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) -{ - char * username = NULL; - char * password = NULL; - char * ruser = NULL; - char * rhost = NULL; - char * rdomain = NULL; - int retval = PAM_SUCCESS; - - /* Get all the values, or prompt for them, or return with - an auth error */ - GET_ITEM(username, PAM_USER); - GET_ITEM(ruser, PAM_TYPE_RDP_USER); - GET_ITEM(rhost, PAM_TYPE_RDP_SERVER); - GET_ITEM(rdomain, PAM_TYPE_RDP_DOMAIN); - GET_ITEM(password, PAM_AUTHTOK); - - struct passwd * pwdent = getpwnam(username); - if (pwdent == NULL) { - retval = PAM_SYSTEM_ERR; - goto done; - } - - if (session_pid != 0) { - unpriveleged_kill(pwdent); - } - - int sessionready[2]; - if (pipe(sessionready) != 0) { - retval = PAM_SYSTEM_ERR; - goto done; - } - - pid_t pid = fork(); - if (pid == 0) { - - int ret = session_socket_handler(pwdent, sessionready[1], ruser, rhost, rdomain, password); - - close(sessionready[1]); - _exit(ret); - } else if (pid < 0) { - close(sessionready[0]); - close(sessionready[1]); - - retval = PAM_SYSTEM_ERR; - } else { - char readbuffer[strlen(ALL_GOOD_SIGNAL) + 1]; - int readlen = 0; - - readlen = read(sessionready[0], readbuffer, strlen(ALL_GOOD_SIGNAL) + 1); - - close(sessionready[0]); - - if (readlen == strlen(ALL_GOOD_SIGNAL) + 1) { - session_pid = pid; - } else { - retval = PAM_SYSTEM_ERR; - } - } - -done: - return retval; -} - -/* Close Session. Make sure our little guy has died so he doesn't become - a zombie and eat things. */ -PAM_EXTERN int -pam_sm_close_session (pam_handle_t *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) -{ - if (session_pid == 0) { - return PAM_IGNORE; - } - - char * username = NULL; - int retval = PAM_SUCCESS; - - GET_ITEM(username, PAM_USER); - - struct passwd * pwdent = getpwnam(username); - if (pwdent == NULL) { - retval = PAM_SYSTEM_ERR; - goto done; - } - - retval = unpriveleged_kill(pwdent); - -done: - return retval; -} - -/* Drop privs and try to kill the process with the PID of session_pid. - This ensures that we don't kill something important if there is PID wrap - around. */ -static int -unpriveleged_kill (struct passwd * pwdent) -{ - int retval = PAM_SUCCESS; - - pid_t pid = fork(); - if (pid == 0) { - /* Setting groups, but allowing EPERM as if we're not 100% root - we might not be able to do this */ - if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) { - _exit(EXIT_FAILURE); - } - - if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 || - setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) { - _exit(EXIT_FAILURE); - } - - if (clearenv() != 0) { - _exit(EXIT_FAILURE); - } - - int killval = kill(session_pid, SIGKILL); - session_pid = 0; - - if (killval != 0) { - printf("Unable to kill\n"); - } - - /* NOTE: We're ignoring whether we could kill it or not. It'd be nice to - track that but there are a lot of reason that we could fail there and - it's not a bad thing. Really we're attempting a best effort to clean up - we won't be able to guarantee it. */ - _exit(EXIT_SUCCESS); - } else if (pid < 0) { - retval = PAM_SYSTEM_ERR; - } else { - int forkret = 0; - - if (waitpid(pid, &forkret, 0) < 0) { - retval = PAM_SYSTEM_ERR; - } - } - - /* We reset this no matter. If we error'd trying to do it, we don't - want to try again. We'll just return the error for this time. */ - session_pid = 0; - - return retval; -} - -/* LightDM likes to have this function around, but we don't need it as we - don't have a token hanging around. */ -PAM_EXTERN int -pam_sm_setcred (pam_handle_t __attribute__((unused)) *pamh, int __attribute__((unused)) flags, int __attribute__((unused)) argc, const char __attribute__((unused)) **argv) -{ - return PAM_SUCCESS; -} - -#ifdef PAM_STATIC - -struct pam_module _pam_freerdp_modstruct = { - "pam_freerdp2", - pam_sm_authenticate, - pam_sm_setcred, - NULL, - pam_sm_open_session, - pam_sm_close_session, - NULL, -}; - -#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index 29b0a98..9aac03c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,16 +5,16 @@ DISTCLEANFILES = EXTRA_DIST = TESTS = \ - test-freerdp2-wrapper \ + test-freerdp-wrapper \ $(NULL) check_PROGRAMS = \ - test-freerdp2-auth \ + test-freerdp-auth \ $(TESTS) \ $(NULL) CLEANFILES += \ - test-freerdp2-auth \ + test-freerdp-auth \ $(TESTS) \ $(NULL) @@ -76,42 +76,42 @@ libgtest_main_a_CXXFLAGS = \ # Wrapper ########################## -test_freerdp2_wrapper: test-freerdp2-auth +test_freerdp_wrapper: test-freerdp-auth -test_freerdp2_wrapper_SOURCES = \ +test_freerdp_wrapper_SOURCES = \ mock_pam.c mock_pam.h \ mock_guest.c mock_guest.h \ - test-freerdp2-wrapper.cc \ + test-freerdp-wrapper.cc \ $(NULL) -test_freerdp2_wrapper_LDADD = \ +test_freerdp_wrapper_LDADD = \ libgtest.a libgtest_main.a \ - ${top_srcdir}/src/pam_freerdp2.la \ - $(FREERDP2_LIBS) \ - $(WINPR2_LIBS) \ + ${top_srcdir}/src/pam_freerdp.la \ + $(FREERDP_LIBS) \ + $(WINPR_LIBS) \ $(NULL) -test_freerdp2_wrapper_CPPFLAGS = \ +test_freerdp_wrapper_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I${top_srcdir}/include \ -I${top_srcdir}/src \ $(GTEST_CPPFLAGS) \ - $(FREERDP2_CPPFLAGS) \ - $(WINPR2_CPPFLAGS) \ + $(FREERDP_CPPFLAGS) \ + $(WINPR_CPPFLAGS) \ $(NULL) -test_freerdp2_wrapper_CXXFLAGS = \ +test_freerdp_wrapper_CXXFLAGS = \ $(AM_CXXFLAGS) \ - -DAUTH_CHECK="\"$(abs_builddir)/test-freerdp2-auth\"" \ + -DAUTH_CHECK="\"$(abs_builddir)/test-freerdp-auth\"" \ $(GTEST_CXXFLAGS) \ - $(FREERDP2_CXXFLAGS) \ - $(WINPR2_CXXFLAGS) \ + $(FREERDP_CXXFLAGS) \ + $(WINPR_CXXFLAGS) \ $(NULL) -test_freerdp2_wrapper_LDFLAGS = \ +test_freerdp_wrapper_LDFLAGS = \ $(GTEST_LDFLAGS) \ - $(FREERDP2_LDFLAGS) \ - $(WINPR2_LDFLAGS) \ + $(FREERDP_LDFLAGS) \ + $(WINPR_LDFLAGS) \ -pthread \ $(NULL) @@ -119,6 +119,6 @@ test_freerdp2_wrapper_LDFLAGS = \ # Auth tool ########################## -test_freerdp2_auth_SOURCES = \ - test-freerdp2-auth.c \ +test_freerdp_auth_SOURCES = \ + test-freerdp-auth.c \ $(NULL) diff --git a/tests/mock_guest.c b/tests/mock_guest.c index 4d10bfb..dad9d5d 100644 --- a/tests/mock_guest.c +++ b/tests/mock_guest.c @@ -89,7 +89,7 @@ socket_sucker () serv_addr.sun_family = AF_UNIX; - unsigned long int printsize = (unsigned long int)snprintf(serv_addr.sun_path, sizeof(serv_addr.sun_path) - 1, "%s/%s", home, ".freerdp2-socket"); + unsigned long int printsize = (unsigned long int)snprintf(serv_addr.sun_path, sizeof(serv_addr.sun_path) - 1, "%s/%s", home, ".freerdp-socket"); if (printsize > sizeof(serv_addr.sun_path) - 1 || printsize < 0) { return -1; } diff --git a/tests/mock_pam.c b/tests/mock_pam.c index f32d95f..ca222ba 100644 --- a/tests/mock_pam.c +++ b/tests/mock_pam.c @@ -9,7 +9,7 @@ #include #include "mock_pam.h" -#include "pam-freerdp2.h" +#include "pam-freerdp.h" struct pam_handle { void *item[PAM_NUM_ITEMS]; @@ -33,15 +33,15 @@ int fake_conv (int __attribute__((unused)) num_msg, response->resp_retcode = 0; - if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_GUESTLOGIN) == 0) { + if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_GUESTLOGIN) == 0) { response->resp = strdup ("guest"); /* IMPORTANT: this needs to be in /etc/passwd */ - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_USER) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_USER) == 0) { response->resp = strdup ("ruser"); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_HOST) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_HOST) == 0) { response->resp = strdup ("protocol://rhost/dummy"); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_PASSWORD) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_PASSWORD) == 0) { response->resp = strdup ("password"); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_DOMAIN) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_DOMAIN) == 0) { response->resp = strdup ("domain"); } else { free(response); @@ -66,15 +66,15 @@ int fake_conv_empty_password (int __attribute__((unused)) num_msg, response->resp_retcode = 0; - if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_GUESTLOGIN) == 0) { + if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_GUESTLOGIN) == 0) { response->resp = strdup ("guest"); /* IMPORTANT: this needs to be in /etc/passwd */ - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_USER) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_USER) == 0) { response->resp = strdup ("ruser"); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_HOST) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_HOST) == 0) { response->resp = strdup ("protocol://rhost/dummy"); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_PASSWORD) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_PASSWORD) == 0) { response->resp = strdup (""); - } else if (strcmp((*msg)->msg, PAM_FREERDP2_PROMPT_DOMAIN) == 0) { + } else if (strcmp((*msg)->msg, PAM_FREERDP_PROMPT_DOMAIN) == 0) { response->resp = strdup ("domain"); } else { free(response); diff --git a/tests/test-freerdp-auth.c b/tests/test-freerdp-auth.c new file mode 100644 index 0000000..a83885e --- /dev/null +++ b/tests/test-freerdp-auth.c @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . + * + * Author: Ted Gould + */ + +#include +#include +#include + +int +main (int argc, char * argv[]) +{ + char password[512]; + if (argc != 4) { + printf("Not enough params"); + return -1; + } + + if (scanf("%511s", password) != 1) { + return -1; + } + + /* Check username */ + if (strcmp(argv[2], "ruser")) { + return -1; + } + + /* Check password */ + if (strcmp(password, "password")) { + return -1; + } + + /* Check domain */ + if (strcmp(argv[3], "domain")) { + return -1; + } + + /* Check hostname */ + if (strcmp(argv[1], "rhost")) { + return -1; + } + + return 0; +} diff --git a/tests/test-freerdp-wrapper.cc b/tests/test-freerdp-wrapper.cc new file mode 100644 index 0000000..7555cb1 --- /dev/null +++ b/tests/test-freerdp-wrapper.cc @@ -0,0 +1,90 @@ +/* + * Copyright © 2012 Canonical Ltd. All rights reserved. + * + * Author(s): David Barth + * + */ + +#include + +extern "C" { + +#include "mock_pam.h" +#include "mock_guest.h" + +#include "pam-freerdp-private.h" + + int freerdpclient_wrapper (int argc, char * argv[]); + +const char * auth_check_path = AUTH_CHECK; + +} + +namespace { + + // The fixture for testing class Foo. + class FreerdpclientWrapperTest : public ::testing::Test { + protected: + // You can remove any or all of the following functions if its body + // is empty. + + FreerdpclientWrapperTest() { + // You can do set-up work for each test here. + setenv("HOME", "/tmp", 1 /* overwrite */); + } + + virtual ~FreerdpclientWrapperTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + unlink("/tmp/.freerdp-socket"); + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + unlink("/tmp/.freerdp-socket"); + } + + // Objects declared here can be used by all tests in the test case for Foo. + }; + + TEST_F(FreerdpclientWrapperTest, canLinkTheWholeGang) { + EXPECT_EQ (1, 1); // right, that's trivial, but that means + // that I got all of the wrapper and pam to link there + } + + TEST_F(FreerdpclientWrapperTest, canHandleEmptyPassword) { + const char *argv[] = { NULL }; + + pam_handle_t *pamh = pam_handle_empty_pswd_new (); + + EXPECT_EQ (PAM_AUTH_ERR, + pam_sm_authenticate (pamh, 0, 0, argv)); + + } + + TEST_F(FreerdpclientWrapperTest, canCallPamOpenSession) { + const char *argv[] = { NULL }; + + pam_handle_t *pamh = pam_handle_new (); + + EXPECT_EQ (PAM_SUCCESS, + pam_sm_authenticate (pamh, 0, 0, argv)); + EXPECT_EQ (PAM_SUCCESS, + pam_sm_setcred (pamh, 0, 0, argv)); + + EXPECT_EQ (PAM_SUCCESS, + pam_sm_open_session (pamh, 0, 0, argv)); + EXPECT_EQ(0, socket_sucker()); + EXPECT_EQ (PAM_SUCCESS, + pam_sm_close_session (pamh, 0, 0, argv)); + } + +} diff --git a/tests/test-freerdp2-auth.c b/tests/test-freerdp2-auth.c deleted file mode 100644 index a83885e..0000000 --- a/tests/test-freerdp2-auth.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, 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 this program. If not, see . - * - * Author: Ted Gould - */ - -#include -#include -#include - -int -main (int argc, char * argv[]) -{ - char password[512]; - if (argc != 4) { - printf("Not enough params"); - return -1; - } - - if (scanf("%511s", password) != 1) { - return -1; - } - - /* Check username */ - if (strcmp(argv[2], "ruser")) { - return -1; - } - - /* Check password */ - if (strcmp(password, "password")) { - return -1; - } - - /* Check domain */ - if (strcmp(argv[3], "domain")) { - return -1; - } - - /* Check hostname */ - if (strcmp(argv[1], "rhost")) { - return -1; - } - - return 0; -} diff --git a/tests/test-freerdp2-wrapper.cc b/tests/test-freerdp2-wrapper.cc deleted file mode 100644 index 33b4168..0000000 --- a/tests/test-freerdp2-wrapper.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2012 Canonical Ltd. All rights reserved. - * - * Author(s): David Barth - * - */ - -#include - -extern "C" { - -#include "mock_pam.h" -#include "mock_guest.h" - -#include "pam-freerdp2-private.h" - - int freerdpclient_wrapper (int argc, char * argv[]); - -const char * auth_check_path = AUTH_CHECK; - -} - -namespace { - - // The fixture for testing class Foo. - class FreerdpclientWrapperTest : public ::testing::Test { - protected: - // You can remove any or all of the following functions if its body - // is empty. - - FreerdpclientWrapperTest() { - // You can do set-up work for each test here. - setenv("HOME", "/tmp", 1 /* overwrite */); - } - - virtual ~FreerdpclientWrapperTest() { - // You can do clean-up work that doesn't throw exceptions here. - } - - // If the constructor and destructor are not enough for setting up - // and cleaning up each test, you can define the following methods: - - virtual void SetUp() { - // Code here will be called immediately after the constructor (right - // before each test). - unlink("/tmp/.freerdp2-socket"); - } - - virtual void TearDown() { - // Code here will be called immediately after each test (right - // before the destructor). - unlink("/tmp/.freerdp2-socket"); - } - - // Objects declared here can be used by all tests in the test case for Foo. - }; - - TEST_F(FreerdpclientWrapperTest, canLinkTheWholeGang) { - EXPECT_EQ (1, 1); // right, that's trivial, but that means - // that I got all of the wrapper and pam to link there - } - - TEST_F(FreerdpclientWrapperTest, canHandleEmptyPassword) { - const char *argv[] = { NULL }; - - pam_handle_t *pamh = pam_handle_empty_pswd_new (); - - EXPECT_EQ (PAM_AUTH_ERR, - pam_sm_authenticate (pamh, 0, 0, argv)); - - } - - TEST_F(FreerdpclientWrapperTest, canCallPamOpenSession) { - const char *argv[] = { NULL }; - - pam_handle_t *pamh = pam_handle_new (); - - EXPECT_EQ (PAM_SUCCESS, - pam_sm_authenticate (pamh, 0, 0, argv)); - EXPECT_EQ (PAM_SUCCESS, - pam_sm_setcred (pamh, 0, 0, argv)); - - EXPECT_EQ (PAM_SUCCESS, - pam_sm_open_session (pamh, 0, 0, argv)); - EXPECT_EQ(0, socket_sucker()); - EXPECT_EQ (PAM_SUCCESS, - pam_sm_close_session (pamh, 0, 0, argv)); - } - -} -- cgit v1.2.3