aboutsummaryrefslogtreecommitdiff
path: root/src/pam-freerdp.c
diff options
context:
space:
mode:
authorMike Gabriel <mike.gabriel@das-netzwerkteam.de>2012-11-09 01:17:16 +0100
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2012-11-09 01:17:16 +0100
commit42b8b279e62e6e2f5a7455e30bb0a211763ee187 (patch)
tree9d0e09c594f340a7ed9db8cc910a717890ef5f28 /src/pam-freerdp.c
parente92b549c49833e3150d60e8773a6731fc49d1249 (diff)
downloadlibpam-x2go-42b8b279e62e6e2f5a7455e30bb0a211763ee187.tar.gz
libpam-x2go-42b8b279e62e6e2f5a7455e30bb0a211763ee187.tar.bz2
libpam-x2go-42b8b279e62e6e2f5a7455e30bb0a211763ee187.zip
fork libpam-x2go from libpam-freerdp
Diffstat (limited to 'src/pam-freerdp.c')
-rw-r--r--src/pam-freerdp.c439
1 files changed, 0 insertions, 439 deletions
diff --git a/src/pam-freerdp.c b/src/pam-freerdp.c
deleted file mode 100644
index 8979e6e..0000000
--- a/src/pam-freerdp.c
+++ /dev/null
@@ -1,439 +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 <http://www.gnu.org/licenses/>.
- *
- * Author: Ted Gould <ted@canonical.com>
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/un.h>
-#include <pwd.h>
-#include <grp.h>
-#include <errno.h>
-
-#include <security/pam_modules.h>
-#include <security/pam_modutil.h>
-#include <security/pam_appl.h>
-
-#include "pam-freerdp-children.h"
-#include "auth-check-path.h"
-
-static int unpriveleged_kill (struct passwd * pwdent);
-
-static char * global_domain = 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 consitently allocating memory */
- if (type != PAM_TYPE_DOMAIN) {
- /* If it's not a domain we can use the PAM functions because the PAM
- functions don't support the domain */
- 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 only have domains, so we can see if the global domain is
- useful for us, if we have it */
- if (global_domain != NULL) {
- return global_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 = "login:";
- break;
- case PAM_RUSER:
- message.msg = "remote login:";
- break;
- case PAM_RHOST:
- message.msg = "remote host:";
- break;
- case PAM_AUTHTOK:
- message.msg = "password:";
- message.msg_style = PAM_PROMPT_ECHO_OFF;
- break;
- case PAM_TYPE_DOMAIN:
- message.msg = "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 (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_RUSER) {
- if (strstr(promptval, " ") != NULL) {
- free(promptval);
- return NULL;
- }
- }
-
- if (type == PAM_RHOST) {
- 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_TYPE_DOMAIN) {
- /* We can only use the PAM functions if it's not the domain */
- 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);
- }
- if (type == PAM_TYPE_DOMAIN) {
- /* The domain can be saved globally so we can use it for open */
- if (global_domain != NULL) {
- free(global_domain);
- }
- global_domain = strdup(promptval);
- retval = global_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 flags, int argc, const char **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_RUSER);
- GET_ITEM(rhost, PAM_RHOST);
- GET_ITEM(rdomain, PAM_TYPE_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 flags, int argc, const char ** 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_RUSER);
- GET_ITEM(rhost, PAM_RHOST);
- GET_ITEM(rdomain, PAM_TYPE_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 flags, int argc, const char **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 gaurantee 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 *pamh, int flags, int argc, const char ** 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