summaryrefslogtreecommitdiffstats
path: root/sesman
diff options
context:
space:
mode:
Diffstat (limited to 'sesman')
-rw-r--r--sesman/Makefile16
-rw-r--r--sesman/sesman.c484
-rw-r--r--sesman/sesman.ini5
3 files changed, 505 insertions, 0 deletions
diff --git a/sesman/Makefile b/sesman/Makefile
new file mode 100644
index 00000000..7844495d
--- /dev/null
+++ b/sesman/Makefile
@@ -0,0 +1,16 @@
+
+SESMANOBJ = sesman.o ../common/os_calls.o
+
+CFLAGS = -Wall -O2 -I../common
+LDFLAGS = -L /usr/gnu/lib
+LIBS = -lpam_userpass -lcrypto -lpthread
+PAMLIB = /lib/libpam.so.0
+CC = gcc
+
+all: sesman
+
+sesman: $(SESMANOBJ)
+ $(CC) $(LDFLAGS) -o sesman $(PAMLIB) $(SESMANOBJ) $(LIBS)
+
+clean:
+ rm -f $(SESMANOBJ) sesman
diff --git a/sesman/sesman.c b/sesman/sesman.c
new file mode 100644
index 00000000..d18096bb
--- /dev/null
+++ b/sesman/sesman.c
@@ -0,0 +1,484 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2005
+
+ session manager
+ linux only
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+
+#include <security/pam_userpass.h>
+
+#include "arch.h"
+#include "parse.h"
+#include "os_calls.h"
+
+#define SERVICE "xrdp"
+
+struct session_item
+{
+ char name[256];
+ int pid; // pid of sesman waiting for wm to end
+ int display;
+ int width;
+ int height;
+ int bpp;
+};
+
+struct session_item session_items[100];
+
+/******************************************************************************/
+struct session_item* find_session_item(char* name, int width,
+ int height, int bpp)
+{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ {
+ if (g_strcmp(name, session_items[i].name) == 0 &&
+ session_items[i].width == width &&
+ session_items[i].height == height &&
+ session_items[i].bpp == bpp)
+ {
+ return session_items + i;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+struct session_item* find_session_item_by_name(char* name)
+{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ {
+ if (g_strcmp(name, session_items[i].name) == 0)
+ {
+ return session_items + i;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+struct session_item* find_session_item_by_display(int display)
+{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ {
+ if (session_items[i].display == display)
+ {
+ return session_items + i;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+int x_server_running(int display)
+{
+ char text[256];
+
+ g_sprintf(text, "/tmp/.X11-unix/X%d", display);
+ return access(text, F_OK) == 0;
+}
+
+/******************************************************************************/
+/* returns boolean */
+int auth_pam_userpass(const char* user, const char* pass)
+{
+ pam_handle_t* pamh;
+ pam_userpass_t userpass;
+ struct pam_conv conv = {pam_userpass_conv, &userpass};
+ const void* template1;
+ int status;
+
+ userpass.user = user;
+ userpass.pass = pass;
+ if (pam_start(SERVICE, user, &conv, &pamh) != PAM_SUCCESS)
+ {
+ return 0;
+ }
+ status = pam_authenticate(pamh, 0);
+ if (status != PAM_SUCCESS)
+ {
+ pam_end(pamh, status);
+ return 0;
+ }
+ status = pam_acct_mgmt(pamh, 0);
+ if (status != PAM_SUCCESS)
+ {
+ pam_end(pamh, status);
+ return 0;
+ }
+ status = pam_get_item(pamh, PAM_USER, &template1);
+ if (status != PAM_SUCCESS)
+ {
+ pam_end(pamh, status);
+ return 0;
+ }
+ if (pam_end(pamh, PAM_SUCCESS) != PAM_SUCCESS)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+void cterm(int s)
+{
+ int i;
+ int pid;
+ int wstat;
+
+ pid = waitpid(0, &wstat, WNOHANG);
+ if (pid > 0)
+ {
+ for (i = 0; i < 100; i++)
+ {
+ if (session_items[i].pid == pid)
+ {
+ g_memset(session_items + i, 0, sizeof(struct session_item));
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+/* ge the next available X display */
+int get_next_display(void)
+{
+ int i;
+
+ for (i = 10; i < 100; i++)
+ {
+ if (!x_server_running(i))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/******************************************************************************/
+int start_session(int width, int height, int bpp, char* username)
+{
+ int display;
+ int pid;
+ int uid;
+ int wmpid;
+ int xpid;
+ struct passwd* pwd_1;
+ char text[256];
+ char geometry[32];
+ char depth[32];
+ char screen[32];
+
+ display = 10;
+ while (x_server_running(display) && display < 50)
+ {
+ display++;
+ }
+ if (display >= 50)
+ {
+ return 0;
+ }
+ wmpid = 0;
+ pid = fork();
+ if (pid == -1)
+ {
+ }
+ else if (pid == 0) // child
+ {
+ pwd_1 = getpwnam(username);
+ if (pwd_1 != 0)
+ {
+ uid = pwd_1->pw_uid;
+ if (setuid(uid) == 0)
+ {
+ setenv("USER", username, 1);
+ g_sprintf(text, "%d", uid);
+ setenv("UID", text, 1);
+ setenv("HOME", pwd_1->pw_dir, 1);
+ chdir(pwd_1->pw_dir);
+ if (access(".bash_profile", F_OK) == 0)
+ {
+ system("sh .bash_profile");
+ }
+ g_sprintf(text, ":%d.0", display);
+ setenv("DISPLAY", text, 1);
+ g_sprintf(geometry, "%dx%d", width, height);
+ g_sprintf(depth, "%d", bpp);
+ g_sprintf(screen, ":%d", display);
+ wmpid = fork();
+ if (wmpid == -1)
+ {
+ }
+ else if (wmpid == 0) // child
+ {
+ // give X a bit to start
+ g_sleep(500);
+ if (x_server_running(display))
+ {
+ execlp("startkde", NULL);
+ // should not get here
+ }
+ g_printf("error\n");
+ _exit(0);
+ }
+ else // parent
+ {
+ xpid = fork();
+ if (xpid == -1)
+ {
+ }
+ else if (xpid == 0) // child
+ {
+ g_sprintf(text, "%s/.vnc/passwd", pwd_1->pw_dir);
+ if (access(text, F_OK) == 0)
+ {
+ execlp("Xvnc", "Xvnc", screen, "-geometry", geometry,
+ "-depth", depth, "-bs", "-rfbauth", text, NULL);
+ }
+ else
+ {
+ execlp("Xvnc", "Xvnc", screen, "-geometry", geometry,
+ "-depth", depth, "-bs", NULL);
+ }
+ // should not get here
+ g_printf("error\n");
+ _exit(0);
+ }
+ else // parent
+ {
+ waitpid(wmpid, 0, 0);
+ kill(xpid, SIGTERM);
+ kill(wmpid, SIGTERM);
+ _exit(0);
+ }
+ }
+ }
+ }
+ }
+ else // parent
+ {
+ signal(SIGCHLD, cterm);
+ session_items[display].pid = pid;
+ g_strcpy(session_items[display].name, username);
+ session_items[display].display = display;
+ session_items[display].width = width;
+ session_items[display].height = height;
+ session_items[display].bpp = bpp;
+ g_sleep(1000);
+ }
+ return display;
+}
+
+/******************************************************************************/
+int main(int argc, char** argv)
+{
+ int sck;
+ int in_sck;
+ int code;
+ int i;
+ int size;
+ int version;
+ int ok;
+ int width;
+ int height;
+ int bpp;
+ int display;
+ struct stream* in_s;
+ struct stream* out_s;
+ char* username;
+ char* password;
+ char user[256];
+ char pass[256];
+ struct session_item* s_item;
+
+ g_memset(&session_items, 0, sizeof(session_items));
+ if (argc == 1)
+ {
+ g_printf("xrdp session manager v0.1\n");
+ g_printf("usage\n");
+ g_printf("sesman wait - wait for connection\n");
+ g_printf("sesman server username password width height bpp - \
+start session\n");
+ }
+ else if (argc == 2 && g_strcmp(argv[1], "wait") == 0)
+ {
+ make_stream(in_s);
+ init_stream(in_s, 8192);
+ make_stream(out_s);
+ init_stream(out_s, 8192);
+ g_printf("listening\n");
+ sck = g_tcp_socket();
+ if (g_tcp_bind(sck, "3350") == 0)
+ {
+ if (g_tcp_listen(sck) == 0)
+ {
+ in_sck = g_tcp_accept(sck);
+ while (in_sck > 0)
+ {
+ init_stream(in_s, 8192);
+ if (g_tcp_force_recv(in_sck, in_s->data, 8) == 0)
+ {
+ in_uint32_be(in_s, version);
+ in_uint32_be(in_s, size);
+ init_stream(in_s, 8192);
+ if (g_tcp_force_recv(in_sck, in_s->data, size - 8) == 0)
+ {
+ if (version == 0)
+ {
+ in_uint16_be(in_s, code);
+ if (code == 0) // check username - password, start session
+ {
+ in_uint16_be(in_s, i);
+ in_uint8a(in_s, user, i);
+ user[i] = 0;
+ //g_printf("%s\n", user);
+ in_uint16_be(in_s, i);
+ in_uint8a(in_s, pass, i);
+ pass[i] = 0;
+ //g_printf("%s\n", pass);
+ in_uint16_be(in_s, width);
+ in_uint16_be(in_s, height);
+ in_uint16_be(in_s, bpp);
+ //g_printf("%d %d %d\n", width, height, bpp);
+ ok = auth_pam_userpass(user, pass);
+ display = 0;
+ if (ok)
+ {
+ s_item = find_session_item(user, width, height, bpp);
+ if (s_item != 0)
+ {
+ display = s_item->display;
+ }
+ else
+ {
+ display = start_session(width, height, bpp, user);
+ }
+ if (display == 0)
+ {
+ ok = 0;
+ }
+ }
+ init_stream(out_s, 8192);
+ out_uint32_be(out_s, 0); // version
+ out_uint32_be(out_s, 14); // size
+ out_uint16_be(out_s, 3); // cmd
+ out_uint16_be(out_s, ok); // data
+ out_uint16_be(out_s, display); // data
+ s_mark_end(out_s);
+ g_tcp_force_send(in_sck, out_s->data,
+ out_s->end - out_s->data);
+ }
+ }
+ }
+ }
+ close(in_sck);
+ in_sck = g_tcp_accept(sck);
+ }
+ }
+ else
+ {
+ g_printf("listen error\n");
+ }
+ }
+ else
+ {
+ g_printf("bind error\n");
+ }
+ g_tcp_close(sck);
+ free_stream(in_s);
+ free_stream(out_s);
+ }
+ else if (argc == 7)
+ {
+ username = argv[2];
+ password = argv[3];
+ width = atoi(argv[4]);
+ height = atoi(argv[5]);
+ bpp = atoi(argv[6]);
+ make_stream(in_s);
+ init_stream(in_s, 8192);
+ make_stream(out_s);
+ init_stream(out_s, 8192);
+ sck = g_tcp_socket();
+ if (g_tcp_connect(sck, argv[1], "3350") == 0)
+ {
+ s_push_layer(out_s, channel_hdr, 8);
+ out_uint16_be(out_s, 0); // code
+ i = g_strlen(username);
+ out_uint16_be(out_s, i);
+ out_uint8a(out_s, username, i);
+ i = g_strlen(password);
+ out_uint16_be(out_s, i);
+ out_uint8a(out_s, password, i);
+ //g_printf("%d\n", width);
+ out_uint16_be(out_s, width);
+ out_uint16_be(out_s, height);
+ out_uint16_be(out_s, bpp);
+ s_mark_end(out_s);
+ s_pop_layer(out_s, channel_hdr);
+ out_uint32_be(out_s, 0); // version
+ out_uint32_be(out_s, out_s->end - out_s->data); // size
+ g_tcp_force_send(sck, out_s->data, out_s->end - out_s->data);
+ if (g_tcp_force_recv(sck, in_s->data, 8) == 0)
+ {
+ in_uint32_be(in_s, version);
+ in_uint32_be(in_s, size);
+ init_stream(in_s, 8192);
+ if (g_tcp_force_recv(sck, in_s->data, size - 8) == 0)
+ {
+ if (version == 0)
+ {
+ in_uint16_be(in_s, code);
+ if (code == 3)
+ {
+ in_uint16_be(in_s, ok);
+ in_uint16_be(in_s, display);
+ g_printf("ok %d display %d\n", ok, display);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ g_printf("connect error\n");
+ }
+ g_tcp_close(sck);
+ free_stream(in_s);
+ free_stream(out_s);
+ }
+ return 0;
+}
diff --git a/sesman/sesman.ini b/sesman/sesman.ini
new file mode 100644
index 00000000..d01e8d2f
--- /dev/null
+++ b/sesman/sesman.ini
@@ -0,0 +1,5 @@
+
+[globals]
+auth=pam
+xserver=Xvnc :%d -geometry %dx%d -depth %d -bs
+wm=startkde