summaryrefslogtreecommitdiffstats
path: root/x11vnc/unixpw.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/unixpw.c')
-rw-r--r--x11vnc/unixpw.c324
1 files changed, 225 insertions, 99 deletions
diff --git a/x11vnc/unixpw.c b/x11vnc/unixpw.c
index c5bf198..fd2dbe0 100644
--- a/x11vnc/unixpw.c
+++ b/x11vnc/unixpw.c
@@ -5,6 +5,7 @@
extern int grantpt(int);
extern int unlockpt(int);
extern char *ptsname(int);
+extern char *crypt(const char*, const char *);
#endif
#include "x11vnc.h"
@@ -14,11 +15,15 @@ extern char *ptsname(int);
#include <rfb/default8x16.h>
#if LIBVNCSERVER_HAVE_FORK
-#if LIBVNCSERVER_HAVE_SYS_WAIT_H
-#if LIBVNCSERVER_HAVE_WAITPID
-#define UNIXPW
+#if LIBVNCSERVER_HAVE_SYS_WAIT_H && LIBVNCSERVER_HAVE_WAITPID
+#define UNIXPW_SU
#endif
#endif
+
+#if LIBVNCSERVER_HAVE_PWD_H && LIBVNCSERVER_HAVE_GETPWNAM
+#if LIBVNCSERVER_HAVE_CRYPT || LIBVNCSERVER_HAVE_LIBCRYPT
+#define UNIXPW_CRYPT
+#endif
#endif
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
@@ -27,9 +32,10 @@ extern char *ptsname(int);
#if LIBVNCSERVER_HAVE_TERMIOS_H
#include <termios.h>
#endif
-#if 0
+#if LIBVNCSERVER_HAVE_SYS_STROPTS_H
#include <sys/stropts.h>
#endif
+
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
#define IS_BSD
#endif
@@ -39,6 +45,7 @@ void unixpw_keystroke(rfbBool down, rfbKeySym keysym, int init);
void unixpw_accept(char *user);
void unixpw_deny(void);
int su_verify(char *user, char *pass);
+int crypt_verify(char *user, char *pass);
static int white(void);
static int text_x(void);
@@ -84,10 +91,17 @@ static int text_y(void) {
}
void unixpw_screen(int init) {
-#ifndef UNIXPW
+ if (unixpw_nis) {
+#ifndef UNIXPW_CRYPT
+ rfbLog("-unixpw_nis is not supported on this OS/machine\n");
+ clean_up_exit(1);
+#endif
+ } else {
+#ifndef UNIXPW_SU
rfbLog("-unixpw is not supported on this OS/machine\n");
clean_up_exit(1);
#endif
+ }
if (init) {
int x, y;
char log[] = "login: ";
@@ -115,6 +129,8 @@ static char slave_str[MAXPATHLEN];
static char slave_str[4096];
#endif
+static int used_get_pty_ptmx = 0;
+
char *get_pty_ptmx(int *fd_p) {
char *slave;
int fd = -1, i, ndevs = 4, tmp;
@@ -130,7 +146,6 @@ char *get_pty_ptmx(int *fd_p) {
#if LIBVNCSERVER_HAVE_GRANTPT
for (i=0; i < ndevs; i++) {
-
#ifdef O_NOCTTY
fd = open(devs[i], O_RDWR|O_NOCTTY);
#else
@@ -146,13 +161,6 @@ char *get_pty_ptmx(int *fd_p) {
return NULL;
}
-#if 0
-#if defined(FIONBIO)
- tmp = 1;
- ioctl(fd, FIONBIO, &tmp);
-#endif
-#endif
-
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCPKT)
tmp = 0;
ioctl(fd, TIOCPKT, (char *) &tmp);
@@ -180,8 +188,6 @@ char *get_pty_ptmx(int *fd_p) {
ioctl(fd, TIOCFLUSH, (char *) 0);
#endif
-
-
strcpy(slave_str, slave);
*fd_p = fd;
return slave_str;
@@ -194,7 +200,6 @@ char *get_pty_ptmx(int *fd_p) {
char *get_pty_loop(int *fd_p) {
- char *slave;
char master_str[16];
int fd = -1, i;
char c;
@@ -233,6 +238,7 @@ char *get_pty_loop(int *fd_p) {
}
char *get_pty(int *fd_p) {
+ used_get_pty_ptmx = 0;
if (getenv("BSD_PTY")) {
return get_pty_loop(fd_p);
}
@@ -240,6 +246,7 @@ char *get_pty(int *fd_p) {
return get_pty_loop(fd_p);
#else
#if LIBVNCSERVER_HAVE_GRANTPT
+ used_get_pty_ptmx = 1;
return get_pty_ptmx(fd_p);
#else
return get_pty_loop(fd_p);
@@ -267,28 +274,76 @@ void try_to_be_nobody(void) {
setegid(pw->pw_gid);
#endif
}
-
#endif /* PWD_H */
}
-static int slave_fd = -1;
+static int slave_fd = -1, alarm_fired = 0;;
+
static void close_alarm (int sig) {
if (slave_fd >= 0) {
close(slave_fd);
}
+ alarm_fired = 1;
+ if (0) sig = 0; /* compiler warning */
+}
+
+static void kill_child (pid_t pid, int fd) {
+ int status;
+
+ slave_fd = -1;
+ alarm_fired = 0;
+ if (fd >= 0) {
+ close(fd);
+ }
+ kill(pid, SIGTERM);
+ waitpid(pid, &status, WNOHANG);
+}
+
+int crypt_verify(char *user, char *pass) {
+#ifndef UNIXPW_CRYPT
+ return 0;
+#else
+ struct passwd *pwd;
+ char *realpw, *cr;
+ int n;
+ pwd = getpwnam(user);
+ if (! pwd) {
+ return 0;
+ }
+
+ realpw = pwd->pw_passwd;
+ if (realpw == NULL || realpw[0] == '\0') {
+ return 0;
+ }
+
+ n = strlen(pass);
+ if (pass[n-1] == '\n') {
+ pass[n-1] = '\0';
+ }
+ cr = crypt(pass, realpw);
+ if (cr == NULL) {
+ return 0;
+ }
+ if (!strcmp(cr, realpw)) {
+ return 1;
+ } else {
+ return 0;
+ }
+#endif /* UNIXPW_CRYPT */
}
int su_verify(char *user, char *pass) {
-#ifndef UNIXPW
+#ifndef UNIXPW_SU
return 0;
#else
int i, j, status, fd = -1, sfd, tfd;
+ int slow_pw = 1;
char *slave, *bin_true = NULL, *bin_su = NULL;
pid_t pid, pidw;
struct stat sbuf;
static int first = 1;
- char instr[16];
+ char instr[32], buf[10];
if (first) {
set_db();
@@ -316,7 +371,15 @@ int su_verify(char *user, char *pass) {
}
}
- if (stat("/bin/su", &sbuf) == 0) {
+#define SU_DEBUG 0
+#if SU_DEBUG
+ if (stat("/su", &sbuf) == 0) {
+ bin_su = "/su"; /* Freesbie read-only-fs /bin/su not suid! */
+#else
+ if (0) {
+ ;
+#endif
+ } else if (stat("/bin/su", &sbuf) == 0) {
bin_su = "/bin/su";
} else if (stat("/usr/bin/su", &sbuf) == 0) {
bin_su = "/usr/bin/su";
@@ -337,10 +400,12 @@ int su_verify(char *user, char *pass) {
}
slave = get_pty(&fd);
+
if (slave == NULL) {
rfbLogPerror("get_pty failed.");
return 0;
}
+
if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
if (fd < 0) {
@@ -358,8 +423,10 @@ if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
}
if (pid == 0) {
+ /* child */
+
int ttyfd;
- char tmp[256];
+ ttyfd = -1; /* compiler warning */
#if LIBVNCSERVER_HAVE_SETSID
if (setsid() == -1) {
@@ -371,7 +438,6 @@ if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
perror("setpgrp");
exit(1);
}
-
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCNOTTY)
ttyfd = open("/dev/tty", O_RDWR);
if (ttyfd >= 0) {
@@ -390,11 +456,21 @@ if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
if (sfd < 0) {
exit(1);
}
- /* sfd should be 0 since we closed 0. */
-#ifdef F_SETFL
- fcntl (sfd, F_SETFL, O_NONBLOCK);
+/* streams options fixups, handle cases as they are found: */
+#if defined(__hpux)
+#if LIBVNCSERVER_HAVE_SYS_STROPTS_H
+#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(I_PUSH)
+ if (used_get_pty_ptmx) {
+ ioctl(sfd, I_PUSH, "ptem");
+ ioctl(sfd, I_PUSH, "ldterm");
+ ioctl(sfd, I_PUSH, "ttcompat");
+ }
#endif
+#endif
+#endif
+
+ /* n.b. sfd will be 0 since we closed 0. so dup it to 1 and 2 */
if (fcntl(sfd, F_DUPFD, 1) == -1) {
exit(1);
}
@@ -402,33 +478,24 @@ if (db) fprintf(stderr, "slave is: %s fd=%d\n", slave, fd);
exit(1);
}
- unlink("/tmp/isatty");
- unlink("/tmp/isastream");
-#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
-#if 0
- if (isastream(sfd)) {
-tfd = open("/tmp/isastream", O_CREAT|O_WRONLY, 0600);
-close(tfd);
- ioctl(sfd, I_PUSH, "ptem");
- ioctl(sfd, I_PUSH, "ldterm");
- ioctl(sfd, I_PUSH, "ttcompat");
- }
-#endif
-#if 1
-#if defined(TIOCSCTTY) && !defined(sun) && !defined(hpux)
+#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCSCTTY)
ioctl(sfd, TIOCSCTTY, (char *) 0);
#endif
-#endif
- if (isatty(sfd)) {
+
+ if (db > 2) {
char nam[256];
-tfd = open("/tmp/isatty", O_CREAT|O_WRONLY, 0600);
-close(tfd);
- sprintf(nam, "stty -a < %s > /tmp/isatty 2>&1", slave);
- system(nam);
+ unlink("/tmp/isatty");
+ tfd = open("/tmp/isatty", O_CREAT|O_WRONLY, 0600);
+ if (isatty(sfd)) {
+ close(tfd);
+ sprintf(nam, "stty -a < %s > /tmp/isatty 2>&1", slave);
+ system(nam);
+ } else {
+ write(tfd, "NOTTTY\n", 7);
+ close(tfd);
+ }
}
-#endif /* SYS_IOCTL_H */
-
chdir("/");
try_to_be_nobody();
@@ -444,102 +511,139 @@ close(tfd);
set_env("LANG", "C");
set_env("SHELL", "/bin/sh");
+ /* synchronize with parent: */
+ write(2, "C", 1);
+
execlp(bin_su, bin_su, user, "-c", bin_true, (char *) NULL);
exit(1);
}
+ /* parent */
if (db) fprintf(stderr, "pid: %d\n", pid);
- if (db > 3) {
- char cmd[32];
- usleep( 100 * 1000 );
- sprintf(cmd, "ps wu %d", pid);
- system(cmd);
- sprintf(cmd, "stty -a < %s", slave);
- system(cmd);
- }
-
- usleep( 500 * 1000 );
-
- /* send the password "early" (i.e. before we drain) */
-if (0) {
- int k;
- for (k = 0; k < strlen(pass); k++) {
- write(fd, pass+k, 1);
- usleep(100 * 1000);
- }
-} else {
- write(fd, pass, strlen(pass));
-}
/*
* set an alarm for blocking read() to close the master
- * (presumably terminating the child. we avoid SIGTERM for now)
+ * (presumably terminating the child. SIGTERM too...)
*/
slave_fd = fd;
+ alarm_fired = 0;
signal(SIGALRM, close_alarm);
alarm(10);
+ /* synchronize with child: */
+ for (i=0; i<10; i++) {
+ int n;
+ buf[0] = '\0';
+ buf[1] = '\0';
+ n = read(fd, buf, 1);
+ if (n < 0 && errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (db) {
+ fprintf(stderr, "read from child: '%s'\n", buf);
+ }
+
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ if (alarm_fired) {
+ kill_child(pid, fd);
+ return 0;
+ }
+
+#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCTRAP)
+ {
+ int control = 1;
+ ioctl(fd, TIOCTRAP, &control);
+ }
+#endif
+
/*
* In addition to checking exit code below, we watch for the
* appearance of the string "Password:". BSD does not seem to
- * ask for a password trying to su to yourself.
+ * ask for a password trying to su to yourself. This is the
+ * setting in /etc/pam.d/su:
+ * auth sufficient pam_self.so
+ * it may be commented out without problem.
*/
- for (i=0; i<16; i++) {
+ for (i=0; i<32; i++) {
instr[i] = '\0';
}
+
+ alarm_fired = 0;
+ signal(SIGALRM, close_alarm);
+ alarm(10);
+
j = 0;
- for (i=0; i < strlen("Password:"); i++) {
+ for (i=0; i < (int) strlen("Password:"); i++) {
char pstr[] = "password:";
- char buf[2];
int n;
buf[0] = '\0';
buf[1] = '\0';
n = read(fd, buf, 1);
+ if (n < 0 && errno == EINTR) {
+ i--;
+ continue;
+ }
-if (db == 1) fprintf(stderr, "%d ", n, db > 1 ? buf : "");
-if (db > 1) fprintf(stderr, "%s", buf);
+if (db) fprintf(stderr, "%s", buf);
if (db > 3 && n == 1 && buf[0] == ':') {
char cmd[32];
usleep( 100 * 1000 );
+ fprintf(stderr, "\n\n");
sprintf(cmd, "ps wu %d", pid);
system(cmd);
sprintf(cmd, "stty -a < %s", slave);
system(cmd);
+ fprintf(stderr, "\n\n");
}
if (n == 1) {
if (isspace(buf[0])) {
+ i--;
continue;
}
instr[j++] = tolower(buf[0]);
}
if (n <= 0 || strstr(pstr, instr) != pstr) {
- rfbLog("\"Password:\" did not appear: '%s' n=%d\n",
- instr, n);
- if (db > 3 && n == 1) {
- continue;
- }
+if (db) {
+ fprintf(stderr, "\"Password:\" did not appear: '%s'" " n=%d\n", instr, n);
+ if (db > 3 && n == 1 && j < 32) {
+ continue;
+ }
+}
alarm(0);
signal(SIGALRM, SIG_DFL);
- slave_fd = -1;
- close(fd);
- kill(pid, SIGTERM);
- waitpid(pid, &status, WNOHANG);
+ kill_child(pid, fd);
return 0;
}
}
+
alarm(0);
signal(SIGALRM, SIG_DFL);
+ if (alarm_fired) {
+ kill_child(pid, fd);
+ return 0;
+ }
- usleep( 250 * 1000 );
-
-#if 0
- tcdrain(fd);
-#endif
+ usleep(100 * 1000);
+ if (slow_pw) {
+ unsigned int k;
+ for (k = 0; k < strlen(pass); k++) {
+ write(fd, pass+k, 1);
+ usleep(100 * 1000);
+ }
+ } else {
+ write(fd, pass, strlen(pass));
+ }
+ alarm_fired = 0;
signal(SIGALRM, close_alarm);
alarm(15);
@@ -549,16 +653,17 @@ if (db > 1) fprintf(stderr, "%s", buf);
* make cause child to die by signal.
*/
for (i = 0; i<4096; i++) {
- char buf[2];
int n;
buf[0] = '\0';
buf[1] = '\0';
n = read(fd, buf, 1);
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
-if (db == 1) fprintf(stderr, "%d ", n, db > 1 ? buf : "");
-if (db > 1) fprintf(stderr, "%s", buf);
+if (db) fprintf(stderr, "%s", buf);
if (n <= 0) {
break;
@@ -569,6 +674,11 @@ if (db) fprintf(stderr, "\n");
alarm(0);
signal(SIGALRM, SIG_DFL);
+ if (alarm_fired) {
+ kill_child(pid, fd);
+ return 0;
+ }
+
slave_fd = -1;
pidw = waitpid(pid, &status, 0);
@@ -577,12 +687,13 @@ if (db) fprintf(stderr, "\n");
if (pid != pidw) {
return 0;
}
+
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return 1; /* this is the only return of success. */
} else {
return 0;
}
-#endif /* UNIXPW */
+#endif /* UNIXPW_SU */
}
static void unixpw_verify(char *user, char *pass) {
@@ -593,9 +704,18 @@ static void unixpw_verify(char *user, char *pass) {
if (db) fprintf(stderr, "unixpw_verify: '%s' '%s'\n", user, db > 1 ? pass : "********");
rfbLog("unixpw_verify: %s\n", user);
- if (su_verify(user, pass)) {
- unixpw_accept(user);
- return;
+ if (unixpw_nis) {
+ if (crypt_verify(user, pass)) {
+ unixpw_accept(user);
+ return;
+ } else {
+ usleep(3000*1000);
+ }
+ } else {
+ if (su_verify(user, pass)) {
+ unixpw_accept(user);
+ return;
+ }
}
if (tries < 2) {
@@ -794,6 +914,13 @@ static void apply_opts (char *user) {
rfbClientPtr cl = unixpw_client;
int i;
+ if (user) {
+ if (cd->unixname) {
+ free(cd->unixname);
+ }
+ cd->unixname = strdup(user);
+ }
+
if (! unixpw_list) {
return;
}
@@ -808,7 +935,7 @@ static void apply_opts (char *user) {
p = strtok(NULL, ",");
continue;
}
- if (!strcmp(user, p)) {
+ if (user && !strcmp(user, p)) {
opts = strdup(q+1);
}
if (!strcmp("*", p)) {
@@ -846,7 +973,6 @@ static void apply_opts (char *user) {
}
void unixpw_accept(char *user) {
-
apply_opts(user);
unixpw_in_progress = 0;