Commit fd084b5d authored by runge's avatar runge

Improvements to -unixpw_cmd and -unixpw_nis.

Experimental X11VNC_WATCH_DX_DY=1 for buggy theme menus,
see: http://ubuntuforums.org/showthread.php?t=1223490
parent 2c6bf923
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -574,18 +574,57 @@ int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input, ...@@ -574,18 +574,57 @@ int run_user_command(char *cmd, rfbClientPtr client, char *mode, char *input,
close_exec_fds(); close_exec_fds();
if (output != NULL) { if (output != NULL) {
FILE *ph = popen(cmd, "r"); FILE *ph;
char line[1024]; char line[1024];
char *cmd2 = NULL;
char tmp[] = "/tmp/x11vnc-tmp.XXXXXX";
int deltmp = 0;
if (input != NULL) {
int tmp_fd = mkstemp(tmp);
if (tmp_fd < 0) {
rfbLog("mkstemp failed on: %s\n", tmp);
clean_up_exit(1);
}
write(tmp_fd, input, len);
close(tmp_fd);
deltmp = 1;
cmd2 = (char *) malloc(100 + strlen(tmp) + strlen(cmd));
sprintf(cmd2, "/bin/cat %s | %s", tmp, cmd);
ph = popen(cmd2, "r");
} else {
ph = popen(cmd, "r");
}
if (ph == NULL) { if (ph == NULL) {
rfbLog("popen(%s) failed", cmd); rfbLog("popen(%s) failed", cmd);
rfbLogPerror("popen"); rfbLogPerror("popen");
clean_up_exit(1); clean_up_exit(1);
} }
while (fgets(line, 1024, ph) != NULL) { memset(line, 0, sizeof(line));
while (fgets(line, sizeof(line), ph) != NULL) {
int j, k = -1;
if (0) fprintf(stderr, "line: %s", line); if (0) fprintf(stderr, "line: %s", line);
fprintf(output, "%s", line); /* take care to handle embedded nulls */
for (j=0; j < sizeof(line); j++) {
if (line[j] != '\0') {
k = j;
}
} }
if (k >= 0) {
write(fileno(output), line, k+1);
}
memset(line, 0, sizeof(line));
}
rc = pclose(ph); rc = pclose(ph);
if (cmd2 != NULL) {
free(cmd2);
}
if (deltmp) {
unlink(tmp);
}
goto got_rc; goto got_rc;
} else if (input != NULL) { } else if (input != NULL) {
FILE *ph = popen(cmd, "w"); FILE *ph = popen(cmd, "w");
...@@ -789,7 +828,7 @@ void client_gone(rfbClientPtr client) { ...@@ -789,7 +828,7 @@ void client_gone(rfbClientPtr client) {
free(userhost); free(userhost);
} else { } else {
rfbLog("client_gone: using cmd: %s\n", client->host); rfbLog("client_gone: using cmd: %s\n", client->host);
run_user_command(gone_cmd, client, "gone", NULL,0,NULL); run_user_command(gone_cmd, client, "gone", NULL, 0, NULL);
} }
} }
......
...@@ -83,8 +83,8 @@ so, delete this exception statement from your version. ...@@ -83,8 +83,8 @@ so, delete this exception statement from your version.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA or see <http://www.gnu.org/licenses/>. * USA or see <http://www.gnu.org/licenses/>.
* *
* In addition, as a special exception, Karl J. Runge * In addition, as a special exception, Karl J. Runge gives permission
* gives permission to link the code of its release of x11vnc with the * to link the code of its release of ultravnc_dsm_helper with the
* OpenSSL project's "OpenSSL" library (or with modified versions of it * OpenSSL project's "OpenSSL" library (or with modified versions of it
* that use the same license as the "OpenSSL" library), and distribute * that use the same license as the "OpenSSL" library), and distribute
* the linked executables. You must obey the GNU General Public License * the linked executables. You must obey the GNU General Public License
......
...@@ -336,7 +336,7 @@ void print_help(int mode) { ...@@ -336,7 +336,7 @@ void print_help(int mode) {
"\n" "\n"
"-scale fraction Scale the framebuffer by factor \"fraction\". Values\n" "-scale fraction Scale the framebuffer by factor \"fraction\". Values\n"
" less than 1 shrink the fb, larger ones expand it. Note:\n" " less than 1 shrink the fb, larger ones expand it. Note:\n"
" image may not be sharp and response may be slower.\n" " the image may not be sharp and response may be slower.\n"
" If \"fraction\" contains a decimal point \".\" it\n" " If \"fraction\" contains a decimal point \".\" it\n"
" is taken as a floating point number, alternatively\n" " is taken as a floating point number, alternatively\n"
" the notation \"m/n\" may be used to denote fractions\n" " the notation \"m/n\" may be used to denote fractions\n"
...@@ -507,7 +507,7 @@ void print_help(int mode) { ...@@ -507,7 +507,7 @@ void print_help(int mode) {
" Repeater mode: Some services provide an intermediate\n" " Repeater mode: Some services provide an intermediate\n"
" \"vnc repeater\": http://www.uvnc.com/addons/repeater.html\n" " \"vnc repeater\": http://www.uvnc.com/addons/repeater.html\n"
" (and also http://koti.mbnet.fi/jtko/ for linux port)\n" " (and also http://koti.mbnet.fi/jtko/ for linux port)\n"
" that acts as a proxy / gateway. Modes like these require\n" " that acts as a proxy/gateway. Modes like these require\n"
" an initial string to be sent for the reverse connection\n" " an initial string to be sent for the reverse connection\n"
" before the VNC protocol is started. Here are the ways\n" " before the VNC protocol is started. Here are the ways\n"
" to do this:\n" " to do this:\n"
...@@ -782,12 +782,12 @@ void print_help(int mode) { ...@@ -782,12 +782,12 @@ void print_help(int mode) {
" full-access passwords)\n" " full-access passwords)\n"
"\n" "\n"
"-unixpw [list] Use Unix username and password authentication. x11vnc\n" "-unixpw [list] Use Unix username and password authentication. x11vnc\n"
" uses the su(1) program to verify the user's password.\n" " will use the su(1) program to verify the user's\n"
" [list] is an optional comma separated list of allowed\n" " password. [list] is an optional comma separated list\n"
" Unix usernames. If the [list] string begins with the\n" " of allowed Unix usernames. If the [list] string begins\n"
" character \"!\" then the entire list is taken as an\n" " with the character \"!\" then the entire list is taken\n"
" exclude list. See below for per-user options that can\n" " as an exclude list. See below for per-user options\n"
" be applied.\n" " that can be applied.\n"
"\n" "\n"
" A familiar \"login:\" and \"Password:\" dialog is\n" " A familiar \"login:\" and \"Password:\" dialog is\n"
" presented to the user on a black screen inside the\n" " presented to the user on a black screen inside the\n"
...@@ -803,8 +803,9 @@ void print_help(int mode) { ...@@ -803,8 +803,9 @@ void print_help(int mode) {
"\n" "\n"
" Since the detailed behavior of su(1) can vary from\n" " Since the detailed behavior of su(1) can vary from\n"
" OS to OS and for local configurations, test the mode\n" " OS to OS and for local configurations, test the mode\n"
" carefully. x11vnc will attempt to be conservative and\n" " before deployment to make sure it is working properly.\n"
" reject a login if anything abnormal occurs.\n" " x11vnc will attempt to be conservative and reject a\n"
" login if anything abnormal occurs.\n"
"\n" "\n"
" One case to note: FreeBSD and the other BSD's by\n" " One case to note: FreeBSD and the other BSD's by\n"
" default it is impossible for the user running x11vnc to\n" " default it is impossible for the user running x11vnc to\n"
...@@ -837,7 +838,7 @@ void print_help(int mode) { ...@@ -837,7 +838,7 @@ void print_help(int mode) {
" to come from the same machine x11vnc is running on\n" " to come from the same machine x11vnc is running on\n"
" (e.g. from a ssh -L port redirection). And that the\n" " (e.g. from a ssh -L port redirection). And that the\n"
" -stunnel SSL mode be used for encryption over the\n" " -stunnel SSL mode be used for encryption over the\n"
" network.(see the description of -stunnel below).\n" " network. (see the description of -stunnel below).\n"
"\n" "\n"
" Note: as a convenience, if you ssh(1) in and start\n" " Note: as a convenience, if you ssh(1) in and start\n"
" x11vnc it will check if the environment variable\n" " x11vnc it will check if the environment variable\n"
...@@ -865,7 +866,7 @@ void print_help(int mode) { ...@@ -865,7 +866,7 @@ void print_help(int mode) {
" Set UNIXPW_DISABLE_LOCALHOST=1 to disable the -localhost\n" " Set UNIXPW_DISABLE_LOCALHOST=1 to disable the -localhost\n"
" requirement in Method 2). One should never do this\n" " requirement in Method 2). One should never do this\n"
" (i.e. allow the Unix passwords to be sniffed on the\n" " (i.e. allow the Unix passwords to be sniffed on the\n"
" network).\n" " network.)\n"
"\n" "\n"
" Regarding reverse connections (e.g. -R connect:host\n" " Regarding reverse connections (e.g. -R connect:host\n"
" and -connect host), when the -localhost constraint is\n" " and -connect host), when the -localhost constraint is\n"
...@@ -883,7 +884,7 @@ void print_help(int mode) { ...@@ -883,7 +884,7 @@ void print_help(int mode) {
" in -inetd mode (thereby bypassing inetd). See the FAQ\n" " in -inetd mode (thereby bypassing inetd). See the FAQ\n"
" for details.\n" " for details.\n"
"\n" "\n"
" The user names in the comma separated [list] can have\n" " The user names in the comma separated [list] may have\n"
" per-user options after a \":\", e.g. \"fred:opts\"\n" " per-user options after a \":\", e.g. \"fred:opts\"\n"
" where \"opts\" is a \"+\" separated list of\n" " where \"opts\" is a \"+\" separated list of\n"
" \"viewonly\", \"fullaccess\", \"input=XXXX\", or\n" " \"viewonly\", \"fullaccess\", \"input=XXXX\", or\n"
...@@ -891,13 +892,13 @@ void print_help(int mode) { ...@@ -891,13 +892,13 @@ void print_help(int mode) {
" For \"input=\" it is the K,M,B,C described under -input.\n" " For \"input=\" it is the K,M,B,C described under -input.\n"
"\n" "\n"
" If an item in the list is \"*\" that means those\n" " If an item in the list is \"*\" that means those\n"
" options apply to all users. It also means all users\n" " options apply to all users. It ALSO implies all users\n"
" are allowed to log in after supplying a valid password.\n" " are allowed to log in after supplying a valid password.\n"
" Use \"deny\" to explicitly deny some users if you use\n" " Use \"deny\" to explicitly deny some users if you use\n"
" \"*\" to set a global option. If [list] begins with\n" " \"*\" to set a global option. If [list] begins with the\n"
" the \"!\" character then \"*\" is ignored for checking\n" " \"!\" character then \"*\" is ignored for checking if\n"
" if the user is allowed, but the any value of options\n" " the user is allowed, but the option values associated\n"
" associated with it does apply as normal.\n" " with it do apply as normal.\n"
"\n" "\n"
" There are also some utilities for testing password\n" " There are also some utilities for testing password\n"
" if [list] starts with the \"%%\" character. See the\n" " if [list] starts with the \"%%\" character. See the\n"
...@@ -922,32 +923,89 @@ void print_help(int mode) { ...@@ -922,32 +923,89 @@ void print_help(int mode) {
"\n" "\n"
" NIS is not required for this mode to work (only that\n" " NIS is not required for this mode to work (only that\n"
" getpwnam(3) return the encrypted password is required),\n" " getpwnam(3) return the encrypted password is required),\n"
" but it is unlikely it will work for any most modern\n" " but it is unlikely it will work (as an ordinary user)\n"
" environments unless x11vnc is run as root to be able\n" " for most modern environments unless NIS is available.\n"
" to access /etc/shadow (note running as root is often\n" " On the other hand, when x11vnc is run as root it will\n"
" done when running x11vnc from inetd and xdm/gdm/kdm).\n" " be able to to access /etc/shadow even if NIS is not\n"
" available (note running as root is often done when\n"
" running x11vnc from inetd and xdm/gdm/kdm).\n"
"\n" "\n"
" Looked at another way, if you do not want to use the\n" " Looked at another way, if you do not want to use the\n"
" su(1) method provided by -unixpw, you can run x11vnc\n" " su(1) method provided by -unixpw (i.e. su_verify()), you\n"
" as root and use -unixpw_nis. Any users with passwords\n" " can run x11vnc as root and use -unixpw_nis. Any users\n"
" in /etc/shadow can then be authenticated. You may want\n" " with passwords in /etc/shadow can then be authenticated.\n"
" to use -users unixpw= to switch the process user after\n" "\n"
" the user logs in.\n" " In -unixpw_nis mode, under no circumstances is x11vnc's\n"
" user password verifying function based on su called\n"
" (i.e. the function su_verify() that runs /bin/su\n"
" in a pseudoterminal to verify passwords.) However,\n"
" if -unixpw_nis is used in conjunction with the -find\n"
" and -create -display WAIT:... modes then, if x11vnc is\n"
" running as root, /bin/su may be called externally to\n"
" run the find or create commands.\n"
"\n" "\n"
"-unixpw_cmd cmd As -unixpw above, however do not use su(1) but rather\n" "-unixpw_cmd cmd As -unixpw above, however do not use su(1) but rather\n"
" run the externally supplied command \"cmd\". The first\n" " run the externally supplied command \"cmd\". The first\n"
" line of its stdin will the username and the second line\n" " line of its stdin will be the username and the second\n"
" the received password. If the command exits with status\n" " line the received password. If the command exits\n"
" 0 (success) the VNC client will be accepted. It will be\n" " with status 0 (success) the VNC user will be accepted.\n"
" rejected for any other return status.\n" " It will be rejected for any other return status.\n"
"\n" "\n"
" Dynamic passwords and non-unix passwords can be\n" " Dynamic passwords and non-unix passwords, e.g. LDAP,\n"
" implemented this way by providing your own custom helper\n" " can be implemented this way by providing your own custom\n"
" program. Note that under unixpw mode the remote viewer\n" " helper program. Note that the remote viewer is given 3\n"
" is given 3 tries to enter the correct password.\n" " tries to enter the correct password, and so the program\n"
"\n" " may be called in a row that many (or more) times.\n"
" If a list of allowed users is needed use -unixpw [list]\n" "\n"
" in addition to this option.\n" " If a list of allowed users is needed to limit who can\n"
" log in, use -unixpw [list] in addition to this option.\n"
"\n"
" In FINDDISPLAY and FINDCREATEDISPLAY modes the \"cmd\"\n"
" will also be run with the RFB_UNIXPW_CMD_RUN env. var.\n"
" non-empty and set to the corresponding display\n"
" find/create command. The first two lines of input are\n"
" the username and passwd as in the normal case described\n"
" above. To support FINDDISPLAY and FINDCREATEDISPLAY,\n"
" \"cmd\" should run the requested command as the user\n"
" (and most likely refusing to run it if the password is\n"
" not correct.) Here is an example script (note it has\n"
" a hardwired bogus password \"abc\"!)\n"
"\n"
" #!/bin/sh\n"
" # Example x11vnc -unixpw_cmd script.\n"
" # Read the first two lines of stdin (user and passwd)\n"
" read user\n"
" read pass\n"
" \n"
" debug=0\n"
" if [ $debug = 1 ]; then\n"
" echo \"user: $user\" 1>&2\n"
" echo \"pass: $pass\" 1>&2\n"
" env | egrep -i 'rfb|vnc' 1>&2\n"
" fi\n"
" \n"
" # Check if the password is valid.\n"
" # (A real example would use ldap lookup, etc!)\n"
" if [ \"X$pass\" != \"Xabc\" ]; then\n"
" exit 1 # incorrect password\n"
" fi\n"
" \n"
" if [ \"X$RFB_UNIXPW_CMD_RUN\" = \"X\" ]; then\n"
" exit 0 # correct password\n"
" else\n"
" # Run the requested command (finddisplay)\n"
" if [ $debug = 1 ]; then\n"
" echo \"run: $RFB_UNIXPW_CMD_RUN\" 1>&2\n"
" fi\n"
" exec /bin/su - \"$user\" -c \"$RFB_UNIXPW_CMD_RUN\"\n"
" fi\n"
"\n"
" In -unixpw_cmd mode, under no circumstances is x11vnc's\n"
" user password verifying function based on su called\n"
" (i.e. the function su_verify() that runs /bin/su in a\n"
" pseudoterminal to verify passwords.) It is up to the\n"
" supplied unixpw_cmd to do user switching if desired\n"
" and if it has the permissions to do so.\n"
"\n" "\n"
"-find Find the user's display using FINDDISPLAY. This is an\n" "-find Find the user's display using FINDDISPLAY. This is an\n"
" alias for \"-display WAIT:cmd=FINDDISPLAY\".\n" " alias for \"-display WAIT:cmd=FINDDISPLAY\".\n"
...@@ -1064,9 +1122,15 @@ void print_help(int mode) { ...@@ -1064,9 +1122,15 @@ void print_help(int mode) {
"\n" "\n"
" xauth extract - $DISPLAY\"\n" " xauth extract - $DISPLAY\"\n"
"\n" "\n"
" In the case of -unixpw (but not -unixpw_nis), then the\n" " In the case of -unixpw (and -unixpw_nis only if x11vnc\n"
" cmd= command is run as the user who just authenticated\n" " is running as root), then the cmd= command is run\n"
" via the login and password prompt.\n" " as the user who just authenticated via the login and\n"
" password prompt.\n"
"\n"
" In the case of -unixpw_cmd, the commands will also be\n"
" run as the logged-in user, as long as the user-supplied\n"
" helper program supports RFB_UNIXPW_CMD_RUN (see the\n"
" -unixpw_cmd option.)\n"
"\n" "\n"
" Also in the case of -unixpw, the user logging in can\n" " Also in the case of -unixpw, the user logging in can\n"
" place a colon at the end of her username and supply\n" " place a colon at the end of her username and supply\n"
......
...@@ -343,11 +343,22 @@ void update_x11_pointer_position(int x, int y) { ...@@ -343,11 +343,22 @@ void update_x11_pointer_position(int x, int y) {
return; return;
#else #else
int rc; int rc;
static int watch_dx_dy = -1;
RAWFB_RET_VOID RAWFB_RET_VOID
if (watch_dx_dy == -1) {
if (getenv("X11VNC_WATCH_DX_DY")) {
watch_dx_dy = 1;
} else {
watch_dx_dy = 0;
}
}
X_LOCK; X_LOCK;
if (use_xwarppointer) { if (watch_dx_dy && cursor_x == x && cursor_y == y) {
;
} else if (use_xwarppointer) {
/* /*
* off_x and off_y not needed with XWarpPointer since * off_x and off_y not needed with XWarpPointer since
* window is used: * window is used:
......
...@@ -96,6 +96,7 @@ void unixpw_accept(char *user); ...@@ -96,6 +96,7 @@ void unixpw_accept(char *user);
void unixpw_deny(void); void unixpw_deny(void);
void unixpw_msg(char *msg, int delay); void unixpw_msg(char *msg, int delay);
int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp); int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp);
int unixpw_cmd_run(char *user, char *pass, char *cmd, char *line, int *n, int nodisp);
int crypt_verify(char *user, char *pass); int crypt_verify(char *user, char *pass);
int cmd_verify(char *user, char *pass); int cmd_verify(char *user, char *pass);
void unixpw_verify_screen(char *user, char *pass); void unixpw_verify_screen(char *user, char *pass);
...@@ -530,6 +531,82 @@ int crypt_verify(char *user, char *pass) { ...@@ -530,6 +531,82 @@ int crypt_verify(char *user, char *pass) {
#endif /* UNIXPW_CRYPT */ #endif /* UNIXPW_CRYPT */
} }
int unixpw_cmd_run(char *user, char *pass, char *cmd, char *line, int *n, int nodisp) {
int i, len, rc;
char *str;
FILE *out;
if (! user || ! pass) {
return 0;
}
if (! unixpw_cmd || *unixpw_cmd == '\0') {
return 0;
}
if (! scheck(user, 100, "username")) {
return 0;
}
if (! scheck(pass, 100, "password")) {
return 0;
}
if (! unixpw_list_match(user)) {
return 0;
}
if (cmd == NULL) {
cmd = "";
}
len = strlen(user) + 1 + strlen(pass) + 1 + 1;
str = (char *) malloc(len);
if (! str) {
return 0;
}
str[0] = '\0';
strcat(str, user);
strcat(str, "\n");
strcat(str, pass);
if (!strchr(pass, '\n')) {
strcat(str, "\n");
}
out = tmpfile();
if (out == NULL) {
rfbLog("unixpw_cmd_run tmpfile() failed.\n");
clean_up_exit(1);
}
set_env("RFB_UNIXPW_CMD_RUN", cmd);
rc = run_user_command(unixpw_cmd, unixpw_client, "cmd_verify",
str, strlen(str), out);
set_env("RFB_UNIXPW_CMD_RUN", "");
for (i=0; i < len; i++) {
str[i] = '\0';
}
free(str);
fflush(out);
rewind(out);
for (i=0; i < (*n) - 1; i++) {
int c = fgetc(out);
if (c == EOF) {
break;
}
line[i] = (char) c;
}
fclose(out);
*n = i;
if (rc == 0) {
return 1;
} else {
return 0;
}
}
int cmd_verify(char *user, char *pass) { int cmd_verify(char *user, char *pass) {
int i, len, rc; int i, len, rc;
char *str; char *str;
...@@ -602,6 +679,7 @@ int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int ...@@ -602,6 +679,7 @@ int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int
set_db(); set_db();
first = 0; first = 0;
} }
rfbLog("su_verify: '%s' for %s.\n", user, cmd ? "command" : "login");
if (! scheck(user, 100, "username")) { if (! scheck(user, 100, "username")) {
return 0; return 0;
...@@ -1043,7 +1121,7 @@ int unixpw_verify(char *user, char *pass) { ...@@ -1043,7 +1121,7 @@ int unixpw_verify(char *user, char *pass) {
" succeeded.\n", user); " succeeded.\n", user);
ok = 1; ok = 1;
} else { } else {
rfbLog("unixpw_verify: crypt_verify login for '%s'" rfbLog("unixpw_verify: cmd_verify login for '%s'"
" failed.\n", user); " failed.\n", user);
usleep(3000*1000); usleep(3000*1000);
ok = 0; ok = 0;
......
...@@ -42,6 +42,7 @@ extern void unixpw_accept(char *user); ...@@ -42,6 +42,7 @@ extern void unixpw_accept(char *user);
extern void unixpw_deny(void); extern void unixpw_deny(void);
extern void unixpw_msg(char *msg, int delay); extern void unixpw_msg(char *msg, int delay);
extern int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp); extern int su_verify(char *user, char *pass, char *cmd, char *rbuf, int *rbuf_size, int nodisp);
extern int unixpw_cmd_run(char *user, char *pass, char *cmd, char *line, int *n, int nodisp);
extern int crypt_verify(char *user, char *pass); extern int crypt_verify(char *user, char *pass);
extern int cmd_verify(char *user, char *pass); extern int cmd_verify(char *user, char *pass);
extern int unixpw_verify(char *user, char *pass); extern int unixpw_verify(char *user, char *pass);
......
...@@ -308,6 +308,9 @@ static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **hom ...@@ -308,6 +308,9 @@ static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **hom
if (strstr(user2group[i], user) == user2group[i]) { if (strstr(user2group[i], user) == user2group[i]) {
char *w = user2group[i] + strlen(user); char *w = user2group[i] + strlen(user);
if (*w == '.') { if (*w == '.') {
#if (SMALL_FOOTPRINT > 2)
gotgroup = 0;
#else
struct group* gr = getgrnam(++w); struct group* gr = getgrnam(++w);
if (! gr) { if (! gr) {
rfbLog("Invalid group: %s\n", w); rfbLog("Invalid group: %s\n", w);
...@@ -320,6 +323,7 @@ static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **hom ...@@ -320,6 +323,7 @@ static void user2uid(char *user, uid_t *uid, gid_t *gid, char **name, char **hom
did[i] = 1; did[i] = 1;
} }
gotgroup = 1; gotgroup = 1;
#endif
} }
} }
i++; i++;
...@@ -761,7 +765,7 @@ static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_ ...@@ -761,7 +765,7 @@ static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_
return 0; return 0;
#else #else
/* /*
* OK tricky here, we need to free the shm... otherwise * OK, tricky here, we need to free the shm... otherwise
* we won't be able to delete it as the other user... * we won't be able to delete it as the other user...
*/ */
if (fb_mode == 1 && (using_shm && ! xform24to32)) { if (fb_mode == 1 && (using_shm && ! xform24to32)) {
...@@ -773,11 +777,13 @@ static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_ ...@@ -773,11 +777,13 @@ static int switch_user_env(uid_t uid, gid_t gid, char *name, char *home, int fb_
#if LIBVNCSERVER_HAVE_PWD_H #if LIBVNCSERVER_HAVE_PWD_H
if (getpwuid(uid) != NULL && getenv("X11VNC_SINGLE_GROUP") == NULL) { if (getpwuid(uid) != NULL && getenv("X11VNC_SINGLE_GROUP") == NULL) {
struct passwd *p = getpwuid(uid); struct passwd *p = getpwuid(uid);
if (initgroups(p->pw_name, gid) == 0) { /* another possibility is p->pw_gid instead of gid */
if (setgid(gid) == 0 && initgroups(p->pw_name, gid) == 0) {
grp_ok = 1; grp_ok = 1;
} else { } else {
rfbLogPerror("initgroups"); rfbLogPerror("initgroups");
} }
endgrent();
} }
#endif #endif
#endif #endif
...@@ -2235,12 +2241,58 @@ static char *get_usslpeer() { ...@@ -2235,12 +2241,58 @@ static char *get_usslpeer() {
return upeer; return upeer;
} }
static void do_try_switch(char *usslpeer, char *users_list_save) {
if (usslpeer) {
char *u = (char *) malloc(strlen(usslpeer+2));
sprintf(u, "+%s", usslpeer);
if (switch_user(u, 0)) {
rfbLog("sslpeer switched to user: %s\n", usslpeer);
} else {
rfbLog("sslpeer failed to switch to user: %s\n", usslpeer);
}
free(u);
} else if (users_list_save && keep_unixpw_user) {
char *user = keep_unixpw_user;
char *u = (char *)malloc(strlen(user)+1);
users_list = users_list_save;
u[0] = '\0';
if (!strcmp(users_list, "unixpw=")) {
sprintf(u, "+%s", user);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("unixpw="), ",");
while (p) {
if (!strcmp(p, user)) {
sprintf(u, "+%s", user);
break;
}
p = strtok(NULL, ",");
}
free(str);
}
if (u[0] == '\0') {
rfbLog("unixpw_accept skipping switch to user: %s (drc)\n", user);
} else if (switch_user(u, 0)) {
rfbLog("unixpw_accept switched to user: %s (drc)\n", user);
} else {
rfbLog("unixpw_accept failed to switch to user: %s (drc)\n", user);
}
free(u);
}
}
static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int created_disp, int db) { static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int created_disp, int db) {
char tmp[] = "/tmp/x11vnc-find_display.XXXXXX"; char tmp[] = "/tmp/x11vnc-find_display.XXXXXX";
char line1[1024], line2[16384]; char line1[1024], line2[16384];
char *q, *usslpeer = NULL; char *q, *usslpeer = NULL;
int n, nodisp = 0, saw_xdmcp = 0; int n, nodisp = 0, saw_xdmcp = 0;
int tmp_fd = -1; int tmp_fd = -1;
int internal_cmd = 0;
int tried_switch = 0;
memset(line1, 0, 1024); memset(line1, 0, 1024);
memset(line2, 0, 16384); memset(line2, 0, 16384);
...@@ -2251,6 +2303,7 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr ...@@ -2251,6 +2303,7 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr
return 0; return 0;
} }
} }
if (getenv("DEBUG_RUN_CMD")) db = 1;
/* only sets environment variables: */ /* only sets environment variables: */
run_user_command("", latest_client, "env", NULL, 0, NULL); run_user_command("", latest_client, "env", NULL, 0, NULL);
...@@ -2265,7 +2318,11 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr ...@@ -2265,7 +2318,11 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr
strstr(cmd, "FINDCREATEDISPLAY") == cmd) { strstr(cmd, "FINDCREATEDISPLAY") == cmd) {
char *nd = ""; char *nd = "";
char fdout[128]; char fdout[128];
internal_cmd = 1;
tmp_fd = mkstemp(tmp); tmp_fd = mkstemp(tmp);
if (tmp_fd < 0) { if (tmp_fd < 0) {
rfbLog("wait_for_client: open failed: %s\n", tmp); rfbLog("wait_for_client: open failed: %s\n", tmp);
rfbLogPerror("mkstemp"); rfbLogPerror("mkstemp");
...@@ -2302,7 +2359,7 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr ...@@ -2302,7 +2359,7 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr
rfbLog("wait_for_client: running: %s\n", cmd); rfbLog("wait_for_client: running: %s\n", cmd);
if (unixpw) { if (unixpw && !unixpw_nis) {
int res = 0, k, j, i; int res = 0, k, j, i;
char line[18000]; char line[18000];
...@@ -2310,9 +2367,14 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr ...@@ -2310,9 +2367,14 @@ static int do_run_cmd(char *cmd, char *create_cmd, char *users_list_save, int cr
if (keep_unixpw_user && keep_unixpw_pass) { if (keep_unixpw_user && keep_unixpw_pass) {
n = 18000; n = 18000;
if (unixpw_cmd != NULL) {
res = unixpw_cmd_run(keep_unixpw_user,
keep_unixpw_pass, cmd, line, &n, nodisp);
} else {
res = su_verify(keep_unixpw_user, res = su_verify(keep_unixpw_user,
keep_unixpw_pass, cmd, line, &n, nodisp); keep_unixpw_pass, cmd, line, &n, nodisp);
} }
}
if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprintf(stderr, "res=%d n=%d\n", res, n);} if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprintf(stderr, "res=%d n=%d\n", res, n);}
if (! res) { if (! res) {
...@@ -2331,7 +2393,13 @@ if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprint ...@@ -2331,7 +2393,13 @@ if (db) {fprintf(stderr, "line: "); write(2, line, n); write(2, "\n", 1); fprint
findcreatedisplay = 1; findcreatedisplay = 1;
if (getuid() != 0) { if (unixpw_cmd != NULL) {
/* let the external unixpw command do it: */
n = 18000;
close_exec_fds();
res = unixpw_cmd_run(keep_unixpw_user,
keep_unixpw_pass, create_cmd, line, &n, nodisp);
} else if (getuid() != 0) {
/* if not root, run as the other user... */ /* if not root, run as the other user... */
n = 18000; n = 18000;
close_exec_fds(); close_exec_fds();
...@@ -2411,6 +2479,7 @@ if (db) fprintf(stderr, "line1: '%s'\n", line1); ...@@ -2411,6 +2479,7 @@ if (db) fprintf(stderr, "line1: '%s'\n", line1);
} }
if (db) write(2, line, 100); if (db) write(2, line, 100);
if (db) fprintf(stderr, "\n"); if (db) fprintf(stderr, "\n");
} else { } else {
FILE *p; FILE *p;
int rc; int rc;
...@@ -2428,9 +2497,22 @@ if (db) fprintf(stderr, "\n"); ...@@ -2428,9 +2497,22 @@ if (db) fprintf(stderr, "\n");
p = popen(c, "r"); p = popen(c, "r");
free(c); free(c);
} else if (unixpw_nis && keep_unixpw_user) {
char *c;
if (getuid() == 0) {
c = (char *) malloc(strlen("su - '' -c \"")
+ strlen(keep_unixpw_user) + strlen(cmd) + 1 + 1);
sprintf(c, "su - '%s' -c \"%s\"", keep_unixpw_user, cmd);
} else {
c = strdup(cmd);
}
p = popen(c, "r");
free(c);
} else { } else {
p = popen(cmd, "r"); p = popen(cmd, "r");
} }
if (! p) { if (! p) {
rfbLog("wait_for_client: cmd failed: %s\n", cmd); rfbLog("wait_for_client: cmd failed: %s\n", cmd);
rfbLogPerror("popen"); rfbLogPerror("popen");
...@@ -2575,49 +2657,13 @@ fprintf(stderr, "\n");} ...@@ -2575,49 +2657,13 @@ fprintf(stderr, "\n");}
} }
} }
if (usslpeer) { if (!tried_switch) {
char *u = (char *) malloc(strlen(usslpeer+2)); do_try_switch(usslpeer, users_list_save);
sprintf(u, "+%s", usslpeer); tried_switch = 1;
if (switch_user(u, 0)) {
rfbLog("sslpeer switched to user: %s\n", usslpeer);
} else {
rfbLog("sslpeer failed to switch to user: %s\n", usslpeer);
}
free(u);
} else if (users_list_save && keep_unixpw_user) {
char *user = keep_unixpw_user;
char *u = (char *)malloc(strlen(user)+1);
users_list = users_list_save;
u[0] = '\0';
if (!strcmp(users_list, "unixpw=")) {
sprintf(u, "+%s", user);
} else {
char *p, *str = strdup(users_list);
p = strtok(str + strlen("unixpw="), ",");
while (p) {
if (!strcmp(p, user)) {
sprintf(u, "+%s", user);
break;
}
p = strtok(NULL, ",");
}
free(str);
}
if (u[0] == '\0') {
rfbLog("unixpw_accept skipping switch to user: %s\n", user);
} else if (switch_user(u, 0)) {
rfbLog("unixpw_accept switched to user: %s\n", user);
} else {
rfbLog("unixpw_accept failed to switch to user: %s\n", user);
}
free(u);
} }
if (unixpw) { if (unixpw) {
/* Some cleanup and messaging for -unixpw case: */
char str[32]; char str[32];
if (keep_unixpw_user && keep_unixpw_pass) { if (keep_unixpw_user && keep_unixpw_pass) {
......
.\" This file was automatically generated from x11vnc -help output. .\" This file was automatically generated from x11vnc -help output.
.TH X11VNC "1" "July 2009" "x11vnc " "User Commands" .TH X11VNC "1" "August 2009" "x11vnc " "User Commands"
.SH NAME .SH NAME
x11vnc - allow VNC connections to real X11 displays x11vnc - allow VNC connections to real X11 displays
version: 0.9.9, lastmod: 2009-07-11 version: 0.9.9, lastmod: 2009-08-10
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
...@@ -348,7 +348,7 @@ is needed for the latter, feel free to ask). ...@@ -348,7 +348,7 @@ is needed for the latter, feel free to ask).
.IP .IP
Scale the framebuffer by factor \fIfraction\fR. Values Scale the framebuffer by factor \fIfraction\fR. Values
less than 1 shrink the fb, larger ones expand it. Note: less than 1 shrink the fb, larger ones expand it. Note:
image may not be sharp and response may be slower. the image may not be sharp and response may be slower.
If \fIfraction\fR contains a decimal point "." it If \fIfraction\fR contains a decimal point "." it
is taken as a floating point number, alternatively is taken as a floating point number, alternatively
the notation "m/n" may be used to denote fractions the notation "m/n" may be used to denote fractions
...@@ -568,7 +568,7 @@ is running as root (e.g. via ...@@ -568,7 +568,7 @@ is running as root (e.g. via
Repeater mode: Some services provide an intermediate Repeater mode: Some services provide an intermediate
"vnc repeater": http://www.uvnc.com/addons/repeater.html "vnc repeater": http://www.uvnc.com/addons/repeater.html
(and also http://koti.mbnet.fi/jtko/ for linux port) (and also http://koti.mbnet.fi/jtko/ for linux port)
that acts as a proxy / gateway. Modes like these require that acts as a proxy/gateway. Modes like these require
an initial string to be sent for the reverse connection an initial string to be sent for the reverse connection
before the VNC protocol is started. Here are the ways before the VNC protocol is started. Here are the ways
to do this: to do this:
...@@ -871,14 +871,14 @@ full-access passwords) ...@@ -871,14 +871,14 @@ full-access passwords)
\fB-unixpw\fR \fI[list]\fR \fB-unixpw\fR \fI[list]\fR
.IP .IP
Use Unix username and password authentication. x11vnc Use Unix username and password authentication. x11vnc
uses the will use the
.IR su (1) .IR su (1)
program to verify the user's password. program to verify the user's
[list] is an optional comma separated list of allowed password. [list] is an optional comma separated list
Unix usernames. If the [list] string begins with the of allowed Unix usernames. If the [list] string begins
character "!" then the entire list is taken as an with the character "!" then the entire list is taken
exclude list. See below for per-user options that can as an exclude list. See below for per-user options
be applied. that can be applied.
.IP .IP
A familiar "login:" and "Password:" dialog is A familiar "login:" and "Password:" dialog is
presented to the user on a black screen inside the presented to the user on a black screen inside the
...@@ -896,8 +896,9 @@ Since the detailed behavior of ...@@ -896,8 +896,9 @@ Since the detailed behavior of
.IR su (1) .IR su (1)
can vary from can vary from
OS to OS and for local configurations, test the mode OS to OS and for local configurations, test the mode
carefully. x11vnc will attempt to be conservative and before deployment to make sure it is working properly.
reject a login if anything abnormal occurs. x11vnc will attempt to be conservative and reject a
login if anything abnormal occurs.
.IP .IP
One case to note: FreeBSD and the other BSD's by One case to note: FreeBSD and the other BSD's by
default it is impossible for the user running x11vnc to default it is impossible for the user running x11vnc to
...@@ -932,7 +933,7 @@ Method 2) requires the viewer connection to appear ...@@ -932,7 +933,7 @@ Method 2) requires the viewer connection to appear
to come from the same machine x11vnc is running on to come from the same machine x11vnc is running on
(e.g. from a ssh \fB-L\fR port redirection). And that the (e.g. from a ssh \fB-L\fR port redirection). And that the
\fB-stunnel\fR SSL mode be used for encryption over the \fB-stunnel\fR SSL mode be used for encryption over the
network.(see the description of \fB-stunnel\fR below). network. (see the description of \fB-stunnel\fR below).
.IP .IP
Note: as a convenience, if you Note: as a convenience, if you
.IR ssh (1) .IR ssh (1)
...@@ -966,7 +967,7 @@ local connections from that machine are accepted). ...@@ -966,7 +967,7 @@ local connections from that machine are accepted).
Set UNIXPW_DISABLE_LOCALHOST=1 to disable the \fB-localhost\fR Set UNIXPW_DISABLE_LOCALHOST=1 to disable the \fB-localhost\fR
requirement in Method 2). One should never do this requirement in Method 2). One should never do this
(i.e. allow the Unix passwords to be sniffed on the (i.e. allow the Unix passwords to be sniffed on the
network). network.)
.IP .IP
Regarding reverse connections (e.g. \fB-R\fR connect:host Regarding reverse connections (e.g. \fB-R\fR connect:host
and \fB-connect\fR host), when the \fB-localhost\fR constraint is and \fB-connect\fR host), when the \fB-localhost\fR constraint is
...@@ -984,7 +985,7 @@ Tip: you can also have your own stunnel spawn x11vnc ...@@ -984,7 +985,7 @@ Tip: you can also have your own stunnel spawn x11vnc
in \fB-inetd\fR mode (thereby bypassing inetd). See the FAQ in \fB-inetd\fR mode (thereby bypassing inetd). See the FAQ
for details. for details.
.IP .IP
The user names in the comma separated [list] can have The user names in the comma separated [list] may have
per-user options after a ":", e.g. "fred:opts" per-user options after a ":", e.g. "fred:opts"
where "opts" is a "+" separated list of where "opts" is a "+" separated list of
"viewonly", "fullaccess", "input=XXXX", or "viewonly", "fullaccess", "input=XXXX", or
...@@ -992,13 +993,13 @@ where "opts" is a "+" separated list of ...@@ -992,13 +993,13 @@ where "opts" is a "+" separated list of
For "input=" it is the K,M,B,C described under \fB-input.\fR For "input=" it is the K,M,B,C described under \fB-input.\fR
.IP .IP
If an item in the list is "*" that means those If an item in the list is "*" that means those
options apply to all users. It also means all users options apply to all users. It ALSO implies all users
are allowed to log in after supplying a valid password. are allowed to log in after supplying a valid password.
Use "deny" to explicitly deny some users if you use Use "deny" to explicitly deny some users if you use
"*" to set a global option. If [list] begins with "*" to set a global option. If [list] begins with the
the "!" character then "*" is ignored for checking "!" character then "*" is ignored for checking if
if the user is allowed, but the any value of options the user is allowed, but the option values associated
associated with it does apply as normal. with it do apply as normal.
.IP .IP
There are also some utilities for testing password There are also some utilities for testing password
if [list] starts with the "%" character. See the if [list] starts with the "%" character. See the
...@@ -1032,18 +1033,27 @@ user can authenticate ANY user. ...@@ -1032,18 +1033,27 @@ user can authenticate ANY user.
NIS is not required for this mode to work (only that NIS is not required for this mode to work (only that
.IR getpwnam (3) .IR getpwnam (3)
return the encrypted password is required), return the encrypted password is required),
but it is unlikely it will work for any most modern but it is unlikely it will work (as an ordinary user)
environments unless x11vnc is run as root to be able for most modern environments unless NIS is available.
to access /etc/shadow (note running as root is often On the other hand, when x11vnc is run as root it will
done when running x11vnc from inetd and xdm/gdm/kdm). be able to to access /etc/shadow even if NIS is not
available (note running as root is often done when
running x11vnc from inetd and xdm/gdm/kdm).
.IP .IP
Looked at another way, if you do not want to use the Looked at another way, if you do not want to use the
.IR su (1) .IR su (1)
method provided by \fB-unixpw,\fR you can run x11vnc method provided by \fB-unixpw\fR (i.e. su_verify()), you
as root and use \fB-unixpw_nis.\fR Any users with passwords can run x11vnc as root and use \fB-unixpw_nis.\fR Any users
in /etc/shadow can then be authenticated. You may want with passwords in /etc/shadow can then be authenticated.
to use \fB-users\fR unixpw= to switch the process user after .IP
the user logs in. In \fB-unixpw_nis\fR mode, under no circumstances is x11vnc's
user password verifying function based on su called
(i.e. the function su_verify() that runs /bin/su
in a pseudoterminal to verify passwords.) However,
if \fB-unixpw_nis\fR is used in conjunction with the \fB-find\fR
and \fB-create\fR \fB-display\fR WAIT:... modes then, if x11vnc is
running as root, /bin/su may be called externally to
run the find or create commands.
.PP .PP
\fB-unixpw_cmd\fR \fIcmd\fR \fB-unixpw_cmd\fR \fIcmd\fR
.IP .IP
...@@ -1051,18 +1061,66 @@ As \fB-unixpw\fR above, however do not use ...@@ -1051,18 +1061,66 @@ As \fB-unixpw\fR above, however do not use
.IR su (1) .IR su (1)
but rather but rather
run the externally supplied command \fIcmd\fR. The first run the externally supplied command \fIcmd\fR. The first
line of its stdin will the username and the second line line of its stdin will be the username and the second
the received password. If the command exits with status line the received password. If the command exits
0 (success) the VNC client will be accepted. It will be with status 0 (success) the VNC user will be accepted.
rejected for any other return status. It will be rejected for any other return status.
.IP .IP
Dynamic passwords and non-unix passwords can be Dynamic passwords and non-unix passwords, e.g. LDAP,
implemented this way by providing your own custom helper can be implemented this way by providing your own custom
program. Note that under unixpw mode the remote viewer helper program. Note that the remote viewer is given 3
is given 3 tries to enter the correct password. tries to enter the correct password, and so the program
.IP may be called in a row that many (or more) times.
If a list of allowed users is needed use \fB-unixpw\fR [list] .IP
in addition to this option. If a list of allowed users is needed to limit who can
log in, use \fB-unixpw\fR [list] in addition to this option.
.IP
In FINDDISPLAY and FINDCREATEDISPLAY modes the \fIcmd\fR
will also be run with the RFB_UNIXPW_CMD_RUN env. var.
non-empty and set to the corresponding display
find/create command. The first two lines of input are
the username and passwd as in the normal case described
above. To support FINDDISPLAY and FINDCREATEDISPLAY,
\fIcmd\fR should run the requested command as the user
(and most likely refusing to run it if the password is
not correct.) Here is an example script (note it has
a hardwired bogus password "abc"!)
.IP
#!/bin/sh
# Example x11vnc \fB-unixpw_cmd\fR script.
# Read the first two lines of stdin (user and passwd)
read user
read pass
.IP
debug=0
if [ $debug = 1 ]; then
echo "user: $user" 1>&2
echo "pass: $pass" 1>&2
env | egrep \fB-i\fR 'rfb|vnc' 1>&2
fi
.IP
# Check if the password is valid.
# (A real example would use ldap lookup, etc!)
if [ "X$pass" != "Xabc" ]; then
exit 1 # incorrect password
fi
.IP
if [ "X$RFB_UNIXPW_CMD_RUN" = "X" ]; then
exit 0 # correct password
else
# Run the requested command (finddisplay)
if [ $debug = 1 ]; then
echo "run: $RFB_UNIXPW_CMD_RUN" 1>&2
fi
exec /bin/su - "$user" \fB-c\fR "$RFB_UNIXPW_CMD_RUN"
fi
.IP
In \fB-unixpw_cmd\fR mode, under no circumstances is x11vnc's
user password verifying function based on su called
(i.e. the function su_verify() that runs /bin/su in a
pseudoterminal to verify passwords.) It is up to the
supplied unixpw_cmd to do user switching if desired
and if it has the permissions to do so.
.PP .PP
\fB-find\fR \fB-find\fR
.IP .IP
...@@ -1214,9 +1272,15 @@ xauthority data for the display. For example; ...@@ -1214,9 +1272,15 @@ xauthority data for the display. For example;
.IP .IP
xauth extract - $DISPLAY" xauth extract - $DISPLAY"
.IP .IP
In the case of \fB-unixpw\fR (but not \fB-unixpw_nis),\fR then the In the case of \fB-unixpw\fR (and \fB-unixpw_nis\fR only if x11vnc
cmd= command is run as the user who just authenticated is running as root), then the cmd= command is run
via the login and password prompt. as the user who just authenticated via the login and
password prompt.
.IP
In the case of \fB-unixpw_cmd,\fR the commands will also be
run as the logged-in user, as long as the user-supplied
helper program supports RFB_UNIXPW_CMD_RUN (see the
\fB-unixpw_cmd\fR option.)
.IP .IP
Also in the case of \fB-unixpw,\fR the user logging in can Also in the case of \fB-unixpw,\fR the user logging in can
place a colon at the end of her username and supply place a colon at the end of her username and supply
...@@ -5827,7 +5891,7 @@ max time in ms to wait for RFB client ...@@ -5827,7 +5891,7 @@ max time in ms to wait for RFB client
\fB-rfbauth\fR \fIpasswd-file\fR \fB-rfbauth\fR \fIpasswd-file\fR
.IP .IP
use authentication on RFB protocol use authentication on RFB protocol
(use 'storepasswd' to create a password file) (use 'x11vnc \fB-storepasswd\fR pass file' to create a password file)
.PP .PP
\fB-rfbversion\fR \fI3.x\fR \fB-rfbversion\fR \fI3.x\fR
.IP .IP
......
...@@ -2482,6 +2482,9 @@ int main(int argc, char* argv[]) { ...@@ -2482,6 +2482,9 @@ int main(int argc, char* argv[]) {
if (unixpw_list) { if (unixpw_list) {
unixpw_list = NULL; unixpw_list = NULL;
} }
if (unixpw_cmd) {
unixpw_cmd = NULL;
}
continue; continue;
} }
if (!strcmp(arg, "-vencrypt")) { if (!strcmp(arg, "-vencrypt")) {
......
...@@ -47,7 +47,7 @@ int xtrap_base_event_type = 0; ...@@ -47,7 +47,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0; int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */ /* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.9 lastmod: 2009-07-11"; char lastmod[] = "0.9.9 lastmod: 2009-08-10";
/* X display info */ /* X display info */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment