From 79310af7e7a289d2baf1bdc295daefdcc76ecc0e Mon Sep 17 00:00:00 2001 From: runge Date: Sat, 25 Feb 2006 05:10:37 +0000 Subject: x11vnc: -unixpw and -stunnel. Add clipboard to input control. --- x11vnc/unixpw.c | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 x11vnc/unixpw.c (limited to 'x11vnc/unixpw.c') diff --git a/x11vnc/unixpw.c b/x11vnc/unixpw.c new file mode 100644 index 0000000..1ab59d7 --- /dev/null +++ b/x11vnc/unixpw.c @@ -0,0 +1,442 @@ +/* -- unixpw.c -- */ + +#ifdef __linux__ +/* some conflict with _XOPEN_SOURCE */ +extern int grantpt(int); +extern int unlockpt(int); +extern char *ptsname(int); +#endif + +#include "x11vnc.h" +#include "scan.h" +#include "cleanup.h" +#include "xinerama.h" +#include + +/* much to do for it to work on *BSD ... */ + +#if LIBVNCSERVER_HAVE_FORK +#if LIBVNCSERVER_HAVE_SETSID +#if LIBVNCSERVER_HAVE_SYS_WAIT_H +#if LIBVNCSERVER_HAVE_PWD_H +#if LIBVNCSERVER_HAVE_SETUID +#if LIBVNCSERVER_HAVE_WAITPID +#if LIBVNCSERVER_HAVE_TERMIOS_H +#if LIBVNCSERVER_HAVE_SYS_IOCTL_H +#if LIBVNCSERVER_HAVE_GRANTPT +#define UNIXPW +#include +#include +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif +#endif + +void unixpw_screen(int init); +void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init); +void unixpw_accept(void); +void unixpw_deny(void); + +static int white(void); +static int text_x(void); +static int text_y(void); +static int su_verify(char *user, char *pass); +static void unixpw_verify(char *user, char *pass); + +int unixpw_in_progress = 0; +time_t unixpw_last_try_time = 0; +rfbClientPtr unixpw_client = NULL; + +static int in_login = 0, in_passwd = 0, tries = 0; +static int char_row = 0, char_col = 0; +static int char_x = 0, char_y = 0, char_w = 8, char_h = 16; + +static int white(void) { + static unsigned long black_pix = 0, white_pix = 1, set = 0; + + if (depth <= 8 && ! set) { + X_LOCK; + black_pix = BlackPixel(dpy, scr); + white_pix = WhitePixel(dpy, scr); + X_UNLOCK; + set = 1; + } + if (depth <= 8) { + return (int) white_pix; + } else if (depth < 24) { + return 0xffff; + } else { + return 0xffffff; + } +} + +static int text_x(void) { + return char_x + char_col * char_w; +} + +static int text_y(void) { + return char_y + char_row * char_h; +} + +void unixpw_screen(int init) { +#ifndef UNIXPW + rfbLog("-unixpw is not supported on this OS/machine\n"); + clean_up_exit(1); +#endif + if (init) { + int x, y; + char log[] = "login: "; + + zero_fb(0, 0, dpy_x, dpy_y); + + x = nfix(dpy_x / 2 - strlen(log) * char_w, dpy_x); + y = dpy_y / 4; + + rfbDrawString(screen, &default8x16Font, x, y, log, white()); + + char_x = x; + char_y = y; + char_col = strlen(log); + char_row = 0; + } + + mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); +} + +static int su_verify(char *user, char *pass) { +#ifdef UNIXPW + int status, fd, sfd; + char *slave; + pid_t pid, pidw; + struct stat sbuf; + + if (unixpw_list) { + char *p, *str = strdup(unixpw_list); + int ok = 0; + + p = strtok(str, ","); + while (p) { + if (!strcmp(user, p)) { + ok = 1; + break; + } + p = strtok(NULL, ","); + } + free(str); + if (! ok) { + return 0; + } + } + if (stat("/bin/su", &sbuf) != 0) { + rfbLogPerror("existence /bin/su"); + return 0; + } + if (stat("/bin/true", &sbuf) != 0) { + rfbLogPerror("existence /bin/true"); + return 0; + } + + fd = open("/dev/ptmx", O_RDWR|O_NOCTTY); + + if (fd < 0) { + rfbLogPerror("open /dev/ptmx"); + return 0; + } + + if (grantpt(fd) != 0) { + rfbLogPerror("grantpt"); + close(fd); + return 0; + } + if (unlockpt(fd) != 0) { + rfbLogPerror("unlockpt"); + close(fd); + return 0; + } + + slave = ptsname(fd); + if (! slave) { + rfbLogPerror("ptsname"); + close(fd); + return 0; + } + + pid = fork(); + if (pid < 0) { + rfbLogPerror("fork"); + close(fd); + return 0; + } + + if (pid == 0) { + int ttyfd; + struct passwd *pw; + + close(fd); + + pw = getpwnam("nobody"); + + if (pw) { + setuid(pw->pw_uid); +#if LIBVNCSERVER_HAVE_SETEUID + seteuid(pw->pw_uid); +#endif + setgid(pw->pw_gid); +#if LIBVNCSERVER_HAVE_SETEGID + setegid(pw->pw_gid); +#endif + } + + if (getuid() == 0 || geteuid() == 0) { + fprintf(stderr, "could not switch to user nobody.\n"); + exit(1); + } + + if (setsid() == -1) { + perror("setsid"); + exit(1); + } + +#ifdef TIOCNOTTY + ttyfd = open("/dev/tty", O_RDWR); + if (ttyfd >= 0) { + (void) ioctl(ttyfd, TIOCNOTTY, (char *)0); + close(ttyfd); + } +#endif + + close(0); + close(1); + close(2); + + sfd = open(slave, O_RDWR); + if (sfd < 0) { + fprintf(stderr, "failed: %s\n", slave); + perror("open"); + exit(1); + } +#ifdef TIOCSCTTY + if (ioctl(sfd, TIOCSCTTY, (char *) 0) != 0) { + perror("ioctl"); + exit(1); + } +#endif + execlp("/bin/su", "/bin/su", user, "-c", "/bin/true", + (char *) NULL); + exit(1); + } + + usleep( 500 * 1000 ); + write(fd, pass, strlen(pass)); + + pidw = waitpid(pid, &status, 0); + close(fd); + + if (pid != pidw) { + return 0; + } + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + return 1; + } else { + return 0; + } +#else + return 0; +#endif +} + +static int db = 0; + +static void unixpw_verify(char *user, char *pass) { + int x, y; + char li[] = "Login incorrect"; + char log[] = "login: "; + +if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********"); + + if (su_verify(user, pass)) { + unixpw_accept(); + return; + } + + if (tries < 2) { + char_row++; + char_col = 0; + + x = text_x(); + y = text_y(); + rfbDrawString(screen, &default8x16Font, x, y, li, white()); + + char_row += 2; + + x = text_x(); + y = text_y(); + rfbDrawString(screen, &default8x16Font, x, y, log, white()); + + char_col = strlen(log); + + mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); + + unixpw_last_try_time = time(0); + unixpw_keystroke(0, 0, 2); + tries++; + } else { + unixpw_deny(); + } +} + +void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init) { + int x, y, i, nmax = 100; + static char user[100], pass[100]; + static int u_cnt = 0, p_cnt = 0, first = 1; + char str[100]; + + if (first) { + if (getenv("DEBUG_UNIXPW")) { + db = atoi(getenv("DEBUG_UNIXPW")); + } + first = 0; + } + + if (init) { + in_login = 1; + in_passwd = 0; + if (init == 1) { + tries = 0; + } + + u_cnt = 0; + p_cnt = 0; + for (i=0; i 0) { + user[u_cnt-1] = '\0'; + x = text_x(); + y = text_y(); + zero_fb(x - char_w, y - char_h, x, y); + mark_rect_as_modified(x - char_w, y - char_h, + x, y, 0); + char_col--; + u_cnt--; + } + return; + } + if (keysym == XK_Return || keysym == XK_Linefeed) { + char pw[] = "Password: "; + + in_login = 0; + in_passwd = 1; + + char_row++; + char_col = 0; + + x = text_x(); + y = text_y(); + rfbDrawString(screen, &default8x16Font, x, y, pw, + white()); + + char_col = strlen(pw); + mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); + return; + } + if (keysym <= ' ' || keysym >= 0x7f) { + return; + } + if (u_cnt >= nmax - 1) { + rfbLog("unixpw_deny: username too long\n"); + unixpw_deny(); + return; + } + + X_LOCK; + sprintf(str, "%s", XKeysymToString(keysym)); + X_UNLOCK; + + user[u_cnt++] = str[0]; + + x = text_x(); + y = text_y(); + +if (db) fprintf(stderr, "u_cnt: %d %d/%d ks: 0x%x %s\n", u_cnt, x, y, keysym, str); + + str[1] = '\0'; + rfbDrawString(screen, &default8x16Font, x, y, str, white()); + + mark_rect_as_modified(x, y-char_h, x+char_w, y, 0); + char_col++; + + } else if (in_passwd) { + if (keysym == XK_BackSpace || keysym == XK_Delete) { + if (p_cnt > 0) { + pass[p_cnt-1] = '\0'; + p_cnt--; + } + return; + } + if (keysym == XK_Return || keysym == XK_Linefeed) { + in_login = 0; + in_passwd = 0; + pass[p_cnt++] = '\n'; + unixpw_verify(user, pass); + return; + } + if (keysym <= ' ' || keysym >= 0x7f) { + return; + } + if (p_cnt >= nmax - 2) { + rfbLog("unixpw_deny: password too long\n"); + unixpw_deny(); + return; + } + pass[p_cnt++] = (char) keysym; + } +} + +void unixpw_accept(void) { + unixpw_in_progress = 0; + unixpw_client = NULL; + mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); +} + +void unixpw_deny(void) { + int x, y, i; + char pd[] = "Permission denied."; + + char_row += 2; + char_col = 0; + x = char_x + char_col * char_w; + y = char_y + char_row * char_h; + + rfbDrawString(screen, &default8x16Font, x, y, pd, white()); + mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); + + for (i=0; i<5; i++) { + rfbPE(-1); + usleep(500 * 1000); + } + + rfbCloseClient(unixpw_client); + rfbClientConnectionGone(unixpw_client); + rfbPE(-1); + + unixpw_in_progress = 0; + unixpw_client = NULL; + copy_screen(); +} + -- cgit v1.2.1