diff options
author | Iftikhar Ahmad <iftikhar.ahmad@gmail.com> | 2012-10-16 14:36:11 +0500 |
---|---|---|
committer | Iftikhar Ahmad <iftikhar.ahmad@gmail.com> | 2012-10-16 14:36:11 +0500 |
commit | 81705411e822377c8b5916b3c32eb044ae3fdff2 (patch) | |
tree | 2b534b2dc4daeec1858a2f36d6ca9165772cbc2a | |
parent | cc83b78511a00c8ae44e4c671b30293960571b75 (diff) | |
download | libpam-freerdp2-81705411e822377c8b5916b3c32eb044ae3fdff2.tar.gz libpam-freerdp2-81705411e822377c8b5916b3c32eb044ae3fdff2.tar.bz2 libpam-freerdp2-81705411e822377c8b5916b3c32eb044ae3fdff2.zip |
Improving the test coverage for libpam-freerdp
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/pam-freerdp.c | 196 | ||||
-rw-r--r-- | tests/mock_guest.c | 71 | ||||
-rw-r--r-- | tests/mock_guest.h | 2 | ||||
-rw-r--r-- | tests/test-freerdp-wrapper.cc | 2 |
5 files changed, 82 insertions, 192 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 34d1ddd..ed9087c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,8 @@ noinst_LTLIBRARIES = \ libfreerdpcore.la libfreerdpcore_la_SOURCES = \ - pam-freerdp.c + pam-freerdp.c \ + pam-freerdp-children.c libfreerdpcore_la_CFLAGS = \ -Wall -Werror \ $(COVERAGE_CFLAGS) diff --git a/src/pam-freerdp.c b/src/pam-freerdp.c index fbfe182..8979e6e 100644 --- a/src/pam-freerdp.c +++ b/src/pam-freerdp.c @@ -34,11 +34,9 @@ #include <security/pam_modutil.h> #include <security/pam_appl.h> +#include "pam-freerdp-children.h" #include "auth-check-path.h" -#define PAM_TYPE_DOMAIN 1234 -#define ALL_GOOD_SIGNAL "Ar, ready to authenticate cap'n" - static int unpriveleged_kill (struct passwd * pwdent); static char * global_domain = NULL; @@ -236,44 +234,7 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc, const char **argv) pid_t pid; switch (pid = fork()) { case 0: { /* child */ - dup2(stdinpipe[0], 0); - - char * args[5]; - - args[0] = (char *)auth_check_path; - args[1] = rhost; - args[2] = ruser; - args[3] = 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(EXIT_FAILURE); + pam_sm_authenticate_helper (stdinpipe, username, rhost, ruser, rdomain); break; } case -1: { /* fork'n error! */ @@ -304,153 +265,7 @@ done: return retval; } -static 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) { - return 0; - } - - return EXIT_FAILURE; -} pid_t session_pid = 0; /* Open Session. Here we need to fork a little process so that we can @@ -492,12 +307,11 @@ pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char ** argv pid_t pid = fork(); if (pid == 0) { - int retval = 0; - - retval = session_socket_handler(pwdent, sessionready[1], ruser, rhost, rdomain, password); + + int ret = session_socket_handler(pwdent, sessionready[1], ruser, rhost, rdomain, password); close(sessionready[1]); - _exit(retval); + _exit(ret); } else if (pid < 0) { close(sessionready[0]); close(sessionready[1]); diff --git a/tests/mock_guest.c b/tests/mock_guest.c index 2cf04b3..8bf2c3a 100644 --- a/tests/mock_guest.c +++ b/tests/mock_guest.c @@ -9,6 +9,11 @@ #include <errno.h> #include <unistd.h> #include <sys/stat.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> static struct passwd guest = { "guest", "password", @@ -49,3 +54,69 @@ int chmod(const char *path, mode_t mode) int chown(const char *path, uid_t owner, gid_t group) { return 0; } +int execvp(const char *file, char *const argv[]) +{ + return 0; +} +/* wrap _exit, to make sure the gcov_exit function installed with atexit() + is really called to collect coverage statistics */ +void _exit (int exitcode) +{ + exit (exitcode); +} + + +#define BUFFER_SIZE 512 + +/*Borrowed this code form socket-sucker.c in lightdm-remote-session-freerdp*/ +int +socket_sucker () +{ + int socket_fd = 0; + int servlen = 0; + struct sockaddr_un serv_addr; + + bzero((char *)&serv_addr, sizeof(serv_addr)); + + const char * home = getenv("HOME"); + if (home == NULL) { + return -1; + } + + serv_addr.sun_family = AF_UNIX; + + int printsize = 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; + } + + servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); + + if ((socket_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + return -1; + } + + if (connect(socket_fd, (struct sockaddr *)&serv_addr, servlen) < 0) { + return -1; + } + + char buffer[BUFFER_SIZE + 2]; + int in = 0; + int out = 0; + + in = read(socket_fd, buffer, BUFFER_SIZE); + + if (in > 0) { + out = write(1, buffer, in); + } + + close(socket_fd); + + if (in > 0 && out > 0 && in == out) { + return 0; + } else { + return -1; + } +} + + diff --git a/tests/mock_guest.h b/tests/mock_guest.h index c4179b9..2c17536 100644 --- a/tests/mock_guest.h +++ b/tests/mock_guest.h @@ -20,5 +20,7 @@ int setegid(gid_t gid); int seteuid(uid_t uid); int chmod(const char *path, mode_t mode); int chown(const char *path, uid_t owner, gid_t group); +int execvp(const char *file, char *const argv[]); +int socket_sucker(); #endif diff --git a/tests/test-freerdp-wrapper.cc b/tests/test-freerdp-wrapper.cc index cfe86de..147682d 100644 --- a/tests/test-freerdp-wrapper.cc +++ b/tests/test-freerdp-wrapper.cc @@ -67,8 +67,10 @@ namespace { 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)); } |